From 657de7b2f35d6d9396916341fb905d2605b74f93 Mon Sep 17 00:00:00 2001 From: tdakkota Date: Wed, 6 Jul 2022 10:14:23 +0300 Subject: [PATCH 1/8] feat(ogen): parse correct line number for YAML --- json/location.go | 10 +- ogen.go | 12 +- parse_error.go | 21 +-- parse_error_test.go | 13 +- schema.go | 150 +++++++++++++---- spec.go | 395 +++++++++++++++++++++++++++++++------------- 6 files changed, 428 insertions(+), 173 deletions(-) diff --git a/json/location.go b/json/location.go index 4527ccf89..cecef51a9 100644 --- a/json/location.go +++ b/json/location.go @@ -101,7 +101,10 @@ func (l Location) String() string { // Locatable is an interface for JSON value location store. type Locatable interface { - setLocation(Location) + // SetLocation sets the location of the value. + SetLocation(Location) + + // Location returns the location of the value if it is set. Location() (Location, bool) } @@ -111,7 +114,8 @@ type Locator struct { set bool } -func (l *Locator) setLocation(loc Location) { +// SetLocation sets the location of the value. +func (l *Locator) SetLocation(loc Location) { l.location = loc l.set = true } @@ -130,7 +134,7 @@ func LocationUnmarshaler(lines Lines) *json.Unmarshalers { offset := d.InputOffset() line, column, _ := lines.LineColumn(offset) - l.setLocation(Location{ + l.SetLocation(Location{ JSONPointer: d.StackPointer(), Offset: offset, Line: line, diff --git a/ogen.go b/ogen.go index 6a7a13068..11d52f298 100644 --- a/ogen.go +++ b/ogen.go @@ -2,7 +2,6 @@ package ogen import ( - "github.com/ghodss/yaml" "github.com/go-faster/errors" "github.com/go-faster/jx" ) @@ -11,14 +10,13 @@ import ( func Parse(data []byte) (s *Spec, err error) { s = &Spec{} if !jx.Valid(data) { - d, err := yaml.YAMLToJSON(data) - if err != nil { + if err := unmarshalYAML(data, s); err != nil { return nil, errors.Wrap(err, "yaml") } - data = d - } - if err := unmarshal(data, s); err != nil { - return nil, errors.Wrap(err, "json") + } else { + if err := unmarshalJSON(data, s); err != nil { + return nil, errors.Wrap(err, "json") + } } return s, nil } diff --git a/parse_error.go b/parse_error.go index 0ae524cfb..1a7bc39c6 100644 --- a/parse_error.go +++ b/parse_error.go @@ -3,11 +3,16 @@ package ogen import ( "github.com/go-faster/errors" "github.com/go-json-experiment/json" + "gopkg.in/yaml.v3" ogenjson "github.com/ogen-go/ogen/json" ) -func unmarshal(data []byte, out any) error { +func unmarshalYAML(data []byte, out any) error { + return yaml.Unmarshal(data, out) +} + +func unmarshalJSON(data []byte, out any) error { var lines ogenjson.Lines lines.Collect(data) @@ -23,15 +28,11 @@ func unmarshal(data []byte, out any) error { } if err := opts.Unmarshal(json.DecodeOptions{}, data, out); err != nil { - return wrapLineOffset(begin, lines, err) + line, column, ok := lines.LineColumn(begin) + if !ok { + return err + } + return errors.Wrapf(err, "line %d:%d", line, column) } return nil } - -func wrapLineOffset(offset int64, lines ogenjson.Lines, err error) error { - line, column, ok := lines.LineColumn(offset) - if !ok { - return err - } - return errors.Wrapf(err, "line %d:%d", line, column) -} diff --git a/parse_error_test.go b/parse_error_test.go index 3a86f87f1..29a23fbba 100644 --- a/parse_error_test.go +++ b/parse_error_test.go @@ -1,14 +1,17 @@ package ogen import ( + _ "embed" "fmt" "strings" "testing" "github.com/stretchr/testify/require" + + ogenjson "github.com/ogen-go/ogen/json" ) -func Test_wrapLineOffset(t *testing.T) { +func Test_unmarshalJSON(t *testing.T) { const testdata = `{ "openapi": "3.1.0", "info": { @@ -32,7 +35,7 @@ func Test_wrapLineOffset(t *testing.T) { }` ubool := func(input []byte) error { var target bool - return unmarshal(input, &target) + return unmarshalJSON(input, &target) } tests := []struct { input string @@ -55,17 +58,17 @@ func Test_wrapLineOffset(t *testing.T) { A int `json:"a"` B bool `json:"b"` } - return unmarshal(input, &target) + return unmarshalJSON(input, &target) }, 3, 6}, {"[\n0,\ntrue\n]", func(input []byte) error { var target []int - return unmarshal(input, &target) + return unmarshalJSON(input, &target) }, 3, 1}, {testdata, func(input []byte) error { var target *Spec - return unmarshal(input, &target) + return unmarshalJSON(input, &target) }, 15, 25}, } for i, tt := range tests { diff --git a/schema.go b/schema.go index eeea68527..7845506d4 100644 --- a/schema.go +++ b/schema.go @@ -5,49 +5,52 @@ import ( "github.com/go-faster/errors" "github.com/go-json-experiment/json" + "gopkg.in/yaml.v3" + + ogenjson "github.com/ogen-go/ogen/json" ) // The Schema Object allows the definition of input and output data types. // These types can be objects, but also primitives and arrays. type Schema struct { - Ref string `json:"$ref,omitzero"` // ref object - Summary string `json:"summary,omitzero"` - Description string `json:"description,omitzero"` + Ref string `json:"$ref,omitzero" yaml:"$ref,omitempty"` // ref object + Summary string `json:"summary,omitzero" yaml:"summary,omitempty"` + Description string `json:"description,omitzero" yaml:"description,omitempty"` // Additional external documentation for this schema. - ExternalDocs *ExternalDocumentation `json:"externalDocs,omitzero"` + ExternalDocs *ExternalDocumentation `json:"externalDocs,omitzero" yaml:"externalDocs,omitempty"` // Value MUST be a string. Multiple types via an array are not supported. - Type string `json:"type,omitzero"` + Type string `json:"type,omitzero" yaml:"type,omitempty"` // See Data Type Formats for further details (https://swagger.io/specification/#data-type-format). // While relying on JSON Schema's defined formats, // the OAS offers a few additional predefined formats. - Format string `json:"format,omitzero"` + Format string `json:"format,omitzero" yaml:"format,omitempty"` // Property definitions MUST be a Schema Object and not a standard JSON Schema // (inline or referenced). - Properties Properties `json:"properties,omitzero"` + Properties Properties `json:"properties,omitzero" yaml:"properties,omitempty"` // Value can be boolean or object. Inline or referenced schema MUST be of a Schema Object // and not a standard JSON Schema. Consistent with JSON Schema, additionalProperties defaults to true. - AdditionalProperties *AdditionalProperties `json:"additionalProperties,omitzero"` + AdditionalProperties *AdditionalProperties `json:"additionalProperties,omitzero" yaml:"additionalProperties,omitempty"` // The value of "patternProperties" MUST be an object. Each property // name of this object SHOULD be a valid regular expression, according // to the ECMA-262 regular expression dialect. Each property value of // this object MUST be a valid JSON Schema. - PatternProperties PatternProperties `json:"patternProperties,omitzero"` + PatternProperties PatternProperties `json:"patternProperties,omitzero" yaml:"patternProperties,omitempty"` // The value of this keyword MUST be an array. // This array MUST have at least one element. // Elements of this array MUST be strings, and MUST be unique. - Required []string `json:"required,omitzero"` + Required []string `json:"required,omitzero" yaml:"required,omitempty"` // Value MUST be an object and not an array. // Inline or referenced schema MUST be of a Schema Object and not a standard JSON Schema. // MUST be present if the Type is "array". - Items *Schema `json:"items,omitzero"` + Items *Schema `json:"items,omitzero" yaml:"items,omitempty"` // A true value adds "null" to the allowed type specified by the type keyword, // only if type is explicitly defined within the same Schema Object. @@ -55,33 +58,33 @@ type Schema struct { // and therefore may disallow the use of null as a value. // A false value leaves the specified or default type unmodified. // The default value is false. - Nullable bool `json:"nullable,omitzero"` + Nullable bool `json:"nullable,omitzero" yaml:"nullable,omitempty"` // AllOf takes an array of object definitions that are used // for independent validation but together compose a single object. // Still, it does not imply a hierarchy between the models. // For that purpose, you should include the discriminator. - AllOf []*Schema `json:"allOf,omitzero"` // TODO: implement. + AllOf []*Schema `json:"allOf,omitzero"` // TODO: implement yaml:"allOf,omitempty"` // TODO: implement. // OneOf validates the value against exactly one of the subschemas - OneOf []*Schema `json:"oneOf,omitzero"` + OneOf []*Schema `json:"oneOf,omitzero" yaml:"oneOf,omitempty"` // AnyOf validates the value against any (one or more) of the subschemas - AnyOf []*Schema `json:"anyOf,omitzero"` + AnyOf []*Schema `json:"anyOf,omitzero" yaml:"anyOf,omitempty"` // Discriminator for subschemas. - Discriminator *Discriminator `json:"discriminator,omitzero"` + Discriminator *Discriminator `json:"discriminator,omitzero" yaml:"discriminator,omitempty"` // The value of this keyword MUST be an array. // This array SHOULD have at least one element. // Elements in the array SHOULD be unique. - Enum Enum `json:"enum,omitzero"` + Enum Enum `json:"enum,omitzero" yaml:"enum,omitempty"` // The value of "multipleOf" MUST be a number, strictly greater than 0. // // A numeric instance is only valid if division by this keyword's value // results in an integer. - MultipleOf Num `json:"multipleOf,omitzero"` + MultipleOf Num `json:"multipleOf,omitzero" yaml:"multipleOf,omitempty"` // The value of "maximum" MUST be a number, representing an upper limit // for a numeric instance. @@ -90,7 +93,7 @@ type Schema struct { // "exclusiveMaximum" is true and instance is less than the provided // value, or else if the instance is less than or exactly equal to the // provided value. - Maximum Num `json:"maximum,omitzero"` + Maximum Num `json:"maximum,omitzero" yaml:"maximum,omitempty"` // The value of "exclusiveMaximum" MUST be a boolean, representing // whether the limit in "maximum" is exclusive or not. An undefined @@ -100,7 +103,7 @@ type Schema struct { // equal to the value specified in "maximum". If "exclusiveMaximum" is // false (or not specified), then a numeric instance MAY be equal to the // value of "maximum". - ExclusiveMaximum bool `json:"exclusiveMaximum,omitzero"` + ExclusiveMaximum bool `json:"exclusiveMaximum,omitzero" yaml:"exclusiveMaximum,omitempty"` // The value of "minimum" MUST be a number, representing a lower limit // for a numeric instance. @@ -109,7 +112,7 @@ type Schema struct { // "exclusiveMinimum" is true and instance is greater than the provided // value, or else if the instance is greater than or exactly equal to // the provided value. - Minimum Num `json:"minimum,omitzero"` + Minimum Num `json:"minimum,omitzero" yaml:"minimum,omitempty"` // The value of "exclusiveMinimum" MUST be a boolean, representing // whether the limit in "minimum" is exclusive or not. An undefined @@ -119,7 +122,7 @@ type Schema struct { // equal to the value specified in "minimum". If "exclusiveMinimum" is // false (or not specified), then a numeric instance MAY be equal to the // value of "minimum". - ExclusiveMinimum bool `json:"exclusiveMinimum,omitzero"` + ExclusiveMinimum bool `json:"exclusiveMinimum,omitzero" yaml:"exclusiveMinimum,omitempty"` // The value of this keyword MUST be a non-negative integer. // @@ -131,7 +134,7 @@ type Schema struct { // // The length of a string instance is defined as the number of its // characters as defined by RFC 7159 [RFC7159]. - MaxLength *uint64 `json:"maxLength,omitzero"` + MaxLength *uint64 `json:"maxLength,omitzero" yaml:"maxLength,omitempty"` // A string instance is valid against this keyword if its length is // greater than, or equal to, the value of this keyword. @@ -144,7 +147,7 @@ type Schema struct { // // "minLength", if absent, may be considered as being present with // integer value 0. - MinLength *uint64 `json:"minLength,omitzero"` + MinLength *uint64 `json:"minLength,omitzero" yaml:"minLength,omitempty"` // The value of this keyword MUST be a string. This string SHOULD be a // valid regular expression, according to the ECMA 262 regular @@ -153,14 +156,14 @@ type Schema struct { // A string instance is considered valid if the regular expression // matches the instance successfully. Recall: regular expressions are // not implicitly anchored. - Pattern string `json:"pattern,omitzero"` + Pattern string `json:"pattern,omitzero" yaml:"pattern,omitempty"` // The value of this keyword MUST be an integer. This integer MUST be // greater than, or equal to, 0. // // An array instance is valid against "maxItems" if its size is less // than, or equal to, the value of this keyword. - MaxItems *uint64 `json:"maxItems,omitzero"` + MaxItems *uint64 `json:"maxItems,omitzero" yaml:"maxItems,omitempty"` // The value of this keyword MUST be an integer. This integer MUST be // greater than, or equal to, 0. @@ -170,7 +173,7 @@ type Schema struct { // // If this keyword is not present, it may be considered present with a // value of 0. - MinItems *uint64 `json:"minItems,omitzero"` + MinItems *uint64 `json:"minItems,omitzero" yaml:"minItems,omitempty"` // The value of this keyword MUST be a boolean. // @@ -180,14 +183,14 @@ type Schema struct { // // If not present, this keyword may be considered present with boolean // value false. - UniqueItems bool `json:"uniqueItems,omitzero"` + UniqueItems bool `json:"uniqueItems,omitzero" yaml:"uniqueItems,omitempty"` // The value of this keyword MUST be an integer. This integer MUST be // greater than, or equal to, 0. // // An object instance is valid against "maxProperties" if its number of // properties is less than, or equal to, the value of this keyword. - MaxProperties *uint64 `json:"maxProperties,omitzero"` + MaxProperties *uint64 `json:"maxProperties,omitzero" yaml:"maxProperties,omitempty"` // The value of this keyword MUST be an integer. This integer MUST be // greater than, or equal to, 0. @@ -197,19 +200,19 @@ type Schema struct { // // If this keyword is not present, it may be considered present with a // value of 0. - MinProperties *uint64 `json:"minProperties,omitzero"` + MinProperties *uint64 `json:"minProperties,omitzero" yaml:"minProperties,omitempty"` // Default value. - Default json.RawValue `json:"default,omitzero"` + Default json.RawValue `json:"default,omitzero" yaml:"default,omitempty"` // A free-form property to include an example of an instance for this schema. // To represent examples that cannot be naturally represented in JSON or YAML, // a string value can be used to contain the example with escaping where necessary. - Example json.RawValue `json:"example,omitzero"` + Example json.RawValue `json:"example,omitzero" yaml:"example,omitempty"` // Specifies that a schema is deprecated and SHOULD be transitioned out // of usage. - Deprecated bool `json:"deprecated,omitzero"` + Deprecated bool `json:"deprecated,omitzero" yaml:"deprecated,omitempty"` // If the instance value is a string, this property defines that the // string SHOULD be interpreted as binary data and decoded using the @@ -220,7 +223,7 @@ type Schema struct { // // The value of this property SHOULD be ignored if the instance // described is not a string. - ContentEncoding string `json:"contentEncoding,omitzero"` + ContentEncoding string `json:"contentEncoding,omitzero" yaml:"contentEncoding,omitempty"` // The value of this property must be a media type, as defined by RFC // 2046. This property defines the media type of instances @@ -230,9 +233,28 @@ type Schema struct { // // The value of this property SHOULD be ignored if the instance // described is not a string. - ContentMediaType string `json:"contentMediaType,omitzero"` + ContentMediaType string `json:"contentMediaType,omitzero" yaml:"contentMediaType,omitempty"` + + Locator `json:"-" yaml:"-"` +} + +// UnmarshalYAML implements yaml.Unmarshaler. +func (s *Schema) UnmarshalYAML(n *yaml.Node) error { + type Alias Schema + var a Alias - Locator `json:"-"` + if err := n.Decode(&a); err != nil { + return err + } + a.SetLocation(ogenjson.Location{ + // FIXME(tdakkota): For some reason, the line number is off by 1. + // And the column number is off by 2. + Line: int64(n.Line) - 1, + Column: int64(n.Column) - 2, + }) + + *s = Schema(a) + return nil } // Property is item of Properties. @@ -305,6 +327,28 @@ func (p *Properties) UnmarshalNextJSON(opts json.UnmarshalOptions, d *json.Decod return nil } +// UnmarshalYAML implements yaml.Unmarshaler. +func (p *Properties) UnmarshalYAML(node *yaml.Node) error { + if node.Kind != yaml.MappingNode { + return errors.Errorf("unexpected YAML kind %v", node.Kind) + } + for i := 0; i < len(node.Content); i += 2 { + var ( + key = node.Content[i] + value = node.Content[i+1] + schema *Schema + ) + if err := value.Decode(&schema); err != nil { + return err + } + *p = append(*p, Property{ + Name: key.Value, + Schema: schema, + }) + } + return nil +} + // AdditionalProperties is JSON Schema additionalProperties validator description. type AdditionalProperties struct { Bool *bool @@ -338,6 +382,18 @@ func (p *AdditionalProperties) UnmarshalNextJSON(opts json.UnmarshalOptions, d * } } +// UnmarshalYAML implements yaml.Unmarshaler. +func (p *AdditionalProperties) UnmarshalYAML(node *yaml.Node) error { + switch node.Kind { + case yaml.ScalarNode: + return node.Decode(&p.Bool) + case yaml.MappingNode: + return node.Decode(&p.Schema) + default: + return errors.Errorf("unexpected YAML kind %v", node.Kind) + } +} + // PatternProperty is item of PatternProperties. type PatternProperty struct { Pattern string @@ -407,3 +463,25 @@ func (p *PatternProperties) UnmarshalNextJSON(opts json.UnmarshalOptions, d *jso *p = patternProperties return nil } + +// UnmarshalYAML implements yaml.Unmarshaler. +func (p *PatternProperties) UnmarshalYAML(node *yaml.Node) error { + if node.Kind != yaml.MappingNode { + return errors.Errorf("unexpected YAML kind %v", node.Kind) + } + for i := 0; i < len(node.Content); i += 2 { + var ( + key = node.Content[i] + value = node.Content[i+1] + schema *Schema + ) + if err := value.Decode(&schema); err != nil { + return err + } + *p = append(*p, PatternProperty{ + Pattern: key.Value, + Schema: schema, + }) + } + return nil +} diff --git a/spec.go b/spec.go index a07d4b6cb..8ab2fbc19 100644 --- a/spec.go +++ b/spec.go @@ -3,6 +3,7 @@ package ogen import ( "github.com/go-faster/errors" "github.com/go-json-experiment/json" + "gopkg.in/yaml.v3" ogenjson "github.com/ogen-go/ogen/json" "github.com/ogen-go/ogen/jsonschema" @@ -21,25 +22,25 @@ type ( type Spec struct { // This string MUST be the semantic version number // of the OpenAPI Specification version that the OpenAPI document uses. - OpenAPI string `json:"openapi"` - Info Info `json:"info"` - Servers []Server `json:"servers,omitzero"` - Paths Paths `json:"paths,omitzero"` - Components *Components `json:"components,omitzero"` - Security SecurityRequirements `json:"security,omitzero"` + OpenAPI string `json:"openapi" yaml:"openapi"` + Info Info `json:"info" yaml:"info"` + Servers []Server `json:"servers,omitzero" yaml:"servers,omitempty"` + Paths Paths `json:"paths,omitzero" yaml:"paths,omitempty"` + Components *Components `json:"components,omitzero" yaml:"components,omitempty"` + Security SecurityRequirements `json:"security,omitzero" yaml:"security,omitempty"` // A list of tags used by the specification with additional metadata. // The order of the tags can be used to reflect on their order by the parsing // tools. Not all tags that are used by the Operation Object must be declared. // The tags that are not declared MAY be organized randomly or based on the tools' logic. // Each tag name in the list MUST be unique. - Tags []Tag `json:"tags,omitzero"` + Tags []Tag `json:"tags,omitzero" yaml:"tags,omitempty"` // Additional external documentation. - ExternalDocs *ExternalDocumentation `json:"externalDocs,omitzero"` + ExternalDocs *ExternalDocumentation `json:"externalDocs,omitzero" yaml:"externalDocs,omitempty"` // Raw JSON value. Used by JSON Schema resolver. - Raw json.RawValue `json:"-"` + Raw json.RawValue `json:"-" yaml:"-"` } // UnmarshalNextJSON implements json.UnmarshalerV2. @@ -72,22 +73,41 @@ func (s *Spec) Init() { // // https://swagger.io/specification/#example-object type Example struct { - Ref string `json:"$ref,omitzero"` // ref object - Summary string `json:"summary,omitzero"` - Description string `json:"description,omitzero"` - Value json.RawValue `json:"value,omitzero"` - ExternalValue string `json:"externalValue,omitzero"` + Ref string `json:"$ref,omitzero"` // ref objec yaml:"$ref,omitempty"` // ref object + Summary string `json:"summary,omitzero" yaml:"summary,omitempty"` + Description string `json:"description,omitzero" yaml:"description,omitempty"` + Value json.RawValue `json:"value,omitzero" yaml:"value,omitempty"` + ExternalValue string `json:"externalValue,omitzero" yaml:"externalValue,omitempty"` - Locator `json:"-"` + Locator `json:"-" yaml:"-"` +} + +// UnmarshalYAML implements yaml.Unmarshaler. +func (e *Example) UnmarshalYAML(n *yaml.Node) error { + type Alias Example + var a Alias + + if err := n.Decode(&a); err != nil { + return err + } + a.SetLocation(ogenjson.Location{ + // FIXME(tdakkota): For some reason, the line number is off by 1. + // And the column number is off by 2. + Line: int64(n.Line) - 1, + Column: int64(n.Column) - 2, + }) + + *e = Example(a) + return nil } // Tag object. // // https://swagger.io/specification/#tag-object type Tag struct { - Name string `json:"name"` - Description string `json:"description,omitzero"` - ExternalDocs *ExternalDocumentation `json:"externalDocs,omitzero"` + Name string `json:"name" yaml:"name"` + Description string `json:"description,omitzero" yaml:"description,omitempty"` + ExternalDocs *ExternalDocumentation `json:"externalDocs,omitzero" yaml:"externalDocs,omitempty"` } // Info provides metadata about the API. @@ -96,33 +116,33 @@ type Tag struct { // and MAY be presented in editing or documentation generation tools for convenience. type Info struct { // REQUIRED. The title of the API. - Title string `json:"title"` + Title string `json:"title" yaml:"title"` // A short summary of the API. - Summary string `json:"summary,omitzero"` + Summary string `json:"summary,omitzero" yaml:"summary,omitempty"` // A short description of the API. // CommonMark syntax MAY be used for rich text representation. - Description string `json:"description,omitzero"` + Description string `json:"description,omitzero" yaml:"description,omitempty"` // A URL to the Terms of Service for the API. MUST be in the format of a URL. - TermsOfService string `json:"termsOfService,omitzero"` + TermsOfService string `json:"termsOfService,omitzero" yaml:"termsOfService,omitempty"` // The contact information for the exposed API. - Contact *Contact `json:"contact,omitzero"` + Contact *Contact `json:"contact,omitzero" yaml:"contact,omitempty"` // The license information for the exposed API. - License *License `json:"license,omitzero"` + License *License `json:"license,omitzero" yaml:"license,omitempty"` // REQUIRED. The version of the OpenAPI document. - Version string `json:"version"` + Version string `json:"version" yaml:"version"` } // Contact information for the exposed API. type Contact struct { - Name string `json:"name,omitzero"` - URL string `json:"url,omitzero"` - Email string `json:"email,omitzero"` + Name string `json:"name,omitzero" yaml:"name,omitempty"` + URL string `json:"url,omitzero" yaml:"url,omitempty"` + Email string `json:"email,omitzero" yaml:"email,omitempty"` } // License information for the exposed API. type License struct { - Name string `json:"name,omitzero"` - URL string `json:"url,omitzero"` + Name string `json:"name,omitzero" yaml:"name,omitempty"` + URL string `json:"url,omitzero" yaml:"url,omitempty"` } // Server represents a Server. @@ -130,12 +150,12 @@ type Server struct { // REQUIRED. A URL to the target host. This URL supports Server Variables and MAY be relative, // to indicate that the host location is relative to the location where the OpenAPI document is being served. // Variable substitutions will be made when a variable is named in {brackets}. - URL string `json:"url"` + URL string `json:"url" yaml:"url"` // An optional string describing the host designated by the URL. // CommonMark syntax MAY be used for rich text representation. - Description string `json:"description,omitzero"` + Description string `json:"description,omitzero" yaml:"description,omitempty"` // A map between a variable name and its value. The value is used for substitution in the server's URL template. - Variables map[string]ServerVariable `json:"variables,omitzero"` + Variables map[string]ServerVariable `json:"variables,omitzero" yaml:"variables,omitempty"` } // ServerVariable describes an object representing a Server Variable for server URL template substitution. @@ -143,38 +163,38 @@ type ServerVariable struct { // An enumeration of string values to be used if the substitution options are from a limited set. // // The array MUST NOT be empty. - Enum []string `json:"enum,omitzero"` + Enum []string `json:"enum,omitzero" yaml:"enum,omitempty"` // REQUIRED. The default value to use for substitution, which SHALL be sent if an alternate value is not supplied. // Note this behavior is different than the Schema Object’s treatment of default values, because in those // cases parameter values are optional. If the enum is defined, the value MUST exist in the enum’s values. - Default string `json:"default"` + Default string `json:"default" yaml:"default"` // An optional description for the server variable. CommonMark syntax MAY be used for rich text representation. - Description string `json:"description,omitzero"` + Description string `json:"description,omitzero" yaml:"description,omitempty"` } // ExternalDocumentation describes a reference to external resource for extended documentation. type ExternalDocumentation struct { // A description of the target documentation. CommonMark syntax MAY be used for rich text representation. - Description string `json:"description,omitzero"` + Description string `json:"description,omitzero" yaml:"description,omitempty"` // REQUIRED. The URL for the target documentation. This MUST be in the form of a URL. - URL string `json:"url"` + URL string `json:"url" yaml:"url"` } // Components hold a set of reusable objects for different aspects of the OAS. // All objects defined within the components object will have no effect on the API // unless they are explicitly referenced from properties outside the components object. type Components struct { - Schemas map[string]*Schema `json:"schemas,omitzero"` - Responses map[string]*Response `json:"responses,omitzero"` - Parameters map[string]*Parameter `json:"parameters,omitzero"` - Examples map[string]*Example `json:"examples,omitzero"` - RequestBodies map[string]*RequestBody `json:"requestBodies,omitzero"` - Headers map[string]*Header `json:"headers,omitzero"` - SecuritySchemes map[string]*SecurityScheme `json:"securitySchemes,omitzero"` - // Links map[string]Link `json:"links"` - // Callbacks map[string]Callback `json:"callback"` - - Locator `json:"-"` + Schemas map[string]*Schema `json:"schemas,omitzero" yaml:"schemas,omitempty"` + Responses map[string]*Response `json:"responses,omitzero" yaml:"responses,omitempty"` + Parameters map[string]*Parameter `json:"parameters,omitzero" yaml:"parameters,omitempty"` + Examples map[string]*Example `json:"examples,omitzero" yaml:"examples,omitempty"` + RequestBodies map[string]*RequestBody `json:"requestBodies,omitzero" yaml:"requestBodies,omitempty"` + Headers map[string]*Header `json:"headers,omitzero" yaml:"headers,omitempty"` + SecuritySchemes map[string]*SecurityScheme `json:"securitySchemes,omitzero" yaml:"securitySchemes,omitempty"` + // Links map[string]Link `json:"links" yaml:"links"` + // Callbacks map[string]Callback `json:"callback" yaml:"callback"` + + Locator `json:"-" yaml:"-"` } // Init initializes all fields. @@ -205,6 +225,25 @@ func (c *Components) Init() { } } +// UnmarshalYAML implements yaml.Unmarshaler. +func (c *Components) UnmarshalYAML(n *yaml.Node) error { + type Alias Components + var a Alias + + if err := n.Decode(&a); err != nil { + return err + } + a.SetLocation(ogenjson.Location{ + // FIXME(tdakkota): For some reason, the line number is off by 1. + // And the column number is off by 2. + Line: int64(n.Line) - 1, + Column: int64(n.Column) - 2, + }) + + *c = Components(a) + return nil +} + // Paths holds the relative paths to the individual endpoints and their operations. // The path is appended to the URL from the Server Object in order to construct the full URL. // The Paths MAY be empty, due to ACL constraints. @@ -219,62 +258,100 @@ type PathItem struct { // The referenced structure MUST be in the format of a Path Item Object. // In case a Path Item Object field appears both // in the defined object and the referenced object, the behavior is undefined. - Ref string `json:"$ref,omitzero"` - Summary string `json:"summary,omitzero"` - Description string `json:"description,omitzero"` - Get *Operation `json:"get,omitzero"` - Put *Operation `json:"put,omitzero"` - Post *Operation `json:"post,omitzero"` - Delete *Operation `json:"delete,omitzero"` - Options *Operation `json:"options,omitzero"` - Head *Operation `json:"head,omitzero"` - Patch *Operation `json:"patch,omitzero"` - Trace *Operation `json:"trace,omitzero"` - Servers []Server `json:"servers,omitzero"` - Parameters []*Parameter `json:"parameters,omitzero"` - - Locator `json:"-"` + Ref string `json:"$ref,omitzero" yaml:"$ref,omitempty"` + Summary string `json:"summary,omitzero" yaml:"summary,omitempty"` + Description string `json:"description,omitzero" yaml:"description,omitempty"` + Get *Operation `json:"get,omitzero" yaml:"get,omitempty"` + Put *Operation `json:"put,omitzero" yaml:"put,omitempty"` + Post *Operation `json:"post,omitzero" yaml:"post,omitempty"` + Delete *Operation `json:"delete,omitzero" yaml:"delete,omitempty"` + Options *Operation `json:"options,omitzero" yaml:"options,omitempty"` + Head *Operation `json:"head,omitzero" yaml:"head,omitempty"` + Patch *Operation `json:"patch,omitzero" yaml:"patch,omitempty"` + Trace *Operation `json:"trace,omitzero" yaml:"trace,omitempty"` + Servers []Server `json:"servers,omitzero" yaml:"servers,omitempty"` + Parameters []*Parameter `json:"parameters,omitzero" yaml:"parameters,omitempty"` + + Locator `json:"-" yaml:"-"` +} + +// UnmarshalYAML implements yaml.Unmarshaler. +func (p *PathItem) UnmarshalYAML(n *yaml.Node) error { + type Alias PathItem + var a Alias + + if err := n.Decode(&a); err != nil { + return err + } + a.SetLocation(ogenjson.Location{ + // FIXME(tdakkota): For some reason, the line number is off by 1. + // And the column number is off by 2. + Line: int64(n.Line) - 1, + Column: int64(n.Column) - 2, + }) + + *p = PathItem(a) + return nil } // Operation describes a single API operation on a path. type Operation struct { - OperationID string `json:"operationId,omitzero"` - Security SecurityRequirements `json:"security,omitzero"` - Parameters []*Parameter `json:"parameters,omitzero"` - RequestBody *RequestBody `json:"requestBody,omitzero"` - Responses Responses `json:"responses,omitzero"` + OperationID string `json:"operationId,omitzero" yaml:"operationId,omitempty"` + Security SecurityRequirements `json:"security,omitzero" yaml:"security,omitempty"` + Parameters []*Parameter `json:"parameters,omitzero" yaml:"parameters,omitempty"` + RequestBody *RequestBody `json:"requestBody,omitzero" yaml:"requestBody,omitempty"` + Responses Responses `json:"responses,omitzero" yaml:"responses,omitempty"` // A list of tags for API documentation control. // Tags can be used for logical grouping of operations by resources or any other qualifier. - Tags []string `json:"tags,omitzero"` - Summary string `json:"summary,omitzero"` - Description string `json:"description,omitzero"` - ExternalDocs *ExternalDocumentation `json:"externalDocs,omitzero"` - Deprecated bool `json:"deprecated,omitzero"` + Tags []string `json:"tags,omitzero" yaml:"tags,omitempty"` + Summary string `json:"summary,omitzero" yaml:"summary,omitempty"` + Description string `json:"description,omitzero" yaml:"description,omitempty"` + ExternalDocs *ExternalDocumentation `json:"externalDocs,omitzero" yaml:"externalDocs,omitempty"` + Deprecated bool `json:"deprecated,omitzero" yaml:"deprecated,omitempty"` + + Locator `json:"-" yaml:"-"` +} + +// UnmarshalYAML implements yaml.Unmarshaler. +func (o *Operation) UnmarshalYAML(n *yaml.Node) error { + type Alias Operation + var a Alias - Locator `json:"-"` + if err := n.Decode(&a); err != nil { + return err + } + a.SetLocation(ogenjson.Location{ + // FIXME(tdakkota): For some reason, the line number is off by 1. + // And the column number is off by 2. + Line: int64(n.Line) - 1, + Column: int64(n.Column) - 2, + }) + + *o = Operation(a) + return nil } // Parameter describes a single operation parameter. // A unique parameter is defined by a combination of a name and location. type Parameter struct { - Ref string `json:"$ref,omitzero"` - Name string `json:"name"` + Ref string `json:"$ref,omitzero" yaml:"$ref,omitempty"` + Name string `json:"name" yaml:"name"` // The location of the parameter. Possible values are "query", "header", "path" or "cookie". - In string `json:"in"` - Description string `json:"description,omitzero"` - Schema *Schema `json:"schema,omitzero"` + In string `json:"in" yaml:"in"` + Description string `json:"description,omitzero" yaml:"description,omitempty"` + Schema *Schema `json:"schema,omitzero" yaml:"schema,omitempty"` // Determines whether this parameter is mandatory. // If the parameter location is "path", this property is REQUIRED // and its value MUST be true. // Otherwise, the property MAY be included and its default value is false. - Required bool `json:"required,omitzero"` + Required bool `json:"required,omitzero" yaml:"required,omitempty"` // Specifies that a parameter is deprecated and SHOULD be transitioned out of usage. // Default value is false. - Deprecated bool `json:"deprecated,omitzero"` + Deprecated bool `json:"deprecated,omitzero" yaml:"deprecated,omitempty"` // For more complex scenarios, the content property can define the media type and schema of the parameter. // A parameter MUST contain either a schema property, or a content property, but not both. @@ -284,39 +361,76 @@ type Parameter struct { // A map containing the representations for the parameter. // The key is the media type and the value describes it. // The map MUST only contain one entry. - Content map[string]Media `json:"content,omitzero"` + Content map[string]Media `json:"content,omitzero" yaml:"content,omitempty"` // Describes how the parameter value will be serialized // depending on the type of the parameter value. - Style string `json:"style,omitzero"` + Style string `json:"style,omitzero" yaml:"style,omitempty"` // When this is true, parameter values of type array or object // generate separate parameters for each value of the array // or key-value pair of the map. // For other types of parameters this property has no effect. - Explode *bool `json:"explode,omitzero"` + Explode *bool `json:"explode,omitzero" yaml:"explode,omitempty"` + + Example json.RawValue `json:"example,omitzero" yaml:"example,omitempty"` + Examples map[string]*Example `json:"examples,omitzero" yaml:"examples,omitempty"` + + Locator `json:"-" yaml:"-"` +} + +// UnmarshalYAML implements yaml.Unmarshaler. +func (p *Parameter) UnmarshalYAML(n *yaml.Node) error { + type Alias Parameter + var a Alias - Example json.RawValue `json:"example,omitzero"` - Examples map[string]*Example `json:"examples,omitzero"` + if err := n.Decode(&a); err != nil { + return err + } + // FIXME(tdakkota): For some reason, go-yaml parses array line-column correctly. + a.SetLocation(ogenjson.Location{ + Line: int64(n.Line), + Column: int64(n.Column), + }) - Locator `json:"-"` + *p = Parameter(a) + return nil } // RequestBody describes a single request body. type RequestBody struct { - Ref string `json:"$ref,omitzero"` - Description string `json:"description,omitzero"` + Ref string `json:"$ref,omitzero" yaml:"$ref,omitempty"` + Description string `json:"description,omitzero" yaml:"description,omitempty"` // The content of the request body. // The key is a media type or media type range and the value describes it. // For requests that match multiple keys, only the most specific key is applicable. // e.g. text/plain overrides text/* - Content map[string]Media `json:"content,omitzero"` + Content map[string]Media `json:"content,omitzero" yaml:"content,omitempty"` // Determines if the request body is required in the request. Defaults to false. - Required bool `json:"required,omitzero"` + Required bool `json:"required,omitzero" yaml:"required,omitempty"` + + Locator `json:"-" yaml:"-"` +} + +// UnmarshalYAML implements yaml.Unmarshaler. +func (r *RequestBody) UnmarshalYAML(n *yaml.Node) error { + type Alias RequestBody + var a Alias - Locator `json:"-"` + if err := n.Decode(&a); err != nil { + return err + } + a.SetLocation(ogenjson.Location{ + // FIXME(tdakkota): For some reason, the line number is off by 1. + // And the column number is off by 2. + Line: int64(n.Line) - 1, + Column: int64(n.Column) - 2, + }) + + *r = RequestBody(a) + return nil } // Responses is a container for the expected responses of an operation. @@ -326,13 +440,32 @@ type Responses map[string]*Response // Response describes a single response from an API Operation, // including design-time, static links to operations based on the response. type Response struct { - Ref string `json:"$ref,omitzero"` - Description string `json:"description,omitzero"` - Headers map[string]*Header `json:"headers,omitzero"` - Content map[string]Media `json:"content,omitzero"` - Links map[string]interface{} `json:"links,omitzero"` // TODO: implement + Ref string `json:"$ref,omitzero" yaml:"$ref,omitempty"` + Description string `json:"description,omitzero" yaml:"description,omitempty"` + Headers map[string]*Header `json:"headers,omitzero" yaml:"headers,omitempty"` + Content map[string]Media `json:"content,omitzero" yaml:"content,omitempty"` + Links map[string]interface{} `json:"links,omitzero" yaml:"links,omitempty"` // TODO: implement + + Locator `json:"-" yaml:"-"` +} + +// UnmarshalYAML implements yaml.Unmarshaler. +func (r *Response) UnmarshalYAML(n *yaml.Node) error { + type Alias Response + var a Alias - Locator `json:"-"` + if err := n.Decode(&a); err != nil { + return err + } + a.SetLocation(ogenjson.Location{ + // FIXME(tdakkota): For some reason, the line number is off by 1. + // And the column number is off by 2. + Line: int64(n.Line) - 1, + Column: int64(n.Column) - 2, + }) + + *r = Response(a) + return nil } // Header describes header response. @@ -348,49 +481,87 @@ type Header = Parameter // Media provides schema and examples for the media type identified by its key. type Media struct { // The schema defining the content of the request, response, or parameter. - Schema *Schema `json:"schema,omitzero"` - Example json.RawValue `json:"example,omitzero"` - Examples map[string]*Example `json:"examples,omitzero"` + Schema *Schema `json:"schema,omitzero" yaml:"schema,omitempty"` + Example json.RawValue `json:"example,omitzero" yaml:"example,omitempty"` + Examples map[string]*Example `json:"examples,omitzero" yaml:"examples,omitempty"` // A map between a property name and its encoding information. The key, being the property name, MUST exist in // the schema as a property. The encoding object SHALL only apply to requestBody objects when the media // type is multipart or application/x-www-form-urlencoded. - Encoding map[string]Encoding `json:"encoding,omitzero"` + Encoding map[string]Encoding `json:"encoding,omitzero" yaml:"encoding,omitempty"` + + Locator `json:"-" yaml:"-"` +} - Locator `json:"-"` +// UnmarshalYAML implements yaml.Unmarshaler. +func (m *Media) UnmarshalYAML(n *yaml.Node) error { + type Alias Media + var a Alias + + if err := n.Decode(&a); err != nil { + return err + } + a.SetLocation(ogenjson.Location{ + // FIXME(tdakkota): For some reason, the line number is off by 1. + // And the column number is off by 2. + Line: int64(n.Line) - 1, + Column: int64(n.Column) - 2, + }) + + *m = Media(a) + return nil } // Encoding describes single encoding definition applied to a single schema property. type Encoding struct { // The Content-Type for encoding a specific property. - ContentType string `json:"contentType,omitzero"` + ContentType string `json:"contentType,omitzero" yaml:"contentType,omitempty"` // A map allowing additional information to be provided as headers, for example Content-Disposition. // Content-Type is described separately and SHALL be ignored in this section. This property SHALL be // ignored if the request body media type is not a multipart. - Headers map[string]*Header `json:"headers,omitzero"` + Headers map[string]*Header `json:"headers,omitzero" yaml:"headers,omitempty"` // Describes how the parameter value will be serialized // depending on the type of the parameter value. - Style string `json:"style,omitzero"` + Style string `json:"style,omitzero" yaml:"style,omitempty"` // When this is true, parameter values of type array or object // generate separate parameters for each value of the array // or key-value pair of the map. // For other types of parameters this property has no effect. - Explode *bool `json:"explode,omitzero"` + Explode *bool `json:"explode,omitzero" yaml:"explode,omitempty"` // Determines whether the parameter value SHOULD allow reserved characters, as defined by // RFC3986 :/?#[]@!$&'()*+,;= to be included without percent-encoding. // The default value is false. This property SHALL be ignored if the request body media type // is not application/x-www-form-urlencoded. - AllowReserved bool `json:"allowReserved,omitzero"` + AllowReserved bool `json:"allowReserved,omitzero" yaml:"allowReserved,omitempty"` + + Locator `json:"-" yaml:"-"` +} + +// UnmarshalYAML implements yaml.Unmarshaler. +func (e *Encoding) UnmarshalYAML(n *yaml.Node) error { + type Alias Encoding + var a Alias - Locator `json:"-"` + if err := n.Decode(&a); err != nil { + return err + } + a.SetLocation(ogenjson.Location{ + // FIXME(tdakkota): For some reason, the line number is off by 1. + // And the column number is off by 2. + Line: int64(n.Line) - 1, + Column: int64(n.Column) - 2, + }) + + *e = Encoding(a) + return nil } // Discriminator discriminates types for OneOf, AllOf, AnyOf. type Discriminator struct { - PropertyName string `json:"propertyName"` - Mapping map[string]string `json:"mapping,omitzero"` + PropertyName string `json:"propertyName" yaml:"propertyName"` + Mapping map[string]string `json:"mapping,omitzero" yaml:"mapping,omitempty"` } From 8a65fe4e2cf9739bae6cef095a15d36900f1b8a1 Mon Sep 17 00:00:00 2001 From: tdakkota Date: Wed, 6 Jul 2022 10:48:35 +0300 Subject: [PATCH 2/8] test: add location parsing tests --- _testdata/location/location_spec.json | 55 ++++++++++++++ _testdata/location/location_spec.yml | 31 ++++++++ parse_error_test.go | 105 ++++++++++++++++++++++++++ 3 files changed, 191 insertions(+) create mode 100644 _testdata/location/location_spec.json create mode 100644 _testdata/location/location_spec.yml diff --git a/_testdata/location/location_spec.json b/_testdata/location/location_spec.json new file mode 100644 index 000000000..ae5be00ac --- /dev/null +++ b/_testdata/location/location_spec.json @@ -0,0 +1,55 @@ +{ + "openapi": "3.0.3", + "info": { + "title": "WARNING: Update TestLocation if you change this file", + "version": "0.1.0" + }, + "paths": { + "/foo": { + "post": { + "parameters": [ + { + "name": "foo", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/User" + } + } + } + }, + "responses": { + "200": { + "description": "User info", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/User" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "User": { + "type": "object", + "properties": { + "name": { + "type": "string" + } + } + } + } + } +} diff --git a/_testdata/location/location_spec.yml b/_testdata/location/location_spec.yml new file mode 100644 index 000000000..16b6366cb --- /dev/null +++ b/_testdata/location/location_spec.yml @@ -0,0 +1,31 @@ +openapi: 3.0.3 +info: + title: 'WARNING: Update TestLocation if you change this file' + version: 0.1.0 +paths: + /foo: + post: + parameters: + - name: foo + in: query + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/User' + responses: + "200": + description: User info + content: + application/json: + schema: + $ref: '#/components/schemas/User' +components: + schemas: + User: + type: object + properties: + name: + type: string diff --git a/parse_error_test.go b/parse_error_test.go index 29a23fbba..67a0455d3 100644 --- a/parse_error_test.go +++ b/parse_error_test.go @@ -6,6 +6,7 @@ import ( "strings" "testing" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ogenjson "github.com/ogen-go/ogen/json" @@ -86,3 +87,107 @@ func Test_unmarshalJSON(t *testing.T) { }) } } + +var ( + //go:embed _testdata/location/location_spec.json + locationSpecJSON string + //go:embed _testdata/location/location_spec.yml + locationSpecYAML string +) + +func TestLocation(t *testing.T) { + t.Run("JSON", func(t *testing.T) { + a := assert.New(t) + equalLoc := func(l ogenjson.Locatable, line, column int64, ptr string) { + t.Helper() + + loc, ok := l.Location() + a.Truef(ok, "ptr: %s", ptr) + type location struct { + Line, Column int64 + Ptr string + } + a.Equalf( + location{line, column, ptr}, + location{loc.Line, loc.Column, loc.JSONPointer}, + "ptr: %s", ptr, + ) + } + + var locationSpec Spec + require.NoError(t, unmarshalJSON([]byte(locationSpecJSON), &locationSpec)) + var ( + foo = locationSpec.Paths["/foo"] + fooLocation = "/paths/~1foo" + + post = foo.Post + postLocation = fooLocation + "/post" + + body = post.RequestBody + bodyLocation = postLocation + "/requestBody" + + media = body.Content["application/json"] + mediaLocation = bodyLocation + "/content/application~1json" + + schema = media.Schema + schemaLocation = mediaLocation + "/schema" + ) + // Compare PathItem and Operation. + equalLoc(foo, 8, 13, fooLocation) + equalLoc(post, 9, 15, postLocation) + + // Compare Parameters. + // FIXME(tdakkota): For some reason, go-json-experiment does not add array index. + equalLoc(post.Parameters[0], 11, 11, postLocation+"/parameters") + + // Compare RequestBody. + equalLoc(body, 19, 24, bodyLocation) + equalLoc(&media, 21, 33, mediaLocation) + equalLoc(schema, 22, 25, schemaLocation) + + var user = locationSpec.Components.Schemas["User"] + equalLoc(user, 45, 15, "/components/schemas/User") + equalLoc(user.Properties[0].Schema, 48, 19, "/components/schemas/User/properties/name") + }) + t.Run("YAML", func(t *testing.T) { + a := assert.New(t) + equalLoc := func(l ogenjson.Locatable, line, column int64) { + t.Helper() + + loc, ok := l.Location() + a.True(ok) + type location struct { + Line, Column int64 + } + a.Equal( + location{line, column}, + location{loc.Line, loc.Column}, + ) + } + + var locationSpec Spec + require.NoError(t, unmarshalYAML([]byte(locationSpecYAML), &locationSpec)) + var ( + foo = locationSpec.Paths["/foo"] + post = foo.Post + body = post.RequestBody + media = body.Content["application/json"] + schema = media.Schema + ) + // Compare PathItem and Operation. + equalLoc(foo, 6, 3) + equalLoc(post, 7, 5) + + // Compare Parameters. + equalLoc(post.Parameters[0], 9, 11) + + // Compare RequestBody. + equalLoc(body, 13, 7) + equalLoc(&media, 15, 11) + equalLoc(schema, 16, 13) + + var user = locationSpec.Components.Schemas["User"] + equalLoc(user, 27, 5) + equalLoc(user.Properties[0].Schema, 30, 9) + }) +} From 861a7d35288be6448c5561218abc7fb7c7b1c154 Mon Sep 17 00:00:00 2001 From: tdakkota Date: Wed, 6 Jul 2022 11:29:49 +0300 Subject: [PATCH 3/8] fix(jsonschema): implement YAML parsing for `Default` and `Example` --- _testdata/location/location_spec.json | 8 +++- _testdata/location/location_spec.yml | 7 +++- dsl.go | 4 +- dsl_test.go | 3 +- jsonschema/parser.go | 7 ++-- jsonschema/raw_schema.go | 34 ++++++++++++++++- jsonschema/raw_schema_test.go | 36 ++++++++++++++++++ jsonschema/yaml.go | 53 +++++++++++++++++++++++++++ schema.go | 4 +- spec.go | 5 +++ 10 files changed, 149 insertions(+), 12 deletions(-) create mode 100644 jsonschema/yaml.go diff --git a/_testdata/location/location_spec.json b/_testdata/location/location_spec.json index ae5be00ac..306a9439e 100644 --- a/_testdata/location/location_spec.json +++ b/_testdata/location/location_spec.json @@ -46,7 +46,13 @@ "type": "object", "properties": { "name": { - "type": "string" + "type": "integer", + "enum": [ + 1, + 2, + 3 + ], + "minimum": 2 } } } diff --git a/_testdata/location/location_spec.yml b/_testdata/location/location_spec.yml index 16b6366cb..2af7bce46 100644 --- a/_testdata/location/location_spec.yml +++ b/_testdata/location/location_spec.yml @@ -28,4 +28,9 @@ components: type: object properties: name: - type: string + type: integer + enum: + - 1 + - 2 + - 3 + minimum: 2 diff --git a/dsl.go b/dsl.go index ea92d1282..62b59632d 100644 --- a/dsl.go +++ b/dsl.go @@ -968,7 +968,7 @@ func (s *Schema) SetMinProperties(m *uint64) *Schema { // SetDefault sets the Default of the Schema. func (s *Schema) SetDefault(d jsonv1.RawMessage) *Schema { - s.Default = jsonv2.RawValue(d) + s.Default = Default(d) return s } @@ -1033,7 +1033,7 @@ func (s *Schema) AsArray() *Schema { func (s *Schema) AsEnum(def jsonv1.RawMessage, values ...jsonv1.RawMessage) *Schema { return &Schema{ Type: s.Type, - Default: jsonv2.RawValue(def), + Default: Default(def), Enum: func() (r []jsonv2.RawValue) { for _, val := range values { r = append(r, jsonv2.RawValue(val)) diff --git a/dsl_test.go b/dsl_test.go index 1902a5bc2..82c2db53c 100644 --- a/dsl_test.go +++ b/dsl_test.go @@ -9,6 +9,7 @@ import ( "github.com/ogen-go/ogen" "github.com/ogen-go/ogen/gen/ir" + "github.com/ogen-go/ogen/jsonschema" ) const ( @@ -374,7 +375,7 @@ func TestBuilder(t *testing.T) { UniqueItems: true, MaxProperties: &umax, MinProperties: &umax, - Default: jsonv2.RawValue("0"), + Default: jsonschema.Default("0"), }, ogen.NewSchema(). SetRef("ref"). SetDescription("desc"). diff --git a/jsonschema/parser.go b/jsonschema/parser.go index 1a51e0310..6022d6ffe 100644 --- a/jsonschema/parser.go +++ b/jsonschema/parser.go @@ -6,6 +6,7 @@ import ( "github.com/go-faster/errors" "github.com/go-faster/jx" + "github.com/go-json-experiment/json" ) // Parser parses JSON schemas. @@ -72,7 +73,7 @@ func (p *Parser) parse1(schema *RawSchema, ctx *resolveCtx, hook func(*Schema) * handleNullableEnum(s) } if d := schema.Default; len(d) > 0 { - v, err := parseJSONValue(s, d) + v, err := parseJSONValue(s, json.RawValue(d)) if err != nil { return nil, errors.Wrap(err, "parse default") } @@ -108,7 +109,7 @@ func (p *Parser) parseSchema(schema *RawSchema, ctx *resolveCtx, hook func(*Sche } if d := schema.Default; p.inferTypes && schema.Type == "" && len(d) > 0 { - typ, err := inferJSONType(d) + typ, err := inferJSONType(json.RawValue(d)) if err != nil { return nil, errors.Wrap(err, "infer default type") } @@ -383,7 +384,7 @@ func (p *Parser) extendInfo(schema *RawSchema, s *Schema) *Schema { s.Summary = schema.Summary s.Description = schema.Description s.Deprecated = schema.Deprecated - s.AddExample(schema.Example) + s.AddExample(json.RawValue(schema.Example)) // Nullable enums will be handled later. if len(s.Enum) < 1 { diff --git a/jsonschema/raw_schema.go b/jsonschema/raw_schema.go index 1ba7ef513..cb6733cbd 100644 --- a/jsonschema/raw_schema.go +++ b/jsonschema/raw_schema.go @@ -5,6 +5,7 @@ import ( "github.com/go-faster/errors" "github.com/go-json-experiment/json" + "gopkg.in/yaml.v3" ogenjson "github.com/ogen-go/ogen/json" ) @@ -12,6 +13,18 @@ import ( // Num represents JSON number. type Num json.RawValue +// UnmarshalYAML implements yaml.Unmarshaler. +func (n *Num) UnmarshalYAML(node *yaml.Node) error { + if t := node.Tag; t != "!!int" && t != "!!float" { + return errors.Errorf("unexpected tag %s", t) + } + val, err := convertYAMLtoRawJSON(node) + if err != nil { + return err + } + return json.Unmarshal(val, n) +} + // MarshalNextJSON implements json.MarshalerV2. func (n Num) MarshalNextJSON(opts json.MarshalOptions, e *json.Encoder) error { val := json.RawValue(n) @@ -71,8 +84,8 @@ type RawSchema struct { UniqueItems bool `json:"uniqueItems,omitzero"` MaxProperties *uint64 `json:"maxProperties,omitzero"` MinProperties *uint64 `json:"minProperties,omitzero"` - Default json.RawValue `json:"default,omitzero"` - Example json.RawValue `json:"example,omitzero"` + Default Default `json:"default,omitzero"` + Example Example `json:"example,omitzero"` Deprecated bool `json:"deprecated,omitzero"` ContentEncoding string `json:"contentEncoding,omitzero"` ContentMediaType string `json:"contentMediaType,omitzero"` @@ -85,6 +98,23 @@ type RawSchema struct { // Enum is JSON Schema enum validator description. type Enum []json.RawValue +// UnmarshalYAML implements yaml.Unmarshaler. +func (n *Enum) UnmarshalYAML(node *yaml.Node) error { + if node.Tag != "!!seq" { + return errors.Errorf("unexpected tag %s", node.Tag) + } + *n = (*n)[:0] + for _, val := range node.Content { + raw, err := convertYAMLtoRawJSON(val) + if err != nil { + return err + } + *n = append(*n, raw) + return nil + } + return nil +} + // UnmarshalNextJSON implements json.UnmarshalerV2. func (n *Enum) UnmarshalNextJSON(opts json.UnmarshalOptions, d *json.Decoder) error { offset := d.InputOffset() diff --git a/jsonschema/raw_schema_test.go b/jsonschema/raw_schema_test.go index 723e136cd..b5f646320 100644 --- a/jsonschema/raw_schema_test.go +++ b/jsonschema/raw_schema_test.go @@ -6,8 +6,44 @@ import ( "github.com/go-json-experiment/json" "github.com/stretchr/testify/require" + "gopkg.in/yaml.v3" ) +func TestNum_UnmarshalYAML(t *testing.T) { + tests := []struct { + data string + value Num + wantErr bool + }{ + {`0`, Num(`0`), false}, + {`1e1`, Num(`10`), false}, + {`0x0a`, Num(`10`), false}, + // Invalid YAML. + {`"`, nil, true}, + {`0ee1`, nil, true}, + // Invalid type. + {`{}`, nil, true}, + {`"100"`, nil, true}, + } + for i, tt := range tests { + tt := tt + t.Run(fmt.Sprintf("Test%d", i+1), func(t *testing.T) { + a := require.New(t) + + var val Num + err := yaml.Unmarshal([]byte(tt.data), &val) + if tt.wantErr { + a.Error(err) + t.Log("Input:", tt.data) + t.Log("Error:", err) + return + } + a.NoError(err) + a.Equal(tt.value, val) + }) + } +} + func TestNum_UnmarshalNextJSON(t *testing.T) { tests := []struct { data string diff --git a/jsonschema/yaml.go b/jsonschema/yaml.go new file mode 100644 index 000000000..07b929e42 --- /dev/null +++ b/jsonschema/yaml.go @@ -0,0 +1,53 @@ +package jsonschema + +import ( + "github.com/go-json-experiment/json" + "gopkg.in/yaml.v3" +) + +type ( + // RawValue is a raw JSON value. + RawValue json.RawValue + // Default is a default value. + Default = RawValue + // Example is an example value. + Example = RawValue +) + +// UnmarshalYAML implements yaml.Unmarshaler. +func (n *RawValue) UnmarshalYAML(node *yaml.Node) error { + raw, err := convertYAMLtoRawJSON(node) + if err != nil { + return err + } + *n = RawValue(raw) + return nil +} + +// MarshalNextJSON implements json.MarshalerV2. +func (n RawValue) MarshalNextJSON(opts json.MarshalOptions, e *json.Encoder) error { + val := json.RawValue(n) + return opts.MarshalNext(e, val) +} + +// UnmarshalNextJSON implements json.UnmarshalerV2. +func (n *RawValue) UnmarshalNextJSON(opts json.UnmarshalOptions, d *json.Decoder) error { + val, err := d.ReadValue() + if err != nil { + return err + } + *n = append((*n)[:0], val...) + return nil +} + +func convertYAMLtoRawJSON(node *yaml.Node) (json.RawValue, error) { + var tmp interface{} + if err := node.Decode(&tmp); err != nil { + return nil, err + } + raw, err := json.Marshal(tmp) + if err != nil { + return nil, err + } + return raw, nil +} diff --git a/schema.go b/schema.go index 7845506d4..835e3c329 100644 --- a/schema.go +++ b/schema.go @@ -203,12 +203,12 @@ type Schema struct { MinProperties *uint64 `json:"minProperties,omitzero" yaml:"minProperties,omitempty"` // Default value. - Default json.RawValue `json:"default,omitzero" yaml:"default,omitempty"` + Default Default `json:"default,omitzero" yaml:"default,omitempty"` // A free-form property to include an example of an instance for this schema. // To represent examples that cannot be naturally represented in JSON or YAML, // a string value can be used to contain the example with escaping where necessary. - Example json.RawValue `json:"example,omitzero" yaml:"example,omitempty"` + Example ExampleValue `json:"example,omitzero" yaml:"example,omitempty"` // Specifies that a schema is deprecated and SHOULD be transitioned out // of usage. diff --git a/spec.go b/spec.go index 8ab2fbc19..e60c0ed40 100644 --- a/spec.go +++ b/spec.go @@ -14,6 +14,11 @@ type ( Num = jsonschema.Num // Enum is JSON Schema enum validator description. Enum = jsonschema.Enum + // Default is a default value. + Default = jsonschema.Default + // ExampleValue is an example value. + ExampleValue = jsonschema.Example + // Locator stores location of JSON value. Locator = ogenjson.Locator ) From 83a13eb11b91dba83658037febdc01b9e5fce83f Mon Sep 17 00:00:00 2001 From: tdakkota Date: Thu, 7 Jul 2022 02:43:11 +0300 Subject: [PATCH 4/8] fix(ogen): correct `allOf` YAML parsing --- parse_error.go => parse.go | 0 parse_error_test.go => parse_test.go | 0 schema.go | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) rename parse_error.go => parse.go (100%) rename parse_error_test.go => parse_test.go (100%) diff --git a/parse_error.go b/parse.go similarity index 100% rename from parse_error.go rename to parse.go diff --git a/parse_error_test.go b/parse_test.go similarity index 100% rename from parse_error_test.go rename to parse_test.go diff --git a/schema.go b/schema.go index 835e3c329..a465bb7f5 100644 --- a/schema.go +++ b/schema.go @@ -64,7 +64,7 @@ type Schema struct { // for independent validation but together compose a single object. // Still, it does not imply a hierarchy between the models. // For that purpose, you should include the discriminator. - AllOf []*Schema `json:"allOf,omitzero"` // TODO: implement yaml:"allOf,omitempty"` // TODO: implement. + AllOf []*Schema `json:"allOf,omitzero" yaml:"allOf,omitempty"` // OneOf validates the value against exactly one of the subschemas OneOf []*Schema `json:"oneOf,omitzero" yaml:"oneOf,omitempty"` From 600c6374d020da1ff7ba1beb2936cdda8557c867 Mon Sep 17 00:00:00 2001 From: tdakkota Date: Thu, 7 Jul 2022 02:43:44 +0300 Subject: [PATCH 5/8] chore(gen): add some context to `complex form schema` error --- gen/gen_contents.go | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/gen/gen_contents.go b/gen/gen_contents.go index 6dfeacefe..54c23ae55 100644 --- a/gen/gen_contents.go +++ b/gen/gen_contents.go @@ -66,17 +66,27 @@ func (g *Generator) generateFormContent( return nil, errors.Wrap(err, "generate schema") } - structType := t + var ( + complexTypeErr = func(bt *ir.Type) error { + impl := &ErrNotImplemented{"complex form schema"} + if bt != t { + return errors.Wrapf(impl, "%s -> %s", t, bt) + } + return errors.Wrapf(impl, "%s", bt) + } + structType = t + ) switch t.Kind { case ir.KindStruct: case ir.KindGeneric: - if v := t.GenericVariant; optional && v.OnlyOptional() && t.GenericOf.IsStruct() { - structType = t.GenericOf + generic := t.GenericOf + if v := t.GenericVariant; optional && v.OnlyOptional() && generic.IsStruct() { + structType = generic break } - fallthrough + return nil, complexTypeErr(generic) default: - return nil, errors.Wrapf(&ErrNotImplemented{"complex form schema"}, "%s", t.Kind) + return nil, complexTypeErr(t) } for _, f := range structType.Fields { From 1a2d81244628e92c488fa2d998ff91f229b6839b Mon Sep 17 00:00:00 2001 From: tdakkota Date: Thu, 7 Jul 2022 02:47:35 +0300 Subject: [PATCH 6/8] chore: go mod tidy --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 8f26448f8..872823daa 100644 --- a/go.mod +++ b/go.mod @@ -18,6 +18,7 @@ require ( golang.org/x/net v0.0.0-20220622184535-263ec571b305 golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f golang.org/x/tools v0.1.11 + gopkg.in/yaml.v3 v3.0.1 ) require ( @@ -35,5 +36,4 @@ require ( golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664 // indirect golang.org/x/text v0.3.7 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect ) From afd81a2dc78f0c5c08e5c28c1832964f60f5e6aa Mon Sep 17 00:00:00 2001 From: tdakkota Date: Thu, 7 Jul 2022 02:54:01 +0300 Subject: [PATCH 7/8] fix(jsonschema): do not return early during `Enum` parsing --- jsonschema/raw_schema.go | 1 - 1 file changed, 1 deletion(-) diff --git a/jsonschema/raw_schema.go b/jsonschema/raw_schema.go index cb6733cbd..a42c6a8ab 100644 --- a/jsonschema/raw_schema.go +++ b/jsonschema/raw_schema.go @@ -110,7 +110,6 @@ func (n *Enum) UnmarshalYAML(node *yaml.Node) error { return err } *n = append(*n, raw) - return nil } return nil } From 0080531a2b6f721beb9f3eab4da99111428ad59d Mon Sep 17 00:00:00 2001 From: tdakkota Date: Thu, 7 Jul 2022 03:04:50 +0300 Subject: [PATCH 8/8] chore: commit generated files --- examples/ex_2ch/oas_faker_gen.go | 238 +-- examples/ex_2ch/oas_json_gen.go | 1540 +++++++++---------- examples/ex_2ch/oas_request_decoders_gen.go | 196 +-- examples/ex_2ch/oas_request_encoders_gen.go | 112 +- examples/ex_2ch/oas_schemas_gen.go | 176 +-- examples/go.mod | 2 - examples/go.sum | 2 - internal/test_allof/oas_faker_gen.go | 14 +- internal/test_allof/oas_json_gen.go | 76 +- internal/test_allof/oas_schemas_gen.go | 4 +- internal/test_allof/oas_validators_gen.go | 70 +- 11 files changed, 1213 insertions(+), 1217 deletions(-) diff --git a/examples/ex_2ch/oas_faker_gen.go b/examples/ex_2ch/oas_faker_gen.go index 2310ca9a2..4c6fc20d9 100644 --- a/examples/ex_2ch/oas_faker_gen.go +++ b/examples/ex_2ch/oas_faker_gen.go @@ -6,136 +6,129 @@ package api func (s *Board) SetFake() { { { - s.BumpLimit = int(0) + s.ID = "string" } } { { - s.Category = "string" + s.Name = "string" } } { { - s.DefaultName = "string" + s.Category = "string" } } { { - s.EnableDices = true + s.Info = "string" } } { { - s.EnableFlags = true + s.InfoOuter = "string" } } { { - s.EnableIcons = true + s.ThreadsPerPage = int(0) } } { { - s.EnableLikes = true + s.BumpLimit = int(0) } } { { - s.EnableNames = true + s.MaxPages = int(0) } } { { - s.EnableOekaki = true + s.DefaultName = "string" } } { { - s.EnablePosting = true + s.EnableNames = true } } { { - s.EnableSage = true + s.EnableTrips = true } } { { - s.EnableShield = true + s.EnableSubject = true } } { { - s.EnableSubject = true + s.EnableSage = true } } { { - s.EnableThreadTags = true + s.EnableIcons = true } } { { - s.EnableTrips = true + s.EnableFlags = true } } { { - s.FileTypes = nil - for i := 0; i < 0; i++ { - var elem string - { - elem = "string" - } - s.FileTypes = append(s.FileTypes, elem) - } + s.EnableDices = true } } { { - s.Icons = nil - for i := 0; i < 0; i++ { - var elem BoardIconsItem - { - elem.SetFake() - } - s.Icons = append(s.Icons, elem) - } + s.EnableShield = true } } { { - s.ID = "string" + s.EnableThreadTags = true } } { { - s.Info = "string" + s.EnablePosting = true } } { { - s.InfoOuter = "string" + s.EnableLikes = true } } { { - s.MaxComment = int(0) + s.EnableOekaki = true } } { { - s.MaxFilesSize = int(0) + s.FileTypes = nil + for i := 0; i < 0; i++ { + var elem string + { + elem = "string" + } + s.FileTypes = append(s.FileTypes, elem) + } } } { { - s.MaxPages = int(0) + s.MaxComment = int(0) } } { { - s.Name = "string" + s.MaxFilesSize = int(0) } } { @@ -152,7 +145,14 @@ func (s *Board) SetFake() { } { { - s.ThreadsPerPage = int(0) + s.Icons = nil + for i := 0; i < 0; i++ { + var elem BoardIconsItem + { + elem.SetFake() + } + s.Icons = append(s.Icons, elem) + } } } } @@ -161,12 +161,12 @@ func (s *Board) SetFake() { func (s *BoardIconsItem) SetFake() { { { - s.Name.SetFake() + s.Num.SetFake() } } { { - s.Num.SetFake() + s.Name.SetFake() } } { @@ -196,32 +196,32 @@ func (s *Boards) SetFake() { func (s *Captcha) SetFake() { { { - s.Error.SetFake() + s.Result = int(0) } } { { - s.Expires.SetFake() + s.Error.SetFake() } } { { - s.ID = "string" + s.Type.SetFake() } } { { - s.Input.SetFake() + s.ID = "string" } } { { - s.Result = int(0) + s.Expires.SetFake() } } { { - s.Type.SetFake() + s.Input.SetFake() } } } @@ -254,92 +254,92 @@ func (s *ErrorCode) SetFake() { func (s *File) SetFake() { { { - s.Displayname = "string" + s.Name = "string" } } { { - s.Duration.SetFake() + s.Fullname = "string" } } { { - s.DurationSecs.SetFake() + s.Displayname = "string" } } { { - s.Fullname = "string" + s.Path = "string" } } { { - s.Height = int(0) + s.Thumbnail = "string" } } { { - s.Install.SetFake() + s.MD5.SetFake() } } { { - s.MD5.SetFake() + s.Type.SetFake() } } { { - s.Name = "string" + s.Size = int(0) } } { { - s.Nsfw.SetFake() + s.Width = int(0) } } { { - s.Pack.SetFake() + s.Height = int(0) } } { { - s.Path = "string" + s.TnWidth = int(0) } } { { - s.Size = int(0) + s.TnHeight = int(0) } } { { - s.Sticker.SetFake() + s.Nsfw.SetFake() } } { { - s.Thumbnail = "string" + s.Duration.SetFake() } } { { - s.TnHeight = int(0) + s.DurationSecs.SetFake() } } { { - s.TnWidth = int(0) + s.Pack.SetFake() } } { { - s.Type.SetFake() + s.Sticker.SetFake() } } { { - s.Width = int(0) + s.Install.SetFake() } } } @@ -353,12 +353,12 @@ func (s *FileType) SetFake() { func (s *Like) SetFake() { { { - s.Error.SetFake() + s.Result.SetFake() } } { { - s.Result.SetFake() + s.Error.SetFake() } } } @@ -367,17 +367,17 @@ func (s *Like) SetFake() { func (s *MobilePost) SetFake() { { { - s.Error.SetFake() + s.Result.SetFake() } } { { - s.Post.SetFake() + s.Error.SetFake() } } { { - s.Result.SetFake() + s.Post.SetFake() } } } @@ -386,12 +386,12 @@ func (s *MobilePost) SetFake() { func (s *MobileThreadLastInfo) SetFake() { { { - s.Error.SetFake() + s.Result.SetFake() } } { { - s.Result.SetFake() + s.Error.SetFake() } } { @@ -410,23 +410,33 @@ func (s *MobileThreadLastInfoThread) SetFake() { } { { - s.Posts.SetFake() + s.Timestamp.SetFake() } } { { - s.Timestamp.SetFake() + s.Posts.SetFake() } } } // SetFake set fake values. func (s *MobileThreadPostsAfter) SetFake() { + { + { + s.Result.SetFake() + } + } { { s.Error.SetFake() } } + { + { + s.UniquePosters.SetFake() + } + } { { s.Posts = nil @@ -439,16 +449,6 @@ func (s *MobileThreadPostsAfter) SetFake() { } } } - { - { - s.Result.SetFake() - } - } - { - { - s.UniquePosters.SetFake() - } - } } // SetFake set fake values. @@ -518,17 +518,17 @@ func (s *OptString) SetFake() { func (s *Passcode) SetFake() { { { - s.Error.SetFake() + s.Result.SetFake() } } { { - s.Passcode.SetFake() + s.Error.SetFake() } } { { - s.Result.SetFake() + s.Passcode.SetFake() } } } @@ -537,12 +537,12 @@ func (s *Passcode) SetFake() { func (s *PasscodePasscode) SetFake() { { { - s.Expires.SetFake() + s.Type.SetFake() } } { { - s.Type.SetFake() + s.Expires.SetFake() } } } @@ -551,7 +551,12 @@ func (s *PasscodePasscode) SetFake() { func (s *Post) SetFake() { { { - s.Banned = int(0) + s.Num = int(0) + } + } + { + { + s.Parent = int(0) } } { @@ -561,12 +566,12 @@ func (s *Post) SetFake() { } { { - s.Closed = int(0) + s.Timestamp = int(0) } } { { - s.Comment = "string" + s.Lasthit = int(0) } } { @@ -576,17 +581,17 @@ func (s *Post) SetFake() { } { { - s.Dislikes.SetFake() + s.Email.SetFake() } } { { - s.Email.SetFake() + s.Subject.SetFake() } } { { - s.Endless = int(0) + s.Comment = "string" } } { @@ -603,27 +608,27 @@ func (s *Post) SetFake() { } { { - s.Icon.SetFake() + s.Views = int(0) } } { { - s.Lasthit = int(0) + s.Sticky = int(0) } } { { - s.Likes.SetFake() + s.Endless = int(0) } } { { - s.Name.SetFake() + s.Closed = int(0) } } { { - s.Num = int(0) + s.Banned = int(0) } } { @@ -633,42 +638,37 @@ func (s *Post) SetFake() { } { { - s.Parent = int(0) - } - } - { - { - s.Sticky = int(0) + s.Name.SetFake() } } { { - s.Subject.SetFake() + s.Icon.SetFake() } } { { - s.Tags.SetFake() + s.Trip.SetFake() } } { { - s.Timestamp = int(0) + s.TripStyle.SetFake() } } { { - s.Trip.SetFake() + s.Tags.SetFake() } } { { - s.TripStyle.SetFake() + s.Likes.SetFake() } } { { - s.Views = int(0) + s.Dislikes.SetFake() } } } @@ -677,17 +677,17 @@ func (s *Post) SetFake() { func (s *PostingNewPost) SetFake() { { { - s.Error.SetFake() + s.Result.SetFake() } } { { - s.Num.SetFake() + s.Error.SetFake() } } { { - s.Result.SetFake() + s.Num.SetFake() } } } @@ -696,12 +696,12 @@ func (s *PostingNewPost) SetFake() { func (s *PostingNewThread) SetFake() { { { - s.Error.SetFake() + s.Result.SetFake() } } { { - s.Result.SetFake() + s.Error.SetFake() } } { @@ -715,12 +715,12 @@ func (s *PostingNewThread) SetFake() { func (s *Report) SetFake() { { { - s.Error.SetFake() + s.Result.SetFake() } } { { - s.Result.SetFake() + s.Error.SetFake() } } } diff --git a/examples/ex_2ch/oas_json_gen.go b/examples/ex_2ch/oas_json_gen.go index 31a7cf29e..fa0d4502e 100644 --- a/examples/ex_2ch/oas_json_gen.go +++ b/examples/ex_2ch/oas_json_gen.go @@ -23,8 +23,13 @@ func (s Board) Encode(e *jx.Encoder) { func (s Board) encodeFields(e *jx.Encoder) { { - e.FieldStart("bump_limit") - e.Int(s.BumpLimit) + e.FieldStart("id") + e.Str(s.ID) + } + { + + e.FieldStart("name") + e.Str(s.Name) } { @@ -33,28 +38,33 @@ func (s Board) encodeFields(e *jx.Encoder) { } { - e.FieldStart("default_name") - e.Str(s.DefaultName) + e.FieldStart("info") + e.Str(s.Info) } { - e.FieldStart("enable_dices") - e.Bool(s.EnableDices) + e.FieldStart("info_outer") + e.Str(s.InfoOuter) } { - e.FieldStart("enable_flags") - e.Bool(s.EnableFlags) + e.FieldStart("threads_per_page") + e.Int(s.ThreadsPerPage) } { - e.FieldStart("enable_icons") - e.Bool(s.EnableIcons) + e.FieldStart("bump_limit") + e.Int(s.BumpLimit) } { - e.FieldStart("enable_likes") - e.Bool(s.EnableLikes) + e.FieldStart("max_pages") + e.Int(s.MaxPages) + } + { + + e.FieldStart("default_name") + e.Str(s.DefaultName) } { @@ -63,13 +73,13 @@ func (s Board) encodeFields(e *jx.Encoder) { } { - e.FieldStart("enable_oekaki") - e.Bool(s.EnableOekaki) + e.FieldStart("enable_trips") + e.Bool(s.EnableTrips) } { - e.FieldStart("enable_posting") - e.Bool(s.EnablePosting) + e.FieldStart("enable_subject") + e.Bool(s.EnableSubject) } { @@ -78,57 +88,52 @@ func (s Board) encodeFields(e *jx.Encoder) { } { - e.FieldStart("enable_shield") - e.Bool(s.EnableShield) + e.FieldStart("enable_icons") + e.Bool(s.EnableIcons) } { - e.FieldStart("enable_subject") - e.Bool(s.EnableSubject) + e.FieldStart("enable_flags") + e.Bool(s.EnableFlags) } { - e.FieldStart("enable_thread_tags") - e.Bool(s.EnableThreadTags) + e.FieldStart("enable_dices") + e.Bool(s.EnableDices) } { - e.FieldStart("enable_trips") - e.Bool(s.EnableTrips) + e.FieldStart("enable_shield") + e.Bool(s.EnableShield) } { - e.FieldStart("file_types") - e.ArrStart() - for _, elem := range s.FileTypes { - e.Str(elem) - } - e.ArrEnd() + e.FieldStart("enable_thread_tags") + e.Bool(s.EnableThreadTags) } { - if s.Icons != nil { - e.FieldStart("icons") - e.ArrStart() - for _, elem := range s.Icons { - elem.Encode(e) - } - e.ArrEnd() - } + + e.FieldStart("enable_posting") + e.Bool(s.EnablePosting) } { - e.FieldStart("id") - e.Str(s.ID) + e.FieldStart("enable_likes") + e.Bool(s.EnableLikes) } { - e.FieldStart("info") - e.Str(s.Info) + e.FieldStart("enable_oekaki") + e.Bool(s.EnableOekaki) } { - e.FieldStart("info_outer") - e.Str(s.InfoOuter) + e.FieldStart("file_types") + e.ArrStart() + for _, elem := range s.FileTypes { + e.Str(elem) + } + e.ArrEnd() } { @@ -140,16 +145,6 @@ func (s Board) encodeFields(e *jx.Encoder) { e.FieldStart("max_files_size") e.Int(s.MaxFilesSize) } - { - - e.FieldStart("max_pages") - e.Int(s.MaxPages) - } - { - - e.FieldStart("name") - e.Str(s.Name) - } { if s.Tags != nil { e.FieldStart("tags") @@ -161,39 +156,44 @@ func (s Board) encodeFields(e *jx.Encoder) { } } { - - e.FieldStart("threads_per_page") - e.Int(s.ThreadsPerPage) + if s.Icons != nil { + e.FieldStart("icons") + e.ArrStart() + for _, elem := range s.Icons { + elem.Encode(e) + } + e.ArrEnd() + } } } var jsonFieldsNameOfBoard = [26]string{ - 0: "bump_limit", - 1: "category", - 2: "default_name", - 3: "enable_dices", - 4: "enable_flags", - 5: "enable_icons", - 6: "enable_likes", - 7: "enable_names", - 8: "enable_oekaki", - 9: "enable_posting", - 10: "enable_sage", - 11: "enable_shield", - 12: "enable_subject", - 13: "enable_thread_tags", - 14: "enable_trips", - 15: "file_types", - 16: "icons", - 17: "id", - 18: "info", - 19: "info_outer", - 20: "max_comment", - 21: "max_files_size", - 22: "max_pages", - 23: "name", + 0: "id", + 1: "name", + 2: "category", + 3: "info", + 4: "info_outer", + 5: "threads_per_page", + 6: "bump_limit", + 7: "max_pages", + 8: "default_name", + 9: "enable_names", + 10: "enable_trips", + 11: "enable_subject", + 12: "enable_sage", + 13: "enable_icons", + 14: "enable_flags", + 15: "enable_dices", + 16: "enable_shield", + 17: "enable_thread_tags", + 18: "enable_posting", + 19: "enable_likes", + 20: "enable_oekaki", + 21: "file_types", + 22: "max_comment", + 23: "max_files_size", 24: "tags", - 25: "threads_per_page", + 25: "icons", } // Decode decodes Board from json. @@ -205,306 +205,301 @@ func (s *Board) Decode(d *jx.Decoder) error { if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { switch string(k) { - case "bump_limit": + case "id": requiredBitSet[0] |= 1 << 0 if err := func() error { - v, err := d.Int() - s.BumpLimit = int(v) + v, err := d.Str() + s.ID = string(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"bump_limit\"") + return errors.Wrap(err, "decode field \"id\"") } - case "category": + case "name": requiredBitSet[0] |= 1 << 1 if err := func() error { v, err := d.Str() - s.Category = string(v) + s.Name = string(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"category\"") + return errors.Wrap(err, "decode field \"name\"") } - case "default_name": + case "category": requiredBitSet[0] |= 1 << 2 if err := func() error { v, err := d.Str() - s.DefaultName = string(v) + s.Category = string(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"default_name\"") + return errors.Wrap(err, "decode field \"category\"") } - case "enable_dices": + case "info": requiredBitSet[0] |= 1 << 3 if err := func() error { - v, err := d.Bool() - s.EnableDices = bool(v) + v, err := d.Str() + s.Info = string(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"enable_dices\"") + return errors.Wrap(err, "decode field \"info\"") } - case "enable_flags": + case "info_outer": requiredBitSet[0] |= 1 << 4 if err := func() error { - v, err := d.Bool() - s.EnableFlags = bool(v) + v, err := d.Str() + s.InfoOuter = string(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"enable_flags\"") + return errors.Wrap(err, "decode field \"info_outer\"") } - case "enable_icons": + case "threads_per_page": requiredBitSet[0] |= 1 << 5 if err := func() error { - v, err := d.Bool() - s.EnableIcons = bool(v) + v, err := d.Int() + s.ThreadsPerPage = int(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"enable_icons\"") + return errors.Wrap(err, "decode field \"threads_per_page\"") } - case "enable_likes": + case "bump_limit": requiredBitSet[0] |= 1 << 6 if err := func() error { - v, err := d.Bool() - s.EnableLikes = bool(v) + v, err := d.Int() + s.BumpLimit = int(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"enable_likes\"") + return errors.Wrap(err, "decode field \"bump_limit\"") } - case "enable_names": + case "max_pages": requiredBitSet[0] |= 1 << 7 if err := func() error { - v, err := d.Bool() - s.EnableNames = bool(v) + v, err := d.Int() + s.MaxPages = int(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"enable_names\"") + return errors.Wrap(err, "decode field \"max_pages\"") } - case "enable_oekaki": + case "default_name": requiredBitSet[1] |= 1 << 0 if err := func() error { - v, err := d.Bool() - s.EnableOekaki = bool(v) + v, err := d.Str() + s.DefaultName = string(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"enable_oekaki\"") + return errors.Wrap(err, "decode field \"default_name\"") } - case "enable_posting": + case "enable_names": requiredBitSet[1] |= 1 << 1 if err := func() error { v, err := d.Bool() - s.EnablePosting = bool(v) + s.EnableNames = bool(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"enable_posting\"") + return errors.Wrap(err, "decode field \"enable_names\"") } - case "enable_sage": + case "enable_trips": requiredBitSet[1] |= 1 << 2 if err := func() error { v, err := d.Bool() - s.EnableSage = bool(v) + s.EnableTrips = bool(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"enable_sage\"") + return errors.Wrap(err, "decode field \"enable_trips\"") } - case "enable_shield": + case "enable_subject": requiredBitSet[1] |= 1 << 3 if err := func() error { v, err := d.Bool() - s.EnableShield = bool(v) + s.EnableSubject = bool(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"enable_shield\"") + return errors.Wrap(err, "decode field \"enable_subject\"") } - case "enable_subject": + case "enable_sage": requiredBitSet[1] |= 1 << 4 if err := func() error { v, err := d.Bool() - s.EnableSubject = bool(v) + s.EnableSage = bool(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"enable_subject\"") + return errors.Wrap(err, "decode field \"enable_sage\"") } - case "enable_thread_tags": + case "enable_icons": requiredBitSet[1] |= 1 << 5 if err := func() error { v, err := d.Bool() - s.EnableThreadTags = bool(v) + s.EnableIcons = bool(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"enable_thread_tags\"") + return errors.Wrap(err, "decode field \"enable_icons\"") } - case "enable_trips": + case "enable_flags": requiredBitSet[1] |= 1 << 6 if err := func() error { v, err := d.Bool() - s.EnableTrips = bool(v) + s.EnableFlags = bool(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"enable_trips\"") + return errors.Wrap(err, "decode field \"enable_flags\"") } - case "file_types": + case "enable_dices": requiredBitSet[1] |= 1 << 7 if err := func() error { - s.FileTypes = make([]string, 0) - if err := d.Arr(func(d *jx.Decoder) error { - var elem string - v, err := d.Str() - elem = string(v) - if err != nil { - return err - } - s.FileTypes = append(s.FileTypes, elem) - return nil - }); err != nil { + v, err := d.Bool() + s.EnableDices = bool(v) + if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"file_types\"") + return errors.Wrap(err, "decode field \"enable_dices\"") } - case "icons": + case "enable_shield": + requiredBitSet[2] |= 1 << 0 if err := func() error { - s.Icons = make([]BoardIconsItem, 0) - if err := d.Arr(func(d *jx.Decoder) error { - var elem BoardIconsItem - if err := elem.Decode(d); err != nil { - return err - } - s.Icons = append(s.Icons, elem) - return nil - }); err != nil { + v, err := d.Bool() + s.EnableShield = bool(v) + if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"icons\"") + return errors.Wrap(err, "decode field \"enable_shield\"") } - case "id": + case "enable_thread_tags": requiredBitSet[2] |= 1 << 1 if err := func() error { - v, err := d.Str() - s.ID = string(v) + v, err := d.Bool() + s.EnableThreadTags = bool(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"id\"") + return errors.Wrap(err, "decode field \"enable_thread_tags\"") } - case "info": + case "enable_posting": requiredBitSet[2] |= 1 << 2 if err := func() error { - v, err := d.Str() - s.Info = string(v) + v, err := d.Bool() + s.EnablePosting = bool(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"info\"") + return errors.Wrap(err, "decode field \"enable_posting\"") } - case "info_outer": + case "enable_likes": requiredBitSet[2] |= 1 << 3 if err := func() error { - v, err := d.Str() - s.InfoOuter = string(v) + v, err := d.Bool() + s.EnableLikes = bool(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"info_outer\"") + return errors.Wrap(err, "decode field \"enable_likes\"") } - case "max_comment": + case "enable_oekaki": requiredBitSet[2] |= 1 << 4 if err := func() error { - v, err := d.Int() - s.MaxComment = int(v) + v, err := d.Bool() + s.EnableOekaki = bool(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"max_comment\"") + return errors.Wrap(err, "decode field \"enable_oekaki\"") } - case "max_files_size": + case "file_types": requiredBitSet[2] |= 1 << 5 if err := func() error { - v, err := d.Int() - s.MaxFilesSize = int(v) - if err != nil { + s.FileTypes = make([]string, 0) + if err := d.Arr(func(d *jx.Decoder) error { + var elem string + v, err := d.Str() + elem = string(v) + if err != nil { + return err + } + s.FileTypes = append(s.FileTypes, elem) + return nil + }); err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"max_files_size\"") + return errors.Wrap(err, "decode field \"file_types\"") } - case "max_pages": + case "max_comment": requiredBitSet[2] |= 1 << 6 if err := func() error { v, err := d.Int() - s.MaxPages = int(v) + s.MaxComment = int(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"max_pages\"") + return errors.Wrap(err, "decode field \"max_comment\"") } - case "name": + case "max_files_size": requiredBitSet[2] |= 1 << 7 if err := func() error { - v, err := d.Str() - s.Name = string(v) + v, err := d.Int() + s.MaxFilesSize = int(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"name\"") + return errors.Wrap(err, "decode field \"max_files_size\"") } case "tags": if err := func() error { @@ -525,17 +520,22 @@ func (s *Board) Decode(d *jx.Decoder) error { }(); err != nil { return errors.Wrap(err, "decode field \"tags\"") } - case "threads_per_page": - requiredBitSet[3] |= 1 << 1 + case "icons": if err := func() error { - v, err := d.Int() - s.ThreadsPerPage = int(v) - if err != nil { + s.Icons = make([]BoardIconsItem, 0) + if err := d.Arr(func(d *jx.Decoder) error { + var elem BoardIconsItem + if err := elem.Decode(d); err != nil { + return err + } + s.Icons = append(s.Icons, elem) + return nil + }); err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"threads_per_page\"") + return errors.Wrap(err, "decode field \"icons\"") } default: return d.Skip() @@ -549,8 +549,8 @@ func (s *Board) Decode(d *jx.Decoder) error { for i, mask := range [4]uint8{ 0b11111111, 0b11111111, - 0b11111110, - 0b00000010, + 0b11111111, + 0b00000000, } { if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { // Mask only required fields and check equality to mask using XOR. @@ -605,18 +605,18 @@ func (s BoardIconsItem) Encode(e *jx.Encoder) { // encodeFields encodes fields. func (s BoardIconsItem) encodeFields(e *jx.Encoder) { - { - if s.Name.Set { - e.FieldStart("name") - s.Name.Encode(e) - } - } { if s.Num.Set { e.FieldStart("num") s.Num.Encode(e) } } + { + if s.Name.Set { + e.FieldStart("name") + s.Name.Encode(e) + } + } { if s.URL.Set { e.FieldStart("url") @@ -626,8 +626,8 @@ func (s BoardIconsItem) encodeFields(e *jx.Encoder) { } var jsonFieldsNameOfBoardIconsItem = [3]string{ - 0: "name", - 1: "num", + 0: "num", + 1: "name", 2: "url", } @@ -639,25 +639,25 @@ func (s *BoardIconsItem) Decode(d *jx.Decoder) error { if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { switch string(k) { - case "name": + case "num": if err := func() error { - s.Name.Reset() - if err := s.Name.Decode(d); err != nil { + s.Num.Reset() + if err := s.Num.Decode(d); err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"name\"") + return errors.Wrap(err, "decode field \"num\"") } - case "num": + case "name": if err := func() error { - s.Num.Reset() - if err := s.Num.Decode(d); err != nil { + s.Name.Reset() + if err := s.Name.Decode(d); err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"num\"") + return errors.Wrap(err, "decode field \"name\"") } case "url": if err := func() error { @@ -752,6 +752,11 @@ func (s Captcha) Encode(e *jx.Encoder) { // encodeFields encodes fields. func (s Captcha) encodeFields(e *jx.Encoder) { + { + + e.FieldStart("result") + e.Int(s.Result) + } { if s.Error.Set { e.FieldStart("error") @@ -759,41 +764,36 @@ func (s Captcha) encodeFields(e *jx.Encoder) { } } { - if s.Expires.Set { - e.FieldStart("expires") - s.Expires.Encode(e) - } + + e.FieldStart("type") + s.Type.Encode(e) } { e.FieldStart("id") e.Str(s.ID) } + { + if s.Expires.Set { + e.FieldStart("expires") + s.Expires.Encode(e) + } + } { if s.Input.Set { e.FieldStart("input") s.Input.Encode(e) } } - { - - e.FieldStart("result") - e.Int(s.Result) - } - { - - e.FieldStart("type") - s.Type.Encode(e) - } } var jsonFieldsNameOfCaptcha = [6]string{ - 0: "error", - 1: "expires", - 2: "id", - 3: "input", - 4: "result", - 5: "type", + 0: "result", + 1: "error", + 2: "type", + 3: "id", + 4: "expires", + 5: "input", } // Decode decodes Captcha from json. @@ -805,6 +805,18 @@ func (s *Captcha) Decode(d *jx.Decoder) error { if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { switch string(k) { + case "result": + requiredBitSet[0] |= 1 << 0 + if err := func() error { + v, err := d.Int() + s.Result = int(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"result\"") + } case "error": if err := func() error { s.Error.Reset() @@ -815,18 +827,18 @@ func (s *Captcha) Decode(d *jx.Decoder) error { }(); err != nil { return errors.Wrap(err, "decode field \"error\"") } - case "expires": + case "type": + requiredBitSet[0] |= 1 << 2 if err := func() error { - s.Expires.Reset() - if err := s.Expires.Decode(d); err != nil { + if err := s.Type.Decode(d); err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"expires\"") + return errors.Wrap(err, "decode field \"type\"") } case "id": - requiredBitSet[0] |= 1 << 2 + requiredBitSet[0] |= 1 << 3 if err := func() error { v, err := d.Str() s.ID = string(v) @@ -837,37 +849,25 @@ func (s *Captcha) Decode(d *jx.Decoder) error { }(); err != nil { return errors.Wrap(err, "decode field \"id\"") } - case "input": - if err := func() error { - s.Input.Reset() - if err := s.Input.Decode(d); err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"input\"") - } - case "result": - requiredBitSet[0] |= 1 << 4 + case "expires": if err := func() error { - v, err := d.Int() - s.Result = int(v) - if err != nil { + s.Expires.Reset() + if err := s.Expires.Decode(d); err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"result\"") + return errors.Wrap(err, "decode field \"expires\"") } - case "type": - requiredBitSet[0] |= 1 << 5 + case "input": if err := func() error { - if err := s.Type.Decode(d); err != nil { + s.Input.Reset() + if err := s.Input.Decode(d); err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"type\"") + return errors.Wrap(err, "decode field \"input\"") } default: return d.Skip() @@ -879,7 +879,7 @@ func (s *Captcha) Decode(d *jx.Decoder) error { // Validate required fields. var failures []validate.FieldError for i, mask := range [1]uint8{ - 0b00110100, + 0b00001101, } { if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { // Mask only required fields and check equality to mask using XOR. @@ -1098,20 +1098,8 @@ func (s File) Encode(e *jx.Encoder) { func (s File) encodeFields(e *jx.Encoder) { { - e.FieldStart("displayname") - e.Str(s.Displayname) - } - { - if s.Duration.Set { - e.FieldStart("duration") - s.Duration.Encode(e) - } - } - { - if s.DurationSecs.Set { - e.FieldStart("duration_secs") - s.DurationSecs.Encode(e) - } + e.FieldStart("name") + e.Str(s.Name) } { @@ -1120,14 +1108,18 @@ func (s File) encodeFields(e *jx.Encoder) { } { - e.FieldStart("height") - e.Int(s.Height) + e.FieldStart("displayname") + e.Str(s.Displayname) } { - if s.Install.Set { - e.FieldStart("install") - s.Install.Encode(e) - } + + e.FieldStart("path") + e.Str(s.Path) + } + { + + e.FieldStart("thumbnail") + e.Str(s.Thumbnail) } { if s.MD5.Set { @@ -1137,83 +1129,91 @@ func (s File) encodeFields(e *jx.Encoder) { } { - e.FieldStart("name") - e.Str(s.Name) + e.FieldStart("type") + s.Type.Encode(e) } { - if s.Nsfw.Set { - e.FieldStart("nsfw") - s.Nsfw.Encode(e) - } + + e.FieldStart("size") + e.Int(s.Size) } { - if s.Pack.Set { - e.FieldStart("pack") - s.Pack.Encode(e) - } + + e.FieldStart("width") + e.Int(s.Width) } { - e.FieldStart("path") - e.Str(s.Path) + e.FieldStart("height") + e.Int(s.Height) } { - e.FieldStart("size") - e.Int(s.Size) + e.FieldStart("tn_width") + e.Int(s.TnWidth) } { - if s.Sticker.Set { - e.FieldStart("sticker") - s.Sticker.Encode(e) + + e.FieldStart("tn_height") + e.Int(s.TnHeight) + } + { + if s.Nsfw.Set { + e.FieldStart("nsfw") + s.Nsfw.Encode(e) } } { - - e.FieldStart("thumbnail") - e.Str(s.Thumbnail) + if s.Duration.Set { + e.FieldStart("duration") + s.Duration.Encode(e) + } } { - - e.FieldStart("tn_height") - e.Int(s.TnHeight) + if s.DurationSecs.Set { + e.FieldStart("duration_secs") + s.DurationSecs.Encode(e) + } } { - - e.FieldStart("tn_width") - e.Int(s.TnWidth) + if s.Pack.Set { + e.FieldStart("pack") + s.Pack.Encode(e) + } } { - - e.FieldStart("type") - s.Type.Encode(e) + if s.Sticker.Set { + e.FieldStart("sticker") + s.Sticker.Encode(e) + } } { - - e.FieldStart("width") - e.Int(s.Width) + if s.Install.Set { + e.FieldStart("install") + s.Install.Encode(e) + } } } var jsonFieldsNameOfFile = [18]string{ - 0: "displayname", - 1: "duration", - 2: "duration_secs", - 3: "fullname", - 4: "height", - 5: "install", - 6: "md5", - 7: "name", - 8: "nsfw", - 9: "pack", - 10: "path", - 11: "size", - 12: "sticker", - 13: "thumbnail", - 14: "tn_height", - 15: "tn_width", - 16: "type", - 17: "width", + 0: "name", + 1: "fullname", + 2: "displayname", + 3: "path", + 4: "thumbnail", + 5: "md5", + 6: "type", + 7: "size", + 8: "width", + 9: "height", + 10: "tn_width", + 11: "tn_height", + 12: "nsfw", + 13: "duration", + 14: "duration_secs", + 15: "pack", + 16: "sticker", + 17: "install", } // Decode decodes File from json. @@ -1225,71 +1225,65 @@ func (s *File) Decode(d *jx.Decoder) error { if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { switch string(k) { - case "displayname": + case "name": requiredBitSet[0] |= 1 << 0 if err := func() error { v, err := d.Str() - s.Displayname = string(v) - if err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"displayname\"") - } - case "duration": - if err := func() error { - s.Duration.Reset() - if err := s.Duration.Decode(d); err != nil { + s.Name = string(v) + if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"duration\"") + return errors.Wrap(err, "decode field \"name\"") } - case "duration_secs": + case "fullname": + requiredBitSet[0] |= 1 << 1 if err := func() error { - s.DurationSecs.Reset() - if err := s.DurationSecs.Decode(d); err != nil { + v, err := d.Str() + s.Fullname = string(v) + if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"duration_secs\"") + return errors.Wrap(err, "decode field \"fullname\"") } - case "fullname": - requiredBitSet[0] |= 1 << 3 + case "displayname": + requiredBitSet[0] |= 1 << 2 if err := func() error { v, err := d.Str() - s.Fullname = string(v) + s.Displayname = string(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"fullname\"") + return errors.Wrap(err, "decode field \"displayname\"") } - case "height": - requiredBitSet[0] |= 1 << 4 + case "path": + requiredBitSet[0] |= 1 << 3 if err := func() error { - v, err := d.Int() - s.Height = int(v) + v, err := d.Str() + s.Path = string(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"height\"") + return errors.Wrap(err, "decode field \"path\"") } - case "install": + case "thumbnail": + requiredBitSet[0] |= 1 << 4 if err := func() error { - s.Install.Reset() - if err := s.Install.Decode(d); err != nil { + v, err := d.Str() + s.Thumbnail = string(v) + if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"install\"") + return errors.Wrap(err, "decode field \"thumbnail\"") } case "md5": if err := func() error { @@ -1301,129 +1295,135 @@ func (s *File) Decode(d *jx.Decoder) error { }(); err != nil { return errors.Wrap(err, "decode field \"md5\"") } - case "name": + case "type": + requiredBitSet[0] |= 1 << 6 + if err := func() error { + if err := s.Type.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"type\"") + } + case "size": requiredBitSet[0] |= 1 << 7 if err := func() error { - v, err := d.Str() - s.Name = string(v) + v, err := d.Int() + s.Size = int(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"name\"") + return errors.Wrap(err, "decode field \"size\"") } - case "nsfw": + case "width": + requiredBitSet[1] |= 1 << 0 if err := func() error { - s.Nsfw.Reset() - if err := s.Nsfw.Decode(d); err != nil { + v, err := d.Int() + s.Width = int(v) + if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"nsfw\"") + return errors.Wrap(err, "decode field \"width\"") } - case "pack": + case "height": + requiredBitSet[1] |= 1 << 1 if err := func() error { - s.Pack.Reset() - if err := s.Pack.Decode(d); err != nil { + v, err := d.Int() + s.Height = int(v) + if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"pack\"") + return errors.Wrap(err, "decode field \"height\"") } - case "path": + case "tn_width": requiredBitSet[1] |= 1 << 2 if err := func() error { - v, err := d.Str() - s.Path = string(v) + v, err := d.Int() + s.TnWidth = int(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"path\"") + return errors.Wrap(err, "decode field \"tn_width\"") } - case "size": + case "tn_height": requiredBitSet[1] |= 1 << 3 if err := func() error { v, err := d.Int() - s.Size = int(v) + s.TnHeight = int(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"size\"") + return errors.Wrap(err, "decode field \"tn_height\"") } - case "sticker": + case "nsfw": if err := func() error { - s.Sticker.Reset() - if err := s.Sticker.Decode(d); err != nil { + s.Nsfw.Reset() + if err := s.Nsfw.Decode(d); err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"sticker\"") + return errors.Wrap(err, "decode field \"nsfw\"") } - case "thumbnail": - requiredBitSet[1] |= 1 << 5 + case "duration": if err := func() error { - v, err := d.Str() - s.Thumbnail = string(v) - if err != nil { + s.Duration.Reset() + if err := s.Duration.Decode(d); err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"thumbnail\"") + return errors.Wrap(err, "decode field \"duration\"") } - case "tn_height": - requiredBitSet[1] |= 1 << 6 + case "duration_secs": if err := func() error { - v, err := d.Int() - s.TnHeight = int(v) - if err != nil { + s.DurationSecs.Reset() + if err := s.DurationSecs.Decode(d); err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"tn_height\"") + return errors.Wrap(err, "decode field \"duration_secs\"") } - case "tn_width": - requiredBitSet[1] |= 1 << 7 + case "pack": if err := func() error { - v, err := d.Int() - s.TnWidth = int(v) - if err != nil { + s.Pack.Reset() + if err := s.Pack.Decode(d); err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"tn_width\"") + return errors.Wrap(err, "decode field \"pack\"") } - case "type": - requiredBitSet[2] |= 1 << 0 + case "sticker": if err := func() error { - if err := s.Type.Decode(d); err != nil { + s.Sticker.Reset() + if err := s.Sticker.Decode(d); err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"type\"") + return errors.Wrap(err, "decode field \"sticker\"") } - case "width": - requiredBitSet[2] |= 1 << 1 + case "install": if err := func() error { - v, err := d.Int() - s.Width = int(v) - if err != nil { + s.Install.Reset() + if err := s.Install.Decode(d); err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"width\"") + return errors.Wrap(err, "decode field \"install\"") } default: return d.Skip() @@ -1435,9 +1435,9 @@ func (s *File) Decode(d *jx.Decoder) error { // Validate required fields. var failures []validate.FieldError for i, mask := range [3]uint8{ - 0b10011001, - 0b11101100, - 0b00000011, + 0b11011111, + 0b00001111, + 0b00000000, } { if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { // Mask only required fields and check equality to mask using XOR. @@ -1524,23 +1524,23 @@ func (s Like) Encode(e *jx.Encoder) { // encodeFields encodes fields. func (s Like) encodeFields(e *jx.Encoder) { - { - if s.Error.Set { - e.FieldStart("error") - s.Error.Encode(e) - } - } { if s.Result.Set { e.FieldStart("result") s.Result.Encode(e) } } + { + if s.Error.Set { + e.FieldStart("error") + s.Error.Encode(e) + } + } } var jsonFieldsNameOfLike = [2]string{ - 0: "error", - 1: "result", + 0: "result", + 1: "error", } // Decode decodes Like from json. @@ -1551,25 +1551,25 @@ func (s *Like) Decode(d *jx.Decoder) error { if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { switch string(k) { - case "error": + case "result": if err := func() error { - s.Error.Reset() - if err := s.Error.Decode(d); err != nil { + s.Result.Reset() + if err := s.Result.Decode(d); err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"error\"") + return errors.Wrap(err, "decode field \"result\"") } - case "result": + case "error": if err := func() error { - s.Result.Reset() - if err := s.Result.Decode(d); err != nil { + s.Error.Reset() + if err := s.Error.Decode(d); err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"result\"") + return errors.Wrap(err, "decode field \"error\"") } default: return d.Skip() @@ -1604,6 +1604,12 @@ func (s MobilePost) Encode(e *jx.Encoder) { // encodeFields encodes fields. func (s MobilePost) encodeFields(e *jx.Encoder) { + { + if s.Result.Set { + e.FieldStart("result") + s.Result.Encode(e) + } + } { if s.Error.Set { e.FieldStart("error") @@ -1616,18 +1622,12 @@ func (s MobilePost) encodeFields(e *jx.Encoder) { s.Post.Encode(e) } } - { - if s.Result.Set { - e.FieldStart("result") - s.Result.Encode(e) - } - } } var jsonFieldsNameOfMobilePost = [3]string{ - 0: "error", - 1: "post", - 2: "result", + 0: "result", + 1: "error", + 2: "post", } // Decode decodes MobilePost from json. @@ -1638,6 +1638,16 @@ func (s *MobilePost) Decode(d *jx.Decoder) error { if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { switch string(k) { + case "result": + if err := func() error { + s.Result.Reset() + if err := s.Result.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"result\"") + } case "error": if err := func() error { s.Error.Reset() @@ -1658,16 +1668,6 @@ func (s *MobilePost) Decode(d *jx.Decoder) error { }(); err != nil { return errors.Wrap(err, "decode field \"post\"") } - case "result": - if err := func() error { - s.Result.Reset() - if err := s.Result.Decode(d); err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"result\"") - } default: return d.Skip() } @@ -1701,18 +1701,18 @@ func (s MobileThreadLastInfo) Encode(e *jx.Encoder) { // encodeFields encodes fields. func (s MobileThreadLastInfo) encodeFields(e *jx.Encoder) { - { - if s.Error.Set { - e.FieldStart("error") - s.Error.Encode(e) - } - } { if s.Result.Set { e.FieldStart("result") s.Result.Encode(e) } } + { + if s.Error.Set { + e.FieldStart("error") + s.Error.Encode(e) + } + } { if s.Thread.Set { e.FieldStart("thread") @@ -1722,8 +1722,8 @@ func (s MobileThreadLastInfo) encodeFields(e *jx.Encoder) { } var jsonFieldsNameOfMobileThreadLastInfo = [3]string{ - 0: "error", - 1: "result", + 0: "result", + 1: "error", 2: "thread", } @@ -1735,25 +1735,25 @@ func (s *MobileThreadLastInfo) Decode(d *jx.Decoder) error { if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { switch string(k) { - case "error": + case "result": if err := func() error { - s.Error.Reset() - if err := s.Error.Decode(d); err != nil { + s.Result.Reset() + if err := s.Result.Decode(d); err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"error\"") + return errors.Wrap(err, "decode field \"result\"") } - case "result": + case "error": if err := func() error { - s.Result.Reset() - if err := s.Result.Decode(d); err != nil { + s.Error.Reset() + if err := s.Error.Decode(d); err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"result\"") + return errors.Wrap(err, "decode field \"error\"") } case "thread": if err := func() error { @@ -1804,24 +1804,24 @@ func (s MobileThreadLastInfoThread) encodeFields(e *jx.Encoder) { s.Num.Encode(e) } } - { - if s.Posts.Set { - e.FieldStart("posts") - s.Posts.Encode(e) - } - } { if s.Timestamp.Set { e.FieldStart("timestamp") s.Timestamp.Encode(e) } } + { + if s.Posts.Set { + e.FieldStart("posts") + s.Posts.Encode(e) + } + } } var jsonFieldsNameOfMobileThreadLastInfoThread = [3]string{ 0: "num", - 1: "posts", - 2: "timestamp", + 1: "timestamp", + 2: "posts", } // Decode decodes MobileThreadLastInfoThread from json. @@ -1842,25 +1842,25 @@ func (s *MobileThreadLastInfoThread) Decode(d *jx.Decoder) error { }(); err != nil { return errors.Wrap(err, "decode field \"num\"") } - case "posts": + case "timestamp": if err := func() error { - s.Posts.Reset() - if err := s.Posts.Decode(d); err != nil { + s.Timestamp.Reset() + if err := s.Timestamp.Decode(d); err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"posts\"") + return errors.Wrap(err, "decode field \"timestamp\"") } - case "timestamp": + case "posts": if err := func() error { - s.Timestamp.Reset() - if err := s.Timestamp.Decode(d); err != nil { + s.Posts.Reset() + if err := s.Posts.Decode(d); err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"timestamp\"") + return errors.Wrap(err, "decode field \"posts\"") } default: return d.Skip() @@ -1895,12 +1895,24 @@ func (s MobileThreadPostsAfter) Encode(e *jx.Encoder) { // encodeFields encodes fields. func (s MobileThreadPostsAfter) encodeFields(e *jx.Encoder) { + { + if s.Result.Set { + e.FieldStart("result") + s.Result.Encode(e) + } + } { if s.Error.Set { e.FieldStart("error") s.Error.Encode(e) } } + { + if s.UniquePosters.Set { + e.FieldStart("unique_posters") + s.UniquePosters.Encode(e) + } + } { if s.Posts != nil { e.FieldStart("posts") @@ -1911,25 +1923,13 @@ func (s MobileThreadPostsAfter) encodeFields(e *jx.Encoder) { e.ArrEnd() } } - { - if s.Result.Set { - e.FieldStart("result") - s.Result.Encode(e) - } - } - { - if s.UniquePosters.Set { - e.FieldStart("unique_posters") - s.UniquePosters.Encode(e) - } - } } var jsonFieldsNameOfMobileThreadPostsAfter = [4]string{ - 0: "error", - 1: "posts", - 2: "result", - 3: "unique_posters", + 0: "result", + 1: "error", + 2: "unique_posters", + 3: "posts", } // Decode decodes MobileThreadPostsAfter from json. @@ -1940,6 +1940,16 @@ func (s *MobileThreadPostsAfter) Decode(d *jx.Decoder) error { if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { switch string(k) { + case "result": + if err := func() error { + s.Result.Reset() + if err := s.Result.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"result\"") + } case "error": if err := func() error { s.Error.Reset() @@ -1950,6 +1960,16 @@ func (s *MobileThreadPostsAfter) Decode(d *jx.Decoder) error { }(); err != nil { return errors.Wrap(err, "decode field \"error\"") } + case "unique_posters": + if err := func() error { + s.UniquePosters.Reset() + if err := s.UniquePosters.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"unique_posters\"") + } case "posts": if err := func() error { s.Posts = make([]Post, 0) @@ -1967,26 +1987,6 @@ func (s *MobileThreadPostsAfter) Decode(d *jx.Decoder) error { }(); err != nil { return errors.Wrap(err, "decode field \"posts\"") } - case "result": - if err := func() error { - s.Result.Reset() - if err := s.Result.Decode(d); err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"result\"") - } - case "unique_posters": - if err := func() error { - s.UniquePosters.Reset() - if err := s.UniquePosters.Decode(d); err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"unique_posters\"") - } default: return d.Skip() } @@ -2255,6 +2255,12 @@ func (s Passcode) Encode(e *jx.Encoder) { // encodeFields encodes fields. func (s Passcode) encodeFields(e *jx.Encoder) { + { + if s.Result.Set { + e.FieldStart("result") + s.Result.Encode(e) + } + } { if s.Error.Set { e.FieldStart("error") @@ -2267,18 +2273,12 @@ func (s Passcode) encodeFields(e *jx.Encoder) { s.Passcode.Encode(e) } } - { - if s.Result.Set { - e.FieldStart("result") - s.Result.Encode(e) - } - } } var jsonFieldsNameOfPasscode = [3]string{ - 0: "error", - 1: "passcode", - 2: "result", + 0: "result", + 1: "error", + 2: "passcode", } // Decode decodes Passcode from json. @@ -2289,6 +2289,16 @@ func (s *Passcode) Decode(d *jx.Decoder) error { if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { switch string(k) { + case "result": + if err := func() error { + s.Result.Reset() + if err := s.Result.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"result\"") + } case "error": if err := func() error { s.Error.Reset() @@ -2309,16 +2319,6 @@ func (s *Passcode) Decode(d *jx.Decoder) error { }(); err != nil { return errors.Wrap(err, "decode field \"passcode\"") } - case "result": - if err := func() error { - s.Result.Reset() - if err := s.Result.Decode(d); err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"result\"") - } default: return d.Skip() } @@ -2352,23 +2352,23 @@ func (s PasscodePasscode) Encode(e *jx.Encoder) { // encodeFields encodes fields. func (s PasscodePasscode) encodeFields(e *jx.Encoder) { - { - if s.Expires.Set { - e.FieldStart("expires") - s.Expires.Encode(e) - } - } { if s.Type.Set { e.FieldStart("type") s.Type.Encode(e) } } + { + if s.Expires.Set { + e.FieldStart("expires") + s.Expires.Encode(e) + } + } } var jsonFieldsNameOfPasscodePasscode = [2]string{ - 0: "expires", - 1: "type", + 0: "type", + 1: "expires", } // Decode decodes PasscodePasscode from json. @@ -2379,25 +2379,25 @@ func (s *PasscodePasscode) Decode(d *jx.Decoder) error { if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { switch string(k) { - case "expires": + case "type": if err := func() error { - s.Expires.Reset() - if err := s.Expires.Decode(d); err != nil { + s.Type.Reset() + if err := s.Type.Decode(d); err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"expires\"") + return errors.Wrap(err, "decode field \"type\"") } - case "type": + case "expires": if err := func() error { - s.Type.Reset() - if err := s.Type.Decode(d); err != nil { + s.Expires.Reset() + if err := s.Expires.Decode(d); err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"type\"") + return errors.Wrap(err, "decode field \"expires\"") } default: return d.Skip() @@ -2434,8 +2434,13 @@ func (s Post) Encode(e *jx.Encoder) { func (s Post) encodeFields(e *jx.Encoder) { { - e.FieldStart("banned") - e.Int(s.Banned) + e.FieldStart("num") + e.Int(s.Num) + } + { + + e.FieldStart("parent") + e.Int(s.Parent) } { @@ -2444,35 +2449,35 @@ func (s Post) encodeFields(e *jx.Encoder) { } { - e.FieldStart("closed") - e.Int(s.Closed) + e.FieldStart("timestamp") + e.Int(s.Timestamp) } { - e.FieldStart("comment") - e.Str(s.Comment) + e.FieldStart("lasthit") + e.Int(s.Lasthit) } { e.FieldStart("date") e.Str(s.Date) } - { - if s.Dislikes.Set { - e.FieldStart("dislikes") - s.Dislikes.Encode(e) - } - } { if s.Email.Set { e.FieldStart("email") s.Email.Encode(e) } } + { + if s.Subject.Set { + e.FieldStart("subject") + s.Subject.Encode(e) + } + } { - e.FieldStart("endless") - e.Int(s.Endless) + e.FieldStart("comment") + e.Str(s.Comment) } { if s.Files != nil { @@ -2484,66 +2489,48 @@ func (s Post) encodeFields(e *jx.Encoder) { e.ArrEnd() } } - { - if s.Icon.Set { - e.FieldStart("icon") - s.Icon.Encode(e) - } - } { - e.FieldStart("lasthit") - e.Int(s.Lasthit) - } - { - if s.Likes.Set { - e.FieldStart("likes") - s.Likes.Encode(e) - } + e.FieldStart("views") + e.Int(s.Views) } { - if s.Name.Set { - e.FieldStart("name") - s.Name.Encode(e) - } + + e.FieldStart("sticky") + e.Int(s.Sticky) } { - e.FieldStart("num") - e.Int(s.Num) + e.FieldStart("endless") + e.Int(s.Endless) } { - e.FieldStart("op") - e.Int(s.Op) + e.FieldStart("closed") + e.Int(s.Closed) } { - e.FieldStart("parent") - e.Int(s.Parent) + e.FieldStart("banned") + e.Int(s.Banned) } { - e.FieldStart("sticky") - e.Int(s.Sticky) + e.FieldStart("op") + e.Int(s.Op) } { - if s.Subject.Set { - e.FieldStart("subject") - s.Subject.Encode(e) + if s.Name.Set { + e.FieldStart("name") + s.Name.Encode(e) } } { - if s.Tags.Set { - e.FieldStart("tags") - s.Tags.Encode(e) + if s.Icon.Set { + e.FieldStart("icon") + s.Icon.Encode(e) } } - { - - e.FieldStart("timestamp") - e.Int(s.Timestamp) - } { if s.Trip.Set { e.FieldStart("trip") @@ -2557,36 +2544,49 @@ func (s Post) encodeFields(e *jx.Encoder) { } } { - - e.FieldStart("views") - e.Int(s.Views) + if s.Tags.Set { + e.FieldStart("tags") + s.Tags.Encode(e) + } + } + { + if s.Likes.Set { + e.FieldStart("likes") + s.Likes.Encode(e) + } + } + { + if s.Dislikes.Set { + e.FieldStart("dislikes") + s.Dislikes.Encode(e) + } } } var jsonFieldsNameOfPost = [23]string{ - 0: "banned", - 1: "board", - 2: "closed", - 3: "comment", - 4: "date", - 5: "dislikes", + 0: "num", + 1: "parent", + 2: "board", + 3: "timestamp", + 4: "lasthit", + 5: "date", 6: "email", - 7: "endless", - 8: "files", - 9: "icon", - 10: "lasthit", - 11: "likes", - 12: "name", - 13: "num", - 14: "op", - 15: "parent", - 16: "sticky", - 17: "subject", - 18: "tags", - 19: "timestamp", - 20: "trip", - 21: "trip_style", - 22: "views", + 7: "subject", + 8: "comment", + 9: "files", + 10: "views", + 11: "sticky", + 12: "endless", + 13: "closed", + 14: "banned", + 15: "op", + 16: "name", + 17: "icon", + 18: "trip", + 19: "trip_style", + 20: "tags", + 21: "likes", + 22: "dislikes", } // Decode decodes Post from json. @@ -2598,20 +2598,32 @@ func (s *Post) Decode(d *jx.Decoder) error { if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { switch string(k) { - case "banned": + case "num": requiredBitSet[0] |= 1 << 0 if err := func() error { v, err := d.Int() - s.Banned = int(v) + s.Num = int(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"num\"") + } + case "parent": + requiredBitSet[0] |= 1 << 1 + if err := func() error { + v, err := d.Int() + s.Parent = int(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"banned\"") + return errors.Wrap(err, "decode field \"parent\"") } case "board": - requiredBitSet[0] |= 1 << 1 + requiredBitSet[0] |= 1 << 2 if err := func() error { v, err := d.Str() s.Board = string(v) @@ -2622,32 +2634,32 @@ func (s *Post) Decode(d *jx.Decoder) error { }(); err != nil { return errors.Wrap(err, "decode field \"board\"") } - case "closed": - requiredBitSet[0] |= 1 << 2 + case "timestamp": + requiredBitSet[0] |= 1 << 3 if err := func() error { v, err := d.Int() - s.Closed = int(v) + s.Timestamp = int(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"closed\"") + return errors.Wrap(err, "decode field \"timestamp\"") } - case "comment": - requiredBitSet[0] |= 1 << 3 + case "lasthit": + requiredBitSet[0] |= 1 << 4 if err := func() error { - v, err := d.Str() - s.Comment = string(v) + v, err := d.Int() + s.Lasthit = int(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"comment\"") + return errors.Wrap(err, "decode field \"lasthit\"") } case "date": - requiredBitSet[0] |= 1 << 4 + requiredBitSet[0] |= 1 << 5 if err := func() error { v, err := d.Str() s.Date = string(v) @@ -2658,37 +2670,37 @@ func (s *Post) Decode(d *jx.Decoder) error { }(); err != nil { return errors.Wrap(err, "decode field \"date\"") } - case "dislikes": + case "email": if err := func() error { - s.Dislikes.Reset() - if err := s.Dislikes.Decode(d); err != nil { + s.Email.Reset() + if err := s.Email.Decode(d); err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"dislikes\"") + return errors.Wrap(err, "decode field \"email\"") } - case "email": + case "subject": if err := func() error { - s.Email.Reset() - if err := s.Email.Decode(d); err != nil { + s.Subject.Reset() + if err := s.Subject.Decode(d); err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"email\"") + return errors.Wrap(err, "decode field \"subject\"") } - case "endless": - requiredBitSet[0] |= 1 << 7 + case "comment": + requiredBitSet[1] |= 1 << 0 if err := func() error { - v, err := d.Int() - s.Endless = int(v) + v, err := d.Str() + s.Comment = string(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"endless\"") + return errors.Wrap(err, "decode field \"comment\"") } case "files": if err := func() error { @@ -2707,159 +2719,147 @@ func (s *Post) Decode(d *jx.Decoder) error { }(); err != nil { return errors.Wrap(err, "decode field \"files\"") } - case "icon": - if err := func() error { - s.Icon.Reset() - if err := s.Icon.Decode(d); err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"icon\"") - } - case "lasthit": + case "views": requiredBitSet[1] |= 1 << 2 if err := func() error { v, err := d.Int() - s.Lasthit = int(v) + s.Views = int(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"lasthit\"") + return errors.Wrap(err, "decode field \"views\"") } - case "likes": + case "sticky": + requiredBitSet[1] |= 1 << 3 if err := func() error { - s.Likes.Reset() - if err := s.Likes.Decode(d); err != nil { + v, err := d.Int() + s.Sticky = int(v) + if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"likes\"") + return errors.Wrap(err, "decode field \"sticky\"") } - case "name": + case "endless": + requiredBitSet[1] |= 1 << 4 if err := func() error { - s.Name.Reset() - if err := s.Name.Decode(d); err != nil { + v, err := d.Int() + s.Endless = int(v) + if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"name\"") + return errors.Wrap(err, "decode field \"endless\"") } - case "num": + case "closed": requiredBitSet[1] |= 1 << 5 if err := func() error { v, err := d.Int() - s.Num = int(v) + s.Closed = int(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"num\"") + return errors.Wrap(err, "decode field \"closed\"") } - case "op": + case "banned": requiredBitSet[1] |= 1 << 6 if err := func() error { v, err := d.Int() - s.Op = int(v) + s.Banned = int(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"op\"") + return errors.Wrap(err, "decode field \"banned\"") } - case "parent": + case "op": requiredBitSet[1] |= 1 << 7 if err := func() error { v, err := d.Int() - s.Parent = int(v) + s.Op = int(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"parent\"") + return errors.Wrap(err, "decode field \"op\"") } - case "sticky": - requiredBitSet[2] |= 1 << 0 + case "name": if err := func() error { - v, err := d.Int() - s.Sticky = int(v) - if err != nil { + s.Name.Reset() + if err := s.Name.Decode(d); err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"sticky\"") + return errors.Wrap(err, "decode field \"name\"") } - case "subject": + case "icon": if err := func() error { - s.Subject.Reset() - if err := s.Subject.Decode(d); err != nil { + s.Icon.Reset() + if err := s.Icon.Decode(d); err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"subject\"") + return errors.Wrap(err, "decode field \"icon\"") } - case "tags": + case "trip": if err := func() error { - s.Tags.Reset() - if err := s.Tags.Decode(d); err != nil { + s.Trip.Reset() + if err := s.Trip.Decode(d); err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"tags\"") + return errors.Wrap(err, "decode field \"trip\"") } - case "timestamp": - requiredBitSet[2] |= 1 << 3 + case "trip_style": if err := func() error { - v, err := d.Int() - s.Timestamp = int(v) - if err != nil { + s.TripStyle.Reset() + if err := s.TripStyle.Decode(d); err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"timestamp\"") + return errors.Wrap(err, "decode field \"trip_style\"") } - case "trip": + case "tags": if err := func() error { - s.Trip.Reset() - if err := s.Trip.Decode(d); err != nil { + s.Tags.Reset() + if err := s.Tags.Decode(d); err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"trip\"") + return errors.Wrap(err, "decode field \"tags\"") } - case "trip_style": + case "likes": if err := func() error { - s.TripStyle.Reset() - if err := s.TripStyle.Decode(d); err != nil { + s.Likes.Reset() + if err := s.Likes.Decode(d); err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"trip_style\"") + return errors.Wrap(err, "decode field \"likes\"") } - case "views": - requiredBitSet[2] |= 1 << 6 + case "dislikes": if err := func() error { - v, err := d.Int() - s.Views = int(v) - if err != nil { + s.Dislikes.Reset() + if err := s.Dislikes.Decode(d); err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"views\"") + return errors.Wrap(err, "decode field \"dislikes\"") } default: return d.Skip() @@ -2871,9 +2871,9 @@ func (s *Post) Decode(d *jx.Decoder) error { // Validate required fields. var failures []validate.FieldError for i, mask := range [3]uint8{ - 0b10011111, - 0b11100100, - 0b01001001, + 0b00111111, + 0b11111101, + 0b00000000, } { if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { // Mask only required fields and check equality to mask using XOR. @@ -2928,6 +2928,12 @@ func (s PostingNewPost) Encode(e *jx.Encoder) { // encodeFields encodes fields. func (s PostingNewPost) encodeFields(e *jx.Encoder) { + { + if s.Result.Set { + e.FieldStart("result") + s.Result.Encode(e) + } + } { if s.Error.Set { e.FieldStart("error") @@ -2940,18 +2946,12 @@ func (s PostingNewPost) encodeFields(e *jx.Encoder) { s.Num.Encode(e) } } - { - if s.Result.Set { - e.FieldStart("result") - s.Result.Encode(e) - } - } } var jsonFieldsNameOfPostingNewPost = [3]string{ - 0: "error", - 1: "num", - 2: "result", + 0: "result", + 1: "error", + 2: "num", } // Decode decodes PostingNewPost from json. @@ -2962,6 +2962,16 @@ func (s *PostingNewPost) Decode(d *jx.Decoder) error { if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { switch string(k) { + case "result": + if err := func() error { + s.Result.Reset() + if err := s.Result.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"result\"") + } case "error": if err := func() error { s.Error.Reset() @@ -2982,16 +2992,6 @@ func (s *PostingNewPost) Decode(d *jx.Decoder) error { }(); err != nil { return errors.Wrap(err, "decode field \"num\"") } - case "result": - if err := func() error { - s.Result.Reset() - if err := s.Result.Decode(d); err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"result\"") - } default: return d.Skip() } @@ -3025,18 +3025,18 @@ func (s PostingNewThread) Encode(e *jx.Encoder) { // encodeFields encodes fields. func (s PostingNewThread) encodeFields(e *jx.Encoder) { - { - if s.Error.Set { - e.FieldStart("error") - s.Error.Encode(e) - } - } { if s.Result.Set { e.FieldStart("result") s.Result.Encode(e) } } + { + if s.Error.Set { + e.FieldStart("error") + s.Error.Encode(e) + } + } { if s.Thread.Set { e.FieldStart("thread") @@ -3046,8 +3046,8 @@ func (s PostingNewThread) encodeFields(e *jx.Encoder) { } var jsonFieldsNameOfPostingNewThread = [3]string{ - 0: "error", - 1: "result", + 0: "result", + 1: "error", 2: "thread", } @@ -3059,25 +3059,25 @@ func (s *PostingNewThread) Decode(d *jx.Decoder) error { if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { switch string(k) { - case "error": + case "result": if err := func() error { - s.Error.Reset() - if err := s.Error.Decode(d); err != nil { + s.Result.Reset() + if err := s.Result.Decode(d); err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"error\"") + return errors.Wrap(err, "decode field \"result\"") } - case "result": + case "error": if err := func() error { - s.Result.Reset() - if err := s.Result.Decode(d); err != nil { + s.Error.Reset() + if err := s.Error.Decode(d); err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"result\"") + return errors.Wrap(err, "decode field \"error\"") } case "thread": if err := func() error { @@ -3122,23 +3122,23 @@ func (s Report) Encode(e *jx.Encoder) { // encodeFields encodes fields. func (s Report) encodeFields(e *jx.Encoder) { - { - if s.Error.Set { - e.FieldStart("error") - s.Error.Encode(e) - } - } { if s.Result.Set { e.FieldStart("result") s.Result.Encode(e) } } + { + if s.Error.Set { + e.FieldStart("error") + s.Error.Encode(e) + } + } } var jsonFieldsNameOfReport = [2]string{ - 0: "error", - 1: "result", + 0: "result", + 1: "error", } // Decode decodes Report from json. @@ -3149,25 +3149,25 @@ func (s *Report) Decode(d *jx.Decoder) error { if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { switch string(k) { - case "error": + case "result": if err := func() error { - s.Error.Reset() - if err := s.Error.Decode(d); err != nil { + s.Result.Reset() + if err := s.Result.Decode(d); err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"error\"") + return errors.Wrap(err, "decode field \"result\"") } - case "result": + case "error": if err := func() error { - s.Result.Reset() - if err := s.Result.Decode(d); err != nil { + s.Error.Reset() + if err := s.Error.Decode(d); err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"result\"") + return errors.Wrap(err, "decode field \"error\"") } default: return d.Skip() diff --git a/examples/ex_2ch/oas_request_decoders_gen.go b/examples/ex_2ch/oas_request_decoders_gen.go index be0afa275..45d46cf9c 100644 --- a/examples/ex_2ch/oas_request_decoders_gen.go +++ b/examples/ex_2ch/oas_request_decoders_gen.go @@ -137,7 +137,7 @@ func (s *Server) decodeUserPostingPostRequest(r *http.Request, span trace.Span) q := uri.NewQueryDecoder(form) { cfg := uri.QueryParameterDecodingConfig{ - Name: "board", + Name: "captcha_type", Style: uri.QueryStyleForm, Explode: true, } @@ -153,10 +153,18 @@ func (s *Server) decodeUserPostingPostRequest(r *http.Request, span trace.Span) return err } - optForm.Board = c + optForm.CaptchaType = CaptchaType(c) return nil }); err != nil { - return req, close, errors.Wrap(err, "decode \"board\"") + return req, close, errors.Wrap(err, "decode \"captcha_type\"") + } + if err := func() error { + if err := optForm.CaptchaType.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return req, close, errors.Wrap(err, "validate") } } else { return req, close, errors.Wrap(err, "query") @@ -164,7 +172,7 @@ func (s *Server) decodeUserPostingPostRequest(r *http.Request, span trace.Span) } { cfg := uri.QueryParameterDecodingConfig{ - Name: "captcha_type", + Name: "board", Style: uri.QueryStyleForm, Explode: true, } @@ -180,18 +188,10 @@ func (s *Server) decodeUserPostingPostRequest(r *http.Request, span trace.Span) return err } - optForm.CaptchaType = CaptchaType(c) + optForm.Board = c return nil }); err != nil { - return req, close, errors.Wrap(err, "decode \"captcha_type\"") - } - if err := func() error { - if err := optForm.CaptchaType.Validate(); err != nil { - return err - } - return nil - }(); err != nil { - return req, close, errors.Wrap(err, "validate") + return req, close, errors.Wrap(err, "decode \"board\"") } } else { return req, close, errors.Wrap(err, "query") @@ -199,45 +199,45 @@ func (s *Server) decodeUserPostingPostRequest(r *http.Request, span trace.Span) } { cfg := uri.QueryParameterDecodingConfig{ - Name: "comment", + Name: "thread", Style: uri.QueryStyleForm, Explode: true, } if err := q.HasParam(cfg); err == nil { if err := q.DecodeParam(cfg, func(d uri.Decoder) error { - var optFormDotCommentVal string + var optFormDotThreadVal int if err := func() error { val, err := d.DecodeValue() if err != nil { return err } - c, err := conv.ToString(val) + c, err := conv.ToInt(val) if err != nil { return err } - optFormDotCommentVal = c + optFormDotThreadVal = c return nil }(); err != nil { return err } - optForm.Comment.SetTo(optFormDotCommentVal) + optForm.Thread.SetTo(optFormDotThreadVal) return nil }); err != nil { - return req, close, errors.Wrap(err, "decode \"comment\"") + return req, close, errors.Wrap(err, "decode \"thread\"") } } } { cfg := uri.QueryParameterDecodingConfig{ - Name: "email", + Name: "name", Style: uri.QueryStyleForm, Explode: true, } if err := q.HasParam(cfg); err == nil { if err := q.DecodeParam(cfg, func(d uri.Decoder) error { - var optFormDotEmailVal string + var optFormDotNameVal string if err := func() error { val, err := d.DecodeValue() if err != nil { @@ -249,93 +249,91 @@ func (s *Server) decodeUserPostingPostRequest(r *http.Request, span trace.Span) return err } - optFormDotEmailVal = c + optFormDotNameVal = c return nil }(); err != nil { return err } - optForm.Email.SetTo(optFormDotEmailVal) + optForm.Name.SetTo(optFormDotNameVal) return nil }); err != nil { - return req, close, errors.Wrap(err, "decode \"email\"") + return req, close, errors.Wrap(err, "decode \"name\"") } } } { cfg := uri.QueryParameterDecodingConfig{ - Name: "file[]", + Name: "email", Style: uri.QueryStyleForm, Explode: true, } if err := q.HasParam(cfg); err == nil { if err := q.DecodeParam(cfg, func(d uri.Decoder) error { - return d.DecodeArray(func(d uri.Decoder) error { - var optFormDotFileVal string - if err := func() error { - val, err := d.DecodeValue() - if err != nil { - return err - } - - c, err := conv.ToString(val) - if err != nil { - return err - } + var optFormDotEmailVal string + if err := func() error { + val, err := d.DecodeValue() + if err != nil { + return err + } - optFormDotFileVal = c - return nil - }(); err != nil { + c, err := conv.ToString(val) + if err != nil { return err } - optForm.File = append(optForm.File, optFormDotFileVal) + + optFormDotEmailVal = c return nil - }) + }(); err != nil { + return err + } + optForm.Email.SetTo(optFormDotEmailVal) + return nil }); err != nil { - return req, close, errors.Wrap(err, "decode \"file[]\"") + return req, close, errors.Wrap(err, "decode \"email\"") } } } { cfg := uri.QueryParameterDecodingConfig{ - Name: "icon", + Name: "tags", Style: uri.QueryStyleForm, Explode: true, } if err := q.HasParam(cfg); err == nil { if err := q.DecodeParam(cfg, func(d uri.Decoder) error { - var optFormDotIconVal int + var optFormDotTagsVal string if err := func() error { val, err := d.DecodeValue() if err != nil { return err } - c, err := conv.ToInt(val) + c, err := conv.ToString(val) if err != nil { return err } - optFormDotIconVal = c + optFormDotTagsVal = c return nil }(); err != nil { return err } - optForm.Icon.SetTo(optFormDotIconVal) + optForm.Tags.SetTo(optFormDotTagsVal) return nil }); err != nil { - return req, close, errors.Wrap(err, "decode \"icon\"") + return req, close, errors.Wrap(err, "decode \"tags\"") } } } { cfg := uri.QueryParameterDecodingConfig{ - Name: "name", + Name: "subject", Style: uri.QueryStyleForm, Explode: true, } if err := q.HasParam(cfg); err == nil { if err := q.DecodeParam(cfg, func(d uri.Decoder) error { - var optFormDotNameVal string + var optFormDotSubjectVal string if err := func() error { val, err := d.DecodeValue() if err != nil { @@ -347,143 +345,145 @@ func (s *Server) decodeUserPostingPostRequest(r *http.Request, span trace.Span) return err } - optFormDotNameVal = c + optFormDotSubjectVal = c return nil }(); err != nil { return err } - optForm.Name.SetTo(optFormDotNameVal) + optForm.Subject.SetTo(optFormDotSubjectVal) return nil }); err != nil { - return req, close, errors.Wrap(err, "decode \"name\"") + return req, close, errors.Wrap(err, "decode \"subject\"") } } } { cfg := uri.QueryParameterDecodingConfig{ - Name: "op_mark", + Name: "comment", Style: uri.QueryStyleForm, Explode: true, } if err := q.HasParam(cfg); err == nil { if err := q.DecodeParam(cfg, func(d uri.Decoder) error { - var optFormDotOpMarkVal int + var optFormDotCommentVal string if err := func() error { val, err := d.DecodeValue() if err != nil { return err } - c, err := conv.ToInt(val) + c, err := conv.ToString(val) if err != nil { return err } - optFormDotOpMarkVal = c + optFormDotCommentVal = c return nil }(); err != nil { return err } - optForm.OpMark.SetTo(optFormDotOpMarkVal) + optForm.Comment.SetTo(optFormDotCommentVal) return nil }); err != nil { - return req, close, errors.Wrap(err, "decode \"op_mark\"") + return req, close, errors.Wrap(err, "decode \"comment\"") } } } { cfg := uri.QueryParameterDecodingConfig{ - Name: "subject", + Name: "icon", Style: uri.QueryStyleForm, Explode: true, } if err := q.HasParam(cfg); err == nil { if err := q.DecodeParam(cfg, func(d uri.Decoder) error { - var optFormDotSubjectVal string + var optFormDotIconVal int if err := func() error { val, err := d.DecodeValue() if err != nil { return err } - c, err := conv.ToString(val) + c, err := conv.ToInt(val) if err != nil { return err } - optFormDotSubjectVal = c + optFormDotIconVal = c return nil }(); err != nil { return err } - optForm.Subject.SetTo(optFormDotSubjectVal) + optForm.Icon.SetTo(optFormDotIconVal) return nil }); err != nil { - return req, close, errors.Wrap(err, "decode \"subject\"") + return req, close, errors.Wrap(err, "decode \"icon\"") } } } { cfg := uri.QueryParameterDecodingConfig{ - Name: "tags", + Name: "op_mark", Style: uri.QueryStyleForm, Explode: true, } if err := q.HasParam(cfg); err == nil { if err := q.DecodeParam(cfg, func(d uri.Decoder) error { - var optFormDotTagsVal string + var optFormDotOpMarkVal int if err := func() error { val, err := d.DecodeValue() if err != nil { return err } - c, err := conv.ToString(val) + c, err := conv.ToInt(val) if err != nil { return err } - optFormDotTagsVal = c + optFormDotOpMarkVal = c return nil }(); err != nil { return err } - optForm.Tags.SetTo(optFormDotTagsVal) + optForm.OpMark.SetTo(optFormDotOpMarkVal) return nil }); err != nil { - return req, close, errors.Wrap(err, "decode \"tags\"") + return req, close, errors.Wrap(err, "decode \"op_mark\"") } } } { cfg := uri.QueryParameterDecodingConfig{ - Name: "thread", + Name: "file[]", Style: uri.QueryStyleForm, Explode: true, } if err := q.HasParam(cfg); err == nil { if err := q.DecodeParam(cfg, func(d uri.Decoder) error { - var optFormDotThreadVal int - if err := func() error { - val, err := d.DecodeValue() - if err != nil { - return err - } + return d.DecodeArray(func(d uri.Decoder) error { + var optFormDotFileVal string + if err := func() error { + val, err := d.DecodeValue() + if err != nil { + return err + } - c, err := conv.ToInt(val) - if err != nil { + c, err := conv.ToString(val) + if err != nil { + return err + } + + optFormDotFileVal = c + return nil + }(); err != nil { return err } - - optFormDotThreadVal = c + optForm.File = append(optForm.File, optFormDotFileVal) return nil - }(); err != nil { - return err - } - optForm.Thread.SetTo(optFormDotThreadVal) - return nil + }) }); err != nil { - return req, close, errors.Wrap(err, "decode \"thread\"") + return req, close, errors.Wrap(err, "decode \"file[]\"") } } } @@ -567,7 +567,7 @@ func (s *Server) decodeUserReportPostRequest(r *http.Request, span trace.Span) ( } { cfg := uri.QueryParameterDecodingConfig{ - Name: "comment", + Name: "thread", Style: uri.QueryStyleForm, Explode: true, } @@ -578,15 +578,15 @@ func (s *Server) decodeUserReportPostRequest(r *http.Request, span trace.Span) ( return err } - c, err := conv.ToString(val) + c, err := conv.ToInt(val) if err != nil { return err } - optForm.Comment = c + optForm.Thread = c return nil }); err != nil { - return req, close, errors.Wrap(err, "decode \"comment\"") + return req, close, errors.Wrap(err, "decode \"thread\"") } } else { return req, close, errors.Wrap(err, "query") @@ -628,7 +628,7 @@ func (s *Server) decodeUserReportPostRequest(r *http.Request, span trace.Span) ( } { cfg := uri.QueryParameterDecodingConfig{ - Name: "thread", + Name: "comment", Style: uri.QueryStyleForm, Explode: true, } @@ -639,15 +639,15 @@ func (s *Server) decodeUserReportPostRequest(r *http.Request, span trace.Span) ( return err } - c, err := conv.ToInt(val) + c, err := conv.ToString(val) if err != nil { return err } - optForm.Thread = c + optForm.Comment = c return nil }); err != nil { - return req, close, errors.Wrap(err, "decode \"thread\"") + return req, close, errors.Wrap(err, "decode \"comment\"") } } else { return req, close, errors.Wrap(err, "query") diff --git a/examples/ex_2ch/oas_request_encoders_gen.go b/examples/ex_2ch/oas_request_encoders_gen.go index 997a7a17c..6b894d735 100644 --- a/examples/ex_2ch/oas_request_encoders_gen.go +++ b/examples/ex_2ch/oas_request_encoders_gen.go @@ -58,41 +58,41 @@ func encodeUserPostingPostRequest( q := uri.NewQueryEncoder() { - // Encode "board" form field. + // Encode "captcha_type" form field. cfg := uri.QueryParameterEncodingConfig{ - Name: "board", + Name: "captcha_type", Style: uri.QueryStyleForm, Explode: true, } if err := q.EncodeParam(cfg, func(e uri.Encoder) error { - return e.EncodeValue(conv.StringToString(request.Board)) + return e.EncodeValue(conv.StringToString(string(request.CaptchaType))) }); err != nil { return errors.Wrap(err, "encode query") } } { - // Encode "captcha_type" form field. + // Encode "board" form field. cfg := uri.QueryParameterEncodingConfig{ - Name: "captcha_type", + Name: "board", Style: uri.QueryStyleForm, Explode: true, } if err := q.EncodeParam(cfg, func(e uri.Encoder) error { - return e.EncodeValue(conv.StringToString(string(request.CaptchaType))) + return e.EncodeValue(conv.StringToString(request.Board)) }); err != nil { return errors.Wrap(err, "encode query") } } { - // Encode "comment" form field. + // Encode "thread" form field. cfg := uri.QueryParameterEncodingConfig{ - Name: "comment", + Name: "thread", Style: uri.QueryStyleForm, Explode: true, } if err := q.EncodeParam(cfg, func(e uri.Encoder) error { - if val, ok := request.Comment.Get(); ok { - return e.EncodeValue(conv.StringToString(val)) + if val, ok := request.Thread.Get(); ok { + return e.EncodeValue(conv.IntToString(val)) } return nil }); err != nil { @@ -100,14 +100,14 @@ func encodeUserPostingPostRequest( } } { - // Encode "email" form field. + // Encode "name" form field. cfg := uri.QueryParameterEncodingConfig{ - Name: "email", + Name: "name", Style: uri.QueryStyleForm, Explode: true, } if err := q.EncodeParam(cfg, func(e uri.Encoder) error { - if val, ok := request.Email.Get(); ok { + if val, ok := request.Name.Get(); ok { return e.EncodeValue(conv.StringToString(val)) } return nil @@ -116,37 +116,31 @@ func encodeUserPostingPostRequest( } } { - // Encode "file[]" form field. + // Encode "email" form field. cfg := uri.QueryParameterEncodingConfig{ - Name: "file[]", + Name: "email", Style: uri.QueryStyleForm, Explode: true, } if err := q.EncodeParam(cfg, func(e uri.Encoder) error { - return e.EncodeArray(func(e uri.Encoder) error { - for i, item := range request.File { - if err := func() error { - return e.EncodeValue(conv.StringToString(item)) - }(); err != nil { - return errors.Wrapf(err, "[%d]", i) - } - } - return nil - }) + if val, ok := request.Email.Get(); ok { + return e.EncodeValue(conv.StringToString(val)) + } + return nil }); err != nil { return errors.Wrap(err, "encode query") } } { - // Encode "icon" form field. + // Encode "tags" form field. cfg := uri.QueryParameterEncodingConfig{ - Name: "icon", + Name: "tags", Style: uri.QueryStyleForm, Explode: true, } if err := q.EncodeParam(cfg, func(e uri.Encoder) error { - if val, ok := request.Icon.Get(); ok { - return e.EncodeValue(conv.IntToString(val)) + if val, ok := request.Tags.Get(); ok { + return e.EncodeValue(conv.StringToString(val)) } return nil }); err != nil { @@ -154,14 +148,14 @@ func encodeUserPostingPostRequest( } } { - // Encode "name" form field. + // Encode "subject" form field. cfg := uri.QueryParameterEncodingConfig{ - Name: "name", + Name: "subject", Style: uri.QueryStyleForm, Explode: true, } if err := q.EncodeParam(cfg, func(e uri.Encoder) error { - if val, ok := request.Name.Get(); ok { + if val, ok := request.Subject.Get(); ok { return e.EncodeValue(conv.StringToString(val)) } return nil @@ -170,15 +164,15 @@ func encodeUserPostingPostRequest( } } { - // Encode "op_mark" form field. + // Encode "comment" form field. cfg := uri.QueryParameterEncodingConfig{ - Name: "op_mark", + Name: "comment", Style: uri.QueryStyleForm, Explode: true, } if err := q.EncodeParam(cfg, func(e uri.Encoder) error { - if val, ok := request.OpMark.Get(); ok { - return e.EncodeValue(conv.IntToString(val)) + if val, ok := request.Comment.Get(); ok { + return e.EncodeValue(conv.StringToString(val)) } return nil }); err != nil { @@ -186,15 +180,15 @@ func encodeUserPostingPostRequest( } } { - // Encode "subject" form field. + // Encode "icon" form field. cfg := uri.QueryParameterEncodingConfig{ - Name: "subject", + Name: "icon", Style: uri.QueryStyleForm, Explode: true, } if err := q.EncodeParam(cfg, func(e uri.Encoder) error { - if val, ok := request.Subject.Get(); ok { - return e.EncodeValue(conv.StringToString(val)) + if val, ok := request.Icon.Get(); ok { + return e.EncodeValue(conv.IntToString(val)) } return nil }); err != nil { @@ -202,15 +196,15 @@ func encodeUserPostingPostRequest( } } { - // Encode "tags" form field. + // Encode "op_mark" form field. cfg := uri.QueryParameterEncodingConfig{ - Name: "tags", + Name: "op_mark", Style: uri.QueryStyleForm, Explode: true, } if err := q.EncodeParam(cfg, func(e uri.Encoder) error { - if val, ok := request.Tags.Get(); ok { - return e.EncodeValue(conv.StringToString(val)) + if val, ok := request.OpMark.Get(); ok { + return e.EncodeValue(conv.IntToString(val)) } return nil }); err != nil { @@ -218,17 +212,23 @@ func encodeUserPostingPostRequest( } } { - // Encode "thread" form field. + // Encode "file[]" form field. cfg := uri.QueryParameterEncodingConfig{ - Name: "thread", + Name: "file[]", Style: uri.QueryStyleForm, Explode: true, } if err := q.EncodeParam(cfg, func(e uri.Encoder) error { - if val, ok := request.Thread.Get(); ok { - return e.EncodeValue(conv.IntToString(val)) - } - return nil + return e.EncodeArray(func(e uri.Encoder) error { + for i, item := range request.File { + if err := func() error { + return e.EncodeValue(conv.StringToString(item)) + }(); err != nil { + return errors.Wrapf(err, "[%d]", i) + } + } + return nil + }) }); err != nil { return errors.Wrap(err, "encode query") } @@ -267,14 +267,14 @@ func encodeUserReportPostRequest( } } { - // Encode "comment" form field. + // Encode "thread" form field. cfg := uri.QueryParameterEncodingConfig{ - Name: "comment", + Name: "thread", Style: uri.QueryStyleForm, Explode: true, } if err := q.EncodeParam(cfg, func(e uri.Encoder) error { - return e.EncodeValue(conv.StringToString(request.Comment)) + return e.EncodeValue(conv.IntToString(request.Thread)) }); err != nil { return errors.Wrap(err, "encode query") } @@ -302,14 +302,14 @@ func encodeUserReportPostRequest( } } { - // Encode "thread" form field. + // Encode "comment" form field. cfg := uri.QueryParameterEncodingConfig{ - Name: "thread", + Name: "comment", Style: uri.QueryStyleForm, Explode: true, } if err := q.EncodeParam(cfg, func(e uri.Encoder) error { - return e.EncodeValue(conv.IntToString(request.Thread)) + return e.EncodeValue(conv.StringToString(request.Comment)) }); err != nil { return errors.Wrap(err, "encode query") } diff --git a/examples/ex_2ch/oas_schemas_gen.go b/examples/ex_2ch/oas_schemas_gen.go index 775dd5985..99482fc74 100644 --- a/examples/ex_2ch/oas_schemas_gen.go +++ b/examples/ex_2ch/oas_schemas_gen.go @@ -21,43 +21,43 @@ type APICaptchaRecaptchaMobileGetOK struct{} // Модель доски. // Ref: #/components/schemas/Board type Board struct { + ID string "json:\"id\"" + Name string "json:\"name\"" + Category string "json:\"category\"" + // Информация о доске. + Info string "json:\"info\"" + // Информация о доске для главной. + InfoOuter string "json:\"info_outer\"" + ThreadsPerPage int "json:\"threads_per_page\"" BumpLimit int "json:\"bump_limit\"" - Category string "json:\"category\"" + MaxPages int "json:\"max_pages\"" DefaultName string "json:\"default_name\"" - EnableDices bool "json:\"enable_dices\"" - EnableFlags bool "json:\"enable_flags\"" - EnableIcons bool "json:\"enable_icons\"" - EnableLikes bool "json:\"enable_likes\"" EnableNames bool "json:\"enable_names\"" - EnableOekaki bool "json:\"enable_oekaki\"" - EnablePosting bool "json:\"enable_posting\"" + EnableTrips bool "json:\"enable_trips\"" + EnableSubject bool "json:\"enable_subject\"" EnableSage bool "json:\"enable_sage\"" + EnableIcons bool "json:\"enable_icons\"" + EnableFlags bool "json:\"enable_flags\"" + EnableDices bool "json:\"enable_dices\"" EnableShield bool "json:\"enable_shield\"" - EnableSubject bool "json:\"enable_subject\"" EnableThreadTags bool "json:\"enable_thread_tags\"" - EnableTrips bool "json:\"enable_trips\"" + EnablePosting bool "json:\"enable_posting\"" + EnableLikes bool "json:\"enable_likes\"" + EnableOekaki bool "json:\"enable_oekaki\"" FileTypes []string "json:\"file_types\"" + MaxComment int "json:\"max_comment\"" + MaxFilesSize int "json:\"max_files_size\"" + // Массив тегов, которые доступны на этой доске, если они + // включены. + Tags []string "json:\"tags\"" // Массив иконок, которые доступны на этой доске, если // они включены. Icons []BoardIconsItem "json:\"icons\"" - ID string "json:\"id\"" - // Информация о доске. - Info string "json:\"info\"" - // Информация о доске для главной. - InfoOuter string "json:\"info_outer\"" - MaxComment int "json:\"max_comment\"" - MaxFilesSize int "json:\"max_files_size\"" - MaxPages int "json:\"max_pages\"" - Name string "json:\"name\"" - // Массив тегов, которые доступны на этой доске, если они - // включены. - Tags []string "json:\"tags\"" - ThreadsPerPage int "json:\"threads_per_page\"" } type BoardIconsItem struct { - Name OptString "json:\"name\"" Num OptInt "json:\"num\"" + Name OptString "json:\"name\"" URL OptString "json:\"url\"" } @@ -65,11 +65,13 @@ type Boards []Board // Ref: #/components/schemas/Captcha type Captcha struct { - Error OptError "json:\"error\"" + Result int "json:\"result\"" + Error OptError "json:\"error\"" + Type CaptchaType "json:\"type\"" + ID string "json:\"id\"" // Время в секундах после которого id перестанет // действовать. Expires OptInt "json:\"expires\"" - ID string "json:\"id\"" // Тип текста, изображённого на картинке капчи. // Возможные варианты: // * numeric - только цифры. (0123456789) @@ -78,9 +80,7 @@ type Captcha struct { // (0123456789абвгдеёжзийклмнопрстуфхцчшщъыьэюя) // * all - цифры, русские и английские буквы. // (0123456789abcdefghijklmnopqrstuvwxyzабвгдеёжзийклмнопрстуфхцчшщъыьэюя). - Input OptString "json:\"input\"" - Result int "json:\"result\"" - Type CaptchaType "json:\"type\"" + Input OptString "json:\"input\"" } // Каждый тип капчи так же требует дополнительные @@ -213,34 +213,34 @@ const ( // Модель файла. // Ref: #/components/schemas/File type File struct { - Displayname string "json:\"displayname\"" + Name string "json:\"name\"" + Fullname string "json:\"fullname\"" + Displayname string "json:\"displayname\"" + Path string "json:\"path\"" + Thumbnail string "json:\"thumbnail\"" + MD5 OptString "json:\"md5\"" + Type FileType "json:\"type\"" + // Размер файла, в КБ. + Size int "json:\"size\"" + Width int "json:\"width\"" + Height int "json:\"height\"" + TnWidth int "json:\"tn_width\"" + TnHeight int "json:\"tn_height\"" + // Если >= 0, файл содержит NSFW контент, в данный момент + // реализовано не на всех досках. + Nsfw OptInt "json:\"nsfw\"" // В случае видео/аудио файла, содержит // продолжительность в формате XX:XX:XX. Duration OptString "json:\"duration\"" // В случае видео/аудио файла, содержит // продолжительность в секундах. DurationSecs OptInt "json:\"duration_secs\"" - Fullname string "json:\"fullname\"" - Height int "json:\"height\"" - // В случае стикера, содержит ссылку на установку. - Install OptString "json:\"install\"" - MD5 OptString "json:\"md5\"" - Name string "json:\"name\"" - // Если >= 0, файл содержит NSFW контент, в данный момент - // реализовано не на всех досках. - Nsfw OptInt "json:\"nsfw\"" // В случае стикера, содержит ID стикер пака. Pack OptString "json:\"pack\"" - Path string "json:\"path\"" - // Размер файла, в КБ. - Size int "json:\"size\"" // В случае стикера, содержит ID стикера. - Sticker OptString "json:\"sticker\"" - Thumbnail string "json:\"thumbnail\"" - TnHeight int "json:\"tn_height\"" - TnWidth int "json:\"tn_width\"" - Type FileType "json:\"type\"" - Width int "json:\"width\"" + Sticker OptString "json:\"sticker\"" + // В случае стикера, содержит ссылку на установку. + Install OptString "json:\"install\"" } // * 0 FileTypeNone @@ -273,36 +273,36 @@ const ( // Ref: #/components/schemas/Like type Like struct { - Error OptError "json:\"error\"" Result OptInt "json:\"result\"" + Error OptError "json:\"error\"" } // Ref: #/components/schemas/MobilePost type MobilePost struct { + Result OptInt "json:\"result\"" Error OptError "json:\"error\"" Post OptPost "json:\"post\"" - Result OptInt "json:\"result\"" } // Ref: #/components/schemas/MobileThreadLastInfo type MobileThreadLastInfo struct { - Error OptError "json:\"error\"" Result OptInt "json:\"result\"" + Error OptError "json:\"error\"" Thread OptMobileThreadLastInfoThread "json:\"thread\"" } type MobileThreadLastInfoThread struct { Num OptInt "json:\"num\"" - Posts OptInt "json:\"posts\"" Timestamp OptInt "json:\"timestamp\"" + Posts OptInt "json:\"posts\"" } // Ref: #/components/schemas/MobileThreadPostsAfter type MobileThreadPostsAfter struct { - Error OptError "json:\"error\"" - Posts []Post "json:\"posts\"" Result OptInt "json:\"result\"" + Error OptError "json:\"error\"" UniquePosters OptInt "json:\"unique_posters\"" + Posts []Post "json:\"posts\"" } // NewOptError returns new OptError with value set to v. @@ -813,64 +813,64 @@ func (o OptUserReportPostReq) Or(d UserReportPostReq) UserReportPostReq { // Ref: #/components/schemas/Passcode type Passcode struct { + Result OptInt "json:\"result\"" Error OptError "json:\"error\"" Passcode OptPasscodePasscode "json:\"passcode\"" - Result OptInt "json:\"result\"" } type PasscodePasscode struct { - Expires OptInt "json:\"expires\"" Type OptString "json:\"type\"" + Expires OptInt "json:\"expires\"" } // Модель поста. // Ref: #/components/schemas/Post type Post struct { - Banned int "json:\"banned\"" + Num int "json:\"num\"" + Parent int "json:\"parent\"" Board string "json:\"board\"" - Closed int "json:\"closed\"" - Comment string "json:\"comment\"" + Timestamp int "json:\"timestamp\"" + Lasthit int "json:\"lasthit\"" Date string "json:\"date\"" - Dislikes OptInt "json:\"dislikes\"" Email OptString "json:\"email\"" - Endless int "json:\"endless\"" + Subject OptString "json:\"subject\"" + Comment string "json:\"comment\"" Files []File "json:\"files\"" - Icon OptString "json:\"icon\"" - Lasthit int "json:\"lasthit\"" - Likes OptInt "json:\"likes\"" - Name OptString "json:\"name\"" - Num int "json:\"num\"" - Op int "json:\"op\"" - Parent int "json:\"parent\"" + Views int "json:\"views\"" Sticky int "json:\"sticky\"" - Subject OptString "json:\"subject\"" - Tags OptString "json:\"tags\"" - Timestamp int "json:\"timestamp\"" + Endless int "json:\"endless\"" + Closed int "json:\"closed\"" + Banned int "json:\"banned\"" + Op int "json:\"op\"" + Name OptString "json:\"name\"" + Icon OptString "json:\"icon\"" Trip OptString "json:\"trip\"" TripStyle OptString "json:\"trip_style\"" - Views int "json:\"views\"" + Tags OptString "json:\"tags\"" + Likes OptInt "json:\"likes\"" + Dislikes OptInt "json:\"dislikes\"" } // Ref: #/components/schemas/PostingNewPost type PostingNewPost struct { - Error OptError "json:\"error\"" + Result OptInt "json:\"result\"" + Error OptError "json:\"error\"" // Номер нового поста. - Num OptInt "json:\"num\"" - Result OptInt "json:\"result\"" + Num OptInt "json:\"num\"" } // Ref: #/components/schemas/PostingNewThread type PostingNewThread struct { - Error OptError "json:\"error\"" Result OptInt "json:\"result\"" + Error OptError "json:\"error\"" // Номер нового треда. Thread OptInt "json:\"thread\"" } // Ref: #/components/schemas/Report type Report struct { - Error OptError "json:\"error\"" Result OptInt "json:\"result\"" + Error OptError "json:\"error\"" } type UserPassloginPostReq struct { @@ -944,33 +944,33 @@ func NewPostingNewPostUserPostingPostOK(v PostingNewPost) UserPostingPostOK { } type UserPostingPostReq struct { - Board string "json:\"board\"" CaptchaType CaptchaType "json:\"captcha_type\"" - Comment OptString "json:\"comment\"" + Board string "json:\"board\"" + // Если не указано, будет создан тред. + Thread OptInt "json:\"thread\"" // Если не включено в настройках доски - поле будет // проигнорировано. - Email OptString "json:\"email\"" - File []string "json:\"file[]\"" - Icon OptInt "json:\"icon\"" + Name OptString "json:\"name\"" // Если не включено в настройках доски - поле будет // проигнорировано. - Name OptString "json:\"name\"" + Email OptString "json:\"email\"" // Если не включено в настройках доски - поле будет // проигнорировано. - OpMark OptInt "json:\"op_mark\"" + Tags OptString "json:\"tags\"" // Если не включено в настройках доски - поле будет // проигнорировано. Subject OptString "json:\"subject\"" + Comment OptString "json:\"comment\"" + Icon OptInt "json:\"icon\"" // Если не включено в настройках доски - поле будет // проигнорировано. - Tags OptString "json:\"tags\"" - // Если не указано, будет создан тред. - Thread OptInt "json:\"thread\"" + OpMark OptInt "json:\"op_mark\"" + File []string "json:\"file[]\"" } type UserReportPostReq struct { Board string "json:\"board\"" - Comment string "json:\"comment\"" - Post []int "json:\"post\"" Thread int "json:\"thread\"" + Post []int "json:\"post\"" + Comment string "json:\"comment\"" } diff --git a/examples/go.mod b/examples/go.mod index 70f55045c..851e18ca0 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -16,7 +16,6 @@ require ( require ( github.com/davecgh/go-spew v1.1.1 // indirect - github.com/ghodss/yaml v1.0.0 // indirect github.com/go-json-experiment/json v0.0.0-20220620174529-794765d0bd38 // indirect github.com/go-logr/logr v1.2.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect @@ -25,7 +24,6 @@ require ( go.uber.org/atomic v1.9.0 // indirect golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f // indirect golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/examples/go.sum b/examples/go.sum index d013a9a9a..4a2365734 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -3,7 +3,6 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-faster/errors v0.6.1 h1:nNIPOBkprlKzkThvS/0YaX8Zs9KewLCOSFQS5BU06FI= github.com/go-faster/errors v0.6.1/go.mod h1:5MGV2/2T9yvlrbhe9pD9LO5Z/2zCSq2T8j+Jpi2LAyY= github.com/go-faster/jx v0.38.0 h1:8nVYdlMfFt9/sdpgQ7ov0+PQ0rzXTphOeVVQ71YBc8Y= @@ -56,7 +55,6 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/internal/test_allof/oas_faker_gen.go b/internal/test_allof/oas_faker_gen.go index d9a00faf4..21e5f7088 100644 --- a/internal/test_allof/oas_faker_gen.go +++ b/internal/test_allof/oas_faker_gen.go @@ -22,11 +22,6 @@ func (s *Location) SetFake() { // SetFake set fake values. func (s *ObjectsWithConflictingArrayPropertyReq) SetFake() { - { - { - s.Bar = int(0) - } - } { { s.Foo = nil @@ -39,18 +34,23 @@ func (s *ObjectsWithConflictingArrayPropertyReq) SetFake() { } } } + { + { + s.Bar = int(0) + } + } } // SetFake set fake values. func (s *ObjectsWithConflictingPropertiesReq) SetFake() { { { - s.Bar.SetFake() + s.Foo = "string" } } { { - s.Foo = "string" + s.Bar.SetFake() } } } diff --git a/internal/test_allof/oas_json_gen.go b/internal/test_allof/oas_json_gen.go index f33f11663..19f4f4c46 100644 --- a/internal/test_allof/oas_json_gen.go +++ b/internal/test_allof/oas_json_gen.go @@ -137,11 +137,6 @@ func (s ObjectsWithConflictingArrayPropertyReq) Encode(e *jx.Encoder) { // encodeFields encodes fields. func (s ObjectsWithConflictingArrayPropertyReq) encodeFields(e *jx.Encoder) { - { - - e.FieldStart("bar") - e.Int(s.Bar) - } { e.FieldStart("foo") @@ -151,11 +146,16 @@ func (s ObjectsWithConflictingArrayPropertyReq) encodeFields(e *jx.Encoder) { } e.ArrEnd() } + { + + e.FieldStart("bar") + e.Int(s.Bar) + } } var jsonFieldsNameOfObjectsWithConflictingArrayPropertyReq = [2]string{ - 0: "bar", - 1: "foo", + 0: "foo", + 1: "bar", } // Decode decodes ObjectsWithConflictingArrayPropertyReq from json. @@ -167,20 +167,8 @@ func (s *ObjectsWithConflictingArrayPropertyReq) Decode(d *jx.Decoder) error { if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { switch string(k) { - case "bar": - requiredBitSet[0] |= 1 << 0 - if err := func() error { - v, err := d.Int() - s.Bar = int(v) - if err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"bar\"") - } case "foo": - requiredBitSet[0] |= 1 << 1 + requiredBitSet[0] |= 1 << 0 if err := func() error { s.Foo = make([]int, 0) if err := d.Arr(func(d *jx.Decoder) error { @@ -199,6 +187,18 @@ func (s *ObjectsWithConflictingArrayPropertyReq) Decode(d *jx.Decoder) error { }(); err != nil { return errors.Wrap(err, "decode field \"foo\"") } + case "bar": + requiredBitSet[0] |= 1 << 1 + if err := func() error { + v, err := d.Int() + s.Bar = int(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"bar\"") + } default: return d.Skip() } @@ -264,22 +264,22 @@ func (s ObjectsWithConflictingPropertiesReq) Encode(e *jx.Encoder) { // encodeFields encodes fields. func (s ObjectsWithConflictingPropertiesReq) encodeFields(e *jx.Encoder) { + { + + e.FieldStart("foo") + e.Str(s.Foo) + } { if s.Bar.Set { e.FieldStart("bar") s.Bar.Encode(e) } } - { - - e.FieldStart("foo") - e.Str(s.Foo) - } } var jsonFieldsNameOfObjectsWithConflictingPropertiesReq = [2]string{ - 0: "bar", - 1: "foo", + 0: "foo", + 1: "bar", } // Decode decodes ObjectsWithConflictingPropertiesReq from json. @@ -291,27 +291,27 @@ func (s *ObjectsWithConflictingPropertiesReq) Decode(d *jx.Decoder) error { if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { switch string(k) { - case "bar": + case "foo": + requiredBitSet[0] |= 1 << 0 if err := func() error { - s.Bar.Reset() - if err := s.Bar.Decode(d); err != nil { + v, err := d.Str() + s.Foo = string(v) + if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"bar\"") + return errors.Wrap(err, "decode field \"foo\"") } - case "foo": - requiredBitSet[0] |= 1 << 1 + case "bar": if err := func() error { - v, err := d.Str() - s.Foo = string(v) - if err != nil { + s.Bar.Reset() + if err := s.Bar.Decode(d); err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"foo\"") + return errors.Wrap(err, "decode field \"bar\"") } default: return d.Skip() @@ -323,7 +323,7 @@ func (s *ObjectsWithConflictingPropertiesReq) Decode(d *jx.Decoder) error { // Validate required fields. var failures []validate.FieldError for i, mask := range [1]uint8{ - 0b00000010, + 0b00000001, } { if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { // Mask only required fields and check equality to mask using XOR. diff --git a/internal/test_allof/oas_schemas_gen.go b/internal/test_allof/oas_schemas_gen.go index 02c13404b..c636e3c41 100644 --- a/internal/test_allof/oas_schemas_gen.go +++ b/internal/test_allof/oas_schemas_gen.go @@ -20,9 +20,9 @@ type ObjectsWithConflictingArrayPropertyOK struct{} // Merged schema. type ObjectsWithConflictingArrayPropertyReq struct { - Bar int "json:\"bar\"" // Merged property. Foo []int "json:\"foo\"" + Bar int "json:\"bar\"" } // ObjectsWithConflictingPropertiesOK is response for ObjectsWithConflictingProperties operation. @@ -30,9 +30,9 @@ type ObjectsWithConflictingPropertiesOK struct{} // Merged schema. type ObjectsWithConflictingPropertiesReq struct { - Bar OptInt "json:\"bar\"" // Merged property. Foo string "json:\"foo\"" + Bar OptInt "json:\"bar\"" } // NewOptBool returns new OptBool with value set to v. diff --git a/internal/test_allof/oas_validators_gen.go b/internal/test_allof/oas_validators_gen.go index 0589460b4..fd184bd00 100644 --- a/internal/test_allof/oas_validators_gen.go +++ b/internal/test_allof/oas_validators_gen.go @@ -39,6 +39,25 @@ func (s Location) Validate() error { } func (s ObjectsWithConflictingArrayPropertyReq) Validate() error { var failures []validate.FieldError + if err := func() error { + if s.Foo == nil { + return errors.New("nil is invalid value") + } + if err := (validate.Array{ + MinLength: 1, + MinLengthSet: true, + MaxLength: 5, + MaxLengthSet: true, + }).ValidateLength(len(s.Foo)); err != nil { + return errors.Wrap(err, "array") + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: "foo", + Error: err, + }) + } if err := func() error { if err := (validate.Int{ MinSet: true, @@ -59,17 +78,24 @@ func (s ObjectsWithConflictingArrayPropertyReq) Validate() error { Error: err, }) } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } + return nil +} +func (s ObjectsWithConflictingPropertiesReq) Validate() error { + var failures []validate.FieldError if err := func() error { - if s.Foo == nil { - return errors.New("nil is invalid value") - } - if err := (validate.Array{ - MinLength: 1, + if err := (validate.String{ + MinLength: 10, MinLengthSet: true, - MaxLength: 5, - MaxLengthSet: true, - }).ValidateLength(len(s.Foo)); err != nil { - return errors.Wrap(err, "array") + MaxLength: 0, + MaxLengthSet: false, + Email: false, + Hostname: false, + Regex: nil, + }).Validate(string(s.Foo)); err != nil { + return errors.Wrap(err, "string") } return nil }(); err != nil { @@ -78,13 +104,6 @@ func (s ObjectsWithConflictingArrayPropertyReq) Validate() error { Error: err, }) } - if len(failures) > 0 { - return &validate.Error{Fields: failures} - } - return nil -} -func (s ObjectsWithConflictingPropertiesReq) Validate() error { - var failures []validate.FieldError if err := func() error { if s.Bar.Set { if err := func() error { @@ -112,25 +131,6 @@ func (s ObjectsWithConflictingPropertiesReq) Validate() error { Error: err, }) } - if err := func() error { - if err := (validate.String{ - MinLength: 10, - MinLengthSet: true, - MaxLength: 0, - MaxLengthSet: false, - Email: false, - Hostname: false, - Regex: nil, - }).Validate(string(s.Foo)); err != nil { - return errors.Wrap(err, "string") - } - return nil - }(); err != nil { - failures = append(failures, validate.FieldError{ - Name: "foo", - Error: err, - }) - } if len(failures) > 0 { return &validate.Error{Fields: failures} }