Update dependency go modules in client for k8s v1.26.0-rc.0
This commit is contained in:
202
client/vendor/k8s.io/kube-openapi/LICENSE
generated
vendored
Normal file
202
client/vendor/k8s.io/kube-openapi/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
76
client/vendor/k8s.io/kube-openapi/cmd/openapi-gen/args/args.go
generated
vendored
Normal file
76
client/vendor/k8s.io/kube-openapi/cmd/openapi-gen/args/args.go
generated
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package args
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
"k8s.io/gengo/args"
|
||||
)
|
||||
|
||||
// CustomArgs is used by the gengo framework to pass args specific to this generator.
|
||||
type CustomArgs struct {
|
||||
// ReportFilename is added to CustomArgs for specifying name of report file used
|
||||
// by API linter. If specified, API rule violations will be printed to report file.
|
||||
// Otherwise default value "-" will be used which indicates stdout.
|
||||
ReportFilename string
|
||||
}
|
||||
|
||||
// NewDefaults returns default arguments for the generator. Returning the arguments instead
|
||||
// of using default flag parsing allows registering custom arguments afterwards
|
||||
func NewDefaults() (*args.GeneratorArgs, *CustomArgs) {
|
||||
// Default() sets a couple of flag default values for example the boilerplate.
|
||||
// WithoutDefaultFlagParsing() disables implicit addition of command line flags and parsing,
|
||||
// which allows registering custom arguments afterwards
|
||||
genericArgs := args.Default().WithoutDefaultFlagParsing()
|
||||
genericArgs.GoHeaderFilePath = filepath.Join(args.DefaultSourceTree(), "k8s.io/kube-openapi/boilerplate/boilerplate.go.txt")
|
||||
|
||||
customArgs := &CustomArgs{}
|
||||
genericArgs.CustomArgs = customArgs
|
||||
|
||||
// Default value for report filename is "-", which stands for stdout
|
||||
customArgs.ReportFilename = "-"
|
||||
// Default value for output file base name
|
||||
genericArgs.OutputFileBaseName = "openapi_generated"
|
||||
|
||||
return genericArgs, customArgs
|
||||
}
|
||||
|
||||
// AddFlags add the generator flags to the flag set.
|
||||
func (c *CustomArgs) AddFlags(fs *pflag.FlagSet) {
|
||||
fs.StringVarP(&c.ReportFilename, "report-filename", "r", c.ReportFilename, "Name of report file used by API linter to print API violations. Default \"-\" stands for standard output. NOTE that if valid filename other than \"-\" is specified, API linter won't return error on detected API violations. This allows further check of existing API violations without stopping the OpenAPI generation toolchain.")
|
||||
}
|
||||
|
||||
// Validate checks the given arguments.
|
||||
func Validate(genericArgs *args.GeneratorArgs) error {
|
||||
c, ok := genericArgs.CustomArgs.(*CustomArgs)
|
||||
if !ok {
|
||||
return fmt.Errorf("input arguments don't contain valid custom arguments")
|
||||
}
|
||||
if len(c.ReportFilename) == 0 {
|
||||
return fmt.Errorf("report filename cannot be empty. specify a valid filename or use \"-\" for stdout")
|
||||
}
|
||||
if len(genericArgs.OutputFileBaseName) == 0 {
|
||||
return fmt.Errorf("output file base name cannot be empty")
|
||||
}
|
||||
if len(genericArgs.OutputPackagePath) == 0 {
|
||||
return fmt.Errorf("output package cannot be empty")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
51
client/vendor/k8s.io/kube-openapi/pkg/builder3/util/util.go
generated
vendored
Normal file
51
client/vendor/k8s.io/kube-openapi/pkg/builder3/util/util.go
generated
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
Copyright 2022 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"k8s.io/kube-openapi/pkg/schemamutation"
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
)
|
||||
|
||||
// wrapRefs wraps OpenAPI V3 Schema refs that contain sibling elements.
|
||||
// AllOf is used to wrap the Ref to prevent references from having sibling elements
|
||||
// Please see https://github.com/kubernetes/kubernetes/issues/106387#issuecomment-967640388
|
||||
func WrapRefs(schema *spec.Schema) *spec.Schema {
|
||||
walker := schemamutation.Walker{
|
||||
SchemaCallback: func(schema *spec.Schema) *spec.Schema {
|
||||
orig := schema
|
||||
clone := func() {
|
||||
if orig == schema {
|
||||
schema = new(spec.Schema)
|
||||
*schema = *orig
|
||||
}
|
||||
}
|
||||
if schema.Ref.String() != "" && !reflect.DeepEqual(*schema, spec.Schema{SchemaProps: spec.SchemaProps{Ref: schema.Ref}}) {
|
||||
clone()
|
||||
refSchema := new(spec.Schema)
|
||||
refSchema.Ref = schema.Ref
|
||||
schema.Ref = spec.Ref{}
|
||||
schema.AllOf = []spec.Schema{*refSchema}
|
||||
}
|
||||
return schema
|
||||
},
|
||||
RefCallback: schemamutation.RefCallbackNoop,
|
||||
}
|
||||
return walker.WalkSchema(schema)
|
||||
}
|
||||
320
client/vendor/k8s.io/kube-openapi/pkg/common/common.go
generated
vendored
Normal file
320
client/vendor/k8s.io/kube-openapi/pkg/common/common.go
generated
vendored
Normal file
@@ -0,0 +1,320 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package common
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/emicklei/go-restful/v3"
|
||||
|
||||
"k8s.io/kube-openapi/pkg/openapiconv"
|
||||
"k8s.io/kube-openapi/pkg/spec3"
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
)
|
||||
|
||||
const (
|
||||
// TODO: Make this configurable.
|
||||
ExtensionPrefix = "x-kubernetes-"
|
||||
ExtensionV2Schema = ExtensionPrefix + "v2-schema"
|
||||
)
|
||||
|
||||
// OpenAPIDefinition describes single type. Normally these definitions are auto-generated using gen-openapi.
|
||||
type OpenAPIDefinition struct {
|
||||
Schema spec.Schema
|
||||
Dependencies []string
|
||||
}
|
||||
|
||||
type ReferenceCallback func(path string) spec.Ref
|
||||
|
||||
// GetOpenAPIDefinitions is collection of all definitions.
|
||||
type GetOpenAPIDefinitions func(ReferenceCallback) map[string]OpenAPIDefinition
|
||||
|
||||
// OpenAPIDefinitionGetter gets openAPI definitions for a given type. If a type implements this interface,
|
||||
// the definition returned by it will be used, otherwise the auto-generated definitions will be used. See
|
||||
// GetOpenAPITypeFormat for more information about trade-offs of using this interface or GetOpenAPITypeFormat method when
|
||||
// possible.
|
||||
type OpenAPIDefinitionGetter interface {
|
||||
OpenAPIDefinition() *OpenAPIDefinition
|
||||
}
|
||||
|
||||
type OpenAPIV3DefinitionGetter interface {
|
||||
OpenAPIV3Definition() *OpenAPIDefinition
|
||||
}
|
||||
|
||||
type PathHandler interface {
|
||||
Handle(path string, handler http.Handler)
|
||||
}
|
||||
|
||||
type PathHandlerByGroupVersion interface {
|
||||
Handle(path string, handler http.Handler)
|
||||
HandlePrefix(path string, handler http.Handler)
|
||||
}
|
||||
|
||||
// Config is set of configuration for openAPI spec generation.
|
||||
type Config struct {
|
||||
// List of supported protocols such as https, http, etc.
|
||||
ProtocolList []string
|
||||
|
||||
// Info is general information about the API.
|
||||
Info *spec.Info
|
||||
|
||||
// DefaultResponse will be used if an operation does not have any responses listed. It
|
||||
// will show up as ... "responses" : {"default" : $DefaultResponse} in the spec.
|
||||
DefaultResponse *spec.Response
|
||||
|
||||
// ResponseDefinitions will be added to "responses" under the top-level swagger object. This is an object
|
||||
// that holds responses definitions that can be used across operations. This property does not define
|
||||
// global responses for all operations. For more info please refer:
|
||||
// https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#fixed-fields
|
||||
ResponseDefinitions map[string]spec.Response
|
||||
|
||||
// CommonResponses will be added as a response to all operation specs. This is a good place to add common
|
||||
// responses such as authorization failed.
|
||||
CommonResponses map[int]spec.Response
|
||||
|
||||
// List of webservice's path prefixes to ignore
|
||||
IgnorePrefixes []string
|
||||
|
||||
// OpenAPIDefinitions should provide definition for all models used by routes. Failure to provide this map
|
||||
// or any of the models will result in spec generation failure.
|
||||
GetDefinitions GetOpenAPIDefinitions
|
||||
|
||||
// Provides the definition for all models used by routes. One of GetDefinitions or Definitions must be defined to generate a spec.
|
||||
// This takes precedent over the GetDefinitions function
|
||||
Definitions map[string]OpenAPIDefinition
|
||||
|
||||
// GetOperationIDAndTags returns operation id and tags for a restful route. It is an optional function to customize operation IDs.
|
||||
//
|
||||
// Deprecated: GetOperationIDAndTagsFromRoute should be used instead. This cannot be specified if using the new Route
|
||||
// interface set of funcs.
|
||||
GetOperationIDAndTags func(r *restful.Route) (string, []string, error)
|
||||
|
||||
// GetOperationIDAndTagsFromRoute returns operation id and tags for a Route. It is an optional function to customize operation IDs.
|
||||
GetOperationIDAndTagsFromRoute func(r Route) (string, []string, error)
|
||||
|
||||
// GetDefinitionName returns a friendly name for a definition base on the serving path. parameter `name` is the full name of the definition.
|
||||
// It is an optional function to customize model names.
|
||||
GetDefinitionName func(name string) (string, spec.Extensions)
|
||||
|
||||
// PostProcessSpec runs after the spec is ready to serve. It allows a final modification to the spec before serving.
|
||||
PostProcessSpec func(*spec.Swagger) (*spec.Swagger, error)
|
||||
|
||||
// SecurityDefinitions is list of all security definitions for OpenAPI service. If this is not nil, the user of config
|
||||
// is responsible to provide DefaultSecurity and (maybe) add unauthorized response to CommonResponses.
|
||||
SecurityDefinitions *spec.SecurityDefinitions
|
||||
|
||||
// DefaultSecurity for all operations. This will pass as spec.SwaggerProps.Security to OpenAPI.
|
||||
// For most cases, this will be list of acceptable definitions in SecurityDefinitions.
|
||||
DefaultSecurity []map[string][]string
|
||||
}
|
||||
|
||||
// OpenAPIV3Config is set of configuration for OpenAPI V3 spec generation.
|
||||
type OpenAPIV3Config struct {
|
||||
// Info is general information about the API.
|
||||
Info *spec.Info
|
||||
|
||||
// DefaultResponse will be used if an operation does not have any responses listed. It
|
||||
// will show up as ... "responses" : {"default" : $DefaultResponse} in the spec.
|
||||
DefaultResponse *spec3.Response
|
||||
|
||||
// ResponseDefinitions will be added to responses component. This is an object
|
||||
// that holds responses that can be used across operations.
|
||||
ResponseDefinitions map[string]*spec3.Response
|
||||
|
||||
// CommonResponses will be added as a response to all operation specs. This is a good place to add common
|
||||
// responses such as authorization failed.
|
||||
CommonResponses map[int]*spec3.Response
|
||||
|
||||
// List of webservice's path prefixes to ignore
|
||||
IgnorePrefixes []string
|
||||
|
||||
// OpenAPIDefinitions should provide definition for all models used by routes. Failure to provide this map
|
||||
// or any of the models will result in spec generation failure.
|
||||
// One of GetDefinitions or Definitions must be defined to generate a spec.
|
||||
GetDefinitions GetOpenAPIDefinitions
|
||||
|
||||
// Provides the definition for all models used by routes. One of GetDefinitions or Definitions must be defined to generate a spec.
|
||||
// This takes precedent over the GetDefinitions function
|
||||
Definitions map[string]OpenAPIDefinition
|
||||
|
||||
// GetOperationIDAndTags returns operation id and tags for a restful route. It is an optional function to customize operation IDs.
|
||||
//
|
||||
// Deprecated: GetOperationIDAndTagsFromRoute should be used instead. This cannot be specified if using the new Route
|
||||
// interface set of funcs.
|
||||
GetOperationIDAndTags func(r *restful.Route) (string, []string, error)
|
||||
|
||||
// GetOperationIDAndTagsFromRoute returns operation id and tags for a Route. It is an optional function to customize operation IDs.
|
||||
GetOperationIDAndTagsFromRoute func(r Route) (string, []string, error)
|
||||
|
||||
// GetDefinitionName returns a friendly name for a definition base on the serving path. parameter `name` is the full name of the definition.
|
||||
// It is an optional function to customize model names.
|
||||
GetDefinitionName func(name string) (string, spec.Extensions)
|
||||
|
||||
// SecuritySchemes is list of all security schemes for OpenAPI service.
|
||||
SecuritySchemes spec3.SecuritySchemes
|
||||
|
||||
// DefaultSecurity for all operations.
|
||||
DefaultSecurity []map[string][]string
|
||||
}
|
||||
|
||||
// ConvertConfigToV3 converts a Config object to an OpenAPIV3Config object
|
||||
func ConvertConfigToV3(config *Config) *OpenAPIV3Config {
|
||||
if config == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
v3Config := &OpenAPIV3Config{
|
||||
Info: config.Info,
|
||||
IgnorePrefixes: config.IgnorePrefixes,
|
||||
GetDefinitions: config.GetDefinitions,
|
||||
GetOperationIDAndTags: config.GetOperationIDAndTags,
|
||||
GetOperationIDAndTagsFromRoute: config.GetOperationIDAndTagsFromRoute,
|
||||
GetDefinitionName: config.GetDefinitionName,
|
||||
Definitions: config.Definitions,
|
||||
SecuritySchemes: make(spec3.SecuritySchemes),
|
||||
DefaultSecurity: config.DefaultSecurity,
|
||||
DefaultResponse: openapiconv.ConvertResponse(config.DefaultResponse, []string{"application/json"}),
|
||||
|
||||
CommonResponses: make(map[int]*spec3.Response),
|
||||
ResponseDefinitions: make(map[string]*spec3.Response),
|
||||
}
|
||||
|
||||
if config.SecurityDefinitions != nil {
|
||||
for s, securityScheme := range *config.SecurityDefinitions {
|
||||
v3Config.SecuritySchemes[s] = openapiconv.ConvertSecurityScheme(securityScheme)
|
||||
}
|
||||
}
|
||||
for k, commonResponse := range config.CommonResponses {
|
||||
v3Config.CommonResponses[k] = openapiconv.ConvertResponse(&commonResponse, []string{"application/json"})
|
||||
}
|
||||
|
||||
for k, responseDefinition := range config.ResponseDefinitions {
|
||||
v3Config.ResponseDefinitions[k] = openapiconv.ConvertResponse(&responseDefinition, []string{"application/json"})
|
||||
}
|
||||
return v3Config
|
||||
}
|
||||
|
||||
type typeInfo struct {
|
||||
name string
|
||||
format string
|
||||
zero interface{}
|
||||
}
|
||||
|
||||
var schemaTypeFormatMap = map[string]typeInfo{
|
||||
"uint": {"integer", "int32", 0.},
|
||||
"uint8": {"integer", "byte", 0.},
|
||||
"uint16": {"integer", "int32", 0.},
|
||||
"uint32": {"integer", "int64", 0.},
|
||||
"uint64": {"integer", "int64", 0.},
|
||||
"int": {"integer", "int32", 0.},
|
||||
"int8": {"integer", "byte", 0.},
|
||||
"int16": {"integer", "int32", 0.},
|
||||
"int32": {"integer", "int32", 0.},
|
||||
"int64": {"integer", "int64", 0.},
|
||||
"byte": {"integer", "byte", 0},
|
||||
"float64": {"number", "double", 0.},
|
||||
"float32": {"number", "float", 0.},
|
||||
"bool": {"boolean", "", false},
|
||||
"time.Time": {"string", "date-time", ""},
|
||||
"string": {"string", "", ""},
|
||||
"integer": {"integer", "", 0.},
|
||||
"number": {"number", "", 0.},
|
||||
"boolean": {"boolean", "", false},
|
||||
"[]byte": {"string", "byte", ""}, // base64 encoded characters
|
||||
"interface{}": {"object", "", interface{}(nil)},
|
||||
}
|
||||
|
||||
// This function is a reference for converting go (or any custom type) to a simple open API type,format pair. There are
|
||||
// two ways to customize spec for a type. If you add it here, a type will be converted to a simple type and the type
|
||||
// comment (the comment that is added before type definition) will be lost. The spec will still have the property
|
||||
// comment. The second way is to implement OpenAPIDefinitionGetter interface. That function can customize the spec (so
|
||||
// the spec does not need to be simple type,format) or can even return a simple type,format (e.g. IntOrString). For simple
|
||||
// type formats, the benefit of adding OpenAPIDefinitionGetter interface is to keep both type and property documentation.
|
||||
// Example:
|
||||
// type Sample struct {
|
||||
// ...
|
||||
// // port of the server
|
||||
// port IntOrString
|
||||
// ...
|
||||
// }
|
||||
// // IntOrString documentation...
|
||||
// type IntOrString { ... }
|
||||
//
|
||||
// Adding IntOrString to this function:
|
||||
// "port" : {
|
||||
// format: "string",
|
||||
// type: "int-or-string",
|
||||
// Description: "port of the server"
|
||||
// }
|
||||
//
|
||||
// Implement OpenAPIDefinitionGetter for IntOrString:
|
||||
//
|
||||
// "port" : {
|
||||
// $Ref: "#/definitions/IntOrString"
|
||||
// Description: "port of the server"
|
||||
// }
|
||||
// ...
|
||||
// definitions:
|
||||
// {
|
||||
// "IntOrString": {
|
||||
// format: "string",
|
||||
// type: "int-or-string",
|
||||
// Description: "IntOrString documentation..." // new
|
||||
// }
|
||||
// }
|
||||
//
|
||||
func OpenAPITypeFormat(typeName string) (string, string) {
|
||||
mapped, ok := schemaTypeFormatMap[typeName]
|
||||
if !ok {
|
||||
return "", ""
|
||||
}
|
||||
return mapped.name, mapped.format
|
||||
}
|
||||
|
||||
// Returns the zero-value for the given type along with true if the type
|
||||
// could be found.
|
||||
func OpenAPIZeroValue(typeName string) (interface{}, bool) {
|
||||
mapped, ok := schemaTypeFormatMap[typeName]
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
return mapped.zero, true
|
||||
}
|
||||
|
||||
func EscapeJsonPointer(p string) string {
|
||||
// Escaping reference name using rfc6901
|
||||
p = strings.Replace(p, "~", "~0", -1)
|
||||
p = strings.Replace(p, "/", "~1", -1)
|
||||
return p
|
||||
}
|
||||
|
||||
func EmbedOpenAPIDefinitionIntoV2Extension(main OpenAPIDefinition, embedded OpenAPIDefinition) OpenAPIDefinition {
|
||||
if main.Schema.Extensions == nil {
|
||||
main.Schema.Extensions = make(map[string]interface{})
|
||||
}
|
||||
main.Schema.Extensions[ExtensionV2Schema] = embedded.Schema
|
||||
return main
|
||||
}
|
||||
|
||||
// GenerateOpenAPIV3OneOfSchema generate the set of schemas that MUST be assigned to SchemaProps.OneOf
|
||||
func GenerateOpenAPIV3OneOfSchema(types []string) (oneOf []spec.Schema) {
|
||||
for _, t := range types {
|
||||
oneOf = append(oneOf, spec.Schema{SchemaProps: spec.SchemaProps{Type: []string{t}}})
|
||||
}
|
||||
return
|
||||
}
|
||||
19
client/vendor/k8s.io/kube-openapi/pkg/common/doc.go
generated
vendored
Normal file
19
client/vendor/k8s.io/kube-openapi/pkg/common/doc.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// package common holds shared code and types between open API code
|
||||
// generator and spec generator.
|
||||
package common
|
||||
88
client/vendor/k8s.io/kube-openapi/pkg/common/interfaces.go
generated
vendored
Normal file
88
client/vendor/k8s.io/kube-openapi/pkg/common/interfaces.go
generated
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
package common
|
||||
|
||||
// RouteContainer is the entrypoint for a service, which may contain multiple
|
||||
// routes under a common path with a common set of path parameters.
|
||||
type RouteContainer interface {
|
||||
// RootPath is the path that all contained routes are nested under.
|
||||
RootPath() string
|
||||
// PathParameters are common parameters defined in the root path.
|
||||
PathParameters() []Parameter
|
||||
// Routes are all routes exposed under the root path.
|
||||
Routes() []Route
|
||||
}
|
||||
|
||||
// Route is a logical endpoint of a service.
|
||||
type Route interface {
|
||||
// Method defines the HTTP Method.
|
||||
Method() string
|
||||
// Path defines the route's endpoint.
|
||||
Path() string
|
||||
// OperationName defines a machine-readable ID for the route.
|
||||
OperationName() string
|
||||
// Parameters defines the list of accepted parameters.
|
||||
Parameters() []Parameter
|
||||
// Description is a human-readable route description.
|
||||
Description() string
|
||||
// Consumes defines the consumed content-types.
|
||||
Consumes() []string
|
||||
// Produces defines the produced content-types.
|
||||
Produces() []string
|
||||
// Metadata allows adding extensions to the generated spec.
|
||||
Metadata() map[string]interface{}
|
||||
// RequestPayloadSample defines an example request payload. Can return nil.
|
||||
RequestPayloadSample() interface{}
|
||||
// ResponsePayloadSample defines an example response payload. Can return nil.
|
||||
ResponsePayloadSample() interface{}
|
||||
// StatusCodeResponses defines a mapping of HTTP Status Codes to the specific response(s).
|
||||
// Multiple responses with the same HTTP Status Code are acceptable.
|
||||
StatusCodeResponses() []StatusCodeResponse
|
||||
}
|
||||
|
||||
// StatusCodeResponse is an explicit response type with an HTTP Status Code.
|
||||
type StatusCodeResponse interface {
|
||||
// Code defines the HTTP Status Code.
|
||||
Code() int
|
||||
// Message returns the human-readable message.
|
||||
Message() string
|
||||
// Model defines an example payload for this response.
|
||||
Model() interface{}
|
||||
}
|
||||
|
||||
// Parameter is a Route parameter.
|
||||
type Parameter interface {
|
||||
// Name defines the unique-per-route identifier.
|
||||
Name() string
|
||||
// Description is the human-readable description of the param.
|
||||
Description() string
|
||||
// Required defines if this parameter must be provided.
|
||||
Required() bool
|
||||
// Kind defines the type of the parameter itself.
|
||||
Kind() ParameterKind
|
||||
// DataType defines the type of data the parameter carries.
|
||||
DataType() string
|
||||
// AllowMultiple defines if more than one value can be supplied for the parameter.
|
||||
AllowMultiple() bool
|
||||
}
|
||||
|
||||
// ParameterKind is an enum of route parameter types.
|
||||
type ParameterKind int
|
||||
|
||||
const (
|
||||
// PathParameterKind indicates the request parameter type is "path".
|
||||
PathParameterKind = ParameterKind(iota)
|
||||
|
||||
// QueryParameterKind indicates the request parameter type is "query".
|
||||
QueryParameterKind
|
||||
|
||||
// BodyParameterKind indicates the request parameter type is "body".
|
||||
BodyParameterKind
|
||||
|
||||
// HeaderParameterKind indicates the request parameter type is "header".
|
||||
HeaderParameterKind
|
||||
|
||||
// FormParameterKind indicates the request parameter type is "form".
|
||||
FormParameterKind
|
||||
|
||||
// UnknownParameterKind indicates the request parameter type has not been specified.
|
||||
UnknownParameterKind
|
||||
)
|
||||
49
client/vendor/k8s.io/kube-openapi/pkg/generators/README.md
generated
vendored
Normal file
49
client/vendor/k8s.io/kube-openapi/pkg/generators/README.md
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
# Generate OpenAPI definitions
|
||||
|
||||
- To generate definition for a specific type or package add "+k8s:openapi-gen=true" tag to the type/package comment lines.
|
||||
- To exclude a type or a member from a tagged package/type, add "+k8s:openapi-gen=false" tag to the comment lines.
|
||||
|
||||
# OpenAPI Extensions
|
||||
|
||||
OpenAPI spec can have extensions on types. To define one or more extensions on a type or its member
|
||||
add `+k8s:openapi-gen=x-kubernetes-$NAME:$VALUE` to the comment lines before type/member. A type/member can
|
||||
have multiple extensions. The rest of the line in the comment will be used as $VALUE so there is no need to
|
||||
escape or quote the value string. Extensions can be used to pass more information to client generators or
|
||||
documentation generators. For example a type might have a friendly name to be displayed in documentation or
|
||||
being used in a client's fluent interface.
|
||||
|
||||
# Custom OpenAPI type definitions
|
||||
|
||||
Custom types which otherwise don't map directly to OpenAPI can override their
|
||||
OpenAPI definition by implementing a function named "OpenAPIDefinition" with
|
||||
the following signature:
|
||||
|
||||
```go
|
||||
import openapi "k8s.io/kube-openapi/pkg/common"
|
||||
|
||||
// ...
|
||||
|
||||
type Time struct {
|
||||
time.Time
|
||||
}
|
||||
|
||||
func (_ Time) OpenAPIDefinition() openapi.OpenAPIDefinition {
|
||||
return openapi.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"string"},
|
||||
Format: "date-time",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Alternatively, the type can avoid the "openapi" import by defining the following
|
||||
methods. The following example produces the same OpenAPI definition as the
|
||||
example above:
|
||||
|
||||
```go
|
||||
func (_ Time) OpenAPISchemaType() []string { return []string{"string"} }
|
||||
func (_ Time) OpenAPISchemaFormat() string { return "date-time" }
|
||||
```
|
||||
220
client/vendor/k8s.io/kube-openapi/pkg/generators/api_linter.go
generated
vendored
Normal file
220
client/vendor/k8s.io/kube-openapi/pkg/generators/api_linter.go
generated
vendored
Normal file
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package generators
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"sort"
|
||||
|
||||
"k8s.io/kube-openapi/pkg/generators/rules"
|
||||
|
||||
"k8s.io/gengo/generator"
|
||||
"k8s.io/gengo/types"
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
const apiViolationFileType = "api-violation"
|
||||
|
||||
type apiViolationFile struct {
|
||||
// Since our file actually is unrelated to the package structure, use a
|
||||
// path that hasn't been mangled by the framework.
|
||||
unmangledPath string
|
||||
}
|
||||
|
||||
func (a apiViolationFile) AssembleFile(f *generator.File, path string) error {
|
||||
path = a.unmangledPath
|
||||
klog.V(2).Infof("Assembling file %q", path)
|
||||
if path == "-" {
|
||||
_, err := io.Copy(os.Stdout, &f.Body)
|
||||
return err
|
||||
}
|
||||
|
||||
output, err := os.Create(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer output.Close()
|
||||
_, err = io.Copy(output, &f.Body)
|
||||
return err
|
||||
}
|
||||
|
||||
func (a apiViolationFile) VerifyFile(f *generator.File, path string) error {
|
||||
if path == "-" {
|
||||
// Nothing to verify against.
|
||||
return nil
|
||||
}
|
||||
path = a.unmangledPath
|
||||
|
||||
formatted := f.Body.Bytes()
|
||||
existing, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to read file %q for comparison: %v", path, err)
|
||||
}
|
||||
if bytes.Compare(formatted, existing) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Be nice and find the first place where they differ
|
||||
// (Copied from gengo's default file type)
|
||||
i := 0
|
||||
for i < len(formatted) && i < len(existing) && formatted[i] == existing[i] {
|
||||
i++
|
||||
}
|
||||
eDiff, fDiff := existing[i:], formatted[i:]
|
||||
if len(eDiff) > 100 {
|
||||
eDiff = eDiff[:100]
|
||||
}
|
||||
if len(fDiff) > 100 {
|
||||
fDiff = fDiff[:100]
|
||||
}
|
||||
return fmt.Errorf("output for %q differs; first existing/expected diff: \n %q\n %q", path, string(eDiff), string(fDiff))
|
||||
}
|
||||
|
||||
func newAPIViolationGen() *apiViolationGen {
|
||||
return &apiViolationGen{
|
||||
linter: newAPILinter(),
|
||||
}
|
||||
}
|
||||
|
||||
type apiViolationGen struct {
|
||||
generator.DefaultGen
|
||||
|
||||
linter *apiLinter
|
||||
}
|
||||
|
||||
func (v *apiViolationGen) FileType() string { return apiViolationFileType }
|
||||
func (v *apiViolationGen) Filename() string {
|
||||
return "this file is ignored by the file assembler"
|
||||
}
|
||||
|
||||
func (v *apiViolationGen) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error {
|
||||
klog.V(5).Infof("validating API rules for type %v", t)
|
||||
if err := v.linter.validate(t); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Finalize prints the API rule violations to report file (if specified from
|
||||
// arguments) or stdout (default)
|
||||
func (v *apiViolationGen) Finalize(c *generator.Context, w io.Writer) error {
|
||||
// NOTE: we don't return error here because we assume that the report file will
|
||||
// get evaluated afterwards to determine if error should be raised. For example,
|
||||
// you can have make rules that compare the report file with existing known
|
||||
// violations (whitelist) and determine no error if no change is detected.
|
||||
v.linter.report(w)
|
||||
return nil
|
||||
}
|
||||
|
||||
// apiLinter is the framework hosting multiple API rules and recording API rule
|
||||
// violations
|
||||
type apiLinter struct {
|
||||
// API rules that implement APIRule interface and output API rule violations
|
||||
rules []APIRule
|
||||
violations []apiViolation
|
||||
}
|
||||
|
||||
// newAPILinter creates an apiLinter object with API rules in package rules. Please
|
||||
// add APIRule here when new API rule is implemented.
|
||||
func newAPILinter() *apiLinter {
|
||||
return &apiLinter{
|
||||
rules: []APIRule{
|
||||
&rules.NamesMatch{},
|
||||
&rules.OmitEmptyMatchCase{},
|
||||
&rules.ListTypeMissing{},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// apiViolation uniquely identifies single API rule violation
|
||||
type apiViolation struct {
|
||||
// Name of rule from APIRule.Name()
|
||||
rule string
|
||||
|
||||
packageName string
|
||||
typeName string
|
||||
|
||||
// Optional: name of field that violates API rule. Empty fieldName implies that
|
||||
// the entire type violates the rule.
|
||||
field string
|
||||
}
|
||||
|
||||
// apiViolations implements sort.Interface for []apiViolation based on the fields: rule,
|
||||
// packageName, typeName and field.
|
||||
type apiViolations []apiViolation
|
||||
|
||||
func (a apiViolations) Len() int { return len(a) }
|
||||
func (a apiViolations) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
func (a apiViolations) Less(i, j int) bool {
|
||||
if a[i].rule != a[j].rule {
|
||||
return a[i].rule < a[j].rule
|
||||
}
|
||||
if a[i].packageName != a[j].packageName {
|
||||
return a[i].packageName < a[j].packageName
|
||||
}
|
||||
if a[i].typeName != a[j].typeName {
|
||||
return a[i].typeName < a[j].typeName
|
||||
}
|
||||
return a[i].field < a[j].field
|
||||
}
|
||||
|
||||
// APIRule is the interface for validating API rule on Go types
|
||||
type APIRule interface {
|
||||
// Validate evaluates API rule on type t and returns a list of field names in
|
||||
// the type that violate the rule. Empty field name [""] implies the entire
|
||||
// type violates the rule.
|
||||
Validate(t *types.Type) ([]string, error)
|
||||
|
||||
// Name returns the name of APIRule
|
||||
Name() string
|
||||
}
|
||||
|
||||
// validate runs all API rules on type t and records any API rule violation
|
||||
func (l *apiLinter) validate(t *types.Type) error {
|
||||
for _, r := range l.rules {
|
||||
klog.V(5).Infof("validating API rule %v for type %v", r.Name(), t)
|
||||
fields, err := r.Validate(t)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, field := range fields {
|
||||
l.violations = append(l.violations, apiViolation{
|
||||
rule: r.Name(),
|
||||
packageName: t.Name.Package,
|
||||
typeName: t.Name.Name,
|
||||
field: field,
|
||||
})
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// report prints any API rule violation to writer w and returns error if violation exists
|
||||
func (l *apiLinter) report(w io.Writer) error {
|
||||
sort.Sort(apiViolations(l.violations))
|
||||
for _, v := range l.violations {
|
||||
fmt.Fprintf(w, "API rule violation: %s,%s,%s,%s\n", v.rule, v.packageName, v.typeName, v.field)
|
||||
}
|
||||
if len(l.violations) > 0 {
|
||||
return fmt.Errorf("API rule violations exist")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
91
client/vendor/k8s.io/kube-openapi/pkg/generators/config.go
generated
vendored
Normal file
91
client/vendor/k8s.io/kube-openapi/pkg/generators/config.go
generated
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package generators
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
"k8s.io/gengo/args"
|
||||
"k8s.io/gengo/generator"
|
||||
"k8s.io/gengo/namer"
|
||||
"k8s.io/gengo/types"
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
generatorargs "k8s.io/kube-openapi/cmd/openapi-gen/args"
|
||||
)
|
||||
|
||||
type identityNamer struct{}
|
||||
|
||||
func (_ identityNamer) Name(t *types.Type) string {
|
||||
return t.Name.String()
|
||||
}
|
||||
|
||||
var _ namer.Namer = identityNamer{}
|
||||
|
||||
// NameSystems returns the name system used by the generators in this package.
|
||||
func NameSystems() namer.NameSystems {
|
||||
return namer.NameSystems{
|
||||
"raw": namer.NewRawNamer("", nil),
|
||||
"sorting_namer": identityNamer{},
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultNameSystem returns the default name system for ordering the types to be
|
||||
// processed by the generators in this package.
|
||||
func DefaultNameSystem() string {
|
||||
return "sorting_namer"
|
||||
}
|
||||
|
||||
func Packages(context *generator.Context, arguments *args.GeneratorArgs) generator.Packages {
|
||||
boilerplate, err := arguments.LoadGoBoilerplate()
|
||||
if err != nil {
|
||||
klog.Fatalf("Failed loading boilerplate: %v", err)
|
||||
}
|
||||
header := append([]byte(fmt.Sprintf("// +build !%s\n\n", arguments.GeneratedBuildTag)), boilerplate...)
|
||||
header = append(header, []byte(
|
||||
`
|
||||
// This file was autogenerated by openapi-gen. Do not edit it manually!
|
||||
|
||||
`)...)
|
||||
|
||||
reportPath := "-"
|
||||
if customArgs, ok := arguments.CustomArgs.(*generatorargs.CustomArgs); ok {
|
||||
reportPath = customArgs.ReportFilename
|
||||
}
|
||||
context.FileTypes[apiViolationFileType] = apiViolationFile{
|
||||
unmangledPath: reportPath,
|
||||
}
|
||||
|
||||
return generator.Packages{
|
||||
&generator.DefaultPackage{
|
||||
PackageName: filepath.Base(arguments.OutputPackagePath),
|
||||
PackagePath: arguments.OutputPackagePath,
|
||||
HeaderText: header,
|
||||
GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
|
||||
return []generator.Generator{
|
||||
newOpenAPIGen(
|
||||
arguments.OutputFileBaseName,
|
||||
arguments.OutputPackagePath,
|
||||
),
|
||||
newAPIViolationGen(),
|
||||
}
|
||||
},
|
||||
FilterFunc: apiTypeFilterFunc,
|
||||
},
|
||||
}
|
||||
}
|
||||
152
client/vendor/k8s.io/kube-openapi/pkg/generators/enum.go
generated
vendored
Normal file
152
client/vendor/k8s.io/kube-openapi/pkg/generators/enum.go
generated
vendored
Normal file
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
Copyright 2021 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package generators
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"k8s.io/gengo/generator"
|
||||
"k8s.io/gengo/types"
|
||||
)
|
||||
|
||||
const tagEnumType = "enum"
|
||||
const enumTypeDescriptionHeader = "Possible enum values:"
|
||||
|
||||
type enumValue struct {
|
||||
Name string
|
||||
Value string
|
||||
Comment string
|
||||
}
|
||||
|
||||
type enumType struct {
|
||||
Name types.Name
|
||||
Values []*enumValue
|
||||
}
|
||||
|
||||
// enumMap is a map from the name to the matching enum type.
|
||||
type enumMap map[types.Name]*enumType
|
||||
|
||||
type enumContext struct {
|
||||
enumTypes enumMap
|
||||
}
|
||||
|
||||
func newEnumContext(c *generator.Context) *enumContext {
|
||||
return &enumContext{enumTypes: parseEnums(c)}
|
||||
}
|
||||
|
||||
// EnumType checks and finds the enumType for a given type.
|
||||
// If the given type is a known enum type, returns the enumType, true
|
||||
// Otherwise, returns nil, false
|
||||
func (ec *enumContext) EnumType(t *types.Type) (enum *enumType, isEnum bool) {
|
||||
enum, ok := ec.enumTypes[t.Name]
|
||||
return enum, ok
|
||||
}
|
||||
|
||||
// ValueStrings returns all possible values of the enum type as strings
|
||||
// the results are sorted and quoted as Go literals.
|
||||
func (et *enumType) ValueStrings() []string {
|
||||
var values []string
|
||||
for _, value := range et.Values {
|
||||
// use "%q" format to generate a Go literal of the string const value
|
||||
values = append(values, fmt.Sprintf("%q", value.Value))
|
||||
}
|
||||
sort.Strings(values)
|
||||
return values
|
||||
}
|
||||
|
||||
// DescriptionLines returns a description of the enum in this format:
|
||||
//
|
||||
// Possible enum values:
|
||||
// - `"value1"` description 1
|
||||
// - `"value2"` description 2
|
||||
func (et *enumType) DescriptionLines() []string {
|
||||
var lines []string
|
||||
for _, value := range et.Values {
|
||||
lines = append(lines, value.Description())
|
||||
}
|
||||
sort.Strings(lines)
|
||||
// Prepend an empty string to initiate a new paragraph.
|
||||
return append([]string{"", enumTypeDescriptionHeader}, lines...)
|
||||
}
|
||||
|
||||
func parseEnums(c *generator.Context) enumMap {
|
||||
// First, find the builtin "string" type
|
||||
stringType := c.Universe.Type(types.Name{Name: "string"})
|
||||
|
||||
enumTypes := make(enumMap)
|
||||
for _, p := range c.Universe {
|
||||
// find all enum types.
|
||||
for _, t := range p.Types {
|
||||
if isEnumType(stringType, t) {
|
||||
if _, ok := enumTypes[t.Name]; !ok {
|
||||
enumTypes[t.Name] = &enumType{
|
||||
Name: t.Name,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// find all enum values from constants, and try to match each with its type.
|
||||
for _, c := range p.Constants {
|
||||
enumType := c.Underlying
|
||||
if _, ok := enumTypes[enumType.Name]; ok {
|
||||
value := &enumValue{
|
||||
Name: c.Name.Name,
|
||||
Value: *c.ConstValue,
|
||||
Comment: strings.Join(c.CommentLines, " "),
|
||||
}
|
||||
enumTypes[enumType.Name].appendValue(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return enumTypes
|
||||
}
|
||||
|
||||
func (et *enumType) appendValue(value *enumValue) {
|
||||
et.Values = append(et.Values, value)
|
||||
}
|
||||
|
||||
// Description returns the description line for the enumValue
|
||||
// with the format:
|
||||
// - `"FooValue"` is the Foo value
|
||||
func (ev *enumValue) Description() string {
|
||||
comment := strings.TrimSpace(ev.Comment)
|
||||
// The comment should starts with the type name, trim it first.
|
||||
comment = strings.TrimPrefix(comment, ev.Name)
|
||||
// Trim the possible space after previous step.
|
||||
comment = strings.TrimSpace(comment)
|
||||
// The comment may be multiline, cascade all consecutive whitespaces.
|
||||
comment = whitespaceRegex.ReplaceAllString(comment, " ")
|
||||
return fmt.Sprintf(" - `%q` %s", ev.Value, comment)
|
||||
}
|
||||
|
||||
// isEnumType checks if a given type is an enum by the definition
|
||||
// An enum type should be an alias of string and has tag '+enum' in its comment.
|
||||
// Additionally, pass the type of builtin 'string' to check against.
|
||||
func isEnumType(stringType *types.Type, t *types.Type) bool {
|
||||
return t.Kind == types.Alias && t.Underlying == stringType && hasEnumTag(t)
|
||||
}
|
||||
|
||||
func hasEnumTag(t *types.Type) bool {
|
||||
return types.ExtractCommentTags("+", t.CommentLines)[tagEnumType] != nil
|
||||
}
|
||||
|
||||
// whitespaceRegex is the regex for consecutive whitespaces.
|
||||
var whitespaceRegex = regexp.MustCompile(`\s+`)
|
||||
202
client/vendor/k8s.io/kube-openapi/pkg/generators/extension.go
generated
vendored
Normal file
202
client/vendor/k8s.io/kube-openapi/pkg/generators/extension.go
generated
vendored
Normal file
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package generators
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"k8s.io/gengo/examples/set-gen/sets"
|
||||
"k8s.io/gengo/types"
|
||||
)
|
||||
|
||||
const extensionPrefix = "x-kubernetes-"
|
||||
|
||||
// extensionAttributes encapsulates common traits for particular extensions.
|
||||
type extensionAttributes struct {
|
||||
xName string
|
||||
kind types.Kind
|
||||
allowedValues sets.String
|
||||
enforceArray bool
|
||||
}
|
||||
|
||||
// Extension tag to openapi extension attributes
|
||||
var tagToExtension = map[string]extensionAttributes{
|
||||
"patchMergeKey": {
|
||||
xName: "x-kubernetes-patch-merge-key",
|
||||
kind: types.Slice,
|
||||
},
|
||||
"patchStrategy": {
|
||||
xName: "x-kubernetes-patch-strategy",
|
||||
kind: types.Slice,
|
||||
allowedValues: sets.NewString("merge", "retainKeys"),
|
||||
},
|
||||
"listMapKey": {
|
||||
xName: "x-kubernetes-list-map-keys",
|
||||
kind: types.Slice,
|
||||
enforceArray: true,
|
||||
},
|
||||
"listType": {
|
||||
xName: "x-kubernetes-list-type",
|
||||
kind: types.Slice,
|
||||
allowedValues: sets.NewString("atomic", "set", "map"),
|
||||
},
|
||||
"mapType": {
|
||||
xName: "x-kubernetes-map-type",
|
||||
kind: types.Map,
|
||||
allowedValues: sets.NewString("atomic", "granular"),
|
||||
},
|
||||
"structType": {
|
||||
xName: "x-kubernetes-map-type",
|
||||
kind: types.Struct,
|
||||
allowedValues: sets.NewString("atomic", "granular"),
|
||||
},
|
||||
"validations": {
|
||||
xName: "x-kubernetes-validations",
|
||||
kind: types.Slice,
|
||||
},
|
||||
}
|
||||
|
||||
// Extension encapsulates information necessary to generate an OpenAPI extension.
|
||||
type extension struct {
|
||||
idlTag string // Example: listType
|
||||
xName string // Example: x-kubernetes-list-type
|
||||
values []string // Example: [atomic]
|
||||
}
|
||||
|
||||
func (e extension) hasAllowedValues() bool {
|
||||
return tagToExtension[e.idlTag].allowedValues.Len() > 0
|
||||
}
|
||||
|
||||
func (e extension) allowedValues() sets.String {
|
||||
return tagToExtension[e.idlTag].allowedValues
|
||||
}
|
||||
|
||||
func (e extension) hasKind() bool {
|
||||
return len(tagToExtension[e.idlTag].kind) > 0
|
||||
}
|
||||
|
||||
func (e extension) kind() types.Kind {
|
||||
return tagToExtension[e.idlTag].kind
|
||||
}
|
||||
|
||||
func (e extension) validateAllowedValues() error {
|
||||
// allowedValues not set means no restrictions on values.
|
||||
if !e.hasAllowedValues() {
|
||||
return nil
|
||||
}
|
||||
// Check for missing value.
|
||||
if len(e.values) == 0 {
|
||||
return fmt.Errorf("%s needs a value, none given.", e.idlTag)
|
||||
}
|
||||
// For each extension value, validate that it is allowed.
|
||||
allowedValues := e.allowedValues()
|
||||
if !allowedValues.HasAll(e.values...) {
|
||||
return fmt.Errorf("%v not allowed for %s. Allowed values: %v",
|
||||
e.values, e.idlTag, allowedValues.List())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e extension) validateType(kind types.Kind) error {
|
||||
// If this extension class has no kind, then don't validate the type.
|
||||
if !e.hasKind() {
|
||||
return nil
|
||||
}
|
||||
if kind != e.kind() {
|
||||
return fmt.Errorf("tag %s on type %v; only allowed on type %v",
|
||||
e.idlTag, kind, e.kind())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e extension) hasMultipleValues() bool {
|
||||
return len(e.values) > 1
|
||||
}
|
||||
|
||||
func (e extension) isAlwaysArrayFormat() bool {
|
||||
return tagToExtension[e.idlTag].enforceArray
|
||||
}
|
||||
|
||||
// Returns sorted list of map keys. Needed for deterministic testing.
|
||||
func sortedMapKeys(m map[string][]string) []string {
|
||||
keys := make([]string, len(m))
|
||||
i := 0
|
||||
for k := range m {
|
||||
keys[i] = k
|
||||
i++
|
||||
}
|
||||
sort.Strings(keys)
|
||||
return keys
|
||||
}
|
||||
|
||||
// Parses comments to return openapi extensions. Returns a list of
|
||||
// extensions which parsed correctly, as well as a list of the
|
||||
// parse errors. Validating extensions is performed separately.
|
||||
// NOTE: Non-empty errors does not mean extensions is empty.
|
||||
func parseExtensions(comments []string) ([]extension, []error) {
|
||||
extensions := []extension{}
|
||||
errors := []error{}
|
||||
// First, generate extensions from "+k8s:openapi-gen=x-kubernetes-*" annotations.
|
||||
values := getOpenAPITagValue(comments)
|
||||
for _, val := range values {
|
||||
// Example: x-kubernetes-member-tag:member_test
|
||||
if strings.HasPrefix(val, extensionPrefix) {
|
||||
parts := strings.SplitN(val, ":", 2)
|
||||
if len(parts) != 2 {
|
||||
errors = append(errors, fmt.Errorf("invalid extension value: %v", val))
|
||||
continue
|
||||
}
|
||||
e := extension{
|
||||
idlTag: tagName, // Example: k8s:openapi-gen
|
||||
xName: parts[0], // Example: x-kubernetes-member-tag
|
||||
values: []string{parts[1]}, // Example: member_test
|
||||
}
|
||||
extensions = append(extensions, e)
|
||||
}
|
||||
}
|
||||
// Next, generate extensions from "idlTags" (e.g. +listType)
|
||||
tagValues := types.ExtractCommentTags("+", comments)
|
||||
for _, idlTag := range sortedMapKeys(tagValues) {
|
||||
xAttrs, exists := tagToExtension[idlTag]
|
||||
if !exists {
|
||||
continue
|
||||
}
|
||||
values := tagValues[idlTag]
|
||||
e := extension{
|
||||
idlTag: idlTag, // listType
|
||||
xName: xAttrs.xName, // x-kubernetes-list-type
|
||||
values: values, // [atomic]
|
||||
}
|
||||
extensions = append(extensions, e)
|
||||
}
|
||||
return extensions, errors
|
||||
}
|
||||
|
||||
func validateMemberExtensions(extensions []extension, m *types.Member) []error {
|
||||
errors := []error{}
|
||||
for _, e := range extensions {
|
||||
if err := e.validateAllowedValues(); err != nil {
|
||||
errors = append(errors, err)
|
||||
}
|
||||
if err := e.validateType(m.Type.Kind); err != nil {
|
||||
errors = append(errors, err)
|
||||
}
|
||||
}
|
||||
return errors
|
||||
}
|
||||
825
client/vendor/k8s.io/kube-openapi/pkg/generators/openapi.go
generated
vendored
Normal file
825
client/vendor/k8s.io/kube-openapi/pkg/generators/openapi.go
generated
vendored
Normal file
@@ -0,0 +1,825 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package generators
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"k8s.io/gengo/generator"
|
||||
"k8s.io/gengo/namer"
|
||||
"k8s.io/gengo/types"
|
||||
openapi "k8s.io/kube-openapi/pkg/common"
|
||||
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
// This is the comment tag that carries parameters for open API generation.
|
||||
const tagName = "k8s:openapi-gen"
|
||||
const tagOptional = "optional"
|
||||
const tagDefault = "default"
|
||||
|
||||
// Known values for the tag.
|
||||
const (
|
||||
tagValueTrue = "true"
|
||||
tagValueFalse = "false"
|
||||
)
|
||||
|
||||
// Used for temporary validation of patch struct tags.
|
||||
// TODO: Remove patch struct tag validation because they we are now consuming OpenAPI on server.
|
||||
var tempPatchTags = [...]string{
|
||||
"patchMergeKey",
|
||||
"patchStrategy",
|
||||
}
|
||||
|
||||
func getOpenAPITagValue(comments []string) []string {
|
||||
return types.ExtractCommentTags("+", comments)[tagName]
|
||||
}
|
||||
|
||||
func getSingleTagsValue(comments []string, tag string) (string, error) {
|
||||
tags, ok := types.ExtractCommentTags("+", comments)[tag]
|
||||
if !ok || len(tags) == 0 {
|
||||
return "", nil
|
||||
}
|
||||
if len(tags) > 1 {
|
||||
return "", fmt.Errorf("multiple values are not allowed for tag %s", tag)
|
||||
}
|
||||
return tags[0], nil
|
||||
}
|
||||
|
||||
func hasOpenAPITagValue(comments []string, value string) bool {
|
||||
tagValues := getOpenAPITagValue(comments)
|
||||
for _, val := range tagValues {
|
||||
if val == value {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// hasOptionalTag returns true if the member has +optional in its comments or
|
||||
// omitempty in its json tags.
|
||||
func hasOptionalTag(m *types.Member) bool {
|
||||
hasOptionalCommentTag := types.ExtractCommentTags(
|
||||
"+", m.CommentLines)[tagOptional] != nil
|
||||
hasOptionalJsonTag := strings.Contains(
|
||||
reflect.StructTag(m.Tags).Get("json"), "omitempty")
|
||||
return hasOptionalCommentTag || hasOptionalJsonTag
|
||||
}
|
||||
|
||||
func apiTypeFilterFunc(c *generator.Context, t *types.Type) bool {
|
||||
// There is a conflict between this codegen and codecgen, we should avoid types generated for codecgen
|
||||
if strings.HasPrefix(t.Name.Name, "codecSelfer") {
|
||||
return false
|
||||
}
|
||||
pkg := c.Universe.Package(t.Name.Package)
|
||||
if hasOpenAPITagValue(pkg.Comments, tagValueTrue) {
|
||||
return !hasOpenAPITagValue(t.CommentLines, tagValueFalse)
|
||||
}
|
||||
if hasOpenAPITagValue(t.CommentLines, tagValueTrue) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
const (
|
||||
specPackagePath = "k8s.io/kube-openapi/pkg/validation/spec"
|
||||
openAPICommonPackagePath = "k8s.io/kube-openapi/pkg/common"
|
||||
)
|
||||
|
||||
// openApiGen produces a file with auto-generated OpenAPI functions.
|
||||
type openAPIGen struct {
|
||||
generator.DefaultGen
|
||||
// TargetPackage is the package that will get GetOpenAPIDefinitions function returns all open API definitions.
|
||||
targetPackage string
|
||||
imports namer.ImportTracker
|
||||
}
|
||||
|
||||
func newOpenAPIGen(sanitizedName string, targetPackage string) generator.Generator {
|
||||
return &openAPIGen{
|
||||
DefaultGen: generator.DefaultGen{
|
||||
OptionalName: sanitizedName,
|
||||
},
|
||||
imports: generator.NewImportTracker(),
|
||||
targetPackage: targetPackage,
|
||||
}
|
||||
}
|
||||
|
||||
const nameTmpl = "schema_$.type|private$"
|
||||
|
||||
func (g *openAPIGen) Namers(c *generator.Context) namer.NameSystems {
|
||||
// Have the raw namer for this file track what it imports.
|
||||
return namer.NameSystems{
|
||||
"raw": namer.NewRawNamer(g.targetPackage, g.imports),
|
||||
"private": &namer.NameStrategy{
|
||||
Join: func(pre string, in []string, post string) string {
|
||||
return strings.Join(in, "_")
|
||||
},
|
||||
PrependPackageNames: 4, // enough to fully qualify from k8s.io/api/...
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (g *openAPIGen) isOtherPackage(pkg string) bool {
|
||||
if pkg == g.targetPackage {
|
||||
return false
|
||||
}
|
||||
if strings.HasSuffix(pkg, "\""+g.targetPackage+"\"") {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (g *openAPIGen) Imports(c *generator.Context) []string {
|
||||
importLines := []string{}
|
||||
for _, singleImport := range g.imports.ImportLines() {
|
||||
importLines = append(importLines, singleImport)
|
||||
}
|
||||
return importLines
|
||||
}
|
||||
|
||||
func argsFromType(t *types.Type) generator.Args {
|
||||
return generator.Args{
|
||||
"type": t,
|
||||
"ReferenceCallback": types.Ref(openAPICommonPackagePath, "ReferenceCallback"),
|
||||
"OpenAPIDefinition": types.Ref(openAPICommonPackagePath, "OpenAPIDefinition"),
|
||||
"SpecSchemaType": types.Ref(specPackagePath, "Schema"),
|
||||
}
|
||||
}
|
||||
|
||||
func (g *openAPIGen) Init(c *generator.Context, w io.Writer) error {
|
||||
sw := generator.NewSnippetWriter(w, c, "$", "$")
|
||||
sw.Do("func GetOpenAPIDefinitions(ref $.ReferenceCallback|raw$) map[string]$.OpenAPIDefinition|raw$ {\n", argsFromType(nil))
|
||||
sw.Do("return map[string]$.OpenAPIDefinition|raw${\n", argsFromType(nil))
|
||||
|
||||
for _, t := range c.Order {
|
||||
err := newOpenAPITypeWriter(sw, c).generateCall(t)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
sw.Do("}\n", nil)
|
||||
sw.Do("}\n\n", nil)
|
||||
|
||||
return sw.Error()
|
||||
}
|
||||
|
||||
func (g *openAPIGen) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error {
|
||||
klog.V(5).Infof("generating for type %v", t)
|
||||
sw := generator.NewSnippetWriter(w, c, "$", "$")
|
||||
err := newOpenAPITypeWriter(sw, c).generate(t)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return sw.Error()
|
||||
}
|
||||
|
||||
func getJsonTags(m *types.Member) []string {
|
||||
jsonTag := reflect.StructTag(m.Tags).Get("json")
|
||||
if jsonTag == "" {
|
||||
return []string{}
|
||||
}
|
||||
return strings.Split(jsonTag, ",")
|
||||
}
|
||||
|
||||
func getReferableName(m *types.Member) string {
|
||||
jsonTags := getJsonTags(m)
|
||||
if len(jsonTags) > 0 {
|
||||
if jsonTags[0] == "-" {
|
||||
return ""
|
||||
} else {
|
||||
return jsonTags[0]
|
||||
}
|
||||
} else {
|
||||
return m.Name
|
||||
}
|
||||
}
|
||||
|
||||
func shouldInlineMembers(m *types.Member) bool {
|
||||
jsonTags := getJsonTags(m)
|
||||
return len(jsonTags) > 1 && jsonTags[1] == "inline"
|
||||
}
|
||||
|
||||
type openAPITypeWriter struct {
|
||||
*generator.SnippetWriter
|
||||
context *generator.Context
|
||||
refTypes map[string]*types.Type
|
||||
enumContext *enumContext
|
||||
GetDefinitionInterface *types.Type
|
||||
}
|
||||
|
||||
func newOpenAPITypeWriter(sw *generator.SnippetWriter, c *generator.Context) openAPITypeWriter {
|
||||
return openAPITypeWriter{
|
||||
SnippetWriter: sw,
|
||||
context: c,
|
||||
refTypes: map[string]*types.Type{},
|
||||
enumContext: newEnumContext(c),
|
||||
}
|
||||
}
|
||||
|
||||
func methodReturnsValue(mt *types.Type, pkg, name string) bool {
|
||||
if len(mt.Signature.Parameters) != 0 || len(mt.Signature.Results) != 1 {
|
||||
return false
|
||||
}
|
||||
r := mt.Signature.Results[0]
|
||||
return r.Name.Name == name && r.Name.Package == pkg
|
||||
}
|
||||
|
||||
func hasOpenAPIV3DefinitionMethod(t *types.Type) bool {
|
||||
for mn, mt := range t.Methods {
|
||||
if mn != "OpenAPIV3Definition" {
|
||||
continue
|
||||
}
|
||||
return methodReturnsValue(mt, openAPICommonPackagePath, "OpenAPIDefinition")
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func hasOpenAPIDefinitionMethod(t *types.Type) bool {
|
||||
for mn, mt := range t.Methods {
|
||||
if mn != "OpenAPIDefinition" {
|
||||
continue
|
||||
}
|
||||
return methodReturnsValue(mt, openAPICommonPackagePath, "OpenAPIDefinition")
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func hasOpenAPIDefinitionMethods(t *types.Type) bool {
|
||||
var hasSchemaTypeMethod, hasOpenAPISchemaFormat bool
|
||||
for mn, mt := range t.Methods {
|
||||
switch mn {
|
||||
case "OpenAPISchemaType":
|
||||
hasSchemaTypeMethod = methodReturnsValue(mt, "", "[]string")
|
||||
case "OpenAPISchemaFormat":
|
||||
hasOpenAPISchemaFormat = methodReturnsValue(mt, "", "string")
|
||||
}
|
||||
}
|
||||
return hasSchemaTypeMethod && hasOpenAPISchemaFormat
|
||||
}
|
||||
|
||||
func hasOpenAPIV3OneOfMethod(t *types.Type) bool {
|
||||
for mn, mt := range t.Methods {
|
||||
if mn != "OpenAPIV3OneOfTypes" {
|
||||
continue
|
||||
}
|
||||
return methodReturnsValue(mt, "", "[]string")
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// typeShortName returns short package name (e.g. the name x appears in package x definition) dot type name.
|
||||
func typeShortName(t *types.Type) string {
|
||||
return filepath.Base(t.Name.Package) + "." + t.Name.Name
|
||||
}
|
||||
|
||||
func (g openAPITypeWriter) generateMembers(t *types.Type, required []string) ([]string, error) {
|
||||
var err error
|
||||
for t.Kind == types.Pointer { // fast-forward to effective type containing members
|
||||
t = t.Elem
|
||||
}
|
||||
for _, m := range t.Members {
|
||||
if hasOpenAPITagValue(m.CommentLines, tagValueFalse) {
|
||||
continue
|
||||
}
|
||||
if shouldInlineMembers(&m) {
|
||||
required, err = g.generateMembers(m.Type, required)
|
||||
if err != nil {
|
||||
return required, err
|
||||
}
|
||||
continue
|
||||
}
|
||||
name := getReferableName(&m)
|
||||
if name == "" {
|
||||
continue
|
||||
}
|
||||
if !hasOptionalTag(&m) {
|
||||
required = append(required, name)
|
||||
}
|
||||
if err = g.generateProperty(&m, t); err != nil {
|
||||
klog.Errorf("Error when generating: %v, %v\n", name, m)
|
||||
return required, err
|
||||
}
|
||||
}
|
||||
return required, nil
|
||||
}
|
||||
|
||||
func (g openAPITypeWriter) generateCall(t *types.Type) error {
|
||||
// Only generate for struct type and ignore the rest
|
||||
switch t.Kind {
|
||||
case types.Struct:
|
||||
args := argsFromType(t)
|
||||
g.Do("\"$.$\": ", t.Name)
|
||||
|
||||
hasV2Definition := hasOpenAPIDefinitionMethod(t)
|
||||
hasV2DefinitionTypeAndFormat := hasOpenAPIDefinitionMethods(t)
|
||||
hasV3Definition := hasOpenAPIV3DefinitionMethod(t)
|
||||
|
||||
switch {
|
||||
case hasV2DefinitionTypeAndFormat:
|
||||
g.Do(nameTmpl+"(ref),\n", args)
|
||||
case hasV2Definition && hasV3Definition:
|
||||
g.Do("common.EmbedOpenAPIDefinitionIntoV2Extension($.type|raw${}.OpenAPIV3Definition(), $.type|raw${}.OpenAPIDefinition()),\n", args)
|
||||
case hasV2Definition:
|
||||
g.Do("$.type|raw${}.OpenAPIDefinition(),\n", args)
|
||||
case hasV3Definition:
|
||||
g.Do("$.type|raw${}.OpenAPIV3Definition(),\n", args)
|
||||
default:
|
||||
g.Do(nameTmpl+"(ref),\n", args)
|
||||
}
|
||||
}
|
||||
return g.Error()
|
||||
}
|
||||
|
||||
func (g openAPITypeWriter) generate(t *types.Type) error {
|
||||
// Only generate for struct type and ignore the rest
|
||||
switch t.Kind {
|
||||
case types.Struct:
|
||||
hasV2Definition := hasOpenAPIDefinitionMethod(t)
|
||||
hasV2DefinitionTypeAndFormat := hasOpenAPIDefinitionMethods(t)
|
||||
hasV3OneOfTypes := hasOpenAPIV3OneOfMethod(t)
|
||||
hasV3Definition := hasOpenAPIV3DefinitionMethod(t)
|
||||
|
||||
if hasV2Definition || (hasV3Definition && !hasV2DefinitionTypeAndFormat) {
|
||||
// already invoked directly
|
||||
return nil
|
||||
}
|
||||
|
||||
args := argsFromType(t)
|
||||
g.Do("func "+nameTmpl+"(ref $.ReferenceCallback|raw$) $.OpenAPIDefinition|raw$ {\n", args)
|
||||
switch {
|
||||
case hasV2DefinitionTypeAndFormat && hasV3Definition:
|
||||
g.Do("return common.EmbedOpenAPIDefinitionIntoV2Extension($.type|raw${}.OpenAPIV3Definition(), $.OpenAPIDefinition|raw${\n"+
|
||||
"Schema: spec.Schema{\n"+
|
||||
"SchemaProps: spec.SchemaProps{\n", args)
|
||||
g.generateDescription(t.CommentLines)
|
||||
g.Do("Type:$.type|raw${}.OpenAPISchemaType(),\n"+
|
||||
"Format:$.type|raw${}.OpenAPISchemaFormat(),\n"+
|
||||
"},\n"+
|
||||
"},\n"+
|
||||
"})\n}\n\n", args)
|
||||
return nil
|
||||
case hasV2DefinitionTypeAndFormat && hasV3OneOfTypes:
|
||||
// generate v3 def.
|
||||
g.Do("return common.EmbedOpenAPIDefinitionIntoV2Extension($.OpenAPIDefinition|raw${\n"+
|
||||
"Schema: spec.Schema{\n"+
|
||||
"SchemaProps: spec.SchemaProps{\n", args)
|
||||
g.generateDescription(t.CommentLines)
|
||||
g.Do("OneOf:common.GenerateOpenAPIV3OneOfSchema($.type|raw${}.OpenAPIV3OneOfTypes()),\n"+
|
||||
"Format:$.type|raw${}.OpenAPISchemaFormat(),\n"+
|
||||
"},\n"+
|
||||
"},\n"+
|
||||
"},", args)
|
||||
// generate v2 def.
|
||||
g.Do("$.OpenAPIDefinition|raw${\n"+
|
||||
"Schema: spec.Schema{\n"+
|
||||
"SchemaProps: spec.SchemaProps{\n", args)
|
||||
g.generateDescription(t.CommentLines)
|
||||
g.Do("Type:$.type|raw${}.OpenAPISchemaType(),\n"+
|
||||
"Format:$.type|raw${}.OpenAPISchemaFormat(),\n"+
|
||||
"},\n"+
|
||||
"},\n"+
|
||||
"})\n}\n\n", args)
|
||||
return nil
|
||||
case hasV2DefinitionTypeAndFormat:
|
||||
g.Do("return $.OpenAPIDefinition|raw${\n"+
|
||||
"Schema: spec.Schema{\n"+
|
||||
"SchemaProps: spec.SchemaProps{\n", args)
|
||||
g.generateDescription(t.CommentLines)
|
||||
g.Do("Type:$.type|raw${}.OpenAPISchemaType(),\n"+
|
||||
"Format:$.type|raw${}.OpenAPISchemaFormat(),\n"+
|
||||
"},\n"+
|
||||
"},\n"+
|
||||
"}\n}\n\n", args)
|
||||
return nil
|
||||
case hasV3OneOfTypes:
|
||||
// having v3 oneOf types without custom v2 type or format does not make sense.
|
||||
return fmt.Errorf("type %q has v3 one of types but not v2 type or format", t.Name)
|
||||
}
|
||||
g.Do("return $.OpenAPIDefinition|raw${\nSchema: spec.Schema{\nSchemaProps: spec.SchemaProps{\n", args)
|
||||
g.generateDescription(t.CommentLines)
|
||||
g.Do("Type: []string{\"object\"},\n", nil)
|
||||
|
||||
// write members into a temporary buffer, in order to postpone writing out the Properties field. We only do
|
||||
// that if it is not empty.
|
||||
propertiesBuf := bytes.Buffer{}
|
||||
bsw := g
|
||||
bsw.SnippetWriter = generator.NewSnippetWriter(&propertiesBuf, g.context, "$", "$")
|
||||
required, err := bsw.generateMembers(t, []string{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if propertiesBuf.Len() > 0 {
|
||||
g.Do("Properties: map[string]$.SpecSchemaType|raw${\n", args)
|
||||
g.Do(strings.Replace(propertiesBuf.String(), "$", "$\"$\"$", -1), nil) // escape $ (used as delimiter of the templates)
|
||||
g.Do("},\n", nil)
|
||||
}
|
||||
|
||||
if len(required) > 0 {
|
||||
g.Do("Required: []string{\"$.$\"},\n", strings.Join(required, "\",\""))
|
||||
}
|
||||
g.Do("},\n", nil)
|
||||
if err := g.generateStructExtensions(t); err != nil {
|
||||
return err
|
||||
}
|
||||
g.Do("},\n", nil)
|
||||
|
||||
// Map order is undefined, sort them or we may get a different file generated each time.
|
||||
keys := []string{}
|
||||
for k := range g.refTypes {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
deps := []string{}
|
||||
for _, k := range keys {
|
||||
v := g.refTypes[k]
|
||||
if t, _ := openapi.OpenAPITypeFormat(v.String()); t != "" {
|
||||
// This is a known type, we do not need a reference to it
|
||||
// Will eliminate special case of time.Time
|
||||
continue
|
||||
}
|
||||
deps = append(deps, k)
|
||||
}
|
||||
if len(deps) > 0 {
|
||||
g.Do("Dependencies: []string{\n", args)
|
||||
for _, k := range deps {
|
||||
g.Do("\"$.$\",", k)
|
||||
}
|
||||
g.Do("},\n", nil)
|
||||
}
|
||||
g.Do("}\n}\n\n", nil)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g openAPITypeWriter) generateStructExtensions(t *types.Type) error {
|
||||
extensions, errors := parseExtensions(t.CommentLines)
|
||||
// Initially, we will only log struct extension errors.
|
||||
if len(errors) > 0 {
|
||||
for _, e := range errors {
|
||||
klog.Errorf("[%s]: %s\n", t.String(), e)
|
||||
}
|
||||
}
|
||||
unions, errors := parseUnions(t)
|
||||
if len(errors) > 0 {
|
||||
for _, e := range errors {
|
||||
klog.Errorf("[%s]: %s\n", t.String(), e)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(seans3): Validate struct extensions here.
|
||||
g.emitExtensions(extensions, unions)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g openAPITypeWriter) generateMemberExtensions(m *types.Member, parent *types.Type) error {
|
||||
extensions, parseErrors := parseExtensions(m.CommentLines)
|
||||
validationErrors := validateMemberExtensions(extensions, m)
|
||||
errors := append(parseErrors, validationErrors...)
|
||||
// Initially, we will only log member extension errors.
|
||||
if len(errors) > 0 {
|
||||
errorPrefix := fmt.Sprintf("[%s] %s:", parent.String(), m.String())
|
||||
for _, e := range errors {
|
||||
klog.V(2).Infof("%s %s\n", errorPrefix, e)
|
||||
}
|
||||
}
|
||||
g.emitExtensions(extensions, nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g openAPITypeWriter) emitExtensions(extensions []extension, unions []union) {
|
||||
// If any extensions exist, then emit code to create them.
|
||||
if len(extensions) == 0 && len(unions) == 0 {
|
||||
return
|
||||
}
|
||||
g.Do("VendorExtensible: spec.VendorExtensible{\nExtensions: spec.Extensions{\n", nil)
|
||||
for _, extension := range extensions {
|
||||
g.Do("\"$.$\": ", extension.xName)
|
||||
if extension.hasMultipleValues() || extension.isAlwaysArrayFormat() {
|
||||
g.Do("[]interface{}{\n", nil)
|
||||
}
|
||||
for _, value := range extension.values {
|
||||
g.Do("\"$.$\",\n", value)
|
||||
}
|
||||
if extension.hasMultipleValues() || extension.isAlwaysArrayFormat() {
|
||||
g.Do("},\n", nil)
|
||||
}
|
||||
}
|
||||
if len(unions) > 0 {
|
||||
g.Do("\"x-kubernetes-unions\": []interface{}{\n", nil)
|
||||
for _, u := range unions {
|
||||
u.emit(g)
|
||||
}
|
||||
g.Do("},\n", nil)
|
||||
}
|
||||
g.Do("},\n},\n", nil)
|
||||
}
|
||||
|
||||
// TODO(#44005): Move this validation outside of this generator (probably to policy verifier)
|
||||
func (g openAPITypeWriter) validatePatchTags(m *types.Member, parent *types.Type) error {
|
||||
// TODO: Remove patch struct tag validation because they we are now consuming OpenAPI on server.
|
||||
for _, tagKey := range tempPatchTags {
|
||||
structTagValue := reflect.StructTag(m.Tags).Get(tagKey)
|
||||
commentTagValue, err := getSingleTagsValue(m.CommentLines, tagKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if structTagValue != commentTagValue {
|
||||
return fmt.Errorf("Tags in comment and struct should match for member (%s) of (%s)",
|
||||
m.Name, parent.Name.String())
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func defaultFromComments(comments []string) (interface{}, error) {
|
||||
tag, err := getSingleTagsValue(comments, tagDefault)
|
||||
if tag == "" {
|
||||
return nil, err
|
||||
}
|
||||
var i interface{}
|
||||
if err := json.Unmarshal([]byte(tag), &i); err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal default: %v", err)
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
|
||||
func mustEnforceDefault(t *types.Type, omitEmpty bool) (interface{}, error) {
|
||||
switch t.Kind {
|
||||
case types.Pointer, types.Map, types.Slice, types.Array, types.Interface:
|
||||
return nil, nil
|
||||
case types.Struct:
|
||||
return map[string]interface{}{}, nil
|
||||
case types.Builtin:
|
||||
if !omitEmpty {
|
||||
if zero, ok := openapi.OpenAPIZeroValue(t.String()); ok {
|
||||
return zero, nil
|
||||
} else {
|
||||
return nil, fmt.Errorf("please add type %v to getOpenAPITypeFormat function", t)
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("not sure how to enforce default for %v", t.Kind)
|
||||
}
|
||||
}
|
||||
|
||||
func (g openAPITypeWriter) generateDefault(comments []string, t *types.Type, omitEmpty bool) error {
|
||||
t = resolveAliasAndEmbeddedType(t)
|
||||
def, err := defaultFromComments(comments)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if enforced, err := mustEnforceDefault(t, omitEmpty); err != nil {
|
||||
return err
|
||||
} else if enforced != nil {
|
||||
if def == nil {
|
||||
def = enforced
|
||||
} else if !reflect.DeepEqual(def, enforced) {
|
||||
enforcedJson, _ := json.Marshal(enforced)
|
||||
return fmt.Errorf("invalid default value (%#v) for non-pointer/non-omitempty. If specified, must be: %v", def, string(enforcedJson))
|
||||
}
|
||||
}
|
||||
if def != nil {
|
||||
g.Do("Default: $.$,\n", fmt.Sprintf("%#v", def))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g openAPITypeWriter) generateDescription(CommentLines []string) {
|
||||
var buffer bytes.Buffer
|
||||
delPrevChar := func() {
|
||||
if buffer.Len() > 0 {
|
||||
buffer.Truncate(buffer.Len() - 1) // Delete the last " " or "\n"
|
||||
}
|
||||
}
|
||||
|
||||
for _, line := range CommentLines {
|
||||
// Ignore all lines after ---
|
||||
if line == "---" {
|
||||
break
|
||||
}
|
||||
line = strings.TrimRight(line, " ")
|
||||
leading := strings.TrimLeft(line, " ")
|
||||
switch {
|
||||
case len(line) == 0: // Keep paragraphs
|
||||
delPrevChar()
|
||||
buffer.WriteString("\n\n")
|
||||
case strings.HasPrefix(leading, "TODO"): // Ignore one line TODOs
|
||||
case strings.HasPrefix(leading, "+"): // Ignore instructions to go2idl
|
||||
default:
|
||||
if strings.HasPrefix(line, " ") || strings.HasPrefix(line, "\t") {
|
||||
delPrevChar()
|
||||
line = "\n" + line + "\n" // Replace it with newline. This is useful when we have a line with: "Example:\n\tJSON-something..."
|
||||
} else {
|
||||
line += " "
|
||||
}
|
||||
buffer.WriteString(line)
|
||||
}
|
||||
}
|
||||
|
||||
postDoc := strings.TrimLeft(buffer.String(), "\n")
|
||||
postDoc = strings.TrimRight(postDoc, "\n")
|
||||
postDoc = strings.Replace(postDoc, "\\\"", "\"", -1) // replace user's \" to "
|
||||
postDoc = strings.Replace(postDoc, "\"", "\\\"", -1) // Escape "
|
||||
postDoc = strings.Replace(postDoc, "\n", "\\n", -1)
|
||||
postDoc = strings.Replace(postDoc, "\t", "\\t", -1)
|
||||
postDoc = strings.Trim(postDoc, " ")
|
||||
if postDoc != "" {
|
||||
g.Do("Description: \"$.$\",\n", postDoc)
|
||||
}
|
||||
}
|
||||
|
||||
func (g openAPITypeWriter) generateProperty(m *types.Member, parent *types.Type) error {
|
||||
name := getReferableName(m)
|
||||
if name == "" {
|
||||
return nil
|
||||
}
|
||||
if err := g.validatePatchTags(m, parent); err != nil {
|
||||
return err
|
||||
}
|
||||
g.Do("\"$.$\": {\n", name)
|
||||
if err := g.generateMemberExtensions(m, parent); err != nil {
|
||||
return err
|
||||
}
|
||||
g.Do("SchemaProps: spec.SchemaProps{\n", nil)
|
||||
var extraComments []string
|
||||
if enumType, isEnum := g.enumContext.EnumType(m.Type); isEnum {
|
||||
extraComments = enumType.DescriptionLines()
|
||||
}
|
||||
g.generateDescription(append(m.CommentLines, extraComments...))
|
||||
jsonTags := getJsonTags(m)
|
||||
if len(jsonTags) > 1 && jsonTags[1] == "string" {
|
||||
g.generateSimpleProperty("string", "")
|
||||
g.Do("},\n},\n", nil)
|
||||
return nil
|
||||
}
|
||||
omitEmpty := strings.Contains(reflect.StructTag(m.Tags).Get("json"), "omitempty")
|
||||
if err := g.generateDefault(m.CommentLines, m.Type, omitEmpty); err != nil {
|
||||
return fmt.Errorf("failed to generate default in %v: %v: %v", parent, m.Name, err)
|
||||
}
|
||||
t := resolveAliasAndPtrType(m.Type)
|
||||
// If we can get a openAPI type and format for this type, we consider it to be simple property
|
||||
typeString, format := openapi.OpenAPITypeFormat(t.String())
|
||||
if typeString != "" {
|
||||
g.generateSimpleProperty(typeString, format)
|
||||
if enumType, isEnum := g.enumContext.EnumType(m.Type); isEnum {
|
||||
// original type is an enum, add "Enum: " and the values
|
||||
g.Do("Enum: []interface{}{$.$}", strings.Join(enumType.ValueStrings(), ", "))
|
||||
}
|
||||
g.Do("},\n},\n", nil)
|
||||
return nil
|
||||
}
|
||||
switch t.Kind {
|
||||
case types.Builtin:
|
||||
return fmt.Errorf("please add type %v to getOpenAPITypeFormat function", t)
|
||||
case types.Map:
|
||||
if err := g.generateMapProperty(t); err != nil {
|
||||
return fmt.Errorf("failed to generate map property in %v: %v: %v", parent, m.Name, err)
|
||||
}
|
||||
case types.Slice, types.Array:
|
||||
if err := g.generateSliceProperty(t); err != nil {
|
||||
return fmt.Errorf("failed to generate slice property in %v: %v: %v", parent, m.Name, err)
|
||||
}
|
||||
case types.Struct, types.Interface:
|
||||
g.generateReferenceProperty(t)
|
||||
default:
|
||||
return fmt.Errorf("cannot generate spec for type %v", t)
|
||||
}
|
||||
g.Do("},\n},\n", nil)
|
||||
return g.Error()
|
||||
}
|
||||
|
||||
func (g openAPITypeWriter) generateSimpleProperty(typeString, format string) {
|
||||
g.Do("Type: []string{\"$.$\"},\n", typeString)
|
||||
g.Do("Format: \"$.$\",\n", format)
|
||||
}
|
||||
|
||||
func (g openAPITypeWriter) generateReferenceProperty(t *types.Type) {
|
||||
g.refTypes[t.Name.String()] = t
|
||||
g.Do("Ref: ref(\"$.$\"),\n", t.Name.String())
|
||||
}
|
||||
|
||||
func resolveAliasAndEmbeddedType(t *types.Type) *types.Type {
|
||||
var prev *types.Type
|
||||
for prev != t {
|
||||
prev = t
|
||||
if t.Kind == types.Alias {
|
||||
t = t.Underlying
|
||||
}
|
||||
if t.Kind == types.Struct {
|
||||
if len(t.Members) == 1 && t.Members[0].Embedded {
|
||||
t = t.Members[0].Type
|
||||
}
|
||||
}
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
func resolveAliasAndPtrType(t *types.Type) *types.Type {
|
||||
var prev *types.Type
|
||||
for prev != t {
|
||||
prev = t
|
||||
if t.Kind == types.Alias {
|
||||
t = t.Underlying
|
||||
}
|
||||
if t.Kind == types.Pointer {
|
||||
t = t.Elem
|
||||
}
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
func (g openAPITypeWriter) generateMapProperty(t *types.Type) error {
|
||||
keyType := resolveAliasAndPtrType(t.Key)
|
||||
elemType := resolveAliasAndPtrType(t.Elem)
|
||||
|
||||
// According to OpenAPI examples, only map from string is supported
|
||||
if keyType.Name.Name != "string" {
|
||||
return fmt.Errorf("map with non-string keys are not supported by OpenAPI in %v", t)
|
||||
}
|
||||
|
||||
g.Do("Type: []string{\"object\"},\n", nil)
|
||||
g.Do("AdditionalProperties: &spec.SchemaOrBool{\nAllows: true,\nSchema: &spec.Schema{\nSchemaProps: spec.SchemaProps{\n", nil)
|
||||
if err := g.generateDefault(t.Elem.CommentLines, t.Elem, false); err != nil {
|
||||
return err
|
||||
}
|
||||
typeString, format := openapi.OpenAPITypeFormat(elemType.String())
|
||||
if typeString != "" {
|
||||
g.generateSimpleProperty(typeString, format)
|
||||
g.Do("},\n},\n},\n", nil)
|
||||
return nil
|
||||
}
|
||||
switch elemType.Kind {
|
||||
case types.Builtin:
|
||||
return fmt.Errorf("please add type %v to getOpenAPITypeFormat function", elemType)
|
||||
case types.Struct:
|
||||
g.generateReferenceProperty(elemType)
|
||||
case types.Slice, types.Array:
|
||||
if err := g.generateSliceProperty(elemType); err != nil {
|
||||
return err
|
||||
}
|
||||
case types.Map:
|
||||
if err := g.generateMapProperty(elemType); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("map Element kind %v is not supported in %v", elemType.Kind, t.Name)
|
||||
}
|
||||
g.Do("},\n},\n},\n", nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g openAPITypeWriter) generateSliceProperty(t *types.Type) error {
|
||||
elemType := resolveAliasAndPtrType(t.Elem)
|
||||
g.Do("Type: []string{\"array\"},\n", nil)
|
||||
g.Do("Items: &spec.SchemaOrArray{\nSchema: &spec.Schema{\nSchemaProps: spec.SchemaProps{\n", nil)
|
||||
if err := g.generateDefault(t.Elem.CommentLines, t.Elem, false); err != nil {
|
||||
return err
|
||||
}
|
||||
typeString, format := openapi.OpenAPITypeFormat(elemType.String())
|
||||
if typeString != "" {
|
||||
g.generateSimpleProperty(typeString, format)
|
||||
g.Do("},\n},\n},\n", nil)
|
||||
return nil
|
||||
}
|
||||
switch elemType.Kind {
|
||||
case types.Builtin:
|
||||
return fmt.Errorf("please add type %v to getOpenAPITypeFormat function", elemType)
|
||||
case types.Struct:
|
||||
g.generateReferenceProperty(elemType)
|
||||
case types.Slice, types.Array:
|
||||
if err := g.generateSliceProperty(elemType); err != nil {
|
||||
return err
|
||||
}
|
||||
case types.Map:
|
||||
if err := g.generateMapProperty(elemType); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("slice Element kind %v is not supported in %v", elemType.Kind, t)
|
||||
}
|
||||
g.Do("},\n},\n},\n", nil)
|
||||
return nil
|
||||
}
|
||||
4
client/vendor/k8s.io/kube-openapi/pkg/generators/rules/OWNERS
generated
vendored
Normal file
4
client/vendor/k8s.io/kube-openapi/pkg/generators/rules/OWNERS
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
reviewers:
|
||||
- roycaihw
|
||||
approvers:
|
||||
- roycaihw
|
||||
23
client/vendor/k8s.io/kube-openapi/pkg/generators/rules/doc.go
generated
vendored
Normal file
23
client/vendor/k8s.io/kube-openapi/pkg/generators/rules/doc.go
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package rules contains API rules that are enforced in OpenAPI spec generation
|
||||
// as part of the machinery. Files under this package implement APIRule interface
|
||||
// which evaluates Go type and produces list of API rule violations.
|
||||
//
|
||||
// Implementations of APIRule should be added to API linter under openAPIGen code-
|
||||
// generator to get integrated in the generation process.
|
||||
package rules
|
||||
53
client/vendor/k8s.io/kube-openapi/pkg/generators/rules/idl_tag.go
generated
vendored
Normal file
53
client/vendor/k8s.io/kube-openapi/pkg/generators/rules/idl_tag.go
generated
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
package rules
|
||||
|
||||
import (
|
||||
"k8s.io/gengo/types"
|
||||
)
|
||||
|
||||
const ListTypeIDLTag = "listType"
|
||||
|
||||
// ListTypeMissing implements APIRule interface.
|
||||
// A list type is required for inlined list.
|
||||
type ListTypeMissing struct{}
|
||||
|
||||
// Name returns the name of APIRule
|
||||
func (l *ListTypeMissing) Name() string {
|
||||
return "list_type_missing"
|
||||
}
|
||||
|
||||
// Validate evaluates API rule on type t and returns a list of field names in
|
||||
// the type that violate the rule. Empty field name [""] implies the entire
|
||||
// type violates the rule.
|
||||
func (l *ListTypeMissing) Validate(t *types.Type) ([]string, error) {
|
||||
fields := make([]string, 0)
|
||||
|
||||
switch t.Kind {
|
||||
case types.Struct:
|
||||
for _, m := range t.Members {
|
||||
hasListType := types.ExtractCommentTags("+", m.CommentLines)[ListTypeIDLTag] != nil
|
||||
|
||||
if m.Name == "Items" && m.Type.Kind == types.Slice && hasNamedMember(t, "ListMeta") {
|
||||
if hasListType {
|
||||
fields = append(fields, m.Name)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if m.Type.Kind == types.Slice && !hasListType {
|
||||
fields = append(fields, m.Name)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fields, nil
|
||||
}
|
||||
|
||||
func hasNamedMember(t *types.Type, name string) bool {
|
||||
for _, m := range t.Members {
|
||||
if m.Name == name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
172
client/vendor/k8s.io/kube-openapi/pkg/generators/rules/names_match.go
generated
vendored
Normal file
172
client/vendor/k8s.io/kube-openapi/pkg/generators/rules/names_match.go
generated
vendored
Normal file
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package rules
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"k8s.io/kube-openapi/pkg/util/sets"
|
||||
|
||||
"k8s.io/gengo/types"
|
||||
)
|
||||
|
||||
var (
|
||||
// Blacklist of JSON tags that should skip match evaluation
|
||||
jsonTagBlacklist = sets.NewString(
|
||||
// Omitted field is ignored by the package
|
||||
"-",
|
||||
)
|
||||
|
||||
// Blacklist of JSON names that should skip match evaluation
|
||||
jsonNameBlacklist = sets.NewString(
|
||||
// Empty name is used for inline struct field (e.g. metav1.TypeMeta)
|
||||
"",
|
||||
// Special case for object and list meta
|
||||
"metadata",
|
||||
)
|
||||
|
||||
// List of substrings that aren't allowed in Go name and JSON name
|
||||
disallowedNameSubstrings = sets.NewString(
|
||||
// Underscore is not allowed in either name
|
||||
"_",
|
||||
// Dash is not allowed in either name. Note that since dash is a valid JSON tag, this should be checked
|
||||
// after JSON tag blacklist check.
|
||||
"-",
|
||||
)
|
||||
)
|
||||
|
||||
/*
|
||||
NamesMatch implements APIRule interface.
|
||||
Go field names must be CamelCase. JSON field names must be camelCase. Other than capitalization of the
|
||||
initial letter, the two should almost always match. No underscores nor dashes in either.
|
||||
This rule verifies the convention "Other than capitalization of the initial letter, the two should almost always match."
|
||||
Examples (also in unit test):
|
||||
Go name | JSON name | match
|
||||
podSpec false
|
||||
PodSpec podSpec true
|
||||
PodSpec PodSpec false
|
||||
podSpec podSpec false
|
||||
PodSpec spec false
|
||||
Spec podSpec false
|
||||
JSONSpec jsonSpec true
|
||||
JSONSpec jsonspec false
|
||||
HTTPJSONSpec httpJSONSpec true
|
||||
NOTE: this validator cannot tell two sequential all-capital words from one word, therefore the case below
|
||||
is also considered matched.
|
||||
HTTPJSONSpec httpjsonSpec true
|
||||
NOTE: JSON names in jsonNameBlacklist should skip evaluation
|
||||
true
|
||||
podSpec true
|
||||
podSpec - true
|
||||
podSpec metadata true
|
||||
*/
|
||||
type NamesMatch struct{}
|
||||
|
||||
// Name returns the name of APIRule
|
||||
func (n *NamesMatch) Name() string {
|
||||
return "names_match"
|
||||
}
|
||||
|
||||
// Validate evaluates API rule on type t and returns a list of field names in
|
||||
// the type that violate the rule. Empty field name [""] implies the entire
|
||||
// type violates the rule.
|
||||
func (n *NamesMatch) Validate(t *types.Type) ([]string, error) {
|
||||
fields := make([]string, 0)
|
||||
|
||||
// Only validate struct type and ignore the rest
|
||||
switch t.Kind {
|
||||
case types.Struct:
|
||||
for _, m := range t.Members {
|
||||
goName := m.Name
|
||||
jsonTag, ok := reflect.StructTag(m.Tags).Lookup("json")
|
||||
// Distinguish empty JSON tag and missing JSON tag. Empty JSON tag / name is
|
||||
// allowed (in JSON name blacklist) but missing JSON tag is invalid.
|
||||
if !ok {
|
||||
fields = append(fields, goName)
|
||||
continue
|
||||
}
|
||||
if jsonTagBlacklist.Has(jsonTag) {
|
||||
continue
|
||||
}
|
||||
jsonName := strings.Split(jsonTag, ",")[0]
|
||||
if !namesMatch(goName, jsonName) {
|
||||
fields = append(fields, goName)
|
||||
}
|
||||
}
|
||||
}
|
||||
return fields, nil
|
||||
}
|
||||
|
||||
// namesMatch evaluates if goName and jsonName match the API rule
|
||||
// TODO: Use an off-the-shelf CamelCase solution instead of implementing this logic. The following existing
|
||||
// packages have been tried out:
|
||||
// github.com/markbates/inflect
|
||||
// github.com/segmentio/go-camelcase
|
||||
// github.com/iancoleman/strcase
|
||||
// github.com/fatih/camelcase
|
||||
// Please see https://github.com/kubernetes/kube-openapi/pull/83#issuecomment-400842314 for more details
|
||||
// about why they don't satisfy our need. What we need can be a function that detects an acronym at the
|
||||
// beginning of a string.
|
||||
func namesMatch(goName, jsonName string) bool {
|
||||
if jsonNameBlacklist.Has(jsonName) {
|
||||
return true
|
||||
}
|
||||
if !isAllowedName(goName) || !isAllowedName(jsonName) {
|
||||
return false
|
||||
}
|
||||
if strings.ToLower(goName) != strings.ToLower(jsonName) {
|
||||
return false
|
||||
}
|
||||
// Go field names must be CamelCase. JSON field names must be camelCase.
|
||||
if !isCapital(goName[0]) || isCapital(jsonName[0]) {
|
||||
return false
|
||||
}
|
||||
for i := 0; i < len(goName); i++ {
|
||||
if goName[i] == jsonName[i] {
|
||||
// goName[0:i-1] is uppercase and jsonName[0:i-1] is lowercase, goName[i:]
|
||||
// and jsonName[i:] should match;
|
||||
// goName[i] should be lowercase if i is equal to 1, e.g.:
|
||||
// goName | jsonName
|
||||
// PodSpec podSpec
|
||||
// or uppercase if i is greater than 1, e.g.:
|
||||
// goname | jsonName
|
||||
// JSONSpec jsonSpec
|
||||
// This is to rule out cases like:
|
||||
// goname | jsonName
|
||||
// JSONSpec jsonspec
|
||||
return goName[i:] == jsonName[i:] && (i == 1 || isCapital(goName[i]))
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// isCapital returns true if one character is capital
|
||||
func isCapital(b byte) bool {
|
||||
return b >= 'A' && b <= 'Z'
|
||||
}
|
||||
|
||||
// isAllowedName checks the list of disallowedNameSubstrings and returns true if name doesn't contain
|
||||
// any disallowed substring.
|
||||
func isAllowedName(name string) bool {
|
||||
for _, substr := range disallowedNameSubstrings.UnsortedList() {
|
||||
if strings.Contains(name, substr) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
64
client/vendor/k8s.io/kube-openapi/pkg/generators/rules/omitempty_match_case.go
generated
vendored
Normal file
64
client/vendor/k8s.io/kube-openapi/pkg/generators/rules/omitempty_match_case.go
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package rules
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"k8s.io/gengo/types"
|
||||
)
|
||||
|
||||
// OmitEmptyMatchCase implements APIRule interface.
|
||||
// "omitempty" must appear verbatim (no case variants).
|
||||
type OmitEmptyMatchCase struct{}
|
||||
|
||||
func (n *OmitEmptyMatchCase) Name() string {
|
||||
return "omitempty_match_case"
|
||||
}
|
||||
|
||||
func (n *OmitEmptyMatchCase) Validate(t *types.Type) ([]string, error) {
|
||||
fields := make([]string, 0)
|
||||
|
||||
// Only validate struct type and ignore the rest
|
||||
switch t.Kind {
|
||||
case types.Struct:
|
||||
for _, m := range t.Members {
|
||||
goName := m.Name
|
||||
jsonTag, ok := reflect.StructTag(m.Tags).Lookup("json")
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
parts := strings.Split(jsonTag, ",")
|
||||
if len(parts) < 2 {
|
||||
// no tags other than name
|
||||
continue
|
||||
}
|
||||
if parts[0] == "-" {
|
||||
// not serialized
|
||||
continue
|
||||
}
|
||||
for _, part := range parts[1:] {
|
||||
if strings.EqualFold(part, "omitempty") && part != "omitempty" {
|
||||
fields = append(fields, goName)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return fields, nil
|
||||
}
|
||||
207
client/vendor/k8s.io/kube-openapi/pkg/generators/union.go
generated
vendored
Normal file
207
client/vendor/k8s.io/kube-openapi/pkg/generators/union.go
generated
vendored
Normal file
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package generators
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
"k8s.io/gengo/types"
|
||||
)
|
||||
|
||||
const tagUnionMember = "union"
|
||||
const tagUnionDeprecated = "unionDeprecated"
|
||||
const tagUnionDiscriminator = "unionDiscriminator"
|
||||
|
||||
type union struct {
|
||||
discriminator string
|
||||
fieldsToDiscriminated map[string]string
|
||||
}
|
||||
|
||||
// emit prints the union, can be called on a nil union (emits nothing)
|
||||
func (u *union) emit(g openAPITypeWriter) {
|
||||
if u == nil {
|
||||
return
|
||||
}
|
||||
g.Do("map[string]interface{}{\n", nil)
|
||||
if u.discriminator != "" {
|
||||
g.Do("\"discriminator\": \"$.$\",\n", u.discriminator)
|
||||
}
|
||||
g.Do("\"fields-to-discriminateBy\": map[string]interface{}{\n", nil)
|
||||
keys := []string{}
|
||||
for field := range u.fieldsToDiscriminated {
|
||||
keys = append(keys, field)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
for _, field := range keys {
|
||||
g.Do("\"$.$\": ", field)
|
||||
g.Do("\"$.$\",\n", u.fieldsToDiscriminated[field])
|
||||
}
|
||||
g.Do("},\n", nil)
|
||||
g.Do("},\n", nil)
|
||||
}
|
||||
|
||||
// Sets the discriminator if it's not set yet, otherwise return an error
|
||||
func (u *union) setDiscriminator(value string) []error {
|
||||
errors := []error{}
|
||||
if u.discriminator != "" {
|
||||
errors = append(errors, fmt.Errorf("at least two discriminators found: %v and %v", value, u.discriminator))
|
||||
}
|
||||
u.discriminator = value
|
||||
return errors
|
||||
}
|
||||
|
||||
// Add a new member to the union
|
||||
func (u *union) addMember(jsonName, variableName string) {
|
||||
if _, ok := u.fieldsToDiscriminated[jsonName]; ok {
|
||||
panic(fmt.Errorf("same field (%v) found multiple times", jsonName))
|
||||
}
|
||||
u.fieldsToDiscriminated[jsonName] = variableName
|
||||
}
|
||||
|
||||
// Makes sure that the union is valid, specifically looking for re-used discriminated
|
||||
func (u *union) isValid() []error {
|
||||
errors := []error{}
|
||||
// Case 1: discriminator but no fields
|
||||
if u.discriminator != "" && len(u.fieldsToDiscriminated) == 0 {
|
||||
errors = append(errors, fmt.Errorf("discriminator set with no fields in union"))
|
||||
}
|
||||
// Case 2: two fields have the same discriminated value
|
||||
discriminated := map[string]struct{}{}
|
||||
for _, d := range u.fieldsToDiscriminated {
|
||||
if _, ok := discriminated[d]; ok {
|
||||
errors = append(errors, fmt.Errorf("discriminated value is used twice: %v", d))
|
||||
}
|
||||
discriminated[d] = struct{}{}
|
||||
}
|
||||
// Case 3: a field is both discriminator AND part of the union
|
||||
if u.discriminator != "" {
|
||||
if _, ok := u.fieldsToDiscriminated[u.discriminator]; ok {
|
||||
errors = append(errors, fmt.Errorf("%v can't be both discriminator and part of the union", u.discriminator))
|
||||
}
|
||||
}
|
||||
return errors
|
||||
}
|
||||
|
||||
// Find unions either directly on the members (or inlined members, not
|
||||
// going across types) or on the type itself, or on embedded types.
|
||||
func parseUnions(t *types.Type) ([]union, []error) {
|
||||
errors := []error{}
|
||||
unions := []union{}
|
||||
su, err := parseUnionStruct(t)
|
||||
if su != nil {
|
||||
unions = append(unions, *su)
|
||||
}
|
||||
errors = append(errors, err...)
|
||||
eu, err := parseEmbeddedUnion(t)
|
||||
unions = append(unions, eu...)
|
||||
errors = append(errors, err...)
|
||||
mu, err := parseUnionMembers(t)
|
||||
if mu != nil {
|
||||
unions = append(unions, *mu)
|
||||
}
|
||||
errors = append(errors, err...)
|
||||
return unions, errors
|
||||
}
|
||||
|
||||
// Find unions in embedded types, unions shouldn't go across types.
|
||||
func parseEmbeddedUnion(t *types.Type) ([]union, []error) {
|
||||
errors := []error{}
|
||||
unions := []union{}
|
||||
for _, m := range t.Members {
|
||||
if hasOpenAPITagValue(m.CommentLines, tagValueFalse) {
|
||||
continue
|
||||
}
|
||||
if !shouldInlineMembers(&m) {
|
||||
continue
|
||||
}
|
||||
u, err := parseUnions(m.Type)
|
||||
unions = append(unions, u...)
|
||||
errors = append(errors, err...)
|
||||
}
|
||||
return unions, errors
|
||||
}
|
||||
|
||||
// Look for union tag on a struct, and then include all the fields
|
||||
// (except the discriminator if there is one). The struct shouldn't have
|
||||
// embedded types.
|
||||
func parseUnionStruct(t *types.Type) (*union, []error) {
|
||||
errors := []error{}
|
||||
if types.ExtractCommentTags("+", t.CommentLines)[tagUnionMember] == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
u := &union{fieldsToDiscriminated: map[string]string{}}
|
||||
|
||||
for _, m := range t.Members {
|
||||
jsonName := getReferableName(&m)
|
||||
if jsonName == "" {
|
||||
continue
|
||||
}
|
||||
if shouldInlineMembers(&m) {
|
||||
errors = append(errors, fmt.Errorf("union structures can't have embedded fields: %v.%v", t.Name, m.Name))
|
||||
continue
|
||||
}
|
||||
if types.ExtractCommentTags("+", m.CommentLines)[tagUnionDeprecated] != nil {
|
||||
errors = append(errors, fmt.Errorf("union struct can't have unionDeprecated members: %v.%v", t.Name, m.Name))
|
||||
continue
|
||||
}
|
||||
if types.ExtractCommentTags("+", m.CommentLines)[tagUnionDiscriminator] != nil {
|
||||
errors = append(errors, u.setDiscriminator(jsonName)...)
|
||||
} else {
|
||||
if !hasOptionalTag(&m) {
|
||||
errors = append(errors, fmt.Errorf("union members must be optional: %v.%v", t.Name, m.Name))
|
||||
}
|
||||
u.addMember(jsonName, m.Name)
|
||||
}
|
||||
}
|
||||
|
||||
return u, errors
|
||||
}
|
||||
|
||||
// Find unions specifically on members.
|
||||
func parseUnionMembers(t *types.Type) (*union, []error) {
|
||||
errors := []error{}
|
||||
u := &union{fieldsToDiscriminated: map[string]string{}}
|
||||
|
||||
for _, m := range t.Members {
|
||||
jsonName := getReferableName(&m)
|
||||
if jsonName == "" {
|
||||
continue
|
||||
}
|
||||
if shouldInlineMembers(&m) {
|
||||
continue
|
||||
}
|
||||
if types.ExtractCommentTags("+", m.CommentLines)[tagUnionDiscriminator] != nil {
|
||||
errors = append(errors, u.setDiscriminator(jsonName)...)
|
||||
}
|
||||
if types.ExtractCommentTags("+", m.CommentLines)[tagUnionMember] != nil {
|
||||
errors = append(errors, fmt.Errorf("union tag is not accepted on struct members: %v.%v", t.Name, m.Name))
|
||||
continue
|
||||
}
|
||||
if types.ExtractCommentTags("+", m.CommentLines)[tagUnionDeprecated] != nil {
|
||||
if !hasOptionalTag(&m) {
|
||||
errors = append(errors, fmt.Errorf("union members must be optional: %v.%v", t.Name, m.Name))
|
||||
}
|
||||
u.addMember(jsonName, m.Name)
|
||||
}
|
||||
}
|
||||
if len(u.fieldsToDiscriminated) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
return u, append(errors, u.isValid()...)
|
||||
}
|
||||
291
client/vendor/k8s.io/kube-openapi/pkg/handler3/handler.go
generated
vendored
Normal file
291
client/vendor/k8s.io/kube-openapi/pkg/handler3/handler.go
generated
vendored
Normal file
@@ -0,0 +1,291 @@
|
||||
/*
|
||||
Copyright 2021 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package handler3
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha512"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"mime"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
openapi_v3 "github.com/google/gnostic/openapiv3"
|
||||
"github.com/munnerz/goautoneg"
|
||||
"k8s.io/kube-openapi/pkg/common"
|
||||
"k8s.io/kube-openapi/pkg/internal/handler"
|
||||
"k8s.io/kube-openapi/pkg/spec3"
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
)
|
||||
|
||||
const (
|
||||
jsonExt = ".json"
|
||||
|
||||
mimeJson = "application/json"
|
||||
// TODO(mehdy): change @68f4ded to a version tag when gnostic add version tags.
|
||||
mimePb = "application/com.github.googleapis.gnostic.OpenAPIv3@68f4ded+protobuf"
|
||||
mimePbGz = "application/x-gzip"
|
||||
|
||||
subTypeProtobuf = "com.github.proto-openapi.spec.v3@v1.0+protobuf"
|
||||
subTypeJSON = "json"
|
||||
)
|
||||
|
||||
// OpenAPIV3Discovery is the format of the Discovery document for OpenAPI V3
|
||||
// It maps Discovery paths to their corresponding URLs with a hash parameter included
|
||||
type OpenAPIV3Discovery struct {
|
||||
Paths map[string]OpenAPIV3DiscoveryGroupVersion `json:"paths"`
|
||||
}
|
||||
|
||||
// OpenAPIV3DiscoveryGroupVersion includes information about a group version and URL
|
||||
// for accessing the OpenAPI. The URL includes a hash parameter to support client side caching
|
||||
type OpenAPIV3DiscoveryGroupVersion struct {
|
||||
// Path is an absolute path of an OpenAPI V3 document in the form of /openapi/v3/apis/apps/v1?hash=014fbff9a07c
|
||||
ServerRelativeURL string `json:"serverRelativeURL"`
|
||||
}
|
||||
|
||||
// OpenAPIService is the service responsible for serving OpenAPI spec. It has
|
||||
// the ability to safely change the spec while serving it.
|
||||
type OpenAPIService struct {
|
||||
// rwMutex protects All members of this service.
|
||||
rwMutex sync.RWMutex
|
||||
lastModified time.Time
|
||||
v3Schema map[string]*OpenAPIV3Group
|
||||
}
|
||||
|
||||
type OpenAPIV3Group struct {
|
||||
rwMutex sync.RWMutex
|
||||
|
||||
lastModified time.Time
|
||||
|
||||
pbCache handler.HandlerCache
|
||||
jsonCache handler.HandlerCache
|
||||
etagCache handler.HandlerCache
|
||||
}
|
||||
|
||||
func init() {
|
||||
mime.AddExtensionType(".json", mimeJson)
|
||||
mime.AddExtensionType(".pb-v1", mimePb)
|
||||
mime.AddExtensionType(".gz", mimePbGz)
|
||||
}
|
||||
|
||||
func computeETag(data []byte) string {
|
||||
if data == nil {
|
||||
return ""
|
||||
}
|
||||
return fmt.Sprintf("%X", sha512.Sum512(data))
|
||||
}
|
||||
|
||||
func constructServerRelativeURL(gvString, etag string) string {
|
||||
u := url.URL{Path: path.Join("/openapi/v3", gvString)}
|
||||
query := url.Values{}
|
||||
query.Set("hash", etag)
|
||||
u.RawQuery = query.Encode()
|
||||
return u.String()
|
||||
}
|
||||
|
||||
// NewOpenAPIService builds an OpenAPIService starting with the given spec.
|
||||
func NewOpenAPIService(spec *spec.Swagger) (*OpenAPIService, error) {
|
||||
o := &OpenAPIService{}
|
||||
o.v3Schema = make(map[string]*OpenAPIV3Group)
|
||||
return o, nil
|
||||
}
|
||||
|
||||
func (o *OpenAPIService) getGroupBytes() ([]byte, error) {
|
||||
o.rwMutex.RLock()
|
||||
defer o.rwMutex.RUnlock()
|
||||
keys := make([]string, len(o.v3Schema))
|
||||
i := 0
|
||||
for k := range o.v3Schema {
|
||||
keys[i] = k
|
||||
i++
|
||||
}
|
||||
|
||||
sort.Strings(keys)
|
||||
discovery := &OpenAPIV3Discovery{Paths: make(map[string]OpenAPIV3DiscoveryGroupVersion)}
|
||||
for gvString, groupVersion := range o.v3Schema {
|
||||
etagBytes, err := groupVersion.etagCache.Get()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
discovery.Paths[gvString] = OpenAPIV3DiscoveryGroupVersion{
|
||||
ServerRelativeURL: constructServerRelativeURL(gvString, string(etagBytes)),
|
||||
}
|
||||
}
|
||||
j, err := json.Marshal(discovery)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return j, nil
|
||||
}
|
||||
|
||||
func (o *OpenAPIService) getSingleGroupBytes(getType string, group string) ([]byte, string, time.Time, error) {
|
||||
o.rwMutex.RLock()
|
||||
defer o.rwMutex.RUnlock()
|
||||
v, ok := o.v3Schema[group]
|
||||
if !ok {
|
||||
return nil, "", time.Now(), fmt.Errorf("Cannot find CRD group %s", group)
|
||||
}
|
||||
if getType == subTypeJSON {
|
||||
specBytes, err := v.jsonCache.Get()
|
||||
if err != nil {
|
||||
return nil, "", v.lastModified, err
|
||||
}
|
||||
etagBytes, err := v.etagCache.Get()
|
||||
return specBytes, string(etagBytes), v.lastModified, err
|
||||
} else if getType == subTypeProtobuf {
|
||||
specPb, err := v.pbCache.Get()
|
||||
if err != nil {
|
||||
return nil, "", v.lastModified, err
|
||||
}
|
||||
etagBytes, err := v.etagCache.Get()
|
||||
return specPb, string(etagBytes), v.lastModified, err
|
||||
}
|
||||
return nil, "", time.Now(), fmt.Errorf("Invalid accept clause %s", getType)
|
||||
}
|
||||
|
||||
func (o *OpenAPIService) UpdateGroupVersion(group string, openapi *spec3.OpenAPI) (err error) {
|
||||
o.rwMutex.Lock()
|
||||
defer o.rwMutex.Unlock()
|
||||
|
||||
if _, ok := o.v3Schema[group]; !ok {
|
||||
o.v3Schema[group] = &OpenAPIV3Group{}
|
||||
}
|
||||
return o.v3Schema[group].UpdateSpec(openapi)
|
||||
}
|
||||
|
||||
func (o *OpenAPIService) DeleteGroupVersion(group string) {
|
||||
o.rwMutex.Lock()
|
||||
defer o.rwMutex.Unlock()
|
||||
delete(o.v3Schema, group)
|
||||
}
|
||||
|
||||
func ToV3ProtoBinary(json []byte) ([]byte, error) {
|
||||
document, err := openapi_v3.ParseDocument(json)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return proto.Marshal(document)
|
||||
}
|
||||
|
||||
func (o *OpenAPIService) HandleDiscovery(w http.ResponseWriter, r *http.Request) {
|
||||
data, _ := o.getGroupBytes()
|
||||
http.ServeContent(w, r, "/openapi/v3", time.Now(), bytes.NewReader(data))
|
||||
}
|
||||
|
||||
func (o *OpenAPIService) HandleGroupVersion(w http.ResponseWriter, r *http.Request) {
|
||||
url := strings.SplitAfterN(r.URL.Path, "/", 4)
|
||||
group := url[3]
|
||||
|
||||
decipherableFormats := r.Header.Get("Accept")
|
||||
if decipherableFormats == "" {
|
||||
decipherableFormats = "*/*"
|
||||
}
|
||||
clauses := goautoneg.ParseAccept(decipherableFormats)
|
||||
w.Header().Add("Vary", "Accept")
|
||||
|
||||
if len(clauses) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
accepted := []struct {
|
||||
Type string
|
||||
SubType string
|
||||
}{
|
||||
{"application", subTypeJSON},
|
||||
{"application", subTypeProtobuf},
|
||||
}
|
||||
|
||||
for _, clause := range clauses {
|
||||
for _, accepts := range accepted {
|
||||
if clause.Type != accepts.Type && clause.Type != "*" {
|
||||
continue
|
||||
}
|
||||
if clause.SubType != accepts.SubType && clause.SubType != "*" {
|
||||
continue
|
||||
}
|
||||
data, etag, lastModified, err := o.getSingleGroupBytes(accepts.SubType, group)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// ETag must be enclosed in double quotes: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag
|
||||
w.Header().Set("Etag", strconv.Quote(etag))
|
||||
|
||||
if hash := r.URL.Query().Get("hash"); hash != "" {
|
||||
if hash != etag {
|
||||
u := constructServerRelativeURL(group, etag)
|
||||
http.Redirect(w, r, u, 301)
|
||||
return
|
||||
}
|
||||
// The Vary header is required because the Accept header can
|
||||
// change the contents returned. This prevents clients from caching
|
||||
// protobuf as JSON and vice versa.
|
||||
w.Header().Set("Vary", "Accept")
|
||||
|
||||
// Only set these headers when a hash is given.
|
||||
w.Header().Set("Cache-Control", "public, immutable")
|
||||
// Set the Expires directive to the maximum value of one year from the request,
|
||||
// effectively indicating that the cache never expires.
|
||||
w.Header().Set("Expires", time.Now().AddDate(1, 0, 0).Format(time.RFC1123))
|
||||
}
|
||||
http.ServeContent(w, r, "", lastModified, bytes.NewReader(data))
|
||||
return
|
||||
}
|
||||
}
|
||||
w.WriteHeader(406)
|
||||
return
|
||||
}
|
||||
|
||||
func (o *OpenAPIService) RegisterOpenAPIV3VersionedService(servePath string, handler common.PathHandlerByGroupVersion) error {
|
||||
handler.Handle(servePath, http.HandlerFunc(o.HandleDiscovery))
|
||||
handler.HandlePrefix(servePath+"/", http.HandlerFunc(o.HandleGroupVersion))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *OpenAPIV3Group) UpdateSpec(openapi *spec3.OpenAPI) (err error) {
|
||||
o.rwMutex.Lock()
|
||||
defer o.rwMutex.Unlock()
|
||||
|
||||
o.jsonCache = o.jsonCache.New(func() ([]byte, error) {
|
||||
return json.Marshal(openapi)
|
||||
})
|
||||
o.pbCache = o.pbCache.New(func() ([]byte, error) {
|
||||
json, err := o.jsonCache.Get()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ToV3ProtoBinary(json)
|
||||
})
|
||||
// TODO: This forces a json marshal of corresponding group-versions.
|
||||
// We should look to replace this with a faster hashing mechanism.
|
||||
o.etagCache = o.etagCache.New(func() ([]byte, error) {
|
||||
json, err := o.jsonCache.Get()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return []byte(computeETag(json)), nil
|
||||
})
|
||||
o.lastModified = time.Now()
|
||||
return nil
|
||||
}
|
||||
20
client/vendor/k8s.io/kube-openapi/pkg/internal/flags.go
generated
vendored
Normal file
20
client/vendor/k8s.io/kube-openapi/pkg/internal/flags.go
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
Copyright 2022 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package internal
|
||||
|
||||
// Used by tests to selectively disable experimental JSON unmarshaler
|
||||
var UseOptimizedJSONUnmarshaling bool = true
|
||||
57
client/vendor/k8s.io/kube-openapi/pkg/internal/handler/handler_cache.go
generated
vendored
Normal file
57
client/vendor/k8s.io/kube-openapi/pkg/internal/handler/handler_cache.go
generated
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
Copyright 2021 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package handler
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
// HandlerCache represents a lazy cache for generating a byte array
|
||||
// It is used to lazily marshal OpenAPI v2/v3 and lazily generate the ETag
|
||||
type HandlerCache struct {
|
||||
BuildCache func() ([]byte, error)
|
||||
once sync.Once
|
||||
bytes []byte
|
||||
err error
|
||||
}
|
||||
|
||||
// Get either returns the cached value or calls BuildCache() once before caching and returning
|
||||
// its results. If BuildCache returns an error, the last valid value for the cache (from prior
|
||||
// calls to New()) is used instead if possible.
|
||||
func (c *HandlerCache) Get() ([]byte, error) {
|
||||
c.once.Do(func() {
|
||||
bytes, err := c.BuildCache()
|
||||
// if there is an error updating the cache, there can be situations where
|
||||
// c.bytes contains a valid value (carried over from the previous update)
|
||||
// but c.err is also not nil; the cache user is expected to check for this
|
||||
c.err = err
|
||||
if c.err == nil {
|
||||
// don't override previous spec if we had an error
|
||||
c.bytes = bytes
|
||||
}
|
||||
})
|
||||
return c.bytes, c.err
|
||||
}
|
||||
|
||||
// New creates a new HandlerCache for situations where a cache refresh is needed.
|
||||
// This function is not thread-safe and should not be called at the same time as Get().
|
||||
func (c *HandlerCache) New(cacheBuilder func() ([]byte, error)) HandlerCache {
|
||||
return HandlerCache{
|
||||
bytes: c.bytes,
|
||||
BuildCache: cacheBuilder,
|
||||
}
|
||||
}
|
||||
3
client/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/AUTHORS
generated
vendored
Normal file
3
client/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/AUTHORS
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# This source code refers to The Go Authors for copyright purposes.
|
||||
# The master list of authors is in the main Go distribution,
|
||||
# visible at https://tip.golang.org/AUTHORS.
|
||||
3
client/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/CONTRIBUTORS
generated
vendored
Normal file
3
client/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/CONTRIBUTORS
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# This source code was written by the Go contributors.
|
||||
# The master list of contributors is in the main Go distribution,
|
||||
# visible at https://tip.golang.org/CONTRIBUTORS.
|
||||
27
client/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/LICENSE
generated
vendored
Normal file
27
client/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
Copyright (c) 2020 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
321
client/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/README.md
generated
vendored
Normal file
321
client/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/README.md
generated
vendored
Normal file
@@ -0,0 +1,321 @@
|
||||
# JSON Serialization (v2)
|
||||
|
||||
[](https://pkg.go.dev/github.com/go-json-experiment/json)
|
||||
[](https://github.com/go-json-experiment/json/actions)
|
||||
|
||||
This module hosts an experimental implementation of v2 `encoding/json`.
|
||||
The API is unstable and breaking changes will regularly be made.
|
||||
Do not depend on this in publicly available modules.
|
||||
|
||||
## Goals and objectives
|
||||
|
||||
* **Mostly backwards compatible:** If possible, v2 should aim to be _mostly_
|
||||
compatible with v1 in terms of both API and default behavior to ease migration.
|
||||
For example, the `Marshal` and `Unmarshal` functions are the most widely used
|
||||
declarations in the v1 package. It seems sensible for equivalent functionality
|
||||
in v2 to be named the same and have the same signature.
|
||||
Behaviorally, we should aim for 95% to 99% backwards compatibility.
|
||||
We do not aim for 100% compatibility since we want the freedom to break
|
||||
certain behaviors that are now considered to have been a mistake.
|
||||
We may provide options that can bring the v2 implementation to 100% compatibility,
|
||||
but it will not be the default.
|
||||
|
||||
* **More flexible:** There is a
|
||||
[long list of feature requests](https://github.com/golang/go/issues?q=is%3Aissue+is%3Aopen+encoding%2Fjson+in%3Atitle).
|
||||
We should aim to provide the most flexible features that addresses most usages.
|
||||
We do not want to over fit the v2 API to handle every possible use case.
|
||||
Ideally, the features provided should be orthogonal in nature such that
|
||||
any combination of features results in as few surprising edge cases as possible.
|
||||
|
||||
* **More performant:** JSON serialization is widely used and any bit of extra
|
||||
performance gains will be greatly appreciated. Some rarely used behaviors of v1
|
||||
may be dropped in favor of better performance. For example,
|
||||
despite `Encoder` and `Decoder` operating on an `io.Writer` and `io.Reader`,
|
||||
they do not operate in a truly streaming manner,
|
||||
leading to a loss in performance. The v2 implementation should aim to be truly
|
||||
streaming by default (see [#33714](https://golang.org/issue/33714)).
|
||||
|
||||
* **Easy to use (hard to misuse):** The v2 API should aim to make
|
||||
the common case easy and the less common case at least possible.
|
||||
The API should avoid behavior that goes contrary to user expectation,
|
||||
which may result in subtle bugs (see [#36225](https://golang.org/issue/36225)).
|
||||
|
||||
* **v1 and v2 maintainability:** Since the v1 implementation must stay forever,
|
||||
it would be beneficial if v1 could be implemented under the hood with v2,
|
||||
allowing for less maintenance burden in the future. This probably implies that
|
||||
behavioral changes in v2 relative to v1 need to be exposed as options.
|
||||
|
||||
* **Avoid unsafe:** Standard library packages generally avoid the use of
|
||||
package `unsafe` even if it could provide a performance boost.
|
||||
We aim to preserve this property.
|
||||
|
||||
## Expectations
|
||||
|
||||
While this module aims to possibly be the v2 implementation of `encoding/json`,
|
||||
there is no guarantee that this outcome will occur. As with any major change
|
||||
to the Go standard library, this will eventually go through the
|
||||
[Go proposal process](https://github.com/golang/proposal#readme).
|
||||
At the present moment, this is still in the design and experimentation phase
|
||||
and is not ready for a formal proposal.
|
||||
|
||||
There are several possible outcomes from this experiment:
|
||||
1. We determine that a v2 `encoding/json` would not provide sufficient benefit
|
||||
over the existing v1 `encoding/json` package. Thus, we abandon this effort.
|
||||
2. We propose a v2 `encoding/json` design, but it is rejected in favor of some
|
||||
other design that is considered superior.
|
||||
3. We propose a v2 `encoding/json` design, but rather than adding an entirely
|
||||
new v2 `encoding/json` package, we decide to merge its functionality into
|
||||
the existing v1 `encoding/json` package.
|
||||
4. We propose a v2 `encoding/json` design and it is accepted, resulting in
|
||||
its addition to the standard library.
|
||||
5. Some other unforeseen outcome (among the infinite number of possibilities).
|
||||
|
||||
## Development
|
||||
|
||||
This module is primarily developed by
|
||||
[@dsnet](https://github.com/dsnet),
|
||||
[@mvdan](https://github.com/mvdan), and
|
||||
[@johanbrandhorst](https://github.com/johanbrandhorst)
|
||||
with feedback provided by
|
||||
[@rogpeppe](https://github.com/rogpeppe),
|
||||
[@ChrisHines](https://github.com/ChrisHines), and
|
||||
[@rsc](https://github.com/rsc).
|
||||
|
||||
Discussion about semantics occur semi-regularly, where a
|
||||
[record of past meetings can be found here](https://docs.google.com/document/d/1rovrOTd-wTawGMPPlPuKhwXaYBg9VszTXR9AQQL5LfI/edit?usp=sharing).
|
||||
|
||||
## Design overview
|
||||
|
||||
This package aims to provide a clean separation between syntax and semantics.
|
||||
Syntax deals with the structural representation of JSON (as specified in
|
||||
[RFC 4627](https://tools.ietf.org/html/rfc4627),
|
||||
[RFC 7159](https://tools.ietf.org/html/rfc7159),
|
||||
[RFC 7493](https://tools.ietf.org/html/rfc7493),
|
||||
[RFC 8259](https://tools.ietf.org/html/rfc8259), and
|
||||
[RFC 8785](https://tools.ietf.org/html/rfc8785)).
|
||||
Semantics deals with the meaning of syntactic data as usable application data.
|
||||
|
||||
The `Encoder` and `Decoder` types are streaming tokenizers concerned with the
|
||||
packing or parsing of JSON data. They operate on `Token` and `RawValue` types
|
||||
which represent the common data structures that are representable in JSON.
|
||||
`Encoder` and `Decoder` do not aim to provide any interpretation of the data.
|
||||
|
||||
Functions like `Marshal`, `MarshalFull`, `MarshalNext`, `Unmarshal`,
|
||||
`UnmarshalFull`, and `UnmarshalNext` provide semantic meaning by correlating
|
||||
any arbitrary Go type with some JSON representation of that type (as stored in
|
||||
data types like `[]byte`, `io.Writer`, `io.Reader`, `Encoder`, or `Decoder`).
|
||||
|
||||

|
||||
|
||||
This diagram provides a high-level overview of the v2 `json` package.
|
||||
Purple blocks represent types, while blue blocks represent functions or methods.
|
||||
The arrows and their direction represent the approximate flow of data.
|
||||
The bottom half of the diagram contains functionality that is only concerned
|
||||
with syntax, while the upper half contains functionality that assigns
|
||||
semantic meaning to syntactic data handled by the bottom half.
|
||||
|
||||
In contrast to v1 `encoding/json`, options are represented as separate types
|
||||
rather than being setter methods on the `Encoder` or `Decoder` types.
|
||||
|
||||
## Behavior changes
|
||||
|
||||
The v2 `json` package changes the default behavior of `Marshal` and `Unmarshal`
|
||||
relative to the v1 `json` package to be more sensible.
|
||||
Some of these behavior changes have options and workarounds to opt into
|
||||
behavior similar to what v1 provided.
|
||||
|
||||
This table shows an overview of the changes:
|
||||
|
||||
| v1 | v2 | Details |
|
||||
| -- | -- | ------- |
|
||||
| JSON object members are unmarshaled into a Go struct using a **case-insensitive name match**. | JSON object members are unmarshaled into a Go struct using a **case-sensitive name match**. | [CaseSensitivity](/diff_test.go#:~:text=TestCaseSensitivity) |
|
||||
| When marshaling a Go struct, a struct field marked as `omitempty` is omitted if **the field value is an empty Go value**, which is defined as false, 0, a nil pointer, a nil interface value, and any empty array, slice, map, or string. | When marshaling a Go struct, a struct field marked as `omitempty` is omitted if **the field value would encode as an empty JSON value**, which is defined as a JSON null, or an empty JSON string, object, or array. | [OmitEmptyOption](/diff_test.go#:~:text=TestOmitEmptyOption) |
|
||||
| The `string` option **does affect** Go bools. | The `string` option **does not affect** Go bools. | [StringOption](/diff_test.go#:~:text=TestStringOption) |
|
||||
| The `string` option **does not recursively affect** sub-values of the Go field value. | The `string` option **does recursively affect** sub-values of the Go field value. | [StringOption](/diff_test.go#:~:text=TestStringOption) |
|
||||
| The `string` option **sometimes accepts** a JSON null escaped within a JSON string. | The `string` option **never accepts** a JSON null escaped within a JSON string. | [StringOption](/diff_test.go#:~:text=TestStringOption) |
|
||||
| A nil Go slice is marshaled as a **JSON null**. | A nil Go slice is marshaled as an **empty JSON array**. | [NilSlicesAndMaps](/diff_test.go#:~:text=TestNilSlicesAndMaps) |
|
||||
| A nil Go map is marshaled as a **JSON null**. | A nil Go map is marshaled as an **empty JSON object**. | [NilSlicesAndMaps](/diff_test.go#:~:text=TestNilSlicesAndMaps) |
|
||||
| A Go array may be unmarshaled from a **JSON array of any length**. | A Go array must be unmarshaled from a **JSON array of the same length**. | [Arrays](/diff_test.go#:~:text=Arrays) |
|
||||
| A Go byte array is represented as a **JSON array of JSON numbers**. | A Go byte array is represented as a **Base64-encoded JSON string**. | [ByteArrays](/diff_test.go#:~:text=TestByteArrays) |
|
||||
| `MarshalJSON` and `UnmarshalJSON` methods declared on a pointer receiver are **inconsistently called**. | `MarshalJSON` and `UnmarshalJSON` methods declared on a pointer receiver are **consistently called**. | [PointerReceiver](/diff_test.go#:~:text=TestPointerReceiver) |
|
||||
| A Go map is marshaled in a **deterministic order**. | A Go map is marshaled in a **non-deterministic order**. | [MapDeterminism](/diff_test.go#:~:text=TestMapDeterminism) |
|
||||
| JSON strings are encoded **with HTML-specific characters being escaped**. | JSON strings are encoded **without any characters being escaped** (unless necessary). | [EscapeHTML](/diff_test.go#:~:text=TestEscapeHTML) |
|
||||
| When marshaling, invalid UTF-8 within a Go string **are silently replaced**. | When marshaling, invalid UTF-8 within a Go string **results in an error**. | [InvalidUTF8](/diff_test.go#:~:text=TestInvalidUTF8) |
|
||||
| When unmarshaling, invalid UTF-8 within a JSON string **are silently replaced**. | When unmarshaling, invalid UTF-8 within a JSON string **results in an error**. | [InvalidUTF8](/diff_test.go#:~:text=TestInvalidUTF8) |
|
||||
| When marshaling, **an error does not occur** if the output JSON value contains objects with duplicate names. | When marshaling, **an error does occur** if the output JSON value contains objects with duplicate names. | [DuplicateNames](/diff_test.go#:~:text=TestDuplicateNames) |
|
||||
| When unmarshaling, **an error does not occur** if the input JSON value contains objects with duplicate names. | When unmarshaling, **an error does occur** if the input JSON value contains objects with duplicate names. | [DuplicateNames](/diff_test.go#:~:text=TestDuplicateNames) |
|
||||
| Unmarshaling a JSON null into a non-empty Go value **inconsistently clears the value or does nothing**. | Unmarshaling a JSON null into a non-empty Go value **always clears the value**. | [MergeNull](/diff_test.go#:~:text=TestMergeNull) |
|
||||
| Unmarshaling a JSON value into a non-empty Go value **follows inconsistent and bizarre behavior**. | Unmarshaling a JSON value into a non-empty Go value **always merges if the input is an object, and otherwise replaces**. | [MergeComposite](/diff_test.go#:~:text=TestMergeComposite) |
|
||||
| A `time.Duration` is represented as a **JSON number containing the decimal number of nanoseconds**. | A `time.Duration` is represented as a **JSON string containing the formatted duration (e.g., "1h2m3.456s")**. | [TimeDurations](/diff_test.go#:~:text=TestTimeDurations) |
|
||||
| Unmarshaling a JSON number into a Go float beyond its representation **results in an error**. | Unmarshaling a JSON number into a Go float beyond its representation **uses the closest representable value (e.g., ±`math.MaxFloat`)**. | [MaxFloats](/diff_test.go#:~:text=TestMaxFloats) |
|
||||
| A Go struct with only unexported fields **can be serialized**. | A Go struct with only unexported fields **cannot be serialized**. | [EmptyStructs](/diff_test.go#:~:text=TestEmptyStructs) |
|
||||
| A Go struct that embeds an unexported struct type **can sometimes be serialized**. | A Go struct that embeds an unexported struct type **cannot be serialized**. | [EmbedUnexported](/diff_test.go#:~:text=TestEmbedUnexported) |
|
||||
|
||||
See [diff_test.go](/diff_test.go) for details about every change.
|
||||
|
||||
## Performance
|
||||
|
||||
One of the goals of the v2 module is to be more performant than v1.
|
||||
|
||||
Each of the charts below show the performance across
|
||||
several different JSON implementations:
|
||||
|
||||
* `JSONv1` is `encoding/json` at `v1.18.2`
|
||||
* `JSONv2` is `github.com/go-json-experiment/json` at `v0.0.0-20220524042235-dd8be80fc4a7`
|
||||
* `JSONIterator` is `github.com/json-iterator/go` at `v1.1.12`
|
||||
* `SegmentJSON` is `github.com/segmentio/encoding/json` at `v0.3.5`
|
||||
* `GoJSON` is `github.com/goccy/go-json` at `v0.9.7`
|
||||
* `SonicJSON` is `github.com/bytedance/sonic` at `v1.3.0`
|
||||
|
||||
Benchmarks were run across various datasets:
|
||||
|
||||
* `CanadaGeometry` is a GeoJSON (RFC 7946) representation of Canada.
|
||||
It contains many JSON arrays of arrays of two-element arrays of numbers.
|
||||
* `CITMCatalog` contains many JSON objects using numeric names.
|
||||
* `SyntheaFHIR` is sample JSON data from the healthcare industry.
|
||||
It contains many nested JSON objects with mostly string values,
|
||||
where the set of unique string values is relatively small.
|
||||
* `TwitterStatus` is the JSON response from the Twitter API.
|
||||
It contains a mix of all different JSON kinds, where string values
|
||||
are a mix of both single-byte ASCII and multi-byte Unicode.
|
||||
* `GolangSource` is a simple tree representing the Go source code.
|
||||
It contains many nested JSON objects, each with the same schema.
|
||||
* `StringUnicode` contains many strings with multi-byte Unicode runes.
|
||||
|
||||
All of the implementations other than `JSONv1` and `JSONv2` make
|
||||
extensive use of `unsafe`. As such, we expect those to generally be faster,
|
||||
but at the cost of memory and type safety. `SonicJSON` goes a step even further
|
||||
and uses just-in-time compilation to generate machine code specialized
|
||||
for the Go type being marshaled or unmarshaled.
|
||||
Also, `SonicJSON` does not validate JSON strings for valid UTF-8,
|
||||
and so gains a notable performance boost on datasets with multi-byte Unicode.
|
||||
Benchmarks are performed based on the default marshal and unmarshal behavior
|
||||
of each package. Note that `JSONv2` aims to be safe and correct by default,
|
||||
which may not be the most performant strategy.
|
||||
|
||||
`JSONv2` has several semantic changes relative to `JSONv1` that
|
||||
impacts performance:
|
||||
|
||||
1. When marshaling, `JSONv2` no longer sorts the keys of a Go map.
|
||||
This will improve performance.
|
||||
2. When marshaling or unmarshaling, `JSONv2` always checks
|
||||
to make sure JSON object names are unique.
|
||||
This will hurt performance, but is more correct.
|
||||
3. When marshaling or unmarshaling, `JSONv2` always
|
||||
shallow copies the underlying value for a Go interface and
|
||||
shallow copies the key and value for entries in a Go map.
|
||||
This is done to keep the value as addressable so that `JSONv2` can
|
||||
call methods and functions that operate on a pointer receiver.
|
||||
This will hurt performance, but is more correct.
|
||||
|
||||
All of the charts are unit-less since the values are normalized
|
||||
relative to `JSONv1`, which is why `JSONv1` always has a value of 1.
|
||||
A lower value is better (i.e., runs faster).
|
||||
|
||||
Benchmarks were performed on an AMD Ryzen 9 5900X.
|
||||
|
||||
The code for the benchmarks is located at
|
||||
https://github.com/go-json-experiment/jsonbench.
|
||||
|
||||
### Marshal Performance
|
||||
|
||||
#### Concrete types
|
||||
|
||||

|
||||
|
||||
* This compares marshal performance when serializing
|
||||
[from concrete types](/testdata_test.go).
|
||||
* The `JSONv1` implementation is close to optimal (without the use of `unsafe`).
|
||||
* Relative to `JSONv1`, `JSONv2` is generally as fast or slightly faster.
|
||||
* Relative to `JSONIterator`, `JSONv2` is up to 1.3x faster.
|
||||
* Relative to `SegmentJSON`, `JSONv2` is up to 1.8x slower.
|
||||
* Relative to `GoJSON`, `JSONv2` is up to 2.0x slower.
|
||||
* Relative to `SonicJSON`, `JSONv2` is about 1.8x to 3.2x slower
|
||||
(ignoring `StringUnicode` since `SonicJSON` does not validate UTF-8).
|
||||
* For `JSONv1` and `JSONv2`, marshaling from concrete types is
|
||||
mostly limited by the performance of Go reflection.
|
||||
|
||||
#### Interface types
|
||||
|
||||

|
||||
|
||||
* This compares marshal performance when serializing from
|
||||
`any`, `map[string]any`, and `[]any` types.
|
||||
* Relative to `JSONv1`, `JSONv2` is about 1.5x to 4.2x faster.
|
||||
* Relative to `JSONIterator`, `JSONv2` is about 1.1x to 2.4x faster.
|
||||
* Relative to `SegmentJSON`, `JSONv2` is about 1.2x to 1.8x faster.
|
||||
* Relative to `GoJSON`, `JSONv2` is about 1.1x to 2.5x faster.
|
||||
* Relative to `SonicJSON`, `JSONv2` is up to 1.5x slower
|
||||
(ignoring `StringUnicode` since `SonicJSON` does not validate UTF-8).
|
||||
* `JSONv2` is faster than the alternatives.
|
||||
One advantange is because it does not sort the keys for a `map[string]any`,
|
||||
while alternatives (except `SonicJSON` and `JSONIterator`) do sort the keys.
|
||||
|
||||
#### RawValue types
|
||||
|
||||

|
||||
|
||||
* This compares performance when marshaling from a `json.RawValue`.
|
||||
This mostly exercises the underlying encoder and
|
||||
hides the cost of Go reflection.
|
||||
* Relative to `JSONv1`, `JSONv2` is about 3.5x to 7.8x faster.
|
||||
* `JSONIterator` is blazingly fast because
|
||||
[it does not validate whether the raw value is valid](https://go.dev/play/p/bun9IXQCKRe)
|
||||
and simply copies it to the output.
|
||||
* Relative to `SegmentJSON`, `JSONv2` is about 1.5x to 2.7x faster.
|
||||
* Relative to `GoJSON`, `JSONv2` is up to 2.2x faster.
|
||||
* Relative to `SonicJSON`, `JSONv2` is up to 1.5x faster.
|
||||
* Aside from `JSONIterator`, `JSONv2` is generally the fastest.
|
||||
|
||||
### Unmarshal Performance
|
||||
|
||||
#### Concrete types
|
||||
|
||||

|
||||
|
||||
* This compares unmarshal performance when deserializing
|
||||
[into concrete types](/testdata_test.go).
|
||||
* Relative to `JSONv1`, `JSONv2` is about 1.8x to 5.7x faster.
|
||||
* Relative to `JSONIterator`, `JSONv2` is about 1.1x to 1.6x slower.
|
||||
* Relative to `SegmentJSON`, `JSONv2` is up to 2.5x slower.
|
||||
* Relative to `GoJSON`, `JSONv2` is about 1.4x to 2.1x slower.
|
||||
* Relative to `SonicJSON`, `JSONv2` is up to 4.0x slower
|
||||
(ignoring `StringUnicode` since `SonicJSON` does not validate UTF-8).
|
||||
* For `JSONv1` and `JSONv2`, unmarshaling into concrete types is
|
||||
mostly limited by the performance of Go reflection.
|
||||
|
||||
#### Interface types
|
||||
|
||||

|
||||
|
||||
* This compares unmarshal performance when deserializing into
|
||||
`any`, `map[string]any`, and `[]any` types.
|
||||
* Relative to `JSONv1`, `JSONv2` is about 1.tx to 4.3x faster.
|
||||
* Relative to `JSONIterator`, `JSONv2` is up to 1.5x faster.
|
||||
* Relative to `SegmentJSON`, `JSONv2` is about 1.5 to 3.7x faster.
|
||||
* Relative to `GoJSON`, `JSONv2` is up to 1.3x faster.
|
||||
* Relative to `SonicJSON`, `JSONv2` is up to 1.5x slower
|
||||
(ignoring `StringUnicode` since `SonicJSON` does not validate UTF-8).
|
||||
* Aside from `SonicJSON`, `JSONv2` is generally just as fast
|
||||
or faster than all the alternatives.
|
||||
|
||||
#### RawValue types
|
||||
|
||||

|
||||
|
||||
* This compares performance when unmarshaling into a `json.RawValue`.
|
||||
This mostly exercises the underlying decoder and
|
||||
hides away most of the cost of Go reflection.
|
||||
* Relative to `JSONv1`, `JSONv2` is about 8.3x to 17.0x faster.
|
||||
* Relative to `JSONIterator`, `JSONv2` is up to 2.0x faster.
|
||||
* Relative to `SegmentJSON`, `JSONv2` is up to 1.6x faster or 1.7x slower.
|
||||
* Relative to `GoJSON`, `JSONv2` is up to 1.9x faster or 2.1x slower.
|
||||
* Relative to `SonicJSON`, `JSONv2` is up to 2.0x faster
|
||||
(ignoring `StringUnicode` since `SonicJSON` does not validate UTF-8).
|
||||
* `JSONv1` takes a
|
||||
[lexical scanning approach](https://talks.golang.org/2011/lex.slide#1),
|
||||
which performs a virtual function call for every byte of input.
|
||||
In contrast, `JSONv2` makes heavy use of iterative and linear parsing logic
|
||||
(with extra complexity to resume parsing when encountering segmented buffers).
|
||||
* `JSONv2` is comparable to the alternatives that use `unsafe`.
|
||||
Generally it is faster, but sometimes it is slower.
|
||||
506
client/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/arshal.go
generated
vendored
Normal file
506
client/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/arshal.go
generated
vendored
Normal file
@@ -0,0 +1,506 @@
|
||||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package json
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"reflect"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// MarshalOptions configures how Go data is serialized as JSON data.
|
||||
// The zero value is equivalent to the default marshal settings.
|
||||
type MarshalOptions struct {
|
||||
requireKeyedLiterals
|
||||
nonComparable
|
||||
|
||||
// Marshalers is a list of type-specific marshalers to use.
|
||||
Marshalers *Marshalers
|
||||
|
||||
// StringifyNumbers specifies that numeric Go types should be serialized
|
||||
// as a JSON string containing the equivalent JSON number value.
|
||||
//
|
||||
// According to RFC 8259, section 6, a JSON implementation may choose to
|
||||
// limit the representation of a JSON number to an IEEE 754 binary64 value.
|
||||
// This may cause decoders to lose precision for int64 and uint64 types.
|
||||
// Escaping JSON numbers as a JSON string preserves the exact precision.
|
||||
StringifyNumbers bool
|
||||
|
||||
// DiscardUnknownMembers specifies that marshaling should ignore any
|
||||
// JSON object members stored in Go struct fields dedicated to storing
|
||||
// unknown JSON object members.
|
||||
DiscardUnknownMembers bool
|
||||
|
||||
// formatDepth is the depth at which we respect the format flag.
|
||||
formatDepth int
|
||||
// format is custom formatting for the value at the specified depth.
|
||||
format string
|
||||
}
|
||||
|
||||
// Marshal serializes a Go value as a []byte with default options.
|
||||
// It is a thin wrapper over MarshalOptions.Marshal.
|
||||
func Marshal(in any) (out []byte, err error) {
|
||||
return MarshalOptions{}.Marshal(EncodeOptions{}, in)
|
||||
}
|
||||
|
||||
// MarshalFull serializes a Go value into an io.Writer with default options.
|
||||
// It is a thin wrapper over MarshalOptions.MarshalFull.
|
||||
func MarshalFull(out io.Writer, in any) error {
|
||||
return MarshalOptions{}.MarshalFull(EncodeOptions{}, out, in)
|
||||
}
|
||||
|
||||
// Marshal serializes a Go value as a []byte according to the provided
|
||||
// marshal and encode options. It does not terminate the output with a newline.
|
||||
// See MarshalNext for details about the conversion of a Go value into JSON.
|
||||
func (mo MarshalOptions) Marshal(eo EncodeOptions, in any) (out []byte, err error) {
|
||||
enc := getBufferedEncoder(eo)
|
||||
defer putBufferedEncoder(enc)
|
||||
enc.options.omitTopLevelNewline = true
|
||||
err = mo.MarshalNext(enc, in)
|
||||
// TODO(https://go.dev/issue/45038): Use bytes.Clone.
|
||||
return append([]byte(nil), enc.buf...), err
|
||||
}
|
||||
|
||||
// MarshalFull serializes a Go value into an io.Writer according to the provided
|
||||
// marshal and encode options. It does not terminate the output with a newline.
|
||||
// See MarshalNext for details about the conversion of a Go value into JSON.
|
||||
func (mo MarshalOptions) MarshalFull(eo EncodeOptions, out io.Writer, in any) error {
|
||||
enc := getStreamingEncoder(out, eo)
|
||||
defer putStreamingEncoder(enc)
|
||||
enc.options.omitTopLevelNewline = true
|
||||
err := mo.MarshalNext(enc, in)
|
||||
return err
|
||||
}
|
||||
|
||||
// MarshalNext encodes a Go value as the next JSON value according to
|
||||
// the provided marshal options.
|
||||
//
|
||||
// Type-specific marshal functions and methods take precedence
|
||||
// over the default representation of a value.
|
||||
// Functions or methods that operate on *T are only called when encoding
|
||||
// a value of type T (by taking its address) or a non-nil value of *T.
|
||||
// MarshalNext ensures that a value is always addressable
|
||||
// (by boxing it on the heap if necessary) so that
|
||||
// these functions and methods can be consistently called. For performance,
|
||||
// it is recommended that MarshalNext be passed a non-nil pointer to the value.
|
||||
//
|
||||
// The input value is encoded as JSON according the following rules:
|
||||
//
|
||||
// - If any type-specific functions in MarshalOptions.Marshalers match
|
||||
// the value type, then those functions are called to encode the value.
|
||||
// If all applicable functions return SkipFunc,
|
||||
// then the value is encoded according to subsequent rules.
|
||||
//
|
||||
// - If the value type implements MarshalerV2,
|
||||
// then the MarshalNextJSON method is called to encode the value.
|
||||
//
|
||||
// - If the value type implements MarshalerV1,
|
||||
// then the MarshalJSON method is called to encode the value.
|
||||
//
|
||||
// - If the value type implements encoding.TextMarshaler,
|
||||
// then the MarshalText method is called to encode the value and
|
||||
// subsequently encode its result as a JSON string.
|
||||
//
|
||||
// - Otherwise, the value is encoded according to the value's type
|
||||
// as described in detail below.
|
||||
//
|
||||
// Most Go types have a default JSON representation.
|
||||
// Certain types support specialized formatting according to
|
||||
// a format flag optionally specified in the Go struct tag
|
||||
// for the struct field that contains the current value
|
||||
// (see the “JSON Representation of Go structs” section for more details).
|
||||
//
|
||||
// The representation of each type is as follows:
|
||||
//
|
||||
// - A Go boolean is encoded as a JSON boolean (e.g., true or false).
|
||||
// It does not support any custom format flags.
|
||||
//
|
||||
// - A Go string is encoded as a JSON string.
|
||||
// It does not support any custom format flags.
|
||||
//
|
||||
// - A Go []byte or [N]byte is encoded as a JSON string containing
|
||||
// the binary value encoded using RFC 4648.
|
||||
// If the format is "base64" or unspecified, then this uses RFC 4648, section 4.
|
||||
// If the format is "base64url", then this uses RFC 4648, section 5.
|
||||
// If the format is "base32", then this uses RFC 4648, section 6.
|
||||
// If the format is "base32hex", then this uses RFC 4648, section 7.
|
||||
// If the format is "base16" or "hex", then this uses RFC 4648, section 8.
|
||||
// If the format is "array", then the bytes value is encoded as a JSON array
|
||||
// where each byte is recursively JSON-encoded as each JSON array element.
|
||||
//
|
||||
// - A Go integer is encoded as a JSON number without fractions or exponents.
|
||||
// If MarshalOptions.StringifyNumbers is specified, then the JSON number is
|
||||
// encoded within a JSON string. It does not support any custom format
|
||||
// flags.
|
||||
//
|
||||
// - A Go float is encoded as a JSON number.
|
||||
// If MarshalOptions.StringifyNumbers is specified,
|
||||
// then the JSON number is encoded within a JSON string.
|
||||
// If the format is "nonfinite", then NaN, +Inf, and -Inf are encoded as
|
||||
// the JSON strings "NaN", "Infinity", and "-Infinity", respectively.
|
||||
// Otherwise, the presence of non-finite numbers results in a SemanticError.
|
||||
//
|
||||
// - A Go map is encoded as a JSON object, where each Go map key and value
|
||||
// is recursively encoded as a name and value pair in the JSON object.
|
||||
// The Go map key must encode as a JSON string, otherwise this results
|
||||
// in a SemanticError. When encoding keys, MarshalOptions.StringifyNumbers
|
||||
// is automatically applied so that numeric keys encode as JSON strings.
|
||||
// The Go map is traversed in a non-deterministic order.
|
||||
// For deterministic encoding, consider using RawValue.Canonicalize.
|
||||
// If the format is "emitnull", then a nil map is encoded as a JSON null.
|
||||
// Otherwise by default, a nil map is encoded as an empty JSON object.
|
||||
//
|
||||
// - A Go struct is encoded as a JSON object.
|
||||
// See the “JSON Representation of Go structs” section
|
||||
// in the package-level documentation for more details.
|
||||
//
|
||||
// - A Go slice is encoded as a JSON array, where each Go slice element
|
||||
// is recursively JSON-encoded as the elements of the JSON array.
|
||||
// If the format is "emitnull", then a nil slice is encoded as a JSON null.
|
||||
// Otherwise by default, a nil slice is encoded as an empty JSON array.
|
||||
//
|
||||
// - A Go array is encoded as a JSON array, where each Go array element
|
||||
// is recursively JSON-encoded as the elements of the JSON array.
|
||||
// The JSON array length is always identical to the Go array length.
|
||||
// It does not support any custom format flags.
|
||||
//
|
||||
// - A Go pointer is encoded as a JSON null if nil, otherwise it is
|
||||
// the recursively JSON-encoded representation of the underlying value.
|
||||
// Format flags are forwarded to the encoding of the underlying value.
|
||||
//
|
||||
// - A Go interface is encoded as a JSON null if nil, otherwise it is
|
||||
// the recursively JSON-encoded representation of the underlying value.
|
||||
// It does not support any custom format flags.
|
||||
//
|
||||
// - A Go time.Time is encoded as a JSON string containing the timestamp
|
||||
// formatted in RFC 3339 with nanosecond resolution.
|
||||
// If the format matches one of the format constants declared
|
||||
// in the time package (e.g., RFC1123), then that format is used.
|
||||
// Otherwise, the format is used as-is with time.Time.Format if non-empty.
|
||||
//
|
||||
// - A Go time.Duration is encoded as a JSON string containing the duration
|
||||
// formatted according to time.Duration.String.
|
||||
// If the format is "nanos", it is encoded as a JSON number
|
||||
// containing the number of nanoseconds in the duration.
|
||||
//
|
||||
// - All other Go types (e.g., complex numbers, channels, and functions)
|
||||
// have no default representation and result in a SemanticError.
|
||||
//
|
||||
// JSON cannot represent cyclic data structures and
|
||||
// MarshalNext does not handle them.
|
||||
// Passing cyclic structures will result in an error.
|
||||
func (mo MarshalOptions) MarshalNext(out *Encoder, in any) error {
|
||||
v := reflect.ValueOf(in)
|
||||
if !v.IsValid() || (v.Kind() == reflect.Pointer && v.IsNil()) {
|
||||
return out.WriteToken(Null)
|
||||
}
|
||||
// Shallow copy non-pointer values to obtain an addressable value.
|
||||
// It is beneficial to performance to always pass pointers to avoid this.
|
||||
if v.Kind() != reflect.Pointer {
|
||||
v2 := reflect.New(v.Type())
|
||||
v2.Elem().Set(v)
|
||||
v = v2
|
||||
}
|
||||
va := addressableValue{v.Elem()} // dereferenced pointer is always addressable
|
||||
t := va.Type()
|
||||
|
||||
// Lookup and call the marshal function for this type.
|
||||
marshal := lookupArshaler(t).marshal
|
||||
if mo.Marshalers != nil {
|
||||
marshal, _ = mo.Marshalers.lookup(marshal, t)
|
||||
}
|
||||
if err := marshal(mo, out, va); err != nil {
|
||||
if !out.options.AllowDuplicateNames {
|
||||
out.tokens.invalidateDisabledNamespaces()
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalOptions configures how JSON data is deserialized as Go data.
|
||||
// The zero value is equivalent to the default unmarshal settings.
|
||||
type UnmarshalOptions struct {
|
||||
requireKeyedLiterals
|
||||
nonComparable
|
||||
|
||||
// Unmarshalers is a list of type-specific unmarshalers to use.
|
||||
Unmarshalers *Unmarshalers
|
||||
|
||||
// StringifyNumbers specifies that numeric Go types can be deserialized
|
||||
// from either a JSON number or a JSON string containing a JSON number
|
||||
// without any surrounding whitespace.
|
||||
StringifyNumbers bool
|
||||
|
||||
// RejectUnknownMembers specifies that unknown members should be rejected
|
||||
// when unmarshaling a JSON object, regardless of whether there is a field
|
||||
// to store unknown members.
|
||||
RejectUnknownMembers bool
|
||||
|
||||
// formatDepth is the depth at which we respect the format flag.
|
||||
formatDepth int
|
||||
// format is custom formatting for the value at the specified depth.
|
||||
format string
|
||||
}
|
||||
|
||||
// Unmarshal deserializes a Go value from a []byte with default options.
|
||||
// It is a thin wrapper over UnmarshalOptions.Unmarshal.
|
||||
func Unmarshal(in []byte, out any) error {
|
||||
return UnmarshalOptions{}.Unmarshal(DecodeOptions{}, in, out)
|
||||
}
|
||||
|
||||
// UnmarshalFull deserializes a Go value from an io.Reader with default options.
|
||||
// It is a thin wrapper over UnmarshalOptions.UnmarshalFull.
|
||||
func UnmarshalFull(in io.Reader, out any) error {
|
||||
return UnmarshalOptions{}.UnmarshalFull(DecodeOptions{}, in, out)
|
||||
}
|
||||
|
||||
// Unmarshal deserializes a Go value from a []byte according to the
|
||||
// provided unmarshal and decode options. The output must be a non-nil pointer.
|
||||
// The input must be a single JSON value with optional whitespace interspersed.
|
||||
// See UnmarshalNext for details about the conversion of JSON into a Go value.
|
||||
func (uo UnmarshalOptions) Unmarshal(do DecodeOptions, in []byte, out any) error {
|
||||
dec := getBufferedDecoder(in, do)
|
||||
defer putBufferedDecoder(dec)
|
||||
return uo.unmarshalFull(dec, out)
|
||||
}
|
||||
|
||||
// UnmarshalFull deserializes a Go value from an io.Reader according to the
|
||||
// provided unmarshal and decode options. The output must be a non-nil pointer.
|
||||
// The input must be a single JSON value with optional whitespace interspersed.
|
||||
// It consumes the entirety of io.Reader until io.EOF is encountered.
|
||||
// See UnmarshalNext for details about the conversion of JSON into a Go value.
|
||||
func (uo UnmarshalOptions) UnmarshalFull(do DecodeOptions, in io.Reader, out any) error {
|
||||
dec := getStreamingDecoder(in, do)
|
||||
defer putStreamingDecoder(dec)
|
||||
return uo.unmarshalFull(dec, out)
|
||||
}
|
||||
func (uo UnmarshalOptions) unmarshalFull(in *Decoder, out any) error {
|
||||
switch err := uo.UnmarshalNext(in, out); err {
|
||||
case nil:
|
||||
return in.checkEOF()
|
||||
case io.EOF:
|
||||
return io.ErrUnexpectedEOF
|
||||
default:
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// UnmarshalNext decodes the next JSON value into a Go value according to
|
||||
// the provided unmarshal options. The output must be a non-nil pointer.
|
||||
//
|
||||
// Type-specific unmarshal functions and methods take precedence
|
||||
// over the default representation of a value.
|
||||
// Functions or methods that operate on *T are only called when decoding
|
||||
// a value of type T (by taking its address) or a non-nil value of *T.
|
||||
// UnmarshalNext ensures that a value is always addressable
|
||||
// (by boxing it on the heap if necessary) so that
|
||||
// these functions and methods can be consistently called.
|
||||
//
|
||||
// The input is decoded into the output according the following rules:
|
||||
//
|
||||
// - If any type-specific functions in UnmarshalOptions.Unmarshalers match
|
||||
// the value type, then those functions are called to decode the JSON
|
||||
// value. If all applicable functions return SkipFunc,
|
||||
// then the input is decoded according to subsequent rules.
|
||||
//
|
||||
// - If the value type implements UnmarshalerV2,
|
||||
// then the UnmarshalNextJSON method is called to decode the JSON value.
|
||||
//
|
||||
// - If the value type implements UnmarshalerV1,
|
||||
// then the UnmarshalJSON method is called to decode the JSON value.
|
||||
//
|
||||
// - If the value type implements encoding.TextUnmarshaler,
|
||||
// then the input is decoded as a JSON string and
|
||||
// the UnmarshalText method is called with the decoded string value.
|
||||
// This fails with a SemanticError if the input is not a JSON string.
|
||||
//
|
||||
// - Otherwise, the JSON value is decoded according to the value's type
|
||||
// as described in detail below.
|
||||
//
|
||||
// Most Go types have a default JSON representation.
|
||||
// Certain types support specialized formatting according to
|
||||
// a format flag optionally specified in the Go struct tag
|
||||
// for the struct field that contains the current value
|
||||
// (see the “JSON Representation of Go structs” section for more details).
|
||||
// A JSON null may be decoded into every supported Go value where
|
||||
// it is equivalent to storing the zero value of the Go value.
|
||||
// If the input JSON kind is not handled by the current Go value type,
|
||||
// then this fails with a SemanticError. Unless otherwise specified,
|
||||
// the decoded value replaces any pre-existing value.
|
||||
//
|
||||
// The representation of each type is as follows:
|
||||
//
|
||||
// - A Go boolean is decoded from a JSON boolean (e.g., true or false).
|
||||
// It does not support any custom format flags.
|
||||
//
|
||||
// - A Go string is decoded from a JSON string.
|
||||
// It does not support any custom format flags.
|
||||
//
|
||||
// - A Go []byte or [N]byte is decoded from a JSON string
|
||||
// containing the binary value encoded using RFC 4648.
|
||||
// If the format is "base64" or unspecified, then this uses RFC 4648, section 4.
|
||||
// If the format is "base64url", then this uses RFC 4648, section 5.
|
||||
// If the format is "base32", then this uses RFC 4648, section 6.
|
||||
// If the format is "base32hex", then this uses RFC 4648, section 7.
|
||||
// If the format is "base16" or "hex", then this uses RFC 4648, section 8.
|
||||
// If the format is "array", then the Go slice or array is decoded from a
|
||||
// JSON array where each JSON element is recursively decoded for each byte.
|
||||
// When decoding into a non-nil []byte, the slice length is reset to zero
|
||||
// and the decoded input is appended to it.
|
||||
// When decoding into a [N]byte, the input must decode to exactly N bytes,
|
||||
// otherwise it fails with a SemanticError.
|
||||
//
|
||||
// - A Go integer is decoded from a JSON number.
|
||||
// It may also be decoded from a JSON string containing a JSON number
|
||||
// if UnmarshalOptions.StringifyNumbers is specified.
|
||||
// It fails with a SemanticError if the JSON number
|
||||
// has a fractional or exponent component.
|
||||
// It also fails if it overflows the representation of the Go integer type.
|
||||
// It does not support any custom format flags.
|
||||
//
|
||||
// - A Go float is decoded from a JSON number.
|
||||
// It may also be decoded from a JSON string containing a JSON number
|
||||
// if UnmarshalOptions.StringifyNumbers is specified.
|
||||
// The JSON number is parsed as the closest representable Go float value.
|
||||
// If the format is "nonfinite", then the JSON strings
|
||||
// "NaN", "Infinity", and "-Infinity" are decoded as NaN, +Inf, and -Inf.
|
||||
// Otherwise, the presence of such strings results in a SemanticError.
|
||||
//
|
||||
// - A Go map is decoded from a JSON object,
|
||||
// where each JSON object name and value pair is recursively decoded
|
||||
// as the Go map key and value. When decoding keys,
|
||||
// UnmarshalOptions.StringifyNumbers is automatically applied so that
|
||||
// numeric keys can decode from JSON strings. Maps are not cleared.
|
||||
// If the Go map is nil, then a new map is allocated to decode into.
|
||||
// If the decoded key matches an existing Go map entry, the entry value
|
||||
// is reused by decoding the JSON object value into it.
|
||||
// The only supported format is "emitnull" and has no effect when decoding.
|
||||
//
|
||||
// - A Go struct is decoded from a JSON object.
|
||||
// See the “JSON Representation of Go structs” section
|
||||
// in the package-level documentation for more details.
|
||||
//
|
||||
// - A Go slice is decoded from a JSON array, where each JSON element
|
||||
// is recursively decoded and appended to the Go slice.
|
||||
// Before appending into a Go slice, a new slice is allocated if it is nil,
|
||||
// otherwise the slice length is reset to zero.
|
||||
// The only supported format is "emitnull" and has no effect when decoding.
|
||||
//
|
||||
// - A Go array is decoded from a JSON array, where each JSON array element
|
||||
// is recursively decoded as each corresponding Go array element.
|
||||
// Each Go array element is zeroed before decoding into it.
|
||||
// It fails with a SemanticError if the JSON array does not contain
|
||||
// the exact same number of elements as the Go array.
|
||||
// It does not support any custom format flags.
|
||||
//
|
||||
// - A Go pointer is decoded based on the JSON kind and underlying Go type.
|
||||
// If the input is a JSON null, then this stores a nil pointer.
|
||||
// Otherwise, it allocates a new underlying value if the pointer is nil,
|
||||
// and recursively JSON decodes into the underlying value.
|
||||
// Format flags are forwarded to the decoding of the underlying type.
|
||||
//
|
||||
// - A Go interface is decoded based on the JSON kind and underlying Go type.
|
||||
// If the input is a JSON null, then this stores a nil interface value.
|
||||
// Otherwise, a nil interface value of an empty interface type is initialized
|
||||
// with a zero Go bool, string, float64, map[string]any, or []any if the
|
||||
// input is a JSON boolean, string, number, object, or array, respectively.
|
||||
// If the interface value is still nil, then this fails with a SemanticError
|
||||
// since decoding could not determine an appropriate Go type to decode into.
|
||||
// For example, unmarshaling into a nil io.Reader fails since
|
||||
// there is no concrete type to populate the interface value with.
|
||||
// Otherwise an underlying value exists and it recursively decodes
|
||||
// the JSON input into it. It does not support any custom format flags.
|
||||
//
|
||||
// - A Go time.Time is decoded from a JSON string containing the time
|
||||
// formatted in RFC 3339 with nanosecond resolution.
|
||||
// If the format matches one of the format constants declared in
|
||||
// the time package (e.g., RFC1123), then that format is used for parsing.
|
||||
// Otherwise, the format is used as-is with time.Time.Parse if non-empty.
|
||||
//
|
||||
// - A Go time.Duration is decoded from a JSON string by
|
||||
// passing the decoded string to time.ParseDuration.
|
||||
// If the format is "nanos", it is instead decoded from a JSON number
|
||||
// containing the number of nanoseconds in the duration.
|
||||
//
|
||||
// - All other Go types (e.g., complex numbers, channels, and functions)
|
||||
// have no default representation and result in a SemanticError.
|
||||
//
|
||||
// In general, unmarshaling follows merge semantics (similar to RFC 7396)
|
||||
// where the decoded Go value replaces the destination value
|
||||
// for any JSON kind other than an object.
|
||||
// For JSON objects, the input object is merged into the destination value
|
||||
// where matching object members recursively apply merge semantics.
|
||||
func (uo UnmarshalOptions) UnmarshalNext(in *Decoder, out any) error {
|
||||
v := reflect.ValueOf(out)
|
||||
if !v.IsValid() || v.Kind() != reflect.Pointer || v.IsNil() {
|
||||
var t reflect.Type
|
||||
if v.IsValid() {
|
||||
t = v.Type()
|
||||
if t.Kind() == reflect.Pointer {
|
||||
t = t.Elem()
|
||||
}
|
||||
}
|
||||
err := errors.New("value must be passed as a non-nil pointer reference")
|
||||
return &SemanticError{action: "unmarshal", GoType: t, Err: err}
|
||||
}
|
||||
va := addressableValue{v.Elem()} // dereferenced pointer is always addressable
|
||||
t := va.Type()
|
||||
|
||||
// Lookup and call the unmarshal function for this type.
|
||||
unmarshal := lookupArshaler(t).unmarshal
|
||||
if uo.Unmarshalers != nil {
|
||||
unmarshal, _ = uo.Unmarshalers.lookup(unmarshal, t)
|
||||
}
|
||||
if err := unmarshal(uo, in, va); err != nil {
|
||||
if !in.options.AllowDuplicateNames {
|
||||
in.tokens.invalidateDisabledNamespaces()
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// addressableValue is a reflect.Value that is guaranteed to be addressable
|
||||
// such that calling the Addr and Set methods do not panic.
|
||||
//
|
||||
// There is no compile magic that enforces this property,
|
||||
// but rather the need to construct this type makes it easier to examine each
|
||||
// construction site to ensure that this property is upheld.
|
||||
type addressableValue struct{ reflect.Value }
|
||||
|
||||
// newAddressableValue constructs a new addressable value of type t.
|
||||
func newAddressableValue(t reflect.Type) addressableValue {
|
||||
return addressableValue{reflect.New(t).Elem()}
|
||||
}
|
||||
|
||||
// All marshal and unmarshal behavior is implemented using these signatures.
|
||||
type (
|
||||
marshaler = func(MarshalOptions, *Encoder, addressableValue) error
|
||||
unmarshaler = func(UnmarshalOptions, *Decoder, addressableValue) error
|
||||
)
|
||||
|
||||
type arshaler struct {
|
||||
marshal marshaler
|
||||
unmarshal unmarshaler
|
||||
nonDefault bool
|
||||
}
|
||||
|
||||
var lookupArshalerCache sync.Map // map[reflect.Type]*arshaler
|
||||
|
||||
func lookupArshaler(t reflect.Type) *arshaler {
|
||||
if v, ok := lookupArshalerCache.Load(t); ok {
|
||||
return v.(*arshaler)
|
||||
}
|
||||
|
||||
fncs := makeDefaultArshaler(t)
|
||||
fncs = makeMethodArshaler(fncs, t)
|
||||
fncs = makeTimeArshaler(fncs, t)
|
||||
|
||||
// Use the last stored so that duplicate arshalers can be garbage collected.
|
||||
v, _ := lookupArshalerCache.LoadOrStore(t, fncs)
|
||||
return v.(*arshaler)
|
||||
}
|
||||
219
client/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/arshal_any.go
generated
vendored
Normal file
219
client/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/arshal_any.go
generated
vendored
Normal file
@@ -0,0 +1,219 @@
|
||||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package json
|
||||
|
||||
import "reflect"
|
||||
|
||||
// This files contains an optimized marshal and unmarshal implementation
|
||||
// for the any type. This type is often used when the Go program has
|
||||
// no knowledge of the JSON schema. This is a common enough occurrence
|
||||
// to justify the complexity of adding logic for this.
|
||||
|
||||
func marshalValueAny(mo MarshalOptions, enc *Encoder, val any) error {
|
||||
switch val := val.(type) {
|
||||
case nil:
|
||||
return enc.WriteToken(Null)
|
||||
case bool:
|
||||
return enc.WriteToken(Bool(val))
|
||||
case string:
|
||||
return enc.WriteToken(String(val))
|
||||
case float64:
|
||||
return enc.WriteToken(Float(val))
|
||||
case map[string]any:
|
||||
return marshalObjectAny(mo, enc, val)
|
||||
case []any:
|
||||
return marshalArrayAny(mo, enc, val)
|
||||
default:
|
||||
v := newAddressableValue(reflect.TypeOf(val))
|
||||
v.Set(reflect.ValueOf(val))
|
||||
marshal := lookupArshaler(v.Type()).marshal
|
||||
if mo.Marshalers != nil {
|
||||
marshal, _ = mo.Marshalers.lookup(marshal, v.Type())
|
||||
}
|
||||
return marshal(mo, enc, v)
|
||||
}
|
||||
}
|
||||
|
||||
func unmarshalValueAny(uo UnmarshalOptions, dec *Decoder) (any, error) {
|
||||
switch k := dec.PeekKind(); k {
|
||||
case '{':
|
||||
return unmarshalObjectAny(uo, dec)
|
||||
case '[':
|
||||
return unmarshalArrayAny(uo, dec)
|
||||
default:
|
||||
var flags valueFlags
|
||||
val, err := dec.readValue(&flags)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch val.Kind() {
|
||||
case 'n':
|
||||
return nil, nil
|
||||
case 'f':
|
||||
return false, nil
|
||||
case 't':
|
||||
return true, nil
|
||||
case '"':
|
||||
val = unescapeStringMayCopy(val, flags.isVerbatim())
|
||||
if dec.stringCache == nil {
|
||||
dec.stringCache = new(stringCache)
|
||||
}
|
||||
return dec.stringCache.make(val), nil
|
||||
case '0':
|
||||
fv, _ := parseFloat(val, 64) // ignore error since readValue gaurantees val is valid
|
||||
return fv, nil
|
||||
default:
|
||||
panic("BUG: invalid kind: " + k.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func marshalObjectAny(mo MarshalOptions, enc *Encoder, obj map[string]any) error {
|
||||
// Check for cycles.
|
||||
if enc.tokens.depth() > startDetectingCyclesAfter {
|
||||
v := reflect.ValueOf(obj)
|
||||
if err := enc.seenPointers.visit(v); err != nil {
|
||||
return err
|
||||
}
|
||||
defer enc.seenPointers.leave(v)
|
||||
}
|
||||
|
||||
// Optimize for marshaling an empty map without any preceding whitespace.
|
||||
if len(obj) == 0 && !enc.options.multiline && !enc.tokens.last.needObjectName() {
|
||||
enc.buf = enc.tokens.mayAppendDelim(enc.buf, '{')
|
||||
enc.buf = append(enc.buf, "{}"...)
|
||||
enc.tokens.last.increment()
|
||||
if enc.needFlush() {
|
||||
return enc.flush()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := enc.WriteToken(ObjectStart); err != nil {
|
||||
return err
|
||||
}
|
||||
// A Go map guarantees that each entry has a unique key
|
||||
// The only possibility of duplicates is due to invalid UTF-8.
|
||||
if !enc.options.AllowInvalidUTF8 {
|
||||
enc.tokens.last.disableNamespace()
|
||||
}
|
||||
for name, val := range obj {
|
||||
if err := enc.WriteToken(String(name)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := marshalValueAny(mo, enc, val); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := enc.WriteToken(ObjectEnd); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func unmarshalObjectAny(uo UnmarshalOptions, dec *Decoder) (map[string]any, error) {
|
||||
tok, err := dec.ReadToken()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
k := tok.Kind()
|
||||
switch k {
|
||||
case 'n':
|
||||
return nil, nil
|
||||
case '{':
|
||||
obj := make(map[string]any)
|
||||
// A Go map guarantees that each entry has a unique key
|
||||
// The only possibility of duplicates is due to invalid UTF-8.
|
||||
if !dec.options.AllowInvalidUTF8 {
|
||||
dec.tokens.last.disableNamespace()
|
||||
}
|
||||
for dec.PeekKind() != '}' {
|
||||
tok, err := dec.ReadToken()
|
||||
if err != nil {
|
||||
return obj, err
|
||||
}
|
||||
name := tok.String()
|
||||
|
||||
// Manually check for duplicate names.
|
||||
if _, ok := obj[name]; ok {
|
||||
name := dec.previousBuffer()
|
||||
err := &SyntacticError{str: "duplicate name " + string(name) + " in object"}
|
||||
return obj, err.withOffset(dec.InputOffset() - int64(len(name)))
|
||||
}
|
||||
|
||||
val, err := unmarshalValueAny(uo, dec)
|
||||
obj[name] = val
|
||||
if err != nil {
|
||||
return obj, err
|
||||
}
|
||||
}
|
||||
if _, err := dec.ReadToken(); err != nil {
|
||||
return obj, err
|
||||
}
|
||||
return obj, nil
|
||||
}
|
||||
return nil, &SemanticError{action: "unmarshal", JSONKind: k, GoType: mapStringAnyType}
|
||||
}
|
||||
|
||||
func marshalArrayAny(mo MarshalOptions, enc *Encoder, arr []any) error {
|
||||
// Check for cycles.
|
||||
if enc.tokens.depth() > startDetectingCyclesAfter {
|
||||
v := reflect.ValueOf(arr)
|
||||
if err := enc.seenPointers.visit(v); err != nil {
|
||||
return err
|
||||
}
|
||||
defer enc.seenPointers.leave(v)
|
||||
}
|
||||
|
||||
// Optimize for marshaling an empty slice without any preceding whitespace.
|
||||
if len(arr) == 0 && !enc.options.multiline && !enc.tokens.last.needObjectName() {
|
||||
enc.buf = enc.tokens.mayAppendDelim(enc.buf, '[')
|
||||
enc.buf = append(enc.buf, "[]"...)
|
||||
enc.tokens.last.increment()
|
||||
if enc.needFlush() {
|
||||
return enc.flush()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := enc.WriteToken(ArrayStart); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, val := range arr {
|
||||
if err := marshalValueAny(mo, enc, val); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := enc.WriteToken(ArrayEnd); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func unmarshalArrayAny(uo UnmarshalOptions, dec *Decoder) ([]any, error) {
|
||||
tok, err := dec.ReadToken()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
k := tok.Kind()
|
||||
switch k {
|
||||
case 'n':
|
||||
return nil, nil
|
||||
case '[':
|
||||
arr := []any{}
|
||||
for dec.PeekKind() != ']' {
|
||||
val, err := unmarshalValueAny(uo, dec)
|
||||
arr = append(arr, val)
|
||||
if err != nil {
|
||||
return arr, err
|
||||
}
|
||||
}
|
||||
if _, err := dec.ReadToken(); err != nil {
|
||||
return arr, err
|
||||
}
|
||||
return arr, nil
|
||||
}
|
||||
return nil, &SemanticError{action: "unmarshal", JSONKind: k, GoType: sliceAnyType}
|
||||
}
|
||||
1446
client/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/arshal_default.go
generated
vendored
Normal file
1446
client/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/arshal_default.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
387
client/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/arshal_funcs.go
generated
vendored
Normal file
387
client/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/arshal_funcs.go
generated
vendored
Normal file
@@ -0,0 +1,387 @@
|
||||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package json
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// SkipFunc may be returned by MarshalFuncV2 and UnmarshalFuncV2 functions.
|
||||
//
|
||||
// Any function that returns SkipFunc must not cause observable side effects
|
||||
// on the provided Encoder or Decoder. For example, it is permissible to call
|
||||
// Decoder.PeekKind, but not permissible to call Decoder.ReadToken or
|
||||
// Encoder.WriteToken since such methods mutate the state.
|
||||
const SkipFunc = jsonError("skip function")
|
||||
|
||||
// Marshalers is a list of functions that may override the marshal behavior
|
||||
// of specific types. Populate MarshalOptions.Marshalers to use it.
|
||||
// A nil *Marshalers is equivalent to an empty list.
|
||||
type Marshalers = typedMarshalers
|
||||
|
||||
// NewMarshalers constructs a flattened list of marshal functions.
|
||||
// If multiple functions in the list are applicable for a value of a given type,
|
||||
// then those earlier in the list take precedence over those that come later.
|
||||
// If a function returns SkipFunc, then the next applicable function is called,
|
||||
// otherwise the default marshaling behavior is used.
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// m1 := NewMarshalers(f1, f2)
|
||||
// m2 := NewMarshalers(f0, m1, f3) // equivalent to m3
|
||||
// m3 := NewMarshalers(f0, f1, f2, f3) // equivalent to m2
|
||||
func NewMarshalers(ms ...*Marshalers) *Marshalers {
|
||||
return newMarshalers(ms...)
|
||||
}
|
||||
|
||||
// Unmarshalers is a list of functions that may override the unmarshal behavior
|
||||
// of specific types. Populate UnmarshalOptions.Unmarshalers to use it.
|
||||
// A nil *Unmarshalers is equivalent to an empty list.
|
||||
type Unmarshalers = typedUnmarshalers
|
||||
|
||||
// NewUnmarshalers constructs a flattened list of unmarshal functions.
|
||||
// If multiple functions in the list are applicable for a value of a given type,
|
||||
// then those earlier in the list take precedence over those that come later.
|
||||
// If a function returns SkipFunc, then the next applicable function is called,
|
||||
// otherwise the default unmarshaling behavior is used.
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// u1 := NewUnmarshalers(f1, f2)
|
||||
// u2 := NewUnmarshalers(f0, u1, f3) // equivalent to u3
|
||||
// u3 := NewUnmarshalers(f0, f1, f2, f3) // equivalent to u2
|
||||
func NewUnmarshalers(us ...*Unmarshalers) *Unmarshalers {
|
||||
return newUnmarshalers(us...)
|
||||
}
|
||||
|
||||
type typedMarshalers = typedArshalers[MarshalOptions, Encoder]
|
||||
type typedUnmarshalers = typedArshalers[UnmarshalOptions, Decoder]
|
||||
type typedArshalers[Options, Coder any] struct {
|
||||
nonComparable
|
||||
|
||||
fncVals []typedArshaler[Options, Coder]
|
||||
fncCache sync.Map // map[reflect.Type]arshaler
|
||||
|
||||
// fromAny reports whether any of Go types used to represent arbitrary JSON
|
||||
// (i.e., any, bool, string, float64, map[string]any, or []any) matches
|
||||
// any of the provided type-specific arshalers.
|
||||
//
|
||||
// This bit of information is needed in arshal_default.go to determine
|
||||
// whether to use the specialized logic in arshal_any.go to handle
|
||||
// the any interface type. The logic in arshal_any.go does not support
|
||||
// type-specific arshal functions, so we must avoid using that logic
|
||||
// if this is true.
|
||||
fromAny bool
|
||||
}
|
||||
type typedMarshaler = typedArshaler[MarshalOptions, Encoder]
|
||||
type typedUnmarshaler = typedArshaler[UnmarshalOptions, Decoder]
|
||||
type typedArshaler[Options, Coder any] struct {
|
||||
typ reflect.Type
|
||||
fnc func(Options, *Coder, addressableValue) error
|
||||
maySkip bool
|
||||
}
|
||||
|
||||
func newMarshalers(ms ...*Marshalers) *Marshalers { return newTypedArshalers(ms...) }
|
||||
func newUnmarshalers(us ...*Unmarshalers) *Unmarshalers { return newTypedArshalers(us...) }
|
||||
func newTypedArshalers[Options, Coder any](as ...*typedArshalers[Options, Coder]) *typedArshalers[Options, Coder] {
|
||||
var a typedArshalers[Options, Coder]
|
||||
for _, a2 := range as {
|
||||
if a2 != nil {
|
||||
a.fncVals = append(a.fncVals, a2.fncVals...)
|
||||
a.fromAny = a.fromAny || a2.fromAny
|
||||
}
|
||||
}
|
||||
if len(a.fncVals) == 0 {
|
||||
return nil
|
||||
}
|
||||
return &a
|
||||
}
|
||||
|
||||
func (a *typedArshalers[Options, Coder]) lookup(fnc func(Options, *Coder, addressableValue) error, t reflect.Type) (func(Options, *Coder, addressableValue) error, bool) {
|
||||
if a == nil {
|
||||
return fnc, false
|
||||
}
|
||||
if v, ok := a.fncCache.Load(t); ok {
|
||||
if v == nil {
|
||||
return fnc, false
|
||||
}
|
||||
return v.(func(Options, *Coder, addressableValue) error), true
|
||||
}
|
||||
|
||||
// Collect a list of arshalers that can be called for this type.
|
||||
// This list may be longer than 1 since some arshalers can be skipped.
|
||||
var fncs []func(Options, *Coder, addressableValue) error
|
||||
for _, fncVal := range a.fncVals {
|
||||
if !castableTo(t, fncVal.typ) {
|
||||
continue
|
||||
}
|
||||
fncs = append(fncs, fncVal.fnc)
|
||||
if !fncVal.maySkip {
|
||||
break // subsequent arshalers will never be called
|
||||
}
|
||||
}
|
||||
|
||||
if len(fncs) == 0 {
|
||||
a.fncCache.Store(t, nil) // nil to indicate that no funcs found
|
||||
return fnc, false
|
||||
}
|
||||
|
||||
// Construct an arshaler that may call every applicable arshaler.
|
||||
fncDefault := fnc
|
||||
fnc = func(o Options, c *Coder, v addressableValue) error {
|
||||
for _, fnc := range fncs {
|
||||
if err := fnc(o, c, v); err != SkipFunc {
|
||||
return err // may be nil or non-nil
|
||||
}
|
||||
}
|
||||
return fncDefault(o, c, v)
|
||||
}
|
||||
|
||||
// Use the first stored so duplicate work can be garbage collected.
|
||||
v, _ := a.fncCache.LoadOrStore(t, fnc)
|
||||
return v.(func(Options, *Coder, addressableValue) error), true
|
||||
}
|
||||
|
||||
// MarshalFuncV1 constructs a type-specific marshaler that
|
||||
// specifies how to marshal values of type T.
|
||||
// T can be any type except a named pointer.
|
||||
// The function is always provided with a non-nil pointer value
|
||||
// if T is an interface or pointer type.
|
||||
//
|
||||
// The function must marshal exactly one JSON value.
|
||||
// The value of T must not be retained outside the function call.
|
||||
// It may not return SkipFunc.
|
||||
func MarshalFuncV1[T any](fn func(T) ([]byte, error)) *Marshalers {
|
||||
t := reflect.TypeOf((*T)(nil)).Elem()
|
||||
assertCastableTo(t, true)
|
||||
typFnc := typedMarshaler{
|
||||
typ: t,
|
||||
fnc: func(mo MarshalOptions, enc *Encoder, va addressableValue) error {
|
||||
val, err := fn(va.castTo(t).Interface().(T))
|
||||
if err != nil {
|
||||
err = wrapSkipFunc(err, "marshal function of type func(T) ([]byte, error)")
|
||||
// TODO: Avoid wrapping semantic errors.
|
||||
return &SemanticError{action: "marshal", GoType: t, Err: err}
|
||||
}
|
||||
if err := enc.WriteValue(val); err != nil {
|
||||
// TODO: Avoid wrapping semantic or I/O errors.
|
||||
return &SemanticError{action: "marshal", JSONKind: RawValue(val).Kind(), GoType: t, Err: err}
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
return &Marshalers{fncVals: []typedMarshaler{typFnc}, fromAny: castableToFromAny(t)}
|
||||
}
|
||||
|
||||
// MarshalFuncV2 constructs a type-specific marshaler that
|
||||
// specifies how to marshal values of type T.
|
||||
// T can be any type except a named pointer.
|
||||
// The function is always provided with a non-nil pointer value
|
||||
// if T is an interface or pointer type.
|
||||
//
|
||||
// The function must marshal exactly one JSON value by calling write methods
|
||||
// on the provided encoder. It may return SkipFunc such that marshaling can
|
||||
// move on to the next marshal function. However, no mutable method calls may
|
||||
// be called on the encoder if SkipFunc is returned.
|
||||
// The pointer to Encoder and the value of T must not be retained
|
||||
// outside the function call.
|
||||
func MarshalFuncV2[T any](fn func(MarshalOptions, *Encoder, T) error) *Marshalers {
|
||||
t := reflect.TypeOf((*T)(nil)).Elem()
|
||||
assertCastableTo(t, true)
|
||||
typFnc := typedMarshaler{
|
||||
typ: t,
|
||||
fnc: func(mo MarshalOptions, enc *Encoder, va addressableValue) error {
|
||||
prevDepth, prevLength := enc.tokens.depthLength()
|
||||
err := fn(mo, enc, va.castTo(t).Interface().(T))
|
||||
currDepth, currLength := enc.tokens.depthLength()
|
||||
if err == nil && (prevDepth != currDepth || prevLength+1 != currLength) {
|
||||
err = errors.New("must write exactly one JSON value")
|
||||
}
|
||||
if err != nil {
|
||||
if err == SkipFunc {
|
||||
if prevDepth == currDepth && prevLength == currLength {
|
||||
return SkipFunc
|
||||
}
|
||||
err = errors.New("must not write any JSON tokens when skipping")
|
||||
}
|
||||
// TODO: Avoid wrapping semantic or I/O errors.
|
||||
return &SemanticError{action: "marshal", GoType: t, Err: err}
|
||||
}
|
||||
return nil
|
||||
},
|
||||
maySkip: true,
|
||||
}
|
||||
return &Marshalers{fncVals: []typedMarshaler{typFnc}, fromAny: castableToFromAny(t)}
|
||||
}
|
||||
|
||||
// UnmarshalFuncV1 constructs a type-specific unmarshaler that
|
||||
// specifies how to unmarshal values of type T.
|
||||
// T must be an unnamed pointer or an interface type.
|
||||
// The function is always provided with a non-nil pointer value.
|
||||
//
|
||||
// The function must unmarshal exactly one JSON value.
|
||||
// The input []byte must not be mutated.
|
||||
// The input []byte and value T must not be retained outside the function call.
|
||||
// It may not return SkipFunc.
|
||||
func UnmarshalFuncV1[T any](fn func([]byte, T) error) *Unmarshalers {
|
||||
t := reflect.TypeOf((*T)(nil)).Elem()
|
||||
assertCastableTo(t, false)
|
||||
typFnc := typedUnmarshaler{
|
||||
typ: t,
|
||||
fnc: func(uo UnmarshalOptions, dec *Decoder, va addressableValue) error {
|
||||
val, err := dec.ReadValue()
|
||||
if err != nil {
|
||||
return err // must be a syntactic or I/O error
|
||||
}
|
||||
err = fn(val, va.castTo(t).Interface().(T))
|
||||
if err != nil {
|
||||
err = wrapSkipFunc(err, "unmarshal function of type func([]byte, T) error")
|
||||
// TODO: Avoid wrapping semantic, syntactic, or I/O errors.
|
||||
return &SemanticError{action: "unmarshal", JSONKind: val.Kind(), GoType: t, Err: err}
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
return &Unmarshalers{fncVals: []typedUnmarshaler{typFnc}, fromAny: castableToFromAny(t)}
|
||||
}
|
||||
|
||||
// UnmarshalFuncV2 constructs a type-specific unmarshaler that
|
||||
// specifies how to unmarshal values of type T.
|
||||
// T must be an unnamed pointer or an interface type.
|
||||
// The function is always provided with a non-nil pointer value.
|
||||
//
|
||||
// The function must unmarshal exactly one JSON value by calling read methods
|
||||
// on the provided decoder. It may return SkipFunc such that unmarshaling can
|
||||
// move on to the next unmarshal function. However, no mutable method calls may
|
||||
// be called on the decoder if SkipFunc is returned.
|
||||
// The pointer to Decoder and the value of T must not be retained
|
||||
// outside the function call.
|
||||
func UnmarshalFuncV2[T any](fn func(UnmarshalOptions, *Decoder, T) error) *Unmarshalers {
|
||||
t := reflect.TypeOf((*T)(nil)).Elem()
|
||||
assertCastableTo(t, false)
|
||||
typFnc := typedUnmarshaler{
|
||||
typ: t,
|
||||
fnc: func(uo UnmarshalOptions, dec *Decoder, va addressableValue) error {
|
||||
prevDepth, prevLength := dec.tokens.depthLength()
|
||||
err := fn(uo, dec, va.castTo(t).Interface().(T))
|
||||
currDepth, currLength := dec.tokens.depthLength()
|
||||
if err == nil && (prevDepth != currDepth || prevLength+1 != currLength) {
|
||||
err = errors.New("must read exactly one JSON value")
|
||||
}
|
||||
if err != nil {
|
||||
if err == SkipFunc {
|
||||
if prevDepth == currDepth && prevLength == currLength {
|
||||
return SkipFunc
|
||||
}
|
||||
err = errors.New("must not read any JSON tokens when skipping")
|
||||
}
|
||||
// TODO: Avoid wrapping semantic, syntactic, or I/O errors.
|
||||
return &SemanticError{action: "unmarshal", GoType: t, Err: err}
|
||||
}
|
||||
return nil
|
||||
},
|
||||
maySkip: true,
|
||||
}
|
||||
return &Unmarshalers{fncVals: []typedUnmarshaler{typFnc}, fromAny: castableToFromAny(t)}
|
||||
}
|
||||
|
||||
// assertCastableTo asserts that "to" is a valid type to be casted to.
|
||||
// These are the Go types that type-specific arshalers may operate upon.
|
||||
//
|
||||
// Let AllTypes be the universal set of all possible Go types.
|
||||
// This function generally asserts that:
|
||||
//
|
||||
// len([from for from in AllTypes if castableTo(from, to)]) > 0
|
||||
//
|
||||
// otherwise it panics.
|
||||
//
|
||||
// As a special-case if marshal is false, then we forbid any non-pointer or
|
||||
// non-interface type since it is almost always a bug trying to unmarshal
|
||||
// into something where the end-user caller did not pass in an addressable value
|
||||
// since they will not observe the mutations.
|
||||
func assertCastableTo(to reflect.Type, marshal bool) {
|
||||
switch to.Kind() {
|
||||
case reflect.Interface:
|
||||
return
|
||||
case reflect.Pointer:
|
||||
// Only allow unnamed pointers to be consistent with the fact that
|
||||
// taking the address of a value produces an unnamed pointer type.
|
||||
if to.Name() == "" {
|
||||
return
|
||||
}
|
||||
default:
|
||||
// Technically, non-pointer types are permissible for unmarshal.
|
||||
// However, they are often a bug since the receiver would be immutable.
|
||||
// Thus, only allow them for marshaling.
|
||||
if marshal {
|
||||
return
|
||||
}
|
||||
}
|
||||
if marshal {
|
||||
panic(fmt.Sprintf("input type %v must be an interface type, an unnamed pointer type, or a non-pointer type", to))
|
||||
} else {
|
||||
panic(fmt.Sprintf("input type %v must be an interface type or an unnamed pointer type", to))
|
||||
}
|
||||
}
|
||||
|
||||
// castableTo checks whether values of type "from" can be casted to type "to".
|
||||
// Nil pointer or interface "from" values are never considered castable.
|
||||
//
|
||||
// This function must be kept in sync with addressableValue.castTo.
|
||||
func castableTo(from, to reflect.Type) bool {
|
||||
switch to.Kind() {
|
||||
case reflect.Interface:
|
||||
// TODO: This breaks when ordinary interfaces can have type sets
|
||||
// since interfaces now exist where only the value form of a type (T)
|
||||
// implements the interface, but not the pointer variant (*T).
|
||||
// See https://go.dev/issue/45346.
|
||||
return reflect.PointerTo(from).Implements(to)
|
||||
case reflect.Pointer:
|
||||
// Common case for unmarshaling.
|
||||
// From must be a concrete or interface type.
|
||||
return reflect.PointerTo(from) == to
|
||||
default:
|
||||
// Common case for marshaling.
|
||||
// From must be a concrete type.
|
||||
return from == to
|
||||
}
|
||||
}
|
||||
|
||||
// castTo casts va to the specified type.
|
||||
// If the type is an interface, then the underlying type will always
|
||||
// be a non-nil pointer to a concrete type.
|
||||
//
|
||||
// Requirement: castableTo(va.Type(), to) must hold.
|
||||
func (va addressableValue) castTo(to reflect.Type) reflect.Value {
|
||||
switch to.Kind() {
|
||||
case reflect.Interface:
|
||||
return va.Addr().Convert(to)
|
||||
case reflect.Pointer:
|
||||
return va.Addr()
|
||||
default:
|
||||
return va.Value
|
||||
}
|
||||
}
|
||||
|
||||
// castableToFromAny reports whether "to" can be casted to from any
|
||||
// of the dynamic types used to represent arbitrary JSON.
|
||||
func castableToFromAny(to reflect.Type) bool {
|
||||
for _, from := range []reflect.Type{anyType, boolType, stringType, float64Type, mapStringAnyType, sliceAnyType} {
|
||||
if castableTo(from, to) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func wrapSkipFunc(err error, what string) error {
|
||||
if err == SkipFunc {
|
||||
return errors.New(what + " cannot be skipped")
|
||||
}
|
||||
return err
|
||||
}
|
||||
186
client/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/arshal_inlined.go
generated
vendored
Normal file
186
client/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/arshal_inlined.go
generated
vendored
Normal file
@@ -0,0 +1,186 @@
|
||||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package json
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// This package supports "inlining" a Go struct field, where the contents
|
||||
// of the serialized field (which must be a JSON object) are treated as if
|
||||
// they are part of the parent Go struct (which represents a JSON object).
|
||||
//
|
||||
// Generally, inlined fields are of a Go struct type, where the fields of the
|
||||
// nested struct are virtually hoisted up to the parent struct using rules
|
||||
// similar to how Go embedding works (but operating within the JSON namespace).
|
||||
//
|
||||
// However, inlined fields may also be of a Go map type with a string key
|
||||
// or a RawValue. Such inlined fields are called "fallback" fields since they
|
||||
// represent any arbitrary JSON object member. Explicitly named fields take
|
||||
// precedence over the inlined fallback. Only one inlined fallback is allowed.
|
||||
|
||||
var rawValueType = reflect.TypeOf((*RawValue)(nil)).Elem()
|
||||
|
||||
// marshalInlinedFallbackAll marshals all the members in an inlined fallback.
|
||||
func marshalInlinedFallbackAll(mo MarshalOptions, enc *Encoder, va addressableValue, f *structField, insertUnquotedName func([]byte) bool) error {
|
||||
v := addressableValue{va.Field(f.index[0])} // addressable if struct value is addressable
|
||||
if len(f.index) > 1 {
|
||||
v = v.fieldByIndex(f.index[1:], false)
|
||||
if !v.IsValid() {
|
||||
return nil // implies a nil inlined field
|
||||
}
|
||||
}
|
||||
v = v.indirect(false)
|
||||
if !v.IsValid() {
|
||||
return nil
|
||||
}
|
||||
|
||||
if v.Type() == rawValueType {
|
||||
b := v.Interface().(RawValue)
|
||||
if len(b) == 0 { // TODO: Should this be nil? What if it were all whitespace?
|
||||
return nil
|
||||
}
|
||||
|
||||
dec := getBufferedDecoder(b, DecodeOptions{AllowDuplicateNames: true, AllowInvalidUTF8: true})
|
||||
defer putBufferedDecoder(dec)
|
||||
|
||||
tok, err := dec.ReadToken()
|
||||
if err != nil {
|
||||
return &SemanticError{action: "marshal", GoType: rawValueType, Err: err}
|
||||
}
|
||||
if tok.Kind() != '{' {
|
||||
err := errors.New("inlined raw value must be a JSON object")
|
||||
return &SemanticError{action: "marshal", JSONKind: tok.Kind(), GoType: rawValueType, Err: err}
|
||||
}
|
||||
for dec.PeekKind() != '}' {
|
||||
// Parse the JSON object name.
|
||||
var flags valueFlags
|
||||
val, err := dec.readValue(&flags)
|
||||
if err != nil {
|
||||
return &SemanticError{action: "marshal", GoType: rawValueType, Err: err}
|
||||
}
|
||||
if insertUnquotedName != nil {
|
||||
name := unescapeStringMayCopy(val, flags.isVerbatim())
|
||||
if !insertUnquotedName(name) {
|
||||
return &SyntacticError{str: "duplicate name " + string(val) + " in object"}
|
||||
}
|
||||
}
|
||||
if err := enc.WriteValue(val); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Parse the JSON object value.
|
||||
val, err = dec.readValue(&flags)
|
||||
if err != nil {
|
||||
return &SemanticError{action: "marshal", GoType: rawValueType, Err: err}
|
||||
}
|
||||
if err := enc.WriteValue(val); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if _, err := dec.ReadToken(); err != nil {
|
||||
return &SemanticError{action: "marshal", GoType: rawValueType, Err: err}
|
||||
}
|
||||
if err := dec.checkEOF(); err != nil {
|
||||
return &SemanticError{action: "marshal", GoType: rawValueType, Err: err}
|
||||
}
|
||||
return nil
|
||||
} else {
|
||||
if v.Len() == 0 {
|
||||
return nil
|
||||
}
|
||||
m := v
|
||||
mv := newAddressableValue(m.Type().Elem())
|
||||
for iter := m.MapRange(); iter.Next(); {
|
||||
b, err := appendString(enc.UnusedBuffer(), iter.Key().String(), !enc.options.AllowInvalidUTF8, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if insertUnquotedName != nil {
|
||||
isVerbatim := consumeSimpleString(b) == len(b)
|
||||
name := unescapeStringMayCopy(b, isVerbatim)
|
||||
if !insertUnquotedName(name) {
|
||||
return &SyntacticError{str: "duplicate name " + string(b) + " in object"}
|
||||
}
|
||||
}
|
||||
if err := enc.WriteValue(b); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mv.Set(iter.Value())
|
||||
marshal := f.fncs.marshal
|
||||
if mo.Marshalers != nil {
|
||||
marshal, _ = mo.Marshalers.lookup(marshal, mv.Type())
|
||||
}
|
||||
if err := marshal(mo, enc, mv); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// unmarshalInlinedFallbackNext unmarshals only the next member in an inlined fallback.
|
||||
func unmarshalInlinedFallbackNext(uo UnmarshalOptions, dec *Decoder, va addressableValue, f *structField, quotedName, unquotedName []byte) error {
|
||||
v := addressableValue{va.Field(f.index[0])} // addressable if struct value is addressable
|
||||
if len(f.index) > 1 {
|
||||
v = v.fieldByIndex(f.index[1:], true)
|
||||
}
|
||||
v = v.indirect(true)
|
||||
|
||||
if v.Type() == rawValueType {
|
||||
b := v.Addr().Interface().(*RawValue)
|
||||
if len(*b) == 0 { // TODO: Should this be nil? What if it were all whitespace?
|
||||
*b = append(*b, '{')
|
||||
} else {
|
||||
*b = trimSuffixWhitespace(*b)
|
||||
if hasSuffixByte(*b, '}') {
|
||||
// TODO: When merging into an object for the first time,
|
||||
// should we verify that it is valid?
|
||||
*b = trimSuffixByte(*b, '}')
|
||||
*b = trimSuffixWhitespace(*b)
|
||||
if !hasSuffixByte(*b, ',') && !hasSuffixByte(*b, '{') {
|
||||
*b = append(*b, ',')
|
||||
}
|
||||
} else {
|
||||
err := errors.New("inlined raw value must be a JSON object")
|
||||
return &SemanticError{action: "unmarshal", GoType: rawValueType, Err: err}
|
||||
}
|
||||
}
|
||||
*b = append(*b, quotedName...)
|
||||
*b = append(*b, ':')
|
||||
rawValue, err := dec.ReadValue()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*b = append(*b, rawValue...)
|
||||
*b = append(*b, '}')
|
||||
return nil
|
||||
} else {
|
||||
name := string(unquotedName) // TODO: Intern this?
|
||||
|
||||
m := v
|
||||
if m.IsNil() {
|
||||
m.Set(reflect.MakeMap(m.Type()))
|
||||
}
|
||||
mk := reflect.ValueOf(name)
|
||||
mv := newAddressableValue(v.Type().Elem()) // TODO: Cache across calls?
|
||||
if v2 := m.MapIndex(mk); v2.IsValid() {
|
||||
mv.Set(v2)
|
||||
}
|
||||
|
||||
unmarshal := f.fncs.unmarshal
|
||||
if uo.Unmarshalers != nil {
|
||||
unmarshal, _ = uo.Unmarshalers.lookup(unmarshal, mv.Type())
|
||||
}
|
||||
err := unmarshal(uo, dec, mv)
|
||||
m.SetMapIndex(mk, mv.Value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
229
client/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/arshal_methods.go
generated
vendored
Normal file
229
client/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/arshal_methods.go
generated
vendored
Normal file
@@ -0,0 +1,229 @@
|
||||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package json
|
||||
|
||||
import (
|
||||
"encoding"
|
||||
"errors"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// Interfaces for custom serialization.
|
||||
var (
|
||||
jsonMarshalerV1Type = reflect.TypeOf((*MarshalerV1)(nil)).Elem()
|
||||
jsonMarshalerV2Type = reflect.TypeOf((*MarshalerV2)(nil)).Elem()
|
||||
jsonUnmarshalerV1Type = reflect.TypeOf((*UnmarshalerV1)(nil)).Elem()
|
||||
jsonUnmarshalerV2Type = reflect.TypeOf((*UnmarshalerV2)(nil)).Elem()
|
||||
textMarshalerType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
|
||||
textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()
|
||||
)
|
||||
|
||||
// MarshalerV1 is implemented by types that can marshal themselves.
|
||||
// It is recommended that types implement MarshalerV2 unless
|
||||
// the implementation is trying to avoid a hard dependency on this package.
|
||||
//
|
||||
// It is recommended that implementations return a buffer that is safe
|
||||
// for the caller to retain and potentially mutate.
|
||||
type MarshalerV1 interface {
|
||||
MarshalJSON() ([]byte, error)
|
||||
}
|
||||
|
||||
// MarshalerV2 is implemented by types that can marshal themselves.
|
||||
// It is recommended that types implement MarshalerV2 instead of MarshalerV1
|
||||
// since this is both more performant and flexible.
|
||||
// If a type implements both MarshalerV1 and MarshalerV2,
|
||||
// then MarshalerV2 takes precedence. In such a case, both implementations
|
||||
// should aim to have equivalent behavior for the default marshal options.
|
||||
//
|
||||
// The implementation must write only one JSON value to the Encoder and
|
||||
// must not retain the pointer to Encoder.
|
||||
type MarshalerV2 interface {
|
||||
MarshalNextJSON(MarshalOptions, *Encoder) error
|
||||
|
||||
// TODO: Should users call the MarshalOptions.MarshalNext method or
|
||||
// should/can they call this method directly? Does it matter?
|
||||
}
|
||||
|
||||
// UnmarshalerV1 is implemented by types that can unmarshal themselves.
|
||||
// It is recommended that types implement UnmarshalerV2 unless
|
||||
// the implementation is trying to avoid a hard dependency on this package.
|
||||
//
|
||||
// The input can be assumed to be a valid encoding of a JSON value
|
||||
// if called from unmarshal functionality in this package.
|
||||
// UnmarshalJSON must copy the JSON data if it is retained after returning.
|
||||
// It is recommended that UnmarshalJSON implement merge semantics when
|
||||
// unmarshaling into a pre-populated value.
|
||||
//
|
||||
// Implementations must not retain or mutate the input []byte.
|
||||
type UnmarshalerV1 interface {
|
||||
UnmarshalJSON([]byte) error
|
||||
}
|
||||
|
||||
// UnmarshalerV2 is implemented by types that can unmarshal themselves.
|
||||
// It is recommended that types implement UnmarshalerV2 instead of UnmarshalerV1
|
||||
// since this is both more performant and flexible.
|
||||
// If a type implements both UnmarshalerV1 and UnmarshalerV2,
|
||||
// then UnmarshalerV2 takes precedence. In such a case, both implementations
|
||||
// should aim to have equivalent behavior for the default unmarshal options.
|
||||
//
|
||||
// The implementation must read only one JSON value from the Decoder.
|
||||
// It is recommended that UnmarshalNextJSON implement merge semantics when
|
||||
// unmarshaling into a pre-populated value.
|
||||
//
|
||||
// Implementations must not retain the pointer to Decoder.
|
||||
type UnmarshalerV2 interface {
|
||||
UnmarshalNextJSON(UnmarshalOptions, *Decoder) error
|
||||
|
||||
// TODO: Should users call the UnmarshalOptions.UnmarshalNext method or
|
||||
// should/can they call this method directly? Does it matter?
|
||||
}
|
||||
|
||||
func makeMethodArshaler(fncs *arshaler, t reflect.Type) *arshaler {
|
||||
// Avoid injecting method arshaler on the pointer or interface version
|
||||
// to avoid ever calling the method on a nil pointer or interface receiver.
|
||||
// Let it be injected on the value receiver (which is always addressable).
|
||||
if t.Kind() == reflect.Pointer || t.Kind() == reflect.Interface {
|
||||
return fncs
|
||||
}
|
||||
|
||||
// Handle custom marshaler.
|
||||
switch which, needAddr := implementsWhich(t, jsonMarshalerV2Type, jsonMarshalerV1Type, textMarshalerType); which {
|
||||
case jsonMarshalerV2Type:
|
||||
fncs.nonDefault = true
|
||||
fncs.marshal = func(mo MarshalOptions, enc *Encoder, va addressableValue) error {
|
||||
prevDepth, prevLength := enc.tokens.depthLength()
|
||||
err := va.addrWhen(needAddr).Interface().(MarshalerV2).MarshalNextJSON(mo, enc)
|
||||
currDepth, currLength := enc.tokens.depthLength()
|
||||
if (prevDepth != currDepth || prevLength+1 != currLength) && err == nil {
|
||||
err = errors.New("must write exactly one JSON value")
|
||||
}
|
||||
if err != nil {
|
||||
err = wrapSkipFunc(err, "marshal method")
|
||||
// TODO: Avoid wrapping semantic or I/O errors.
|
||||
return &SemanticError{action: "marshal", GoType: t, Err: err}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
case jsonMarshalerV1Type:
|
||||
fncs.nonDefault = true
|
||||
fncs.marshal = func(mo MarshalOptions, enc *Encoder, va addressableValue) error {
|
||||
marshaler := va.addrWhen(needAddr).Interface().(MarshalerV1)
|
||||
val, err := marshaler.MarshalJSON()
|
||||
if err != nil {
|
||||
err = wrapSkipFunc(err, "marshal method")
|
||||
// TODO: Avoid wrapping semantic errors.
|
||||
return &SemanticError{action: "marshal", GoType: t, Err: err}
|
||||
}
|
||||
if err := enc.WriteValue(val); err != nil {
|
||||
// TODO: Avoid wrapping semantic or I/O errors.
|
||||
return &SemanticError{action: "marshal", JSONKind: RawValue(val).Kind(), GoType: t, Err: err}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
case textMarshalerType:
|
||||
fncs.nonDefault = true
|
||||
fncs.marshal = func(mo MarshalOptions, enc *Encoder, va addressableValue) error {
|
||||
marshaler := va.addrWhen(needAddr).Interface().(encoding.TextMarshaler)
|
||||
s, err := marshaler.MarshalText()
|
||||
if err != nil {
|
||||
err = wrapSkipFunc(err, "marshal method")
|
||||
// TODO: Avoid wrapping semantic errors.
|
||||
return &SemanticError{action: "marshal", JSONKind: '"', GoType: t, Err: err}
|
||||
}
|
||||
val := enc.UnusedBuffer()
|
||||
val, err = appendString(val, string(s), true, nil)
|
||||
if err != nil {
|
||||
return &SemanticError{action: "marshal", JSONKind: '"', GoType: t, Err: err}
|
||||
}
|
||||
if err := enc.WriteValue(val); err != nil {
|
||||
// TODO: Avoid wrapping syntactic or I/O errors.
|
||||
return &SemanticError{action: "marshal", JSONKind: '"', GoType: t, Err: err}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Handle custom unmarshaler.
|
||||
switch which, needAddr := implementsWhich(t, jsonUnmarshalerV2Type, jsonUnmarshalerV1Type, textUnmarshalerType); which {
|
||||
case jsonUnmarshalerV2Type:
|
||||
fncs.nonDefault = true
|
||||
fncs.unmarshal = func(uo UnmarshalOptions, dec *Decoder, va addressableValue) error {
|
||||
prevDepth, prevLength := dec.tokens.depthLength()
|
||||
err := va.addrWhen(needAddr).Interface().(UnmarshalerV2).UnmarshalNextJSON(uo, dec)
|
||||
currDepth, currLength := dec.tokens.depthLength()
|
||||
if (prevDepth != currDepth || prevLength+1 != currLength) && err == nil {
|
||||
err = errors.New("must read exactly one JSON value")
|
||||
}
|
||||
if err != nil {
|
||||
err = wrapSkipFunc(err, "unmarshal method")
|
||||
// TODO: Avoid wrapping semantic, syntactic, or I/O errors.
|
||||
return &SemanticError{action: "unmarshal", GoType: t, Err: err}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
case jsonUnmarshalerV1Type:
|
||||
fncs.nonDefault = true
|
||||
fncs.unmarshal = func(uo UnmarshalOptions, dec *Decoder, va addressableValue) error {
|
||||
val, err := dec.ReadValue()
|
||||
if err != nil {
|
||||
return err // must be a syntactic or I/O error
|
||||
}
|
||||
unmarshaler := va.addrWhen(needAddr).Interface().(UnmarshalerV1)
|
||||
if err := unmarshaler.UnmarshalJSON(val); err != nil {
|
||||
err = wrapSkipFunc(err, "unmarshal method")
|
||||
// TODO: Avoid wrapping semantic, syntactic, or I/O errors.
|
||||
return &SemanticError{action: "unmarshal", JSONKind: val.Kind(), GoType: t, Err: err}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
case textUnmarshalerType:
|
||||
fncs.nonDefault = true
|
||||
fncs.unmarshal = func(uo UnmarshalOptions, dec *Decoder, va addressableValue) error {
|
||||
var flags valueFlags
|
||||
val, err := dec.readValue(&flags)
|
||||
if err != nil {
|
||||
return err // must be a syntactic or I/O error
|
||||
}
|
||||
if val.Kind() != '"' {
|
||||
err = errors.New("JSON value must be string type")
|
||||
return &SemanticError{action: "unmarshal", JSONKind: val.Kind(), GoType: t, Err: err}
|
||||
}
|
||||
s := unescapeStringMayCopy(val, flags.isVerbatim())
|
||||
unmarshaler := va.addrWhen(needAddr).Interface().(encoding.TextUnmarshaler)
|
||||
if err := unmarshaler.UnmarshalText(s); err != nil {
|
||||
err = wrapSkipFunc(err, "unmarshal method")
|
||||
// TODO: Avoid wrapping semantic, syntactic, or I/O errors.
|
||||
return &SemanticError{action: "unmarshal", JSONKind: val.Kind(), GoType: t, Err: err}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return fncs
|
||||
}
|
||||
|
||||
// implementsWhich is like t.Implements(ifaceType) for a list of interfaces,
|
||||
// but checks whether either t or reflect.PointerTo(t) implements the interface.
|
||||
// It returns the first interface type that matches and whether a value of t
|
||||
// needs to be addressed first before it implements the interface.
|
||||
func implementsWhich(t reflect.Type, ifaceTypes ...reflect.Type) (which reflect.Type, needAddr bool) {
|
||||
for _, ifaceType := range ifaceTypes {
|
||||
switch {
|
||||
case t.Implements(ifaceType):
|
||||
return ifaceType, false
|
||||
case reflect.PointerTo(t).Implements(ifaceType):
|
||||
return ifaceType, true
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// addrWhen returns va.Addr if addr is specified, otherwise it returns itself.
|
||||
func (va addressableValue) addrWhen(addr bool) reflect.Value {
|
||||
if addr {
|
||||
return va.Addr()
|
||||
}
|
||||
return va.Value
|
||||
}
|
||||
196
client/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/arshal_time.go
generated
vendored
Normal file
196
client/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/arshal_time.go
generated
vendored
Normal file
@@ -0,0 +1,196 @@
|
||||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package json
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
timeDurationType = reflect.TypeOf((*time.Duration)(nil)).Elem()
|
||||
timeTimeType = reflect.TypeOf((*time.Time)(nil)).Elem()
|
||||
)
|
||||
|
||||
func makeTimeArshaler(fncs *arshaler, t reflect.Type) *arshaler {
|
||||
// Ideally, time types would implement MarshalerV2 and UnmarshalerV2,
|
||||
// but that would incur a dependency on package json from package time.
|
||||
// Given how widely used time is, it is more acceptable that we incur a
|
||||
// dependency on time from json.
|
||||
//
|
||||
// Injecting the arshaling functionality like this will not be identical
|
||||
// to actually declaring methods on the time types since embedding of the
|
||||
// time types will not be able to forward this functionality.
|
||||
switch t {
|
||||
case timeDurationType:
|
||||
fncs.nonDefault = true
|
||||
marshalNanos := fncs.marshal
|
||||
fncs.marshal = func(mo MarshalOptions, enc *Encoder, va addressableValue) error {
|
||||
if mo.format != "" && mo.formatDepth == enc.tokens.depth() {
|
||||
if mo.format == "nanos" {
|
||||
mo.format = ""
|
||||
return marshalNanos(mo, enc, va)
|
||||
} else {
|
||||
return newInvalidFormatError("marshal", t, mo.format)
|
||||
}
|
||||
}
|
||||
|
||||
td := va.Interface().(time.Duration)
|
||||
b := enc.UnusedBuffer()
|
||||
b = append(b, '"')
|
||||
b = append(b, td.String()...) // never contains special characters
|
||||
b = append(b, '"')
|
||||
return enc.WriteValue(b)
|
||||
}
|
||||
unmarshalNanos := fncs.unmarshal
|
||||
fncs.unmarshal = func(uo UnmarshalOptions, dec *Decoder, va addressableValue) error {
|
||||
// TODO: Should there be a flag that specifies that we can unmarshal
|
||||
// from either form since there would be no ambiguity?
|
||||
if uo.format != "" && uo.formatDepth == dec.tokens.depth() {
|
||||
if uo.format == "nanos" {
|
||||
uo.format = ""
|
||||
return unmarshalNanos(uo, dec, va)
|
||||
} else {
|
||||
return newInvalidFormatError("unmarshal", t, uo.format)
|
||||
}
|
||||
}
|
||||
|
||||
var flags valueFlags
|
||||
td := va.Addr().Interface().(*time.Duration)
|
||||
val, err := dec.readValue(&flags)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch k := val.Kind(); k {
|
||||
case 'n':
|
||||
*td = time.Duration(0)
|
||||
return nil
|
||||
case '"':
|
||||
val = unescapeStringMayCopy(val, flags.isVerbatim())
|
||||
td2, err := time.ParseDuration(string(val))
|
||||
if err != nil {
|
||||
return &SemanticError{action: "unmarshal", JSONKind: k, GoType: t, Err: err}
|
||||
}
|
||||
*td = td2
|
||||
return nil
|
||||
default:
|
||||
return &SemanticError{action: "unmarshal", JSONKind: k, GoType: t}
|
||||
}
|
||||
}
|
||||
case timeTimeType:
|
||||
fncs.nonDefault = true
|
||||
fncs.marshal = func(mo MarshalOptions, enc *Encoder, va addressableValue) error {
|
||||
format := time.RFC3339Nano
|
||||
if mo.format != "" && mo.formatDepth == enc.tokens.depth() {
|
||||
var err error
|
||||
format, err = checkTimeFormat(mo.format)
|
||||
if err != nil {
|
||||
return &SemanticError{action: "marshal", GoType: t, Err: err}
|
||||
}
|
||||
}
|
||||
|
||||
tt := va.Interface().(time.Time)
|
||||
if y := tt.Year(); y < 0 || y >= 10000 {
|
||||
// RFC 3339 is clear that years are 4 digits exactly.
|
||||
// See https://go.dev/issue/4556#c15 for more discussion.
|
||||
err := fmt.Errorf("year %d outside of range [0,9999]", y)
|
||||
return &SemanticError{action: "marshal", GoType: t, Err: err}
|
||||
}
|
||||
b := enc.UnusedBuffer()
|
||||
b = append(b, '"')
|
||||
b = tt.AppendFormat(b, format)
|
||||
b = append(b, '"')
|
||||
// The format may contain special characters that need escaping.
|
||||
// Verify that the result is a valid JSON string (common case),
|
||||
// otherwise escape the string correctly (slower case).
|
||||
if consumeSimpleString(b) != len(b) {
|
||||
b, _ = appendString(nil, string(b[len(`"`):len(b)-len(`"`)]), true, nil)
|
||||
}
|
||||
return enc.WriteValue(b)
|
||||
}
|
||||
fncs.unmarshal = func(uo UnmarshalOptions, dec *Decoder, va addressableValue) error {
|
||||
format := time.RFC3339Nano
|
||||
if uo.format != "" && uo.formatDepth == dec.tokens.depth() {
|
||||
var err error
|
||||
format, err = checkTimeFormat(uo.format)
|
||||
if err != nil {
|
||||
return &SemanticError{action: "unmarshal", GoType: t, Err: err}
|
||||
}
|
||||
}
|
||||
|
||||
var flags valueFlags
|
||||
tt := va.Addr().Interface().(*time.Time)
|
||||
val, err := dec.readValue(&flags)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
k := val.Kind()
|
||||
switch k {
|
||||
case 'n':
|
||||
*tt = time.Time{}
|
||||
return nil
|
||||
case '"':
|
||||
val = unescapeStringMayCopy(val, flags.isVerbatim())
|
||||
tt2, err := time.Parse(format, string(val))
|
||||
if err != nil {
|
||||
return &SemanticError{action: "unmarshal", JSONKind: k, GoType: t, Err: err}
|
||||
}
|
||||
*tt = tt2
|
||||
return nil
|
||||
default:
|
||||
return &SemanticError{action: "unmarshal", JSONKind: k, GoType: t}
|
||||
}
|
||||
}
|
||||
}
|
||||
return fncs
|
||||
}
|
||||
|
||||
func checkTimeFormat(format string) (string, error) {
|
||||
// We assume that an exported constant in the time package will
|
||||
// always start with an uppercase ASCII letter.
|
||||
if len(format) > 0 && 'A' <= format[0] && format[0] <= 'Z' {
|
||||
switch format {
|
||||
case "ANSIC":
|
||||
return time.ANSIC, nil
|
||||
case "UnixDate":
|
||||
return time.UnixDate, nil
|
||||
case "RubyDate":
|
||||
return time.RubyDate, nil
|
||||
case "RFC822":
|
||||
return time.RFC822, nil
|
||||
case "RFC822Z":
|
||||
return time.RFC822Z, nil
|
||||
case "RFC850":
|
||||
return time.RFC850, nil
|
||||
case "RFC1123":
|
||||
return time.RFC1123, nil
|
||||
case "RFC1123Z":
|
||||
return time.RFC1123Z, nil
|
||||
case "RFC3339":
|
||||
return time.RFC3339, nil
|
||||
case "RFC3339Nano":
|
||||
return time.RFC3339Nano, nil
|
||||
case "Kitchen":
|
||||
return time.Kitchen, nil
|
||||
case "Stamp":
|
||||
return time.Stamp, nil
|
||||
case "StampMilli":
|
||||
return time.StampMilli, nil
|
||||
case "StampMicro":
|
||||
return time.StampMicro, nil
|
||||
case "StampNano":
|
||||
return time.StampNano, nil
|
||||
default:
|
||||
// Reject any format that is an exported Go identifier in case
|
||||
// new format constants are added to the time package.
|
||||
if strings.TrimFunc(format, isLetterOrDigit) == "" {
|
||||
return "", fmt.Errorf("undefined format layout: %v", format)
|
||||
}
|
||||
}
|
||||
}
|
||||
return format, nil
|
||||
}
|
||||
1655
client/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/decode.go
generated
vendored
Normal file
1655
client/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/decode.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
185
client/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/doc.go
generated
vendored
Normal file
185
client/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/doc.go
generated
vendored
Normal file
@@ -0,0 +1,185 @@
|
||||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package json implements serialization of JSON
|
||||
// as specified in RFC 4627, RFC 7159, RFC 7493, RFC 8259, and RFC 8785.
|
||||
// JSON is a simple data interchange format that can represent
|
||||
// primitive data types such as booleans, strings, and numbers,
|
||||
// in addition to structured data types such as objects and arrays.
|
||||
//
|
||||
//
|
||||
// Terminology
|
||||
//
|
||||
// This package uses the terms "encode" and "decode" for syntactic functionality
|
||||
// that is concerned with processing JSON based on its grammar, and
|
||||
// uses the terms "marshal" and "unmarshal" for semantic functionality
|
||||
// that determines the meaning of JSON values as Go values and vice-versa.
|
||||
// It aims to provide a clear distinction between functionality that
|
||||
// is purely concerned with encoding versus that of marshaling.
|
||||
// For example, one can directly encode a stream of JSON tokens without
|
||||
// needing to marshal a concrete Go value representing them.
|
||||
// Similarly, one can decode a stream of JSON tokens without
|
||||
// needing to unmarshal them into a concrete Go value.
|
||||
//
|
||||
// This package uses JSON terminology when discussing JSON, which may differ
|
||||
// from related concepts in Go or elsewhere in computing literature.
|
||||
//
|
||||
// - A JSON "object" refers to an unordered collection of name/value members.
|
||||
// - A JSON "array" refers to an ordered sequence of elements.
|
||||
// - A JSON "value" refers to either a literal (i.e., null, false, or true),
|
||||
// string, number, object, or array.
|
||||
//
|
||||
// See RFC 8259 for more information.
|
||||
//
|
||||
//
|
||||
// Specifications
|
||||
//
|
||||
// Relevant specifications include RFC 4627, RFC 7159, RFC 7493, RFC 8259,
|
||||
// and RFC 8785. Each RFC is generally a stricter subset of another RFC.
|
||||
// In increasing order of strictness:
|
||||
//
|
||||
// - RFC 4627 and RFC 7159 do not require (but recommend) the use of UTF-8
|
||||
// and also do not require (but recommend) that object names be unique.
|
||||
// - RFC 8259 requires the use of UTF-8,
|
||||
// but does not require (but recommends) that object names be unique.
|
||||
// - RFC 7493 requires the use of UTF-8
|
||||
// and also requires that object names be unique.
|
||||
// - RFC 8785 defines a canonical representation. It requires the use of UTF-8
|
||||
// and also requires that object names be unique and in a specific ordering.
|
||||
// It specifies exactly how strings and numbers must be formatted.
|
||||
//
|
||||
// The primary difference between RFC 4627 and RFC 7159 is that the former
|
||||
// restricted top-level values to only JSON objects and arrays, while
|
||||
// RFC 7159 and subsequent RFCs permit top-level values to additionally be
|
||||
// JSON nulls, booleans, strings, or numbers.
|
||||
//
|
||||
// By default, this package operates on RFC 7493, but can be configured
|
||||
// to operate according to the other RFC specifications.
|
||||
// RFC 7493 is a stricter subset of RFC 8259 and fully compliant with it.
|
||||
// In particular, it makes specific choices about behavior that RFC 8259
|
||||
// leaves as undefined in order to ensure greater interoperability.
|
||||
//
|
||||
//
|
||||
// JSON Representation of Go structs
|
||||
//
|
||||
// A Go struct is naturally represented as a JSON object,
|
||||
// where each Go struct field corresponds with a JSON object member.
|
||||
// When marshaling, all Go struct fields are recursively encoded in depth-first
|
||||
// order as JSON object members except those that are ignored or omitted.
|
||||
// When unmarshaling, JSON object members are recursively decoded
|
||||
// into the corresponding Go struct fields.
|
||||
// Object members that do not match any struct fields,
|
||||
// also known as “unknown members”, are ignored by default or rejected
|
||||
// if UnmarshalOptions.RejectUnknownMembers is specified.
|
||||
//
|
||||
// The representation of each struct field can be customized in the
|
||||
// "json" struct field tag, where the tag is a comma separated list of options.
|
||||
// As a special case, if the entire tag is `json:"-"`,
|
||||
// then the field is ignored with regard to its JSON representation.
|
||||
//
|
||||
// The first option is the JSON object name override for the Go struct field.
|
||||
// If the name is not specified, then the Go struct field name
|
||||
// is used as the JSON object name. JSON names containing commas or quotes,
|
||||
// or names identical to "" or "-", can be specified using
|
||||
// a single-quoted string literal, where the syntax is identical to
|
||||
// the Go grammar for a double-quoted string literal,
|
||||
// but instead uses single quotes as the delimiters.
|
||||
// By default, unmarshaling uses case-sensitive matching to identify
|
||||
// the Go struct field associated with a JSON object name.
|
||||
//
|
||||
// After the name, the following tag options are supported:
|
||||
//
|
||||
// - omitzero: When marshaling, the "omitzero" option specifies that
|
||||
// the struct field should be omitted if the field value is zero
|
||||
// as determined by the "IsZero() bool" method if present,
|
||||
// otherwise based on whether the field is the zero Go value.
|
||||
// This option has no effect when unmarshaling.
|
||||
//
|
||||
// - omitempty: When marshaling, the "omitempty" option specifies that
|
||||
// the struct field should be omitted if the field value would have been
|
||||
// encoded as a JSON null, empty string, empty object, or empty array.
|
||||
// This option has no effect when unmarshaling.
|
||||
//
|
||||
// - string: The "string" option specifies that
|
||||
// MarshalOptions.StringifyNumbers and UnmarshalOptions.StringifyNumbers
|
||||
// be set when marshaling or unmarshaling a struct field value.
|
||||
// This causes numeric types to be encoded as a JSON number
|
||||
// within a JSON string, and to be decoded from either a JSON number or
|
||||
// a JSON string containing a JSON number.
|
||||
// This extra level of encoding is often necessary since
|
||||
// many JSON parsers cannot precisely represent 64-bit integers.
|
||||
//
|
||||
// - nocase: When unmarshaling, the "nocase" option specifies that
|
||||
// if the JSON object name does not exactly match the JSON name
|
||||
// for any of the struct fields, then it attempts to match the struct field
|
||||
// using a case-insensitive match that also ignores dashes and underscores.
|
||||
// If multiple fields match, the first declared field in breadth-first order
|
||||
// takes precedence. This option has no effect when marshaling.
|
||||
//
|
||||
// - inline: The "inline" option specifies that
|
||||
// the JSON representable content of this field type is to be promoted
|
||||
// as if they were specified in the parent struct.
|
||||
// It is the JSON equivalent of Go struct embedding.
|
||||
// A Go embedded field is implicitly inlined unless an explicit JSON name
|
||||
// is specified. The inlined field must be a Go struct
|
||||
// (that does not implement any JSON methods), RawValue, map[string]T,
|
||||
// or an unnamed pointer to such types. When marshaling,
|
||||
// inlined fields from a pointer type are omitted if it is nil.
|
||||
// Inlined fields of type RawValue and map[string]T are called
|
||||
// “inlined fallbacks” as they can represent all possible
|
||||
// JSON object members not directly handled by the parent struct.
|
||||
// Only one inlined fallback field may be specified in a struct,
|
||||
// while many non-fallback fields may be specified. This option
|
||||
// must not be specified with any other option (including the JSON name).
|
||||
//
|
||||
// - unknown: The "unknown" option is a specialized variant
|
||||
// of the inlined fallback to indicate that this Go struct field
|
||||
// contains any number of unknown JSON object members. The field type
|
||||
// must be a RawValue, map[string]T, or an unnamed pointer to such types.
|
||||
// If MarshalOptions.DiscardUnknownMembers is specified when marshaling,
|
||||
// the contents of this field are ignored.
|
||||
// If UnmarshalOptions.RejectUnknownMembers is specified when unmarshaling,
|
||||
// any unknown object members are rejected regardless of whether
|
||||
// an inlined fallback with the "unknown" option exists. This option
|
||||
// must not be specified with any other option (including the JSON name).
|
||||
//
|
||||
// - format: The "format" option specifies a format flag
|
||||
// used to specialize the formatting of the field value.
|
||||
// The option is a key-value pair specified as "format:value" where
|
||||
// the value must be either a literal consisting of letters and numbers
|
||||
// (e.g., "format:RFC3339") or a single-quoted string literal
|
||||
// (e.g., "format:'2006-01-02'"). The interpretation of the format flag
|
||||
// is determined by the struct field type.
|
||||
//
|
||||
// The "omitzero" and "omitempty" options are mostly semantically identical.
|
||||
// The former is defined in terms of the Go type system,
|
||||
// while the latter in terms of the JSON type system.
|
||||
// Consequently they behave differently in some circumstances.
|
||||
// For example, only a nil slice or map is omitted under "omitzero", while
|
||||
// an empty slice or map is omitted under "omitempty" regardless of nilness.
|
||||
// The "omitzero" option is useful for types with a well-defined zero value
|
||||
// (e.g., netip.Addr) or have an IsZero method (e.g., time.Time).
|
||||
//
|
||||
// Every Go struct corresponds to a list of JSON representable fields
|
||||
// which is constructed by performing a breadth-first search over
|
||||
// all struct fields (excluding unexported or ignored fields),
|
||||
// where the search recursively descends into inlined structs.
|
||||
// The set of non-inlined fields in a struct must have unique JSON names.
|
||||
// If multiple fields all have the same JSON name, then the one
|
||||
// at shallowest depth takes precedence and the other fields at deeper depths
|
||||
// are excluded from the list of JSON representable fields.
|
||||
// If multiple fields at the shallowest depth have the same JSON name,
|
||||
// then all of those fields are excluded from the list. This is analogous to
|
||||
// Go visibility rules for struct field selection with embedded struct types.
|
||||
//
|
||||
// Marshaling or unmarshaling a non-empty struct
|
||||
// without any JSON representable fields results in a SemanticError.
|
||||
// Unexported fields must not have any `json` tags except for `json:"-"`.
|
||||
package json
|
||||
|
||||
// requireKeyedLiterals can be embedded in a struct to require keyed literals.
|
||||
type requireKeyedLiterals struct{}
|
||||
|
||||
// nonComparable can be embedded in a struct to prevent comparability.
|
||||
type nonComparable [0]func()
|
||||
1146
client/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/encode.go
generated
vendored
Normal file
1146
client/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/encode.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
183
client/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/errors.go
generated
vendored
Normal file
183
client/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/errors.go
generated
vendored
Normal file
@@ -0,0 +1,183 @@
|
||||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package json
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
const errorPrefix = "json: "
|
||||
|
||||
// Error matches errors returned by this package according to errors.Is.
|
||||
const Error = jsonError("json error")
|
||||
|
||||
type jsonError string
|
||||
|
||||
func (e jsonError) Error() string {
|
||||
return string(e)
|
||||
}
|
||||
func (e jsonError) Is(target error) bool {
|
||||
return e == target || target == Error
|
||||
}
|
||||
|
||||
type ioError struct {
|
||||
action string // either "read" or "write"
|
||||
err error
|
||||
}
|
||||
|
||||
func (e *ioError) Error() string {
|
||||
return errorPrefix + e.action + " error: " + e.err.Error()
|
||||
}
|
||||
func (e *ioError) Unwrap() error {
|
||||
return e.err
|
||||
}
|
||||
func (e *ioError) Is(target error) bool {
|
||||
return e == target || target == Error || errors.Is(e.err, target)
|
||||
}
|
||||
|
||||
// SemanticError describes an error determining the meaning
|
||||
// of JSON data as Go data or vice-versa.
|
||||
//
|
||||
// The contents of this error as produced by this package may change over time.
|
||||
type SemanticError struct {
|
||||
requireKeyedLiterals
|
||||
nonComparable
|
||||
|
||||
action string // either "marshal" or "unmarshal"
|
||||
|
||||
// ByteOffset indicates that an error occurred after this byte offset.
|
||||
ByteOffset int64
|
||||
// JSONPointer indicates that an error occurred within this JSON value
|
||||
// as indicated using the JSON Pointer notation (see RFC 6901).
|
||||
JSONPointer string
|
||||
|
||||
// JSONKind is the JSON kind that could not be handled.
|
||||
JSONKind Kind // may be zero if unknown
|
||||
// GoType is the Go type that could not be handled.
|
||||
GoType reflect.Type // may be nil if unknown
|
||||
|
||||
// Err is the underlying error.
|
||||
Err error // may be nil
|
||||
}
|
||||
|
||||
func (e *SemanticError) Error() string {
|
||||
var sb strings.Builder
|
||||
sb.WriteString(errorPrefix)
|
||||
|
||||
// Hyrum-proof the error message by deliberately switching between
|
||||
// two equivalent renderings of the same error message.
|
||||
// The randomization is tied to the Hyrum-proofing already applied
|
||||
// on map iteration in Go.
|
||||
for phrase := range map[string]struct{}{"cannot": {}, "unable to": {}} {
|
||||
sb.WriteString(phrase)
|
||||
break // use whichever phrase we get in the first iteration
|
||||
}
|
||||
|
||||
// Format action.
|
||||
var preposition string
|
||||
switch e.action {
|
||||
case "marshal":
|
||||
sb.WriteString(" marshal")
|
||||
preposition = " from"
|
||||
case "unmarshal":
|
||||
sb.WriteString(" unmarshal")
|
||||
preposition = " into"
|
||||
default:
|
||||
sb.WriteString(" handle")
|
||||
preposition = " with"
|
||||
}
|
||||
|
||||
// Format JSON kind.
|
||||
var omitPreposition bool
|
||||
switch e.JSONKind {
|
||||
case 'n':
|
||||
sb.WriteString(" JSON null")
|
||||
case 'f', 't':
|
||||
sb.WriteString(" JSON boolean")
|
||||
case '"':
|
||||
sb.WriteString(" JSON string")
|
||||
case '0':
|
||||
sb.WriteString(" JSON number")
|
||||
case '{', '}':
|
||||
sb.WriteString(" JSON object")
|
||||
case '[', ']':
|
||||
sb.WriteString(" JSON array")
|
||||
default:
|
||||
omitPreposition = true
|
||||
}
|
||||
|
||||
// Format Go type.
|
||||
if e.GoType != nil {
|
||||
if !omitPreposition {
|
||||
sb.WriteString(preposition)
|
||||
}
|
||||
sb.WriteString(" Go value of type ")
|
||||
sb.WriteString(e.GoType.String())
|
||||
}
|
||||
|
||||
// Format where.
|
||||
switch {
|
||||
case e.JSONPointer != "":
|
||||
sb.WriteString(" within JSON value at ")
|
||||
sb.WriteString(strconv.Quote(e.JSONPointer))
|
||||
case e.ByteOffset > 0:
|
||||
sb.WriteString(" after byte offset ")
|
||||
sb.WriteString(strconv.FormatInt(e.ByteOffset, 10))
|
||||
}
|
||||
|
||||
// Format underlying error.
|
||||
if e.Err != nil {
|
||||
sb.WriteString(": ")
|
||||
sb.WriteString(e.Err.Error())
|
||||
}
|
||||
|
||||
return sb.String()
|
||||
}
|
||||
func (e *SemanticError) Is(target error) bool {
|
||||
return e == target || target == Error || errors.Is(e.Err, target)
|
||||
}
|
||||
func (e *SemanticError) Unwrap() error {
|
||||
return e.Err
|
||||
}
|
||||
|
||||
// SyntacticError is a description of a syntactic error that occurred when
|
||||
// encoding or decoding JSON according to the grammar.
|
||||
//
|
||||
// The contents of this error as produced by this package may change over time.
|
||||
type SyntacticError struct {
|
||||
requireKeyedLiterals
|
||||
nonComparable
|
||||
|
||||
// ByteOffset indicates that an error occurred after this byte offset.
|
||||
ByteOffset int64
|
||||
str string
|
||||
}
|
||||
|
||||
func (e *SyntacticError) Error() string {
|
||||
return errorPrefix + e.str
|
||||
}
|
||||
func (e *SyntacticError) Is(target error) bool {
|
||||
return e == target || target == Error
|
||||
}
|
||||
func (e *SyntacticError) withOffset(pos int64) error {
|
||||
return &SyntacticError{ByteOffset: pos, str: e.str}
|
||||
}
|
||||
|
||||
func newInvalidCharacterError(prefix []byte, where string) *SyntacticError {
|
||||
what := quoteRune(prefix)
|
||||
return &SyntacticError{str: "invalid character " + what + " " + where}
|
||||
}
|
||||
|
||||
func quoteRune(b []byte) string {
|
||||
r, n := utf8.DecodeRune(b)
|
||||
if r == utf8.RuneError && n == 1 {
|
||||
return `'\x` + strconv.FormatUint(uint64(b[0]), 16) + `'`
|
||||
}
|
||||
return strconv.QuoteRune(r)
|
||||
}
|
||||
509
client/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/fields.go
generated
vendored
Normal file
509
client/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/fields.go
generated
vendored
Normal file
@@ -0,0 +1,509 @@
|
||||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package json
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
var errIgnoredField = errors.New("ignored field")
|
||||
|
||||
type isZeroer interface {
|
||||
IsZero() bool
|
||||
}
|
||||
|
||||
var isZeroerType = reflect.TypeOf((*isZeroer)(nil)).Elem()
|
||||
|
||||
type structFields struct {
|
||||
flattened []structField // listed in depth-first ordering
|
||||
byActualName map[string]*structField
|
||||
byFoldedName map[string][]*structField
|
||||
inlinedFallback *structField
|
||||
}
|
||||
|
||||
type structField struct {
|
||||
id int // unique numeric ID in breadth-first ordering
|
||||
index []int // index into a struct according to reflect.Type.FieldByIndex
|
||||
typ reflect.Type
|
||||
fncs *arshaler
|
||||
isZero func(addressableValue) bool
|
||||
isEmpty func(addressableValue) bool
|
||||
fieldOptions
|
||||
}
|
||||
|
||||
func makeStructFields(root reflect.Type) (structFields, *SemanticError) {
|
||||
var fs structFields
|
||||
fs.byActualName = make(map[string]*structField, root.NumField())
|
||||
fs.byFoldedName = make(map[string][]*structField, root.NumField())
|
||||
|
||||
// ambiguous is a sentinel value to indicate that at least two fields
|
||||
// at the same depth have the same name, and thus cancel each other out.
|
||||
// This follows the same rules as selecting a field on embedded structs
|
||||
// where the shallowest field takes precedence. If more than one field
|
||||
// exists at the shallowest depth, then the selection is illegal.
|
||||
// See https://go.dev/ref/spec#Selectors.
|
||||
ambiguous := new(structField)
|
||||
|
||||
// Setup a queue for a breath-first search.
|
||||
var queueIndex int
|
||||
type queueEntry struct {
|
||||
typ reflect.Type
|
||||
index []int
|
||||
visitChildren bool // whether to recursively visit inlined field in this struct
|
||||
}
|
||||
queue := []queueEntry{{root, nil, true}}
|
||||
seen := map[reflect.Type]bool{root: true}
|
||||
|
||||
// Perform a breadth-first search over all reachable fields.
|
||||
// This ensures that len(f.index) will be monotonically increasing.
|
||||
for queueIndex < len(queue) {
|
||||
qe := queue[queueIndex]
|
||||
queueIndex++
|
||||
|
||||
t := qe.typ
|
||||
inlinedFallbackIndex := -1 // index of last inlined fallback field in current struct
|
||||
namesIndex := make(map[string]int) // index of each field with a given JSON object name in current struct
|
||||
var hasAnyJSONTag bool // whether any Go struct field has a `json` tag
|
||||
var hasAnyJSONField bool // whether any JSON serializable fields exist in current struct
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
sf := t.Field(i)
|
||||
_, hasTag := sf.Tag.Lookup("json")
|
||||
hasAnyJSONTag = hasAnyJSONTag || hasTag
|
||||
options, err := parseFieldOptions(sf)
|
||||
if err != nil {
|
||||
if err == errIgnoredField {
|
||||
continue
|
||||
}
|
||||
return structFields{}, &SemanticError{GoType: t, Err: err}
|
||||
}
|
||||
hasAnyJSONField = true
|
||||
f := structField{
|
||||
// Allocate a new slice (len=N+1) to hold both
|
||||
// the parent index (len=N) and the current index (len=1).
|
||||
// Do this to avoid clobbering the memory of the parent index.
|
||||
index: append(append(make([]int, 0, len(qe.index)+1), qe.index...), i),
|
||||
typ: sf.Type,
|
||||
fieldOptions: options,
|
||||
}
|
||||
if sf.Anonymous && !f.hasName {
|
||||
f.inline = true // implied by use of Go embedding without an explicit name
|
||||
}
|
||||
if f.inline || f.unknown {
|
||||
// Handle an inlined field that serializes to/from
|
||||
// zero or more JSON object members.
|
||||
|
||||
if f.inline && f.unknown {
|
||||
err := fmt.Errorf("Go struct field %s cannot have both `inline` and `unknown` specified", sf.Name)
|
||||
return structFields{}, &SemanticError{GoType: t, Err: err}
|
||||
}
|
||||
switch f.fieldOptions {
|
||||
case fieldOptions{name: f.name, quotedName: f.quotedName, inline: true}:
|
||||
case fieldOptions{name: f.name, quotedName: f.quotedName, unknown: true}:
|
||||
default:
|
||||
err := fmt.Errorf("Go struct field %s cannot have any options other than `inline` or `unknown` specified", sf.Name)
|
||||
return structFields{}, &SemanticError{GoType: t, Err: err}
|
||||
}
|
||||
|
||||
// Unwrap one level of pointer indirection similar to how Go
|
||||
// only allows embedding either T or *T, but not **T.
|
||||
tf := f.typ
|
||||
if tf.Kind() == reflect.Pointer && tf.Name() == "" {
|
||||
tf = tf.Elem()
|
||||
}
|
||||
// Reject any types with custom serialization otherwise
|
||||
// it becomes impossible to know what sub-fields to inline.
|
||||
if which, _ := implementsWhich(tf,
|
||||
jsonMarshalerV2Type, jsonMarshalerV1Type, textMarshalerType,
|
||||
jsonUnmarshalerV2Type, jsonUnmarshalerV1Type, textUnmarshalerType,
|
||||
); which != nil && tf != rawValueType {
|
||||
err := fmt.Errorf("inlined Go struct field %s of type %s must not implement JSON marshal or unmarshal methods", sf.Name, tf)
|
||||
return structFields{}, &SemanticError{GoType: t, Err: err}
|
||||
}
|
||||
|
||||
// Handle an inlined field that serializes to/from
|
||||
// a finite number of JSON object members backed by a Go struct.
|
||||
if tf.Kind() == reflect.Struct {
|
||||
if f.unknown {
|
||||
err := fmt.Errorf("inlined Go struct field %s of type %s with `unknown` tag must be a Go map of string key or a json.RawValue", sf.Name, tf)
|
||||
return structFields{}, &SemanticError{GoType: t, Err: err}
|
||||
}
|
||||
if qe.visitChildren {
|
||||
queue = append(queue, queueEntry{tf, f.index, !seen[tf]})
|
||||
}
|
||||
seen[tf] = true
|
||||
continue
|
||||
}
|
||||
|
||||
// Handle an inlined field that serializes to/from any number of
|
||||
// JSON object members back by a Go map or RawValue.
|
||||
switch {
|
||||
case tf == rawValueType:
|
||||
f.fncs = nil // specially handled in arshal_inlined.go
|
||||
case tf.Kind() == reflect.Map && tf.Key() == stringType:
|
||||
f.fncs = lookupArshaler(tf.Elem())
|
||||
default:
|
||||
err := fmt.Errorf("inlined Go struct field %s of type %s must be a Go struct, Go map of string key, or json.RawValue", sf.Name, tf)
|
||||
return structFields{}, &SemanticError{GoType: t, Err: err}
|
||||
}
|
||||
|
||||
// Reject multiple inlined fallback fields within the same struct.
|
||||
if inlinedFallbackIndex >= 0 {
|
||||
err := fmt.Errorf("inlined Go struct fields %s and %s cannot both be a Go map or json.RawValue", t.Field(inlinedFallbackIndex).Name, sf.Name)
|
||||
return structFields{}, &SemanticError{GoType: t, Err: err}
|
||||
}
|
||||
inlinedFallbackIndex = i
|
||||
|
||||
// Multiple inlined fallback fields across different structs
|
||||
// follow the same precedence rules as Go struct embedding.
|
||||
if fs.inlinedFallback == nil {
|
||||
fs.inlinedFallback = &f // store first occurrence at lowest depth
|
||||
} else if len(fs.inlinedFallback.index) == len(f.index) {
|
||||
fs.inlinedFallback = ambiguous // at least two occurrences at same depth
|
||||
}
|
||||
} else {
|
||||
// Handle normal Go struct field that serializes to/from
|
||||
// a single JSON object member.
|
||||
|
||||
// Provide a function that uses a type's IsZero method.
|
||||
switch {
|
||||
case sf.Type.Kind() == reflect.Interface && sf.Type.Implements(isZeroerType):
|
||||
f.isZero = func(va addressableValue) bool {
|
||||
// Avoid panics calling IsZero on a nil interface or
|
||||
// non-nil interface with nil pointer.
|
||||
return va.IsNil() || (va.Elem().Kind() == reflect.Pointer && va.Elem().IsNil()) || va.Interface().(isZeroer).IsZero()
|
||||
}
|
||||
case sf.Type.Kind() == reflect.Pointer && sf.Type.Implements(isZeroerType):
|
||||
f.isZero = func(va addressableValue) bool {
|
||||
// Avoid panics calling IsZero on nil pointer.
|
||||
return va.IsNil() || va.Interface().(isZeroer).IsZero()
|
||||
}
|
||||
case sf.Type.Implements(isZeroerType):
|
||||
f.isZero = func(va addressableValue) bool { return va.Interface().(isZeroer).IsZero() }
|
||||
case reflect.PointerTo(sf.Type).Implements(isZeroerType):
|
||||
f.isZero = func(va addressableValue) bool { return va.Addr().Interface().(isZeroer).IsZero() }
|
||||
}
|
||||
|
||||
// Provide a function that can determine whether the value would
|
||||
// serialize as an empty JSON value.
|
||||
switch sf.Type.Kind() {
|
||||
case reflect.String, reflect.Map, reflect.Array, reflect.Slice:
|
||||
f.isEmpty = func(va addressableValue) bool { return va.Len() == 0 }
|
||||
case reflect.Pointer, reflect.Interface:
|
||||
f.isEmpty = func(va addressableValue) bool { return va.IsNil() }
|
||||
}
|
||||
|
||||
f.id = len(fs.flattened)
|
||||
f.fncs = lookupArshaler(sf.Type)
|
||||
fs.flattened = append(fs.flattened, f)
|
||||
|
||||
// Reject user-specified names with invalid UTF-8.
|
||||
if !utf8.ValidString(f.name) {
|
||||
err := fmt.Errorf("Go struct field %s has JSON object name %q with invalid UTF-8", sf.Name, f.name)
|
||||
return structFields{}, &SemanticError{GoType: t, Err: err}
|
||||
}
|
||||
// Reject multiple fields with same name within the same struct.
|
||||
if j, ok := namesIndex[f.name]; ok {
|
||||
err := fmt.Errorf("Go struct fields %s and %s conflict over JSON object name %q", t.Field(j).Name, sf.Name, f.name)
|
||||
return structFields{}, &SemanticError{GoType: t, Err: err}
|
||||
}
|
||||
namesIndex[f.name] = i
|
||||
|
||||
// Multiple fields of the same name across different structs
|
||||
// follow the same precedence rules as Go struct embedding.
|
||||
if f2 := fs.byActualName[f.name]; f2 == nil {
|
||||
fs.byActualName[f.name] = &fs.flattened[len(fs.flattened)-1] // store first occurrence at lowest depth
|
||||
} else if len(f2.index) == len(f.index) {
|
||||
fs.byActualName[f.name] = ambiguous // at least two occurrences at same depth
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: New users to the json package are occasionally surprised that
|
||||
// unexported fields are ignored. This occurs by necessity due to our
|
||||
// inability to directly introspect such fields with Go reflection
|
||||
// without the use of unsafe.
|
||||
//
|
||||
// To reduce friction here, refuse to serialize any Go struct that
|
||||
// has no JSON serializable fields, has at least one Go struct field,
|
||||
// and does not have any `json` tags present. For example,
|
||||
// errors returned by errors.New would fail to serialize.
|
||||
isEmptyStruct := t.NumField() == 0
|
||||
if !isEmptyStruct && !hasAnyJSONTag && !hasAnyJSONField {
|
||||
err := errors.New("Go struct has no exported fields")
|
||||
return structFields{}, &SemanticError{GoType: t, Err: err}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove all fields that are duplicates.
|
||||
// This may move elements forward to fill the holes from removed fields.
|
||||
var n int
|
||||
for _, f := range fs.flattened {
|
||||
switch f2 := fs.byActualName[f.name]; {
|
||||
case f2 == ambiguous:
|
||||
delete(fs.byActualName, f.name)
|
||||
case f2 == nil:
|
||||
continue // may be nil due to previous delete
|
||||
// TODO(https://go.dev/issue/45955): Use slices.Equal.
|
||||
case reflect.DeepEqual(f.index, f2.index):
|
||||
f.id = n
|
||||
fs.flattened[n] = f
|
||||
fs.byActualName[f.name] = &fs.flattened[n] // fix pointer to new location
|
||||
n++
|
||||
}
|
||||
}
|
||||
fs.flattened = fs.flattened[:n]
|
||||
if fs.inlinedFallback == ambiguous {
|
||||
fs.inlinedFallback = nil
|
||||
}
|
||||
if len(fs.flattened) != len(fs.byActualName) {
|
||||
panic(fmt.Sprintf("BUG: flattened list of fields mismatches fields mapped by name: %d != %d", len(fs.flattened), len(fs.byActualName)))
|
||||
}
|
||||
|
||||
// Sort the fields according to a depth-first ordering.
|
||||
// This operation will cause pointers in byActualName to become incorrect,
|
||||
// which we will correct in another loop shortly thereafter.
|
||||
sort.Slice(fs.flattened, func(i, j int) bool {
|
||||
si := fs.flattened[i].index
|
||||
sj := fs.flattened[j].index
|
||||
for len(si) > 0 && len(sj) > 0 {
|
||||
switch {
|
||||
case si[0] < sj[0]:
|
||||
return true
|
||||
case si[0] > sj[0]:
|
||||
return false
|
||||
default:
|
||||
si = si[1:]
|
||||
sj = sj[1:]
|
||||
}
|
||||
}
|
||||
return len(si) < len(sj)
|
||||
})
|
||||
|
||||
// Recompute the mapping of fields in the byActualName map.
|
||||
// Pre-fold all names so that we can lookup folded names quickly.
|
||||
for i, f := range fs.flattened {
|
||||
foldedName := string(foldName([]byte(f.name)))
|
||||
fs.byActualName[f.name] = &fs.flattened[i]
|
||||
fs.byFoldedName[foldedName] = append(fs.byFoldedName[foldedName], &fs.flattened[i])
|
||||
}
|
||||
for foldedName, fields := range fs.byFoldedName {
|
||||
if len(fields) > 1 {
|
||||
// The precedence order for conflicting nocase names
|
||||
// is by breadth-first order, rather than depth-first order.
|
||||
sort.Slice(fields, func(i, j int) bool {
|
||||
return fields[i].id < fields[j].id
|
||||
})
|
||||
fs.byFoldedName[foldedName] = fields
|
||||
}
|
||||
}
|
||||
|
||||
return fs, nil
|
||||
}
|
||||
|
||||
type fieldOptions struct {
|
||||
name string
|
||||
quotedName string // quoted name per RFC 8785, section 3.2.2.2.
|
||||
hasName bool
|
||||
nocase bool
|
||||
inline bool
|
||||
unknown bool
|
||||
omitzero bool
|
||||
omitempty bool
|
||||
string bool
|
||||
format string
|
||||
}
|
||||
|
||||
// parseFieldOptions parses the `json` tag in a Go struct field as
|
||||
// a structured set of options configuring parameters such as
|
||||
// the JSON member name and other features.
|
||||
// As a special case, it returns errIgnoredField if the field is ignored.
|
||||
func parseFieldOptions(sf reflect.StructField) (out fieldOptions, err error) {
|
||||
tag, hasTag := sf.Tag.Lookup("json")
|
||||
|
||||
// Check whether this field is explicitly ignored.
|
||||
if tag == "-" {
|
||||
return fieldOptions{}, errIgnoredField
|
||||
}
|
||||
|
||||
// Check whether this field is unexported.
|
||||
if !sf.IsExported() {
|
||||
// In contrast to v1, v2 no longer forwards exported fields from
|
||||
// embedded fields of unexported types since Go reflection does not
|
||||
// allow the same set of operations that are available in normal cases
|
||||
// of purely exported fields.
|
||||
// See https://go.dev/issue/21357 and https://go.dev/issue/24153.
|
||||
if sf.Anonymous {
|
||||
return fieldOptions{}, fmt.Errorf("embedded Go struct field %s of an unexported type must be explicitly ignored with a `json:\"-\"` tag", sf.Type.Name())
|
||||
}
|
||||
// Tag options specified on an unexported field suggests user error.
|
||||
if hasTag {
|
||||
return fieldOptions{}, fmt.Errorf("unexported Go struct field %s cannot have non-ignored `json:%q` tag", sf.Name, tag)
|
||||
}
|
||||
return fieldOptions{}, errIgnoredField
|
||||
}
|
||||
|
||||
// Determine the JSON member name for this Go field. A user-specified name
|
||||
// may be provided as either an identifier or a single-quoted string.
|
||||
// The single-quoted string allows arbitrary characters in the name.
|
||||
// See https://go.dev/issue/2718 and https://go.dev/issue/3546.
|
||||
out.name = sf.Name // always starts with an uppercase character
|
||||
if len(tag) > 0 && !strings.HasPrefix(tag, ",") {
|
||||
// For better compatibility with v1, accept almost any unescaped name.
|
||||
n := len(tag) - len(strings.TrimLeftFunc(tag, func(r rune) bool {
|
||||
return !strings.ContainsRune(",\\'\"`", r) // reserve comma, backslash, and quotes
|
||||
}))
|
||||
opt := tag[:n]
|
||||
if n == 0 {
|
||||
// Allow a single quoted string for arbitrary names.
|
||||
opt, n, err = consumeTagOption(tag)
|
||||
if err != nil {
|
||||
return fieldOptions{}, fmt.Errorf("Go struct field %s has malformed `json` tag: %v", sf.Name, err)
|
||||
}
|
||||
}
|
||||
out.hasName = true
|
||||
out.name = opt
|
||||
tag = tag[n:]
|
||||
}
|
||||
b, _ := appendString(nil, out.name, false, nil)
|
||||
out.quotedName = string(b)
|
||||
|
||||
// Handle any additional tag options (if any).
|
||||
var wasFormat bool
|
||||
seenOpts := make(map[string]bool)
|
||||
for len(tag) > 0 {
|
||||
// Consume comma delimiter.
|
||||
if tag[0] != ',' {
|
||||
return fieldOptions{}, fmt.Errorf("Go struct field %s has malformed `json` tag: invalid character %q before next option (expecting ',')", sf.Name, tag[0])
|
||||
}
|
||||
tag = tag[len(","):]
|
||||
if len(tag) == 0 {
|
||||
return fieldOptions{}, fmt.Errorf("Go struct field %s has malformed `json` tag: invalid trailing ',' character", sf.Name)
|
||||
}
|
||||
|
||||
// Consume and process the tag option.
|
||||
opt, n, err := consumeTagOption(tag)
|
||||
if err != nil {
|
||||
return fieldOptions{}, fmt.Errorf("Go struct field %s has malformed `json` tag: %v", sf.Name, err)
|
||||
}
|
||||
rawOpt := tag[:n]
|
||||
tag = tag[n:]
|
||||
switch {
|
||||
case wasFormat:
|
||||
return fieldOptions{}, fmt.Errorf("Go struct field %s has `format` tag option that was not specified last", sf.Name)
|
||||
case strings.HasPrefix(rawOpt, "'") && strings.TrimFunc(opt, isLetterOrDigit) == "":
|
||||
return fieldOptions{}, fmt.Errorf("Go struct field %s has unnecessarily quoted appearance of `%s` tag option; specify `%s` instead", sf.Name, rawOpt, opt)
|
||||
}
|
||||
switch opt {
|
||||
case "nocase":
|
||||
out.nocase = true
|
||||
case "inline":
|
||||
out.inline = true
|
||||
case "unknown":
|
||||
out.unknown = true
|
||||
case "omitzero":
|
||||
out.omitzero = true
|
||||
case "omitempty":
|
||||
out.omitempty = true
|
||||
case "string":
|
||||
out.string = true
|
||||
case "format":
|
||||
if !strings.HasPrefix(tag, ":") {
|
||||
return fieldOptions{}, fmt.Errorf("Go struct field %s is missing value for `format` tag option", sf.Name)
|
||||
}
|
||||
tag = tag[len(":"):]
|
||||
opt, n, err := consumeTagOption(tag)
|
||||
if err != nil {
|
||||
return fieldOptions{}, fmt.Errorf("Go struct field %s has malformed value for `format` tag option: %v", sf.Name, err)
|
||||
}
|
||||
tag = tag[n:]
|
||||
out.format = opt
|
||||
wasFormat = true
|
||||
default:
|
||||
// Reject keys that resemble one of the supported options.
|
||||
// This catches invalid mutants such as "omitEmpty" or "omit_empty".
|
||||
normOpt := strings.ReplaceAll(strings.ToLower(opt), "_", "")
|
||||
switch normOpt {
|
||||
case "nocase", "inline", "unknown", "omitzero", "omitempty", "string", "format":
|
||||
return fieldOptions{}, fmt.Errorf("Go struct field %s has invalid appearance of `%s` tag option; specify `%s` instead", sf.Name, opt, normOpt)
|
||||
}
|
||||
|
||||
// NOTE: Everything else is ignored. This does not mean it is
|
||||
// forward compatible to insert arbitrary tag options since
|
||||
// a future version of this package may understand that tag.
|
||||
}
|
||||
|
||||
// Reject duplicates.
|
||||
if seenOpts[opt] {
|
||||
return fieldOptions{}, fmt.Errorf("Go struct field %s has duplicate appearance of `%s` tag option", sf.Name, rawOpt)
|
||||
}
|
||||
seenOpts[opt] = true
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func consumeTagOption(in string) (string, int, error) {
|
||||
switch r, _ := utf8.DecodeRuneInString(in); {
|
||||
// Option as a Go identifier.
|
||||
case r == '_' || unicode.IsLetter(r):
|
||||
n := len(in) - len(strings.TrimLeftFunc(in, isLetterOrDigit))
|
||||
return in[:n], n, nil
|
||||
// Option as a single-quoted string.
|
||||
case r == '\'':
|
||||
// The grammar is nearly identical to a double-quoted Go string literal,
|
||||
// but uses single quotes as the terminators. The reason for a custom
|
||||
// grammar is because both backtick and double quotes cannot be used
|
||||
// verbatim in a struct tag.
|
||||
//
|
||||
// Convert a single-quoted string to a double-quote string and rely on
|
||||
// strconv.Unquote to handle the rest.
|
||||
var inEscape bool
|
||||
b := []byte{'"'}
|
||||
n := len(`'`)
|
||||
for len(in) > n {
|
||||
r, rn := utf8.DecodeRuneInString(in[n:])
|
||||
switch {
|
||||
case inEscape:
|
||||
if r == '\'' {
|
||||
b = b[:len(b)-1] // remove escape character: `\'` => `'`
|
||||
}
|
||||
inEscape = false
|
||||
case r == '\\':
|
||||
inEscape = true
|
||||
case r == '"':
|
||||
b = append(b, '\\') // insert escape character: `"` => `\"`
|
||||
case r == '\'':
|
||||
b = append(b, '"')
|
||||
n += len(`'`)
|
||||
out, err := strconv.Unquote(string(b))
|
||||
if err != nil {
|
||||
return "", 0, fmt.Errorf("invalid single-quoted string: %s", in[:n])
|
||||
}
|
||||
return out, n, nil
|
||||
}
|
||||
b = append(b, in[n:][:rn]...)
|
||||
n += rn
|
||||
}
|
||||
if n > 10 {
|
||||
n = 10 // limit the amount of context printed in the error
|
||||
}
|
||||
return "", 0, fmt.Errorf("single-quoted string not terminated: %s...", in[:n])
|
||||
case len(in) == 0:
|
||||
return "", 0, io.ErrUnexpectedEOF
|
||||
default:
|
||||
return "", 0, fmt.Errorf("invalid character %q at start of option (expecting Unicode letter or single quote)", r)
|
||||
}
|
||||
}
|
||||
|
||||
func isLetterOrDigit(r rune) bool {
|
||||
return r == '_' || unicode.IsLetter(r) || unicode.IsNumber(r)
|
||||
}
|
||||
56
client/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/fold.go
generated
vendored
Normal file
56
client/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/fold.go
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package json
|
||||
|
||||
import (
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// foldName returns a folded string such that foldName(x) == foldName(y)
|
||||
// is similar to strings.EqualFold(x, y), but ignores underscore and dashes.
|
||||
// This allows foldName to match common naming conventions.
|
||||
func foldName(in []byte) []byte {
|
||||
// This is inlinable to take advantage of "function outlining".
|
||||
// See https://blog.filippo.io/efficient-go-apis-with-the-inliner/
|
||||
var arr [32]byte // large enough for most JSON names
|
||||
return appendFoldedName(arr[:0], in)
|
||||
}
|
||||
func appendFoldedName(out, in []byte) []byte {
|
||||
for i := 0; i < len(in); {
|
||||
// Handle single-byte ASCII.
|
||||
if c := in[i]; c < utf8.RuneSelf {
|
||||
if c != '_' && c != '-' {
|
||||
if 'a' <= c && c <= 'z' {
|
||||
c -= 'a' - 'A'
|
||||
}
|
||||
out = append(out, c)
|
||||
}
|
||||
i++
|
||||
continue
|
||||
}
|
||||
// Handle multi-byte Unicode.
|
||||
r, n := utf8.DecodeRune(in[i:])
|
||||
out = utf8.AppendRune(out, foldRune(r))
|
||||
i += n
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// foldRune is a variation on unicode.SimpleFold that returns the same rune
|
||||
// for all runes in the same fold set.
|
||||
//
|
||||
// Invariant:
|
||||
//
|
||||
// foldRune(x) == foldRune(y) ⇔ strings.EqualFold(string(x), string(y))
|
||||
func foldRune(r rune) rune {
|
||||
for {
|
||||
r2 := unicode.SimpleFold(r)
|
||||
if r2 <= r {
|
||||
return r2 // smallest character in the fold set
|
||||
}
|
||||
r = r2
|
||||
}
|
||||
}
|
||||
86
client/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/intern.go
generated
vendored
Normal file
86
client/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/intern.go
generated
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package json
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"math/bits"
|
||||
)
|
||||
|
||||
// stringCache is a cache for strings converted from a []byte.
|
||||
type stringCache [256]string // 256*unsafe.Sizeof(string("")) => 4KiB
|
||||
|
||||
// make returns the string form of b.
|
||||
// It returns a pre-allocated string from c if present, otherwise
|
||||
// it allocates a new string, inserts it into the cache, and returns it.
|
||||
func (c *stringCache) make(b []byte) string {
|
||||
const (
|
||||
minCachedLen = 2 // single byte strings are already interned by the runtime
|
||||
maxCachedLen = 256 // large enough for UUIDs, IPv6 addresses, SHA-256 checksums, etc.
|
||||
)
|
||||
if c == nil || len(b) < minCachedLen || len(b) > maxCachedLen {
|
||||
return string(b)
|
||||
}
|
||||
|
||||
// Compute a hash from the fixed-width prefix and suffix of the string.
|
||||
// This ensures hashing a string is a constant time operation.
|
||||
var h uint32
|
||||
switch {
|
||||
case len(b) >= 8:
|
||||
lo := binary.LittleEndian.Uint64(b[:8])
|
||||
hi := binary.LittleEndian.Uint64(b[len(b)-8:])
|
||||
h = hash64(uint32(lo), uint32(lo>>32)) ^ hash64(uint32(hi), uint32(hi>>32))
|
||||
case len(b) >= 4:
|
||||
lo := binary.LittleEndian.Uint32(b[:4])
|
||||
hi := binary.LittleEndian.Uint32(b[len(b)-4:])
|
||||
h = hash64(lo, hi)
|
||||
case len(b) >= 2:
|
||||
lo := binary.LittleEndian.Uint16(b[:2])
|
||||
hi := binary.LittleEndian.Uint16(b[len(b)-2:])
|
||||
h = hash64(uint32(lo), uint32(hi))
|
||||
}
|
||||
|
||||
// Check the cache for the string.
|
||||
i := h % uint32(len(*c))
|
||||
if s := (*c)[i]; s == string(b) {
|
||||
return s
|
||||
}
|
||||
s := string(b)
|
||||
(*c)[i] = s
|
||||
return s
|
||||
}
|
||||
|
||||
// hash64 returns the hash of two uint32s as a single uint32.
|
||||
func hash64(lo, hi uint32) uint32 {
|
||||
// If avalanche=true, this is identical to XXH32 hash on a 8B string:
|
||||
// var b [8]byte
|
||||
// binary.LittleEndian.PutUint32(b[:4], lo)
|
||||
// binary.LittleEndian.PutUint32(b[4:], hi)
|
||||
// return xxhash.Sum32(b[:])
|
||||
const (
|
||||
prime1 = 0x9e3779b1
|
||||
prime2 = 0x85ebca77
|
||||
prime3 = 0xc2b2ae3d
|
||||
prime4 = 0x27d4eb2f
|
||||
prime5 = 0x165667b1
|
||||
)
|
||||
h := prime5 + uint32(8)
|
||||
h += lo * prime3
|
||||
h = bits.RotateLeft32(h, 17) * prime4
|
||||
h += hi * prime3
|
||||
h = bits.RotateLeft32(h, 17) * prime4
|
||||
// Skip final mix (avalanche) step of XXH32 for performance reasons.
|
||||
// Empirical testing shows that the improvements in unbiased distribution
|
||||
// does not outweigh the extra cost in computational complexity.
|
||||
const avalanche = false
|
||||
if avalanche {
|
||||
h ^= h >> 15
|
||||
h *= prime2
|
||||
h ^= h >> 13
|
||||
h *= prime3
|
||||
h ^= h >> 16
|
||||
}
|
||||
return h
|
||||
}
|
||||
150
client/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/pools.go
generated
vendored
Normal file
150
client/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/pools.go
generated
vendored
Normal file
@@ -0,0 +1,150 @@
|
||||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package json
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"math/bits"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// TODO(https://go.dev/issue/47657): Use sync.PoolOf.
|
||||
|
||||
var (
|
||||
// This owns the internal buffer since there is no io.Writer to output to.
|
||||
// Since the buffer can get arbitrarily large in normal usage,
|
||||
// there is statistical tracking logic to determine whether to recycle
|
||||
// the internal buffer or not based on a history of utilization.
|
||||
bufferedEncoderPool = &sync.Pool{New: func() any { return new(Encoder) }}
|
||||
|
||||
// This owns the internal buffer, but it is only used to temporarily store
|
||||
// buffered JSON before flushing it to the underlying io.Writer.
|
||||
// In a sufficiently efficient streaming mode, we do not expect the buffer
|
||||
// to grow arbitrarily large. Thus, we avoid recycling large buffers.
|
||||
streamingEncoderPool = &sync.Pool{New: func() any { return new(Encoder) }}
|
||||
|
||||
// This does not own the internal buffer since
|
||||
// it is taken directly from the provided bytes.Buffer.
|
||||
bytesBufferEncoderPool = &sync.Pool{New: func() any { return new(Encoder) }}
|
||||
)
|
||||
|
||||
// bufferStatistics is statistics to track buffer utilization.
|
||||
// It is used to determine whether to recycle a buffer or not
|
||||
// to avoid https://go.dev/issue/23199.
|
||||
type bufferStatistics struct {
|
||||
strikes int // number of times the buffer was under-utilized
|
||||
prevLen int // length of previous buffer
|
||||
}
|
||||
|
||||
func getBufferedEncoder(o EncodeOptions) *Encoder {
|
||||
e := bufferedEncoderPool.Get().(*Encoder)
|
||||
if e.buf == nil {
|
||||
// Round up to nearest 2ⁿ to make best use of malloc size classes.
|
||||
// See runtime/sizeclasses.go on Go1.15.
|
||||
// Logical OR with 63 to ensure 64 as the minimum buffer size.
|
||||
n := 1 << bits.Len(uint(e.bufStats.prevLen|63))
|
||||
e.buf = make([]byte, 0, n)
|
||||
}
|
||||
e.reset(e.buf[:0], nil, o)
|
||||
return e
|
||||
}
|
||||
func putBufferedEncoder(e *Encoder) {
|
||||
// Recycle large buffers only if sufficiently utilized.
|
||||
// If a buffer is under-utilized enough times sequentially,
|
||||
// then it is discarded, ensuring that a single large buffer
|
||||
// won't be kept alive by a continuous stream of small usages.
|
||||
//
|
||||
// The worst case utilization is computed as:
|
||||
// MIN_UTILIZATION_THRESHOLD / (1 + MAX_NUM_STRIKES)
|
||||
//
|
||||
// For the constants chosen below, this is (25%)/(1+4) ⇒ 5%.
|
||||
// This may seem low, but it ensures a lower bound on
|
||||
// the absolute worst-case utilization. Without this check,
|
||||
// this would be theoretically 0%, which is infinitely worse.
|
||||
//
|
||||
// See https://go.dev/issue/27735.
|
||||
switch {
|
||||
case cap(e.buf) <= 4<<10: // always recycle buffers smaller than 4KiB
|
||||
e.bufStats.strikes = 0
|
||||
case cap(e.buf)/4 <= len(e.buf): // at least 25% utilization
|
||||
e.bufStats.strikes = 0
|
||||
case e.bufStats.strikes < 4: // at most 4 strikes
|
||||
e.bufStats.strikes++
|
||||
default: // discard the buffer; too large and too often under-utilized
|
||||
e.bufStats.strikes = 0
|
||||
e.bufStats.prevLen = len(e.buf) // heuristic for size to allocate next time
|
||||
e.buf = nil
|
||||
}
|
||||
bufferedEncoderPool.Put(e)
|
||||
}
|
||||
|
||||
func getStreamingEncoder(w io.Writer, o EncodeOptions) *Encoder {
|
||||
if _, ok := w.(*bytes.Buffer); ok {
|
||||
e := bytesBufferEncoderPool.Get().(*Encoder)
|
||||
e.reset(nil, w, o) // buffer taken from bytes.Buffer
|
||||
return e
|
||||
} else {
|
||||
e := streamingEncoderPool.Get().(*Encoder)
|
||||
e.reset(e.buf[:0], w, o) // preserve existing buffer
|
||||
return e
|
||||
}
|
||||
}
|
||||
func putStreamingEncoder(e *Encoder) {
|
||||
if _, ok := e.wr.(*bytes.Buffer); ok {
|
||||
bytesBufferEncoderPool.Put(e)
|
||||
} else {
|
||||
if cap(e.buf) > 64<<10 {
|
||||
e.buf = nil // avoid pinning arbitrarily large amounts of memory
|
||||
}
|
||||
streamingEncoderPool.Put(e)
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
// This does not own the internal buffer since it is externally provided.
|
||||
bufferedDecoderPool = &sync.Pool{New: func() any { return new(Decoder) }}
|
||||
|
||||
// This owns the internal buffer, but it is only used to temporarily store
|
||||
// buffered JSON fetched from the underlying io.Reader.
|
||||
// In a sufficiently efficient streaming mode, we do not expect the buffer
|
||||
// to grow arbitrarily large. Thus, we avoid recycling large buffers.
|
||||
streamingDecoderPool = &sync.Pool{New: func() any { return new(Decoder) }}
|
||||
|
||||
// This does not own the internal buffer since
|
||||
// it is taken directly from the provided bytes.Buffer.
|
||||
bytesBufferDecoderPool = bufferedDecoderPool
|
||||
)
|
||||
|
||||
func getBufferedDecoder(b []byte, o DecodeOptions) *Decoder {
|
||||
d := bufferedDecoderPool.Get().(*Decoder)
|
||||
d.reset(b, nil, o)
|
||||
return d
|
||||
}
|
||||
func putBufferedDecoder(d *Decoder) {
|
||||
bufferedDecoderPool.Put(d)
|
||||
}
|
||||
|
||||
func getStreamingDecoder(r io.Reader, o DecodeOptions) *Decoder {
|
||||
if _, ok := r.(*bytes.Buffer); ok {
|
||||
d := bytesBufferDecoderPool.Get().(*Decoder)
|
||||
d.reset(nil, r, o) // buffer taken from bytes.Buffer
|
||||
return d
|
||||
} else {
|
||||
d := streamingDecoderPool.Get().(*Decoder)
|
||||
d.reset(d.buf[:0], r, o) // preserve existing buffer
|
||||
return d
|
||||
}
|
||||
}
|
||||
func putStreamingDecoder(d *Decoder) {
|
||||
if _, ok := d.rd.(*bytes.Buffer); ok {
|
||||
bytesBufferDecoderPool.Put(d)
|
||||
} else {
|
||||
if cap(d.buf) > 64<<10 {
|
||||
d.buf = nil // avoid pinning arbitrarily large amounts of memory
|
||||
}
|
||||
streamingDecoderPool.Put(d)
|
||||
}
|
||||
}
|
||||
747
client/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/state.go
generated
vendored
Normal file
747
client/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/state.go
generated
vendored
Normal file
@@ -0,0 +1,747 @@
|
||||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package json
|
||||
|
||||
import (
|
||||
"math"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
var (
|
||||
errMissingName = &SyntacticError{str: "missing string for object name"}
|
||||
errMissingColon = &SyntacticError{str: "missing character ':' after object name"}
|
||||
errMissingValue = &SyntacticError{str: "missing value after object name"}
|
||||
errMissingComma = &SyntacticError{str: "missing character ',' after object or array value"}
|
||||
errMismatchDelim = &SyntacticError{str: "mismatching structural token for object or array"}
|
||||
)
|
||||
|
||||
const errInvalidNamespace = jsonError("object namespace is in an invalid state")
|
||||
|
||||
type state struct {
|
||||
// tokens validates whether the next token kind is valid.
|
||||
tokens stateMachine
|
||||
|
||||
// names is a stack of object names.
|
||||
// Not used if AllowDuplicateNames is true.
|
||||
names objectNameStack
|
||||
|
||||
// namespaces is a stack of object namespaces.
|
||||
// For performance reasons, Encoder or Decoder may not update this
|
||||
// if Marshal or Unmarshal is able to track names in a more efficient way.
|
||||
// See makeMapArshaler and makeStructArshaler.
|
||||
// Not used if AllowDuplicateNames is true.
|
||||
namespaces objectNamespaceStack
|
||||
}
|
||||
|
||||
func (s *state) reset() {
|
||||
s.tokens.reset()
|
||||
s.names.reset()
|
||||
s.namespaces.reset()
|
||||
}
|
||||
|
||||
// appendStackPointer appends a JSON Pointer (RFC 6901) to the current value.
|
||||
// The returned pointer is only accurate if s.names is populated,
|
||||
// otherwise it uses the numeric index as the object member name.
|
||||
//
|
||||
// Invariant: Must call s.names.copyQuotedBuffer beforehand.
|
||||
func (s state) appendStackPointer(b []byte) []byte {
|
||||
var objectDepth int
|
||||
for i := 1; i < s.tokens.depth(); i++ {
|
||||
e := s.tokens.index(i)
|
||||
if e.length() == 0 {
|
||||
break // empty object or array
|
||||
}
|
||||
b = append(b, '/')
|
||||
switch {
|
||||
case e.isObject():
|
||||
if objectDepth < s.names.length() {
|
||||
for _, c := range s.names.getUnquoted(objectDepth) {
|
||||
// Per RFC 6901, section 3, escape '~' and '/' characters.
|
||||
switch c {
|
||||
case '~':
|
||||
b = append(b, "~0"...)
|
||||
case '/':
|
||||
b = append(b, "~1"...)
|
||||
default:
|
||||
b = append(b, c)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Since the names stack is unpopulated, the name is unknown.
|
||||
// As a best-effort replacement, use the numeric member index.
|
||||
// While inaccurate, it produces a syntactically valid pointer.
|
||||
b = strconv.AppendUint(b, uint64((e.length()-1)/2), 10)
|
||||
}
|
||||
objectDepth++
|
||||
case e.isArray():
|
||||
b = strconv.AppendUint(b, uint64(e.length()-1), 10)
|
||||
}
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// stateMachine is a push-down automaton that validates whether
|
||||
// a sequence of tokens is valid or not according to the JSON grammar.
|
||||
// It is useful for both encoding and decoding.
|
||||
//
|
||||
// It is a stack where each entry represents a nested JSON object or array.
|
||||
// The stack has a minimum depth of 1 where the first level is a
|
||||
// virtual JSON array to handle a stream of top-level JSON values.
|
||||
// The top-level virtual JSON array is special in that it doesn't require commas
|
||||
// between each JSON value.
|
||||
//
|
||||
// For performance, most methods are carefully written to be inlineable.
|
||||
// The zero value is a valid state machine ready for use.
|
||||
type stateMachine struct {
|
||||
stack []stateEntry
|
||||
last stateEntry
|
||||
}
|
||||
|
||||
// reset resets the state machine.
|
||||
// The machine always starts with a minimum depth of 1.
|
||||
func (m *stateMachine) reset() {
|
||||
m.stack = m.stack[:0]
|
||||
if cap(m.stack) > 1<<10 {
|
||||
m.stack = nil
|
||||
}
|
||||
m.last = stateTypeArray
|
||||
}
|
||||
|
||||
// depth is the current nested depth of JSON objects and arrays.
|
||||
// It is one-indexed (i.e., top-level values have a depth of 1).
|
||||
func (m stateMachine) depth() int {
|
||||
return len(m.stack) + 1
|
||||
}
|
||||
|
||||
// index returns a reference to the ith entry.
|
||||
// It is only valid until the next push method call.
|
||||
func (m *stateMachine) index(i int) *stateEntry {
|
||||
if i == len(m.stack) {
|
||||
return &m.last
|
||||
}
|
||||
return &m.stack[i]
|
||||
}
|
||||
|
||||
// depthLength reports the current nested depth and
|
||||
// the length of the last JSON object or array.
|
||||
func (m stateMachine) depthLength() (int, int) {
|
||||
return m.depth(), m.last.length()
|
||||
}
|
||||
|
||||
// appendLiteral appends a JSON literal as the next token in the sequence.
|
||||
// If an error is returned, the state is not mutated.
|
||||
func (m *stateMachine) appendLiteral() error {
|
||||
switch {
|
||||
case m.last.needObjectName():
|
||||
return errMissingName
|
||||
case !m.last.isValidNamespace():
|
||||
return errInvalidNamespace
|
||||
default:
|
||||
m.last.increment()
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// appendString appends a JSON string as the next token in the sequence.
|
||||
// If an error is returned, the state is not mutated.
|
||||
func (m *stateMachine) appendString() error {
|
||||
switch {
|
||||
case !m.last.isValidNamespace():
|
||||
return errInvalidNamespace
|
||||
default:
|
||||
m.last.increment()
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// appendNumber appends a JSON number as the next token in the sequence.
|
||||
// If an error is returned, the state is not mutated.
|
||||
func (m *stateMachine) appendNumber() error {
|
||||
return m.appendLiteral()
|
||||
}
|
||||
|
||||
// pushObject appends a JSON start object token as next in the sequence.
|
||||
// If an error is returned, the state is not mutated.
|
||||
func (m *stateMachine) pushObject() error {
|
||||
switch {
|
||||
case m.last.needObjectName():
|
||||
return errMissingName
|
||||
case !m.last.isValidNamespace():
|
||||
return errInvalidNamespace
|
||||
default:
|
||||
m.last.increment()
|
||||
m.stack = append(m.stack, m.last)
|
||||
m.last = stateTypeObject
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// popObject appends a JSON end object token as next in the sequence.
|
||||
// If an error is returned, the state is not mutated.
|
||||
func (m *stateMachine) popObject() error {
|
||||
switch {
|
||||
case !m.last.isObject():
|
||||
return errMismatchDelim
|
||||
case m.last.needObjectValue():
|
||||
return errMissingValue
|
||||
case !m.last.isValidNamespace():
|
||||
return errInvalidNamespace
|
||||
default:
|
||||
m.last = m.stack[len(m.stack)-1]
|
||||
m.stack = m.stack[:len(m.stack)-1]
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// pushArray appends a JSON start array token as next in the sequence.
|
||||
// If an error is returned, the state is not mutated.
|
||||
func (m *stateMachine) pushArray() error {
|
||||
switch {
|
||||
case m.last.needObjectName():
|
||||
return errMissingName
|
||||
case !m.last.isValidNamespace():
|
||||
return errInvalidNamespace
|
||||
default:
|
||||
m.last.increment()
|
||||
m.stack = append(m.stack, m.last)
|
||||
m.last = stateTypeArray
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// popArray appends a JSON end array token as next in the sequence.
|
||||
// If an error is returned, the state is not mutated.
|
||||
func (m *stateMachine) popArray() error {
|
||||
switch {
|
||||
case !m.last.isArray() || len(m.stack) == 0: // forbid popping top-level virtual JSON array
|
||||
return errMismatchDelim
|
||||
case !m.last.isValidNamespace():
|
||||
return errInvalidNamespace
|
||||
default:
|
||||
m.last = m.stack[len(m.stack)-1]
|
||||
m.stack = m.stack[:len(m.stack)-1]
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// needIndent reports whether indent whitespace should be injected.
|
||||
// A zero value means that no whitespace should be injected.
|
||||
// A positive value means '\n', indentPrefix, and (n-1) copies of indentBody
|
||||
// should be appended to the output immediately before the next token.
|
||||
func (m stateMachine) needIndent(next Kind) (n int) {
|
||||
willEnd := next == '}' || next == ']'
|
||||
switch {
|
||||
case m.depth() == 1:
|
||||
return 0 // top-level values are never indented
|
||||
case m.last.length() == 0 && willEnd:
|
||||
return 0 // an empty object or array is never indented
|
||||
case m.last.length() == 0 || m.last.needImplicitComma(next):
|
||||
return m.depth()
|
||||
case willEnd:
|
||||
return m.depth() - 1
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
// mayAppendDelim appends a colon or comma that may precede the next token.
|
||||
func (m stateMachine) mayAppendDelim(b []byte, next Kind) []byte {
|
||||
switch {
|
||||
case m.last.needImplicitColon():
|
||||
return append(b, ':')
|
||||
case m.last.needImplicitComma(next) && len(m.stack) != 0: // comma not needed for top-level values
|
||||
return append(b, ',')
|
||||
default:
|
||||
return b
|
||||
}
|
||||
}
|
||||
|
||||
// needDelim reports whether a colon or comma token should be implicitly emitted
|
||||
// before the next token of the specified kind.
|
||||
// A zero value means no delimiter should be emitted.
|
||||
func (m stateMachine) needDelim(next Kind) (delim byte) {
|
||||
switch {
|
||||
case m.last.needImplicitColon():
|
||||
return ':'
|
||||
case m.last.needImplicitComma(next) && len(m.stack) != 0: // comma not needed for top-level values
|
||||
return ','
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
// checkDelim reports whether the specified delimiter should be there given
|
||||
// the kind of the next token that appears immediately afterwards.
|
||||
func (m stateMachine) checkDelim(delim byte, next Kind) error {
|
||||
switch needDelim := m.needDelim(next); {
|
||||
case needDelim == delim:
|
||||
return nil
|
||||
case needDelim == ':':
|
||||
return errMissingColon
|
||||
case needDelim == ',':
|
||||
return errMissingComma
|
||||
default:
|
||||
return newInvalidCharacterError([]byte{delim}, "before next token")
|
||||
}
|
||||
}
|
||||
|
||||
// invalidateDisabledNamespaces marks all disabled namespaces as invalid.
|
||||
//
|
||||
// For efficiency, Marshal and Unmarshal may disable namespaces since there are
|
||||
// more efficient ways to track duplicate names. However, if an error occurs,
|
||||
// the namespaces in Encoder or Decoder will be left in an inconsistent state.
|
||||
// Mark the namespaces as invalid so that future method calls on
|
||||
// Encoder or Decoder will return an error.
|
||||
func (m *stateMachine) invalidateDisabledNamespaces() {
|
||||
for i := 0; i < m.depth(); i++ {
|
||||
e := m.index(i)
|
||||
if !e.isActiveNamespace() {
|
||||
e.invalidateNamespace()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// stateEntry encodes several artifacts within a single unsigned integer:
|
||||
// - whether this represents a JSON object or array,
|
||||
// - whether this object should check for duplicate names, and
|
||||
// - how many elements are in this JSON object or array.
|
||||
type stateEntry uint64
|
||||
|
||||
const (
|
||||
// The type mask (1 bit) records whether this is a JSON object or array.
|
||||
stateTypeMask stateEntry = 0x8000_0000_0000_0000
|
||||
stateTypeObject stateEntry = 0x8000_0000_0000_0000
|
||||
stateTypeArray stateEntry = 0x0000_0000_0000_0000
|
||||
|
||||
// The name check mask (2 bit) records whether to update
|
||||
// the namespaces for the current JSON object and
|
||||
// whether the namespace is valid.
|
||||
stateNamespaceMask stateEntry = 0x6000_0000_0000_0000
|
||||
stateDisableNamespace stateEntry = 0x4000_0000_0000_0000
|
||||
stateInvalidNamespace stateEntry = 0x2000_0000_0000_0000
|
||||
|
||||
// The count mask (61 bits) records the number of elements.
|
||||
stateCountMask stateEntry = 0x1fff_ffff_ffff_ffff
|
||||
stateCountLSBMask stateEntry = 0x0000_0000_0000_0001
|
||||
stateCountOdd stateEntry = 0x0000_0000_0000_0001
|
||||
stateCountEven stateEntry = 0x0000_0000_0000_0000
|
||||
)
|
||||
|
||||
// length reports the number of elements in the JSON object or array.
|
||||
// Each name and value in an object entry is treated as a separate element.
|
||||
func (e stateEntry) length() int {
|
||||
return int(e & stateCountMask)
|
||||
}
|
||||
|
||||
// isObject reports whether this is a JSON object.
|
||||
func (e stateEntry) isObject() bool {
|
||||
return e&stateTypeMask == stateTypeObject
|
||||
}
|
||||
|
||||
// isArray reports whether this is a JSON array.
|
||||
func (e stateEntry) isArray() bool {
|
||||
return e&stateTypeMask == stateTypeArray
|
||||
}
|
||||
|
||||
// needObjectName reports whether the next token must be a JSON string,
|
||||
// which is necessary for JSON object names.
|
||||
func (e stateEntry) needObjectName() bool {
|
||||
return e&(stateTypeMask|stateCountLSBMask) == stateTypeObject|stateCountEven
|
||||
}
|
||||
|
||||
// needImplicitColon reports whether an colon should occur next,
|
||||
// which always occurs after JSON object names.
|
||||
func (e stateEntry) needImplicitColon() bool {
|
||||
return e.needObjectValue()
|
||||
}
|
||||
|
||||
// needObjectValue reports whether the next token must be a JSON value,
|
||||
// which is necessary after every JSON object name.
|
||||
func (e stateEntry) needObjectValue() bool {
|
||||
return e&(stateTypeMask|stateCountLSBMask) == stateTypeObject|stateCountOdd
|
||||
}
|
||||
|
||||
// needImplicitComma reports whether an comma should occur next,
|
||||
// which always occurs after a value in a JSON object or array
|
||||
// before the next value (or name).
|
||||
func (e stateEntry) needImplicitComma(next Kind) bool {
|
||||
return !e.needObjectValue() && e.length() > 0 && next != '}' && next != ']'
|
||||
}
|
||||
|
||||
// increment increments the number of elements for the current object or array.
|
||||
// This assumes that overflow won't practically be an issue since
|
||||
// 1<<bits.OnesCount(stateCountMask) is sufficiently large.
|
||||
func (e *stateEntry) increment() {
|
||||
(*e)++
|
||||
}
|
||||
|
||||
// decrement decrements the number of elements for the current object or array.
|
||||
// It is the callers responsibility to ensure that e.length > 0.
|
||||
func (e *stateEntry) decrement() {
|
||||
(*e)--
|
||||
}
|
||||
|
||||
// disableNamespace disables the JSON object namespace such that the
|
||||
// Encoder or Decoder no longer updates the namespace.
|
||||
func (e *stateEntry) disableNamespace() {
|
||||
*e |= stateDisableNamespace
|
||||
}
|
||||
|
||||
// isActiveNamespace reports whether the JSON object namespace is actively
|
||||
// being updated and used for duplicate name checks.
|
||||
func (e stateEntry) isActiveNamespace() bool {
|
||||
return e&(stateDisableNamespace) == 0
|
||||
}
|
||||
|
||||
// invalidateNamespace marks the JSON object namespace as being invalid.
|
||||
func (e *stateEntry) invalidateNamespace() {
|
||||
*e |= stateInvalidNamespace
|
||||
}
|
||||
|
||||
// isValidNamespace reports whether the JSON object namespace is valid.
|
||||
func (e stateEntry) isValidNamespace() bool {
|
||||
return e&(stateInvalidNamespace) == 0
|
||||
}
|
||||
|
||||
// objectNameStack is a stack of names when descending into a JSON object.
|
||||
// In contrast to objectNamespaceStack, this only has to remember a single name
|
||||
// per JSON object.
|
||||
//
|
||||
// This data structure may contain offsets to encodeBuffer or decodeBuffer.
|
||||
// It violates clean abstraction of layers, but is significantly more efficient.
|
||||
// This ensures that popping and pushing in the common case is a trivial
|
||||
// push/pop of an offset integer.
|
||||
//
|
||||
// The zero value is an empty names stack ready for use.
|
||||
type objectNameStack struct {
|
||||
// offsets is a stack of offsets for each name.
|
||||
// A non-negative offset is the ending offset into the local names buffer.
|
||||
// A negative offset is the bit-wise inverse of a starting offset into
|
||||
// a remote buffer (e.g., encodeBuffer or decodeBuffer).
|
||||
// A math.MinInt offset at the end implies that the last object is empty.
|
||||
// Invariant: Positive offsets always occur before negative offsets.
|
||||
offsets []int
|
||||
// unquotedNames is a back-to-back concatenation of names.
|
||||
unquotedNames []byte
|
||||
}
|
||||
|
||||
func (ns *objectNameStack) reset() {
|
||||
ns.offsets = ns.offsets[:0]
|
||||
ns.unquotedNames = ns.unquotedNames[:0]
|
||||
if cap(ns.offsets) > 1<<6 {
|
||||
ns.offsets = nil // avoid pinning arbitrarily large amounts of memory
|
||||
}
|
||||
if cap(ns.unquotedNames) > 1<<10 {
|
||||
ns.unquotedNames = nil // avoid pinning arbitrarily large amounts of memory
|
||||
}
|
||||
}
|
||||
|
||||
func (ns *objectNameStack) length() int {
|
||||
return len(ns.offsets)
|
||||
}
|
||||
|
||||
// getUnquoted retrieves the ith unquoted name in the namespace.
|
||||
// It returns an empty string if the last object is empty.
|
||||
//
|
||||
// Invariant: Must call copyQuotedBuffer beforehand.
|
||||
func (ns *objectNameStack) getUnquoted(i int) []byte {
|
||||
ns.ensureCopiedBuffer()
|
||||
if i == 0 {
|
||||
return ns.unquotedNames[:ns.offsets[0]]
|
||||
} else {
|
||||
return ns.unquotedNames[ns.offsets[i-1]:ns.offsets[i-0]]
|
||||
}
|
||||
}
|
||||
|
||||
// invalidOffset indicates that the last JSON object currently has no name.
|
||||
const invalidOffset = math.MinInt
|
||||
|
||||
// push descends into a nested JSON object.
|
||||
func (ns *objectNameStack) push() {
|
||||
ns.offsets = append(ns.offsets, invalidOffset)
|
||||
}
|
||||
|
||||
// replaceLastQuotedOffset replaces the last name with the starting offset
|
||||
// to the quoted name in some remote buffer. All offsets provided must be
|
||||
// relative to the same buffer until copyQuotedBuffer is called.
|
||||
func (ns *objectNameStack) replaceLastQuotedOffset(i int) {
|
||||
// Use bit-wise inversion instead of naive multiplication by -1 to avoid
|
||||
// ambiguity regarding zero (which is a valid offset into the names field).
|
||||
// Bit-wise inversion is mathematically equivalent to -i-1,
|
||||
// such that 0 becomes -1, 1 becomes -2, and so forth.
|
||||
// This ensures that remote offsets are always negative.
|
||||
ns.offsets[len(ns.offsets)-1] = ^i
|
||||
}
|
||||
|
||||
// replaceLastUnquotedName replaces the last name with the provided name.
|
||||
//
|
||||
// Invariant: Must call copyQuotedBuffer beforehand.
|
||||
func (ns *objectNameStack) replaceLastUnquotedName(s string) {
|
||||
ns.ensureCopiedBuffer()
|
||||
var startOffset int
|
||||
if len(ns.offsets) > 1 {
|
||||
startOffset = ns.offsets[len(ns.offsets)-2]
|
||||
}
|
||||
ns.unquotedNames = append(ns.unquotedNames[:startOffset], s...)
|
||||
ns.offsets[len(ns.offsets)-1] = len(ns.unquotedNames)
|
||||
}
|
||||
|
||||
// clearLast removes any name in the last JSON object.
|
||||
// It is semantically equivalent to ns.push followed by ns.pop.
|
||||
func (ns *objectNameStack) clearLast() {
|
||||
ns.offsets[len(ns.offsets)-1] = invalidOffset
|
||||
}
|
||||
|
||||
// pop ascends out of a nested JSON object.
|
||||
func (ns *objectNameStack) pop() {
|
||||
ns.offsets = ns.offsets[:len(ns.offsets)-1]
|
||||
}
|
||||
|
||||
// copyQuotedBuffer copies names from the remote buffer into the local names
|
||||
// buffer so that there are no more offset references into the remote buffer.
|
||||
// This allows the remote buffer to change contents without affecting
|
||||
// the names that this data structure is trying to remember.
|
||||
func (ns *objectNameStack) copyQuotedBuffer(b []byte) {
|
||||
// Find the first negative offset.
|
||||
var i int
|
||||
for i = len(ns.offsets) - 1; i >= 0 && ns.offsets[i] < 0; i-- {
|
||||
continue
|
||||
}
|
||||
|
||||
// Copy each name from the remote buffer into the local buffer.
|
||||
for i = i + 1; i < len(ns.offsets); i++ {
|
||||
if i == len(ns.offsets)-1 && ns.offsets[i] == invalidOffset {
|
||||
if i == 0 {
|
||||
ns.offsets[i] = 0
|
||||
} else {
|
||||
ns.offsets[i] = ns.offsets[i-1]
|
||||
}
|
||||
break // last JSON object had a push without any names
|
||||
}
|
||||
|
||||
// As a form of Hyrum proofing, we write an invalid character into the
|
||||
// buffer to make misuse of Decoder.ReadToken more obvious.
|
||||
// We need to undo that mutation here.
|
||||
quotedName := b[^ns.offsets[i]:]
|
||||
if quotedName[0] == invalidateBufferByte {
|
||||
quotedName[0] = '"'
|
||||
}
|
||||
|
||||
// Append the unquoted name to the local buffer.
|
||||
var startOffset int
|
||||
if i > 0 {
|
||||
startOffset = ns.offsets[i-1]
|
||||
}
|
||||
if n := consumeSimpleString(quotedName); n > 0 {
|
||||
ns.unquotedNames = append(ns.unquotedNames[:startOffset], quotedName[len(`"`):n-len(`"`)]...)
|
||||
} else {
|
||||
ns.unquotedNames, _ = unescapeString(ns.unquotedNames[:startOffset], quotedName)
|
||||
}
|
||||
ns.offsets[i] = len(ns.unquotedNames)
|
||||
}
|
||||
}
|
||||
|
||||
func (ns *objectNameStack) ensureCopiedBuffer() {
|
||||
if len(ns.offsets) > 0 && ns.offsets[len(ns.offsets)-1] < 0 {
|
||||
panic("BUG: copyQuotedBuffer not called beforehand")
|
||||
}
|
||||
}
|
||||
|
||||
// objectNamespaceStack is a stack of object namespaces.
|
||||
// This data structure assists in detecting duplicate names.
|
||||
type objectNamespaceStack []objectNamespace
|
||||
|
||||
// reset resets the object namespace stack.
|
||||
func (nss *objectNamespaceStack) reset() {
|
||||
if cap(*nss) > 1<<10 {
|
||||
*nss = nil
|
||||
}
|
||||
*nss = (*nss)[:0]
|
||||
}
|
||||
|
||||
// push starts a new namespace for a nested JSON object.
|
||||
func (nss *objectNamespaceStack) push() {
|
||||
if cap(*nss) > len(*nss) {
|
||||
*nss = (*nss)[:len(*nss)+1]
|
||||
nss.last().reset()
|
||||
} else {
|
||||
*nss = append(*nss, objectNamespace{})
|
||||
}
|
||||
}
|
||||
|
||||
// last returns a pointer to the last JSON object namespace.
|
||||
func (nss objectNamespaceStack) last() *objectNamespace {
|
||||
return &nss[len(nss)-1]
|
||||
}
|
||||
|
||||
// pop terminates the namespace for a nested JSON object.
|
||||
func (nss *objectNamespaceStack) pop() {
|
||||
*nss = (*nss)[:len(*nss)-1]
|
||||
}
|
||||
|
||||
// objectNamespace is the namespace for a JSON object.
|
||||
// In contrast to objectNameStack, this needs to remember a all names
|
||||
// per JSON object.
|
||||
//
|
||||
// The zero value is an empty namespace ready for use.
|
||||
type objectNamespace struct {
|
||||
// It relies on a linear search over all the names before switching
|
||||
// to use a Go map for direct lookup.
|
||||
|
||||
// endOffsets is a list of offsets to the end of each name in buffers.
|
||||
// The length of offsets is the number of names in the namespace.
|
||||
endOffsets []uint
|
||||
// allUnquotedNames is a back-to-back concatenation of every name in the namespace.
|
||||
allUnquotedNames []byte
|
||||
// mapNames is a Go map containing every name in the namespace.
|
||||
// Only valid if non-nil.
|
||||
mapNames map[string]struct{}
|
||||
}
|
||||
|
||||
// reset resets the namespace to be empty.
|
||||
func (ns *objectNamespace) reset() {
|
||||
ns.endOffsets = ns.endOffsets[:0]
|
||||
ns.allUnquotedNames = ns.allUnquotedNames[:0]
|
||||
ns.mapNames = nil
|
||||
if cap(ns.endOffsets) > 1<<6 {
|
||||
ns.endOffsets = nil // avoid pinning arbitrarily large amounts of memory
|
||||
}
|
||||
if cap(ns.allUnquotedNames) > 1<<10 {
|
||||
ns.allUnquotedNames = nil // avoid pinning arbitrarily large amounts of memory
|
||||
}
|
||||
}
|
||||
|
||||
// length reports the number of names in the namespace.
|
||||
func (ns *objectNamespace) length() int {
|
||||
return len(ns.endOffsets)
|
||||
}
|
||||
|
||||
// getUnquoted retrieves the ith unquoted name in the namespace.
|
||||
func (ns *objectNamespace) getUnquoted(i int) []byte {
|
||||
if i == 0 {
|
||||
return ns.allUnquotedNames[:ns.endOffsets[0]]
|
||||
} else {
|
||||
return ns.allUnquotedNames[ns.endOffsets[i-1]:ns.endOffsets[i-0]]
|
||||
}
|
||||
}
|
||||
|
||||
// lastUnquoted retrieves the last name in the namespace.
|
||||
func (ns *objectNamespace) lastUnquoted() []byte {
|
||||
return ns.getUnquoted(ns.length() - 1)
|
||||
}
|
||||
|
||||
// insertQuoted inserts a name and reports whether it was inserted,
|
||||
// which only occurs if name is not already in the namespace.
|
||||
// The provided name must be a valid JSON string.
|
||||
func (ns *objectNamespace) insertQuoted(name []byte, isVerbatim bool) bool {
|
||||
if isVerbatim {
|
||||
name = name[len(`"`) : len(name)-len(`"`)]
|
||||
}
|
||||
return ns.insert(name, !isVerbatim)
|
||||
}
|
||||
func (ns *objectNamespace) insertUnquoted(name []byte) bool {
|
||||
return ns.insert(name, false)
|
||||
}
|
||||
func (ns *objectNamespace) insert(name []byte, quoted bool) bool {
|
||||
var allNames []byte
|
||||
if quoted {
|
||||
allNames, _ = unescapeString(ns.allUnquotedNames, name)
|
||||
} else {
|
||||
allNames = append(ns.allUnquotedNames, name...)
|
||||
}
|
||||
name = allNames[len(ns.allUnquotedNames):]
|
||||
|
||||
// Switch to a map if the buffer is too large for linear search.
|
||||
// This does not add the current name to the map.
|
||||
if ns.mapNames == nil && (ns.length() > 64 || len(ns.allUnquotedNames) > 1024) {
|
||||
ns.mapNames = make(map[string]struct{})
|
||||
var startOffset uint
|
||||
for _, endOffset := range ns.endOffsets {
|
||||
name := ns.allUnquotedNames[startOffset:endOffset]
|
||||
ns.mapNames[string(name)] = struct{}{} // allocates a new string
|
||||
startOffset = endOffset
|
||||
}
|
||||
}
|
||||
|
||||
if ns.mapNames == nil {
|
||||
// Perform linear search over the buffer to find matching names.
|
||||
// It provides O(n) lookup, but does not require any allocations.
|
||||
var startOffset uint
|
||||
for _, endOffset := range ns.endOffsets {
|
||||
if string(ns.allUnquotedNames[startOffset:endOffset]) == string(name) {
|
||||
return false
|
||||
}
|
||||
startOffset = endOffset
|
||||
}
|
||||
} else {
|
||||
// Use the map if it is populated.
|
||||
// It provides O(1) lookup, but requires a string allocation per name.
|
||||
if _, ok := ns.mapNames[string(name)]; ok {
|
||||
return false
|
||||
}
|
||||
ns.mapNames[string(name)] = struct{}{} // allocates a new string
|
||||
}
|
||||
|
||||
ns.allUnquotedNames = allNames
|
||||
ns.endOffsets = append(ns.endOffsets, uint(len(ns.allUnquotedNames)))
|
||||
return true
|
||||
}
|
||||
|
||||
// removeLast removes the last name in the namespace.
|
||||
func (ns *objectNamespace) removeLast() {
|
||||
if ns.mapNames != nil {
|
||||
delete(ns.mapNames, string(ns.lastUnquoted()))
|
||||
}
|
||||
if ns.length()-1 == 0 {
|
||||
ns.endOffsets = ns.endOffsets[:0]
|
||||
ns.allUnquotedNames = ns.allUnquotedNames[:0]
|
||||
} else {
|
||||
ns.endOffsets = ns.endOffsets[:ns.length()-1]
|
||||
ns.allUnquotedNames = ns.allUnquotedNames[:ns.endOffsets[ns.length()-1]]
|
||||
}
|
||||
}
|
||||
|
||||
type uintSet64 uint64
|
||||
|
||||
func (s uintSet64) has(i uint) bool { return s&(1<<i) > 0 }
|
||||
func (s *uintSet64) set(i uint) { *s |= 1 << i }
|
||||
|
||||
// uintSet is a set of unsigned integers.
|
||||
// It is optimized for most integers being close to zero.
|
||||
type uintSet struct {
|
||||
lo uintSet64
|
||||
hi []uintSet64
|
||||
}
|
||||
|
||||
// has reports whether i is in the set.
|
||||
func (s *uintSet) has(i uint) bool {
|
||||
if i < 64 {
|
||||
return s.lo.has(i)
|
||||
} else {
|
||||
i -= 64
|
||||
iHi, iLo := int(i/64), uint(i%64)
|
||||
return iHi < len(s.hi) && s.hi[iHi].has(iLo)
|
||||
}
|
||||
}
|
||||
|
||||
// insert inserts i into the set and reports whether it was the first insertion.
|
||||
func (s *uintSet) insert(i uint) bool {
|
||||
// TODO: Make this inlineable at least for the lower 64-bit case.
|
||||
if i < 64 {
|
||||
has := s.lo.has(i)
|
||||
s.lo.set(i)
|
||||
return !has
|
||||
} else {
|
||||
i -= 64
|
||||
iHi, iLo := int(i/64), uint(i%64)
|
||||
if iHi >= len(s.hi) {
|
||||
s.hi = append(s.hi, make([]uintSet64, iHi+1-len(s.hi))...)
|
||||
s.hi = s.hi[:cap(s.hi)]
|
||||
}
|
||||
has := s.hi[iHi].has(iLo)
|
||||
s.hi[iHi].set(iLo)
|
||||
return !has
|
||||
}
|
||||
}
|
||||
522
client/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/token.go
generated
vendored
Normal file
522
client/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/token.go
generated
vendored
Normal file
@@ -0,0 +1,522 @@
|
||||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package json
|
||||
|
||||
import (
|
||||
"math"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// NOTE: Token is analogous to v1 json.Token.
|
||||
|
||||
const (
|
||||
maxInt64 = math.MaxInt64
|
||||
minInt64 = math.MinInt64
|
||||
maxUint64 = math.MaxUint64
|
||||
minUint64 = 0 // for consistency and readability purposes
|
||||
|
||||
invalidTokenPanic = "invalid json.Token; it has been voided by a subsequent json.Decoder call"
|
||||
)
|
||||
|
||||
// Token represents a lexical JSON token, which may be one of the following:
|
||||
// - a JSON literal (i.e., null, true, or false)
|
||||
// - a JSON string (e.g., "hello, world!")
|
||||
// - a JSON number (e.g., 123.456)
|
||||
// - a start or end delimiter for a JSON object (i.e., { or } )
|
||||
// - a start or end delimiter for a JSON array (i.e., [ or ] )
|
||||
//
|
||||
// A Token cannot represent entire array or object values, while a RawValue can.
|
||||
// There is no Token to represent commas and colons since
|
||||
// these structural tokens can be inferred from the surrounding context.
|
||||
type Token struct {
|
||||
nonComparable
|
||||
|
||||
// Tokens can exist in either a "raw" or an "exact" form.
|
||||
// Tokens produced by the Decoder are in the "raw" form.
|
||||
// Tokens returned by constructors are usually in the "exact" form.
|
||||
// The Encoder accepts Tokens in either the "raw" or "exact" form.
|
||||
//
|
||||
// The following chart shows the possible values for each Token type:
|
||||
// ╔═════════════════╦════════════╤════════════╤════════════╗
|
||||
// ║ Token type ║ raw field │ str field │ num field ║
|
||||
// ╠═════════════════╬════════════╪════════════╪════════════╣
|
||||
// ║ null (raw) ║ "null" │ "" │ 0 ║
|
||||
// ║ false (raw) ║ "false" │ "" │ 0 ║
|
||||
// ║ true (raw) ║ "true" │ "" │ 0 ║
|
||||
// ║ string (raw) ║ non-empty │ "" │ offset ║
|
||||
// ║ string (string) ║ nil │ non-empty │ 0 ║
|
||||
// ║ number (raw) ║ non-empty │ "" │ offset ║
|
||||
// ║ number (float) ║ nil │ "f" │ non-zero ║
|
||||
// ║ number (int64) ║ nil │ "i" │ non-zero ║
|
||||
// ║ number (uint64) ║ nil │ "u" │ non-zero ║
|
||||
// ║ object (delim) ║ "{" or "}" │ "" │ 0 ║
|
||||
// ║ array (delim) ║ "[" or "]" │ "" │ 0 ║
|
||||
// ╚═════════════════╩════════════╧════════════╧════════════╝
|
||||
//
|
||||
// Notes:
|
||||
// - For tokens stored in "raw" form, the num field contains the
|
||||
// absolute offset determined by raw.previousOffsetStart().
|
||||
// The buffer itself is stored in raw.previousBuffer().
|
||||
// - JSON literals and structural characters are always in the "raw" form.
|
||||
// - JSON strings and numbers can be in either "raw" or "exact" forms.
|
||||
// - The exact zero value of JSON strings and numbers in the "exact" forms
|
||||
// have ambiguous representation. Thus, they are always represented
|
||||
// in the "raw" form.
|
||||
|
||||
// raw contains a reference to the raw decode buffer.
|
||||
// If non-nil, then its value takes precedence over str and num.
|
||||
// It is only valid if num == raw.previousOffsetStart().
|
||||
raw *decodeBuffer
|
||||
|
||||
// str is the unescaped JSON string if num is zero.
|
||||
// Otherwise, it is "f", "i", or "u" if num should be interpreted
|
||||
// as a float64, int64, or uint64, respectively.
|
||||
str string
|
||||
|
||||
// num is a float64, int64, or uint64 stored as a uint64 value.
|
||||
// It is non-zero for any JSON number in the "exact" form.
|
||||
num uint64
|
||||
}
|
||||
|
||||
// TODO: Does representing 1-byte delimiters as *decodeBuffer cause performance issues?
|
||||
|
||||
var (
|
||||
Null Token = rawToken("null")
|
||||
False Token = rawToken("false")
|
||||
True Token = rawToken("true")
|
||||
|
||||
ObjectStart Token = rawToken("{")
|
||||
ObjectEnd Token = rawToken("}")
|
||||
ArrayStart Token = rawToken("[")
|
||||
ArrayEnd Token = rawToken("]")
|
||||
|
||||
zeroString Token = rawToken(`""`)
|
||||
zeroNumber Token = rawToken(`0`)
|
||||
|
||||
nanString Token = String("NaN")
|
||||
pinfString Token = String("Infinity")
|
||||
ninfString Token = String("-Infinity")
|
||||
)
|
||||
|
||||
func rawToken(s string) Token {
|
||||
return Token{raw: &decodeBuffer{buf: []byte(s), prevStart: 0, prevEnd: len(s)}}
|
||||
}
|
||||
|
||||
// Bool constructs a Token representing a JSON boolean.
|
||||
func Bool(b bool) Token {
|
||||
if b {
|
||||
return True
|
||||
}
|
||||
return False
|
||||
}
|
||||
|
||||
// String construct a Token representing a JSON string.
|
||||
// The provided string should contain valid UTF-8, otherwise invalid characters
|
||||
// may be mangled as the Unicode replacement character.
|
||||
func String(s string) Token {
|
||||
if len(s) == 0 {
|
||||
return zeroString
|
||||
}
|
||||
return Token{str: s}
|
||||
}
|
||||
|
||||
// Float constructs a Token representing a JSON number.
|
||||
// The values NaN, +Inf, and -Inf will be represented
|
||||
// as a JSON string with the values "NaN", "Infinity", and "-Infinity".
|
||||
func Float(n float64) Token {
|
||||
switch {
|
||||
case math.Float64bits(n) == 0:
|
||||
return zeroNumber
|
||||
case math.IsNaN(n):
|
||||
return nanString
|
||||
case math.IsInf(n, +1):
|
||||
return pinfString
|
||||
case math.IsInf(n, -1):
|
||||
return ninfString
|
||||
}
|
||||
return Token{str: "f", num: math.Float64bits(n)}
|
||||
}
|
||||
|
||||
// Int constructs a Token representing a JSON number from an int64.
|
||||
func Int(n int64) Token {
|
||||
if n == 0 {
|
||||
return zeroNumber
|
||||
}
|
||||
return Token{str: "i", num: uint64(n)}
|
||||
}
|
||||
|
||||
// Uint constructs a Token representing a JSON number from a uint64.
|
||||
func Uint(n uint64) Token {
|
||||
if n == 0 {
|
||||
return zeroNumber
|
||||
}
|
||||
return Token{str: "u", num: uint64(n)}
|
||||
}
|
||||
|
||||
// Clone makes a copy of the Token such that its value remains valid
|
||||
// even after a subsequent Decoder.Read call.
|
||||
func (t Token) Clone() Token {
|
||||
// TODO: Allow caller to avoid any allocations?
|
||||
if raw := t.raw; raw != nil {
|
||||
// Avoid copying globals.
|
||||
if t.raw.prevStart == 0 {
|
||||
switch t.raw {
|
||||
case Null.raw:
|
||||
return Null
|
||||
case False.raw:
|
||||
return False
|
||||
case True.raw:
|
||||
return True
|
||||
case ObjectStart.raw:
|
||||
return ObjectStart
|
||||
case ObjectEnd.raw:
|
||||
return ObjectEnd
|
||||
case ArrayStart.raw:
|
||||
return ArrayStart
|
||||
case ArrayEnd.raw:
|
||||
return ArrayEnd
|
||||
}
|
||||
}
|
||||
|
||||
if uint64(raw.previousOffsetStart()) != t.num {
|
||||
panic(invalidTokenPanic)
|
||||
}
|
||||
// TODO(https://go.dev/issue/45038): Use bytes.Clone.
|
||||
buf := append([]byte(nil), raw.previousBuffer()...)
|
||||
return Token{raw: &decodeBuffer{buf: buf, prevStart: 0, prevEnd: len(buf)}}
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
// Bool returns the value for a JSON boolean.
|
||||
// It panics if the token kind is not a JSON boolean.
|
||||
func (t Token) Bool() bool {
|
||||
switch t.raw {
|
||||
case True.raw:
|
||||
return true
|
||||
case False.raw:
|
||||
return false
|
||||
default:
|
||||
panic("invalid JSON token kind: " + t.Kind().String())
|
||||
}
|
||||
}
|
||||
|
||||
// appendString appends a JSON string to dst and returns it.
|
||||
// It panics if t is not a JSON string.
|
||||
func (t Token) appendString(dst []byte, validateUTF8, preserveRaw bool, escapeRune func(rune) bool) ([]byte, error) {
|
||||
if raw := t.raw; raw != nil {
|
||||
// Handle raw string value.
|
||||
buf := raw.previousBuffer()
|
||||
if Kind(buf[0]) == '"' {
|
||||
if escapeRune == nil && consumeSimpleString(buf) == len(buf) {
|
||||
return append(dst, buf...), nil
|
||||
}
|
||||
dst, _, err := reformatString(dst, buf, validateUTF8, preserveRaw, escapeRune)
|
||||
return dst, err
|
||||
}
|
||||
} else if len(t.str) != 0 && t.num == 0 {
|
||||
// Handle exact string value.
|
||||
return appendString(dst, t.str, validateUTF8, escapeRune)
|
||||
}
|
||||
|
||||
panic("invalid JSON token kind: " + t.Kind().String())
|
||||
}
|
||||
|
||||
// String returns the unescaped string value for a JSON string.
|
||||
// For other JSON kinds, this returns the raw JSON represention.
|
||||
func (t Token) String() string {
|
||||
// This is inlinable to take advantage of "function outlining".
|
||||
// This avoids an allocation for the string(b) conversion
|
||||
// if the caller does not use the string in an escaping manner.
|
||||
// See https://blog.filippo.io/efficient-go-apis-with-the-inliner/
|
||||
s, b := t.string()
|
||||
if len(b) > 0 {
|
||||
return string(b)
|
||||
}
|
||||
return s
|
||||
}
|
||||
func (t Token) string() (string, []byte) {
|
||||
if raw := t.raw; raw != nil {
|
||||
if uint64(raw.previousOffsetStart()) != t.num {
|
||||
panic(invalidTokenPanic)
|
||||
}
|
||||
buf := raw.previousBuffer()
|
||||
if buf[0] == '"' {
|
||||
// TODO: Preserve valueFlags in Token?
|
||||
isVerbatim := consumeSimpleString(buf) == len(buf)
|
||||
return "", unescapeStringMayCopy(buf, isVerbatim)
|
||||
}
|
||||
// Handle tokens that are not JSON strings for fmt.Stringer.
|
||||
return "", buf
|
||||
}
|
||||
if len(t.str) != 0 && t.num == 0 {
|
||||
return t.str, nil
|
||||
}
|
||||
// Handle tokens that are not JSON strings for fmt.Stringer.
|
||||
if t.num > 0 {
|
||||
switch t.str[0] {
|
||||
case 'f':
|
||||
return string(appendNumber(nil, math.Float64frombits(t.num), 64)), nil
|
||||
case 'i':
|
||||
return strconv.FormatInt(int64(t.num), 10), nil
|
||||
case 'u':
|
||||
return strconv.FormatUint(uint64(t.num), 10), nil
|
||||
}
|
||||
}
|
||||
return "<invalid json.Token>", nil
|
||||
}
|
||||
|
||||
// appendNumber appends a JSON number to dst and returns it.
|
||||
// It panics if t is not a JSON number.
|
||||
func (t Token) appendNumber(dst []byte, canonicalize bool) ([]byte, error) {
|
||||
if raw := t.raw; raw != nil {
|
||||
// Handle raw number value.
|
||||
buf := raw.previousBuffer()
|
||||
if Kind(buf[0]).normalize() == '0' {
|
||||
if !canonicalize {
|
||||
return append(dst, buf...), nil
|
||||
}
|
||||
dst, _, err := reformatNumber(dst, buf, canonicalize)
|
||||
return dst, err
|
||||
}
|
||||
} else if t.num != 0 {
|
||||
// Handle exact number value.
|
||||
switch t.str[0] {
|
||||
case 'f':
|
||||
return appendNumber(dst, math.Float64frombits(t.num), 64), nil
|
||||
case 'i':
|
||||
return strconv.AppendInt(dst, int64(t.num), 10), nil
|
||||
case 'u':
|
||||
return strconv.AppendUint(dst, uint64(t.num), 10), nil
|
||||
}
|
||||
}
|
||||
|
||||
panic("invalid JSON token kind: " + t.Kind().String())
|
||||
}
|
||||
|
||||
// Float returns the floating-point value for a JSON number.
|
||||
// It returns a NaN, +Inf, or -Inf value for any JSON string
|
||||
// with the values "NaN", "Infinity", or "-Infinity".
|
||||
// It panics for all other cases.
|
||||
func (t Token) Float() float64 {
|
||||
if raw := t.raw; raw != nil {
|
||||
// Handle raw number value.
|
||||
if uint64(raw.previousOffsetStart()) != t.num {
|
||||
panic(invalidTokenPanic)
|
||||
}
|
||||
buf := raw.previousBuffer()
|
||||
if Kind(buf[0]).normalize() == '0' {
|
||||
fv, _ := parseFloat(buf, 64)
|
||||
return fv
|
||||
}
|
||||
} else if t.num != 0 {
|
||||
// Handle exact number value.
|
||||
switch t.str[0] {
|
||||
case 'f':
|
||||
return math.Float64frombits(t.num)
|
||||
case 'i':
|
||||
return float64(int64(t.num))
|
||||
case 'u':
|
||||
return float64(uint64(t.num))
|
||||
}
|
||||
}
|
||||
|
||||
// Handle string values with "NaN", "Infinity", or "-Infinity".
|
||||
if t.Kind() == '"' {
|
||||
switch t.String() {
|
||||
case "NaN":
|
||||
return math.NaN()
|
||||
case "Infinity":
|
||||
return math.Inf(+1)
|
||||
case "-Infinity":
|
||||
return math.Inf(-1)
|
||||
}
|
||||
}
|
||||
|
||||
panic("invalid JSON token kind: " + t.Kind().String())
|
||||
}
|
||||
|
||||
// Int returns the signed integer value for a JSON number.
|
||||
// The fractional component of any number is ignored (truncation toward zero).
|
||||
// Any number beyond the representation of an int64 will be saturated
|
||||
// to the closest representable value.
|
||||
// It panics if the token kind is not a JSON number.
|
||||
func (t Token) Int() int64 {
|
||||
if raw := t.raw; raw != nil {
|
||||
// Handle raw integer value.
|
||||
if uint64(raw.previousOffsetStart()) != t.num {
|
||||
panic(invalidTokenPanic)
|
||||
}
|
||||
neg := false
|
||||
buf := raw.previousBuffer()
|
||||
if len(buf) > 0 && buf[0] == '-' {
|
||||
neg, buf = true, buf[1:]
|
||||
}
|
||||
if numAbs, ok := parseDecUint(buf); ok {
|
||||
if neg {
|
||||
if numAbs > -minInt64 {
|
||||
return minInt64
|
||||
}
|
||||
return -1 * int64(numAbs)
|
||||
} else {
|
||||
if numAbs > +maxInt64 {
|
||||
return maxInt64
|
||||
}
|
||||
return +1 * int64(numAbs)
|
||||
}
|
||||
}
|
||||
} else if t.num != 0 {
|
||||
// Handle exact integer value.
|
||||
switch t.str[0] {
|
||||
case 'i':
|
||||
return int64(t.num)
|
||||
case 'u':
|
||||
if uint64(t.num) > maxInt64 {
|
||||
return maxInt64
|
||||
}
|
||||
return int64(uint64(t.num))
|
||||
}
|
||||
}
|
||||
|
||||
// Handle JSON number that is a floating-point value.
|
||||
if t.Kind() == '0' {
|
||||
switch fv := t.Float(); {
|
||||
case fv >= maxInt64:
|
||||
return maxInt64
|
||||
case fv <= minInt64:
|
||||
return minInt64
|
||||
default:
|
||||
return int64(fv) // truncation toward zero
|
||||
}
|
||||
}
|
||||
|
||||
panic("invalid JSON token kind: " + t.Kind().String())
|
||||
}
|
||||
|
||||
// Uint returns the unsigned integer value for a JSON number.
|
||||
// The fractional component of any number is ignored (truncation toward zero).
|
||||
// Any number beyond the representation of an uint64 will be saturated
|
||||
// to the closest representable value.
|
||||
// It panics if the token kind is not a JSON number.
|
||||
func (t Token) Uint() uint64 {
|
||||
// NOTE: This accessor returns 0 for any negative JSON number,
|
||||
// which might be surprising, but is at least consistent with the behavior
|
||||
// of saturating out-of-bounds numbers to the closest representable number.
|
||||
|
||||
if raw := t.raw; raw != nil {
|
||||
// Handle raw integer value.
|
||||
if uint64(raw.previousOffsetStart()) != t.num {
|
||||
panic(invalidTokenPanic)
|
||||
}
|
||||
neg := false
|
||||
buf := raw.previousBuffer()
|
||||
if len(buf) > 0 && buf[0] == '-' {
|
||||
neg, buf = true, buf[1:]
|
||||
}
|
||||
if num, ok := parseDecUint(buf); ok {
|
||||
if neg {
|
||||
return minUint64
|
||||
}
|
||||
return num
|
||||
}
|
||||
} else if t.num != 0 {
|
||||
// Handle exact integer value.
|
||||
switch t.str[0] {
|
||||
case 'u':
|
||||
return uint64(t.num)
|
||||
case 'i':
|
||||
if int64(t.num) < minUint64 {
|
||||
return minUint64
|
||||
}
|
||||
return uint64(int64(t.num))
|
||||
}
|
||||
}
|
||||
|
||||
// Handle JSON number that is a floating-point value.
|
||||
if t.Kind() == '0' {
|
||||
switch fv := t.Float(); {
|
||||
case fv >= maxUint64:
|
||||
return maxUint64
|
||||
case fv <= minUint64:
|
||||
return minUint64
|
||||
default:
|
||||
return uint64(fv) // truncation toward zero
|
||||
}
|
||||
}
|
||||
|
||||
panic("invalid JSON token kind: " + t.Kind().String())
|
||||
}
|
||||
|
||||
// Kind returns the token kind.
|
||||
func (t Token) Kind() Kind {
|
||||
switch {
|
||||
case t.raw != nil:
|
||||
raw := t.raw
|
||||
if uint64(raw.previousOffsetStart()) != t.num {
|
||||
panic(invalidTokenPanic)
|
||||
}
|
||||
return Kind(t.raw.buf[raw.prevStart]).normalize()
|
||||
case t.num != 0:
|
||||
return '0'
|
||||
case len(t.str) != 0:
|
||||
return '"'
|
||||
default:
|
||||
return invalidKind
|
||||
}
|
||||
}
|
||||
|
||||
// Kind represents each possible JSON token kind with a single byte,
|
||||
// which is conveniently the first byte of that kind's grammar
|
||||
// with the restriction that numbers always be represented with '0':
|
||||
//
|
||||
// - 'n': null
|
||||
// - 'f': false
|
||||
// - 't': true
|
||||
// - '"': string
|
||||
// - '0': number
|
||||
// - '{': object start
|
||||
// - '}': object end
|
||||
// - '[': array start
|
||||
// - ']': array end
|
||||
//
|
||||
// An invalid kind is usually represented using 0,
|
||||
// but may be non-zero due to invalid JSON data.
|
||||
type Kind byte
|
||||
|
||||
const invalidKind Kind = 0
|
||||
|
||||
// String prints the kind in a humanly readable fashion.
|
||||
func (k Kind) String() string {
|
||||
switch k {
|
||||
case 'n':
|
||||
return "null"
|
||||
case 'f':
|
||||
return "false"
|
||||
case 't':
|
||||
return "true"
|
||||
case '"':
|
||||
return "string"
|
||||
case '0':
|
||||
return "number"
|
||||
case '{':
|
||||
return "{"
|
||||
case '}':
|
||||
return "}"
|
||||
case '[':
|
||||
return "["
|
||||
case ']':
|
||||
return "]"
|
||||
default:
|
||||
return "<invalid json.Kind: " + quoteRune([]byte{byte(k)}) + ">"
|
||||
}
|
||||
}
|
||||
|
||||
// normalize coalesces all possible starting characters of a number as just '0'.
|
||||
func (k Kind) normalize() Kind {
|
||||
if k == '-' || ('0' <= k && k <= '9') {
|
||||
return '0'
|
||||
}
|
||||
return k
|
||||
}
|
||||
375
client/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/value.go
generated
vendored
Normal file
375
client/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/value.go
generated
vendored
Normal file
@@ -0,0 +1,375 @@
|
||||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package json
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"io"
|
||||
"sort"
|
||||
"sync"
|
||||
"unicode/utf16"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// NOTE: RawValue is analogous to v1 json.RawMessage.
|
||||
|
||||
// RawValue represents a single raw JSON value, which may be one of the following:
|
||||
// - a JSON literal (i.e., null, true, or false)
|
||||
// - a JSON string (e.g., "hello, world!")
|
||||
// - a JSON number (e.g., 123.456)
|
||||
// - an entire JSON object (e.g., {"fizz":"buzz"} )
|
||||
// - an entire JSON array (e.g., [1,2,3] )
|
||||
//
|
||||
// RawValue can represent entire array or object values, while Token cannot.
|
||||
// RawValue may contain leading and/or trailing whitespace.
|
||||
type RawValue []byte
|
||||
|
||||
// Clone returns a copy of v.
|
||||
func (v RawValue) Clone() RawValue {
|
||||
if v == nil {
|
||||
return nil
|
||||
}
|
||||
return append(RawValue{}, v...)
|
||||
}
|
||||
|
||||
// String returns the string formatting of v.
|
||||
func (v RawValue) String() string {
|
||||
if v == nil {
|
||||
return "null"
|
||||
}
|
||||
return string(v)
|
||||
}
|
||||
|
||||
// IsValid reports whether the raw JSON value is syntactically valid
|
||||
// according to RFC 7493.
|
||||
//
|
||||
// It verifies whether the input is properly encoded as UTF-8,
|
||||
// that escape sequences within strings decode to valid Unicode codepoints, and
|
||||
// that all names in each object are unique.
|
||||
// It does not verify whether numbers are representable within the limits
|
||||
// of any common numeric type (e.g., float64, int64, or uint64).
|
||||
func (v RawValue) IsValid() bool {
|
||||
d := getBufferedDecoder(v, DecodeOptions{})
|
||||
defer putBufferedDecoder(d)
|
||||
_, errVal := d.ReadValue()
|
||||
_, errEOF := d.ReadToken()
|
||||
return errVal == nil && errEOF == io.EOF
|
||||
}
|
||||
|
||||
// Compact removes all whitespace from the raw JSON value.
|
||||
//
|
||||
// It does not reformat JSON strings to use any other representation.
|
||||
// It is guaranteed to succeed if the input is valid.
|
||||
// If the value is already compacted, then the buffer is not mutated.
|
||||
func (v *RawValue) Compact() error {
|
||||
return v.reformat(false, false, "", "")
|
||||
}
|
||||
|
||||
// Indent reformats the whitespace in the raw JSON value so that each element
|
||||
// in a JSON object or array begins on a new, indented line beginning with
|
||||
// prefix followed by one or more copies of indent according to the nesting.
|
||||
// The value does not begin with the prefix nor any indention,
|
||||
// to make it easier to embed inside other formatted JSON data.
|
||||
//
|
||||
// It does not reformat JSON strings to use any other representation.
|
||||
// It is guaranteed to succeed if the input is valid.
|
||||
// If the value is already indented properly, then the buffer is not mutated.
|
||||
func (v *RawValue) Indent(prefix, indent string) error {
|
||||
return v.reformat(false, true, prefix, indent)
|
||||
}
|
||||
|
||||
// Canonicalize canonicalizes the raw JSON value according to the
|
||||
// JSON Canonicalization Scheme (JCS) as defined by RFC 8785
|
||||
// where it produces a stable representation of a JSON value.
|
||||
//
|
||||
// The output stability is dependent on the stability of the application data
|
||||
// (see RFC 8785, Appendix E). It cannot produce stable output from
|
||||
// fundamentally unstable input. For example, if the JSON value
|
||||
// contains ephemeral data (e.g., a frequently changing timestamp),
|
||||
// then the value is still unstable regardless of whether this is called.
|
||||
//
|
||||
// Note that JCS treats all JSON numbers as IEEE 754 double precision numbers.
|
||||
// Any numbers with precision beyond what is representable by that form
|
||||
// will lose their precision when canonicalized. For example, integer values
|
||||
// beyond ±2⁵³ will lose their precision. It is recommended that
|
||||
// int64 and uint64 data types be represented as a JSON string.
|
||||
//
|
||||
// It is guaranteed to succeed if the input is valid.
|
||||
// If the value is already canonicalized, then the buffer is not mutated.
|
||||
func (v *RawValue) Canonicalize() error {
|
||||
return v.reformat(true, false, "", "")
|
||||
}
|
||||
|
||||
// TODO: Instead of implementing the v1 Marshaler/Unmarshaler,
|
||||
// consider implementing the v2 versions instead.
|
||||
|
||||
// MarshalJSON returns v as the JSON encoding of v.
|
||||
// It returns the stored value as the raw JSON output without any validation.
|
||||
// If v is nil, then this returns a JSON null.
|
||||
func (v RawValue) MarshalJSON() ([]byte, error) {
|
||||
// NOTE: This matches the behavior of v1 json.RawMessage.MarshalJSON.
|
||||
if v == nil {
|
||||
return []byte("null"), nil
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets v as the JSON encoding of b.
|
||||
// It stores a copy of the provided raw JSON input without any validation.
|
||||
func (v *RawValue) UnmarshalJSON(b []byte) error {
|
||||
// NOTE: This matches the behavior of v1 json.RawMessage.UnmarshalJSON.
|
||||
if v == nil {
|
||||
return errors.New("json.RawValue: UnmarshalJSON on nil pointer")
|
||||
}
|
||||
*v = append((*v)[:0], b...)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Kind returns the starting token kind.
|
||||
// For a valid value, this will never include '}' or ']'.
|
||||
func (v RawValue) Kind() Kind {
|
||||
if v := v[consumeWhitespace(v):]; len(v) > 0 {
|
||||
return Kind(v[0]).normalize()
|
||||
}
|
||||
return invalidKind
|
||||
}
|
||||
|
||||
func (v *RawValue) reformat(canonical, multiline bool, prefix, indent string) error {
|
||||
var eo EncodeOptions
|
||||
if canonical {
|
||||
eo.AllowInvalidUTF8 = false // per RFC 8785, section 3.2.4
|
||||
eo.AllowDuplicateNames = false // per RFC 8785, section 3.1
|
||||
eo.canonicalizeNumbers = true // per RFC 8785, section 3.2.2.3
|
||||
eo.EscapeRune = nil // per RFC 8785, section 3.2.2.2
|
||||
eo.multiline = false // per RFC 8785, section 3.2.1
|
||||
} else {
|
||||
if s := trimLeftSpaceTab(prefix); len(s) > 0 {
|
||||
panic("json: invalid character " + quoteRune([]byte(s)) + " in indent prefix")
|
||||
}
|
||||
if s := trimLeftSpaceTab(indent); len(s) > 0 {
|
||||
panic("json: invalid character " + quoteRune([]byte(s)) + " in indent")
|
||||
}
|
||||
eo.AllowInvalidUTF8 = true
|
||||
eo.AllowDuplicateNames = true
|
||||
eo.preserveRawStrings = true
|
||||
eo.multiline = multiline // in case indent is empty
|
||||
eo.IndentPrefix = prefix
|
||||
eo.Indent = indent
|
||||
}
|
||||
eo.omitTopLevelNewline = true
|
||||
|
||||
// Write the entire value to reformat all tokens and whitespace.
|
||||
e := getBufferedEncoder(eo)
|
||||
defer putBufferedEncoder(e)
|
||||
if err := e.WriteValue(*v); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// For canonical output, we may need to reorder object members.
|
||||
if canonical {
|
||||
// Obtain a buffered encoder just to use its internal buffer as
|
||||
// a scratch buffer in reorderObjects for reordering object members.
|
||||
e2 := getBufferedEncoder(EncodeOptions{})
|
||||
defer putBufferedEncoder(e2)
|
||||
|
||||
// Disable redundant checks performed earlier during encoding.
|
||||
d := getBufferedDecoder(e.buf, DecodeOptions{AllowInvalidUTF8: true, AllowDuplicateNames: true})
|
||||
defer putBufferedDecoder(d)
|
||||
reorderObjects(d, &e2.buf) // per RFC 8785, section 3.2.3
|
||||
}
|
||||
|
||||
// Store the result back into the value if different.
|
||||
if !bytes.Equal(*v, e.buf) {
|
||||
*v = append((*v)[:0], e.buf...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func trimLeftSpaceTab(s string) string {
|
||||
for i, r := range s {
|
||||
switch r {
|
||||
case ' ', '\t':
|
||||
default:
|
||||
return s[i:]
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type memberName struct {
|
||||
// name is the unescaped name.
|
||||
name []byte
|
||||
// before and after are byte offsets into Decoder.buf that represents
|
||||
// the entire name/value pair. It may contain leading commas.
|
||||
before, after int64
|
||||
}
|
||||
|
||||
var memberNamePool = sync.Pool{New: func() any { return new(memberNames) }}
|
||||
|
||||
func getMemberNames() *memberNames {
|
||||
ns := memberNamePool.Get().(*memberNames)
|
||||
*ns = (*ns)[:0]
|
||||
return ns
|
||||
}
|
||||
func putMemberNames(ns *memberNames) {
|
||||
if cap(*ns) < 1<<10 {
|
||||
for i := range *ns {
|
||||
(*ns)[i] = memberName{} // avoid pinning name
|
||||
}
|
||||
memberNamePool.Put(ns)
|
||||
}
|
||||
}
|
||||
|
||||
type memberNames []memberName
|
||||
|
||||
func (m *memberNames) Len() int { return len(*m) }
|
||||
func (m *memberNames) Less(i, j int) bool { return lessUTF16((*m)[i].name, (*m)[j].name) }
|
||||
func (m *memberNames) Swap(i, j int) { (*m)[i], (*m)[j] = (*m)[j], (*m)[i] }
|
||||
|
||||
// reorderObjects recursively reorders all object members in place
|
||||
// according to the ordering specified in RFC 8785, section 3.2.3.
|
||||
//
|
||||
// Pre-conditions:
|
||||
// - The value is valid (i.e., no decoder errors should ever occur).
|
||||
// - The value is compact (i.e., no whitespace is present).
|
||||
// - Initial call is provided a Decoder reading from the start of v.
|
||||
//
|
||||
// Post-conditions:
|
||||
// - Exactly one JSON value is read from the Decoder.
|
||||
// - All fully-parsed JSON objects are reordered by directly moving
|
||||
// the members in the value buffer.
|
||||
//
|
||||
// The runtime is approximately O(n·log(n)) + O(m·log(m)),
|
||||
// where n is len(v) and m is the total number of object members.
|
||||
func reorderObjects(d *Decoder, scratch *[]byte) {
|
||||
switch tok, _ := d.ReadToken(); tok.Kind() {
|
||||
case '{':
|
||||
// Iterate and collect the name and offsets for every object member.
|
||||
members := getMemberNames()
|
||||
defer putMemberNames(members)
|
||||
var prevName []byte
|
||||
isSorted := true
|
||||
|
||||
beforeBody := d.InputOffset() // offset after '{'
|
||||
for d.PeekKind() != '}' {
|
||||
beforeName := d.InputOffset()
|
||||
var flags valueFlags
|
||||
name, _ := d.readValue(&flags)
|
||||
name = unescapeStringMayCopy(name, flags.isVerbatim())
|
||||
reorderObjects(d, scratch)
|
||||
afterValue := d.InputOffset()
|
||||
|
||||
if isSorted && len(*members) > 0 {
|
||||
isSorted = lessUTF16(prevName, name)
|
||||
}
|
||||
*members = append(*members, memberName{name, beforeName, afterValue})
|
||||
prevName = name
|
||||
}
|
||||
afterBody := d.InputOffset() // offset before '}'
|
||||
d.ReadToken()
|
||||
|
||||
// Sort the members; return early if it's already sorted.
|
||||
if isSorted {
|
||||
return
|
||||
}
|
||||
// TODO(https://go.dev/issue/47619): Use slices.Sort.
|
||||
sort.Sort(members)
|
||||
|
||||
// Append the reordered members to a new buffer,
|
||||
// then copy the reordered members back over the original members.
|
||||
// Avoid swapping in place since each member may be a different size
|
||||
// where moving a member over a smaller member may corrupt the data
|
||||
// for subsequent members before they have been moved.
|
||||
//
|
||||
// The following invariant must hold:
|
||||
// sum([m.after-m.before for m in members]) == afterBody-beforeBody
|
||||
sorted := (*scratch)[:0]
|
||||
for i, member := range *members {
|
||||
if d.buf[member.before] == ',' {
|
||||
member.before++ // trim leading comma
|
||||
}
|
||||
sorted = append(sorted, d.buf[member.before:member.after]...)
|
||||
if i < len(*members)-1 {
|
||||
sorted = append(sorted, ',') // append trailing comma
|
||||
}
|
||||
}
|
||||
if int(afterBody-beforeBody) != len(sorted) {
|
||||
panic("BUG: length invariant violated")
|
||||
}
|
||||
copy(d.buf[beforeBody:afterBody], sorted)
|
||||
|
||||
// Update scratch buffer to the largest amount ever used.
|
||||
if len(sorted) > len(*scratch) {
|
||||
*scratch = sorted
|
||||
}
|
||||
case '[':
|
||||
for d.PeekKind() != ']' {
|
||||
reorderObjects(d, scratch)
|
||||
}
|
||||
d.ReadToken()
|
||||
}
|
||||
}
|
||||
|
||||
// lessUTF16 reports whether x is lexicographically less than y according
|
||||
// to the UTF-16 codepoints of the UTF-8 encoded input strings.
|
||||
// This implements the ordering specified in RFC 8785, section 3.2.3.
|
||||
// The inputs must be valid UTF-8, otherwise this may panic.
|
||||
func lessUTF16(x, y []byte) bool {
|
||||
// NOTE: This is an optimized, allocation-free implementation
|
||||
// of lessUTF16Simple in fuzz_test.go. FuzzLessUTF16 verifies that the
|
||||
// two implementations agree on the result of comparing any two strings.
|
||||
|
||||
isUTF16Self := func(r rune) bool {
|
||||
return ('\u0000' <= r && r <= '\uD7FF') || ('\uE000' <= r && r <= '\uFFFF')
|
||||
}
|
||||
|
||||
for {
|
||||
if len(x) == 0 || len(y) == 0 {
|
||||
return len(x) < len(y)
|
||||
}
|
||||
|
||||
// ASCII fast-path.
|
||||
if x[0] < utf8.RuneSelf || y[0] < utf8.RuneSelf {
|
||||
if x[0] != y[0] {
|
||||
return x[0] < y[0]
|
||||
}
|
||||
x, y = x[1:], y[1:]
|
||||
continue
|
||||
}
|
||||
|
||||
// Decode next pair of runes as UTF-8.
|
||||
rx, nx := utf8.DecodeRune(x)
|
||||
ry, ny := utf8.DecodeRune(y)
|
||||
switch {
|
||||
|
||||
// Both runes encode as either a single or surrogate pair
|
||||
// of UTF-16 codepoints.
|
||||
case isUTF16Self(rx) == isUTF16Self(ry):
|
||||
if rx != ry {
|
||||
return rx < ry
|
||||
}
|
||||
|
||||
// The x rune is a single UTF-16 codepoint, while
|
||||
// the y rune is a surrogate pair of UTF-16 codepoints.
|
||||
case isUTF16Self(rx):
|
||||
ry, _ := utf16.EncodeRune(ry)
|
||||
if rx != ry {
|
||||
return rx < ry
|
||||
}
|
||||
panic("BUG: invalid UTF-8") // implies rx is an unpaired surrogate half
|
||||
|
||||
// The y rune is a single UTF-16 codepoint, while
|
||||
// the x rune is a surrogate pair of UTF-16 codepoints.
|
||||
case isUTF16Self(ry):
|
||||
rx, _ := utf16.EncodeRune(rx)
|
||||
if rx != ry {
|
||||
return rx < ry
|
||||
}
|
||||
panic("BUG: invalid UTF-8") // implies ry is an unpaired surrogate half
|
||||
}
|
||||
x, y = x[nx:], y[ny:]
|
||||
}
|
||||
}
|
||||
322
client/vendor/k8s.io/kube-openapi/pkg/openapiconv/convert.go
generated
vendored
Normal file
322
client/vendor/k8s.io/kube-openapi/pkg/openapiconv/convert.go
generated
vendored
Normal file
@@ -0,0 +1,322 @@
|
||||
/*
|
||||
Copyright 2022 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package openapiconv
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
klog "k8s.io/klog/v2"
|
||||
builderutil "k8s.io/kube-openapi/pkg/builder3/util"
|
||||
"k8s.io/kube-openapi/pkg/spec3"
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
)
|
||||
|
||||
var OpenAPIV2DefPrefix = "#/definitions/"
|
||||
var OpenAPIV3DefPrefix = "#/components/schemas/"
|
||||
|
||||
// ConvertV2ToV3 converts an OpenAPI V2 object into V3.
|
||||
// Certain references may be shared between the V2 and V3 objects in the conversion.
|
||||
func ConvertV2ToV3(v2Spec *spec.Swagger) *spec3.OpenAPI {
|
||||
v3Spec := &spec3.OpenAPI{
|
||||
Version: "3.0.0",
|
||||
Info: v2Spec.Info,
|
||||
ExternalDocs: ConvertExternalDocumentation(v2Spec.ExternalDocs),
|
||||
Paths: ConvertPaths(v2Spec.Paths),
|
||||
Components: ConvertComponents(v2Spec.SecurityDefinitions, v2Spec.Definitions, v2Spec.Responses, v2Spec.Produces),
|
||||
}
|
||||
|
||||
return v3Spec
|
||||
}
|
||||
|
||||
func ConvertExternalDocumentation(v2ED *spec.ExternalDocumentation) *spec3.ExternalDocumentation {
|
||||
if v2ED == nil {
|
||||
return nil
|
||||
}
|
||||
return &spec3.ExternalDocumentation{
|
||||
ExternalDocumentationProps: spec3.ExternalDocumentationProps{
|
||||
Description: v2ED.Description,
|
||||
URL: v2ED.URL,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func ConvertComponents(v2SecurityDefinitions spec.SecurityDefinitions, v2Definitions spec.Definitions, v2Responses map[string]spec.Response, produces []string) *spec3.Components {
|
||||
components := &spec3.Components{}
|
||||
|
||||
if v2Definitions != nil {
|
||||
components.Schemas = make(map[string]*spec.Schema)
|
||||
}
|
||||
for s, schema := range v2Definitions {
|
||||
components.Schemas[s] = ConvertSchema(&schema)
|
||||
}
|
||||
if v2SecurityDefinitions != nil {
|
||||
components.SecuritySchemes = make(spec3.SecuritySchemes)
|
||||
}
|
||||
for s, securityScheme := range v2SecurityDefinitions {
|
||||
components.SecuritySchemes[s] = ConvertSecurityScheme(securityScheme)
|
||||
}
|
||||
if v2Responses != nil {
|
||||
components.Responses = make(map[string]*spec3.Response)
|
||||
}
|
||||
for r, response := range v2Responses {
|
||||
components.Responses[r] = ConvertResponse(&response, produces)
|
||||
}
|
||||
|
||||
return components
|
||||
}
|
||||
|
||||
func ConvertSchema(v2Schema *spec.Schema) *spec.Schema {
|
||||
if v2Schema == nil {
|
||||
return nil
|
||||
}
|
||||
v3Schema := spec.Schema{
|
||||
VendorExtensible: v2Schema.VendorExtensible,
|
||||
SchemaProps: v2Schema.SchemaProps,
|
||||
SwaggerSchemaProps: v2Schema.SwaggerSchemaProps,
|
||||
ExtraProps: v2Schema.ExtraProps,
|
||||
}
|
||||
|
||||
if refString := v2Schema.Ref.String(); refString != "" {
|
||||
if idx := strings.Index(refString, OpenAPIV2DefPrefix); idx != -1 {
|
||||
v3Schema.Ref = spec.MustCreateRef(OpenAPIV3DefPrefix + refString[idx+len(OpenAPIV2DefPrefix):])
|
||||
} else {
|
||||
klog.Errorf("Error: Swagger V2 Ref %s does not contain #/definitions\n", refString)
|
||||
}
|
||||
}
|
||||
|
||||
if v2Schema.Properties != nil {
|
||||
v3Schema.Properties = make(map[string]spec.Schema)
|
||||
for key, property := range v2Schema.Properties {
|
||||
v3Schema.Properties[key] = *ConvertSchema(&property)
|
||||
}
|
||||
}
|
||||
if v2Schema.Items != nil {
|
||||
v3Schema.Items = &spec.SchemaOrArray{
|
||||
Schema: ConvertSchema(v2Schema.Items.Schema),
|
||||
Schemas: ConvertSchemaList(v2Schema.Items.Schemas),
|
||||
}
|
||||
}
|
||||
|
||||
if v2Schema.AdditionalProperties != nil {
|
||||
v3Schema.AdditionalProperties = &spec.SchemaOrBool{
|
||||
Schema: ConvertSchema(v2Schema.AdditionalProperties.Schema),
|
||||
Allows: v2Schema.AdditionalProperties.Allows,
|
||||
}
|
||||
}
|
||||
if v2Schema.AdditionalItems != nil {
|
||||
v3Schema.AdditionalItems = &spec.SchemaOrBool{
|
||||
Schema: ConvertSchema(v2Schema.AdditionalItems.Schema),
|
||||
Allows: v2Schema.AdditionalItems.Allows,
|
||||
}
|
||||
}
|
||||
|
||||
return builderutil.WrapRefs(&v3Schema)
|
||||
}
|
||||
|
||||
func ConvertSchemaList(v2SchemaList []spec.Schema) []spec.Schema {
|
||||
if v2SchemaList == nil {
|
||||
return nil
|
||||
}
|
||||
v3SchemaList := []spec.Schema{}
|
||||
for _, s := range v2SchemaList {
|
||||
v3SchemaList = append(v3SchemaList, *ConvertSchema(&s))
|
||||
}
|
||||
return v3SchemaList
|
||||
}
|
||||
|
||||
func ConvertSecurityScheme(v2securityScheme *spec.SecurityScheme) *spec3.SecurityScheme {
|
||||
if v2securityScheme == nil {
|
||||
return nil
|
||||
}
|
||||
securityScheme := &spec3.SecurityScheme{
|
||||
VendorExtensible: v2securityScheme.VendorExtensible,
|
||||
SecuritySchemeProps: spec3.SecuritySchemeProps{
|
||||
Description: v2securityScheme.Description,
|
||||
Type: v2securityScheme.Type,
|
||||
Name: v2securityScheme.Name,
|
||||
In: v2securityScheme.In,
|
||||
},
|
||||
}
|
||||
|
||||
if v2securityScheme.Flow != "" {
|
||||
securityScheme.Flows = make(map[string]*spec3.OAuthFlow)
|
||||
securityScheme.Flows[v2securityScheme.Flow] = &spec3.OAuthFlow{
|
||||
OAuthFlowProps: spec3.OAuthFlowProps{
|
||||
AuthorizationUrl: v2securityScheme.AuthorizationURL,
|
||||
TokenUrl: v2securityScheme.TokenURL,
|
||||
Scopes: v2securityScheme.Scopes,
|
||||
},
|
||||
}
|
||||
}
|
||||
return securityScheme
|
||||
}
|
||||
|
||||
func ConvertPaths(v2Paths *spec.Paths) *spec3.Paths {
|
||||
if v2Paths == nil {
|
||||
return nil
|
||||
}
|
||||
paths := &spec3.Paths{
|
||||
VendorExtensible: v2Paths.VendorExtensible,
|
||||
}
|
||||
|
||||
if v2Paths.Paths != nil {
|
||||
paths.Paths = make(map[string]*spec3.Path)
|
||||
}
|
||||
for k, v := range v2Paths.Paths {
|
||||
paths.Paths[k] = ConvertPathItem(v)
|
||||
}
|
||||
return paths
|
||||
}
|
||||
|
||||
func ConvertPathItem(v2pathItem spec.PathItem) *spec3.Path {
|
||||
path := &spec3.Path{
|
||||
Refable: v2pathItem.Refable,
|
||||
PathProps: spec3.PathProps{
|
||||
Get: ConvertOperation(v2pathItem.Get),
|
||||
Put: ConvertOperation(v2pathItem.Put),
|
||||
Post: ConvertOperation(v2pathItem.Post),
|
||||
Delete: ConvertOperation(v2pathItem.Delete),
|
||||
Options: ConvertOperation(v2pathItem.Options),
|
||||
Head: ConvertOperation(v2pathItem.Head),
|
||||
Patch: ConvertOperation(v2pathItem.Patch),
|
||||
},
|
||||
VendorExtensible: v2pathItem.VendorExtensible,
|
||||
}
|
||||
for _, param := range v2pathItem.Parameters {
|
||||
path.Parameters = append(path.Parameters, ConvertParameter(param))
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
func ConvertOperation(v2Operation *spec.Operation) *spec3.Operation {
|
||||
if v2Operation == nil {
|
||||
return nil
|
||||
}
|
||||
operation := &spec3.Operation{
|
||||
VendorExtensible: v2Operation.VendorExtensible,
|
||||
OperationProps: spec3.OperationProps{
|
||||
Description: v2Operation.Description,
|
||||
ExternalDocs: ConvertExternalDocumentation(v2Operation.OperationProps.ExternalDocs),
|
||||
Tags: v2Operation.Tags,
|
||||
Summary: v2Operation.Summary,
|
||||
Deprecated: v2Operation.Deprecated,
|
||||
OperationId: v2Operation.ID,
|
||||
},
|
||||
}
|
||||
|
||||
for _, param := range v2Operation.Parameters {
|
||||
if param.ParamProps.Name == "body" && param.ParamProps.Schema != nil {
|
||||
operation.OperationProps.RequestBody = &spec3.RequestBody{
|
||||
RequestBodyProps: spec3.RequestBodyProps{},
|
||||
}
|
||||
if v2Operation.Consumes != nil {
|
||||
operation.RequestBody.Content = make(map[string]*spec3.MediaType)
|
||||
}
|
||||
for _, consumer := range v2Operation.Consumes {
|
||||
operation.RequestBody.Content[consumer] = &spec3.MediaType{
|
||||
MediaTypeProps: spec3.MediaTypeProps{
|
||||
Schema: ConvertSchema(param.ParamProps.Schema),
|
||||
},
|
||||
}
|
||||
}
|
||||
} else {
|
||||
operation.Parameters = append(operation.Parameters, ConvertParameter(param))
|
||||
}
|
||||
}
|
||||
|
||||
operation.Responses = &spec3.Responses{ResponsesProps: spec3.ResponsesProps{
|
||||
Default: ConvertResponse(v2Operation.Responses.Default, v2Operation.Produces),
|
||||
},
|
||||
VendorExtensible: v2Operation.Responses.VendorExtensible,
|
||||
}
|
||||
|
||||
if v2Operation.Responses.StatusCodeResponses != nil {
|
||||
operation.Responses.StatusCodeResponses = make(map[int]*spec3.Response)
|
||||
}
|
||||
for k, v := range v2Operation.Responses.StatusCodeResponses {
|
||||
operation.Responses.StatusCodeResponses[k] = ConvertResponse(&v, v2Operation.Produces)
|
||||
}
|
||||
return operation
|
||||
}
|
||||
|
||||
func ConvertResponse(v2Response *spec.Response, produces []string) *spec3.Response {
|
||||
if v2Response == nil {
|
||||
return nil
|
||||
}
|
||||
response := &spec3.Response{
|
||||
Refable: ConvertRefableResponse(v2Response.Refable),
|
||||
VendorExtensible: v2Response.VendorExtensible,
|
||||
ResponseProps: spec3.ResponseProps{
|
||||
Description: v2Response.Description,
|
||||
},
|
||||
}
|
||||
|
||||
if v2Response.Schema != nil {
|
||||
if produces != nil {
|
||||
response.Content = make(map[string]*spec3.MediaType)
|
||||
}
|
||||
for _, producer := range produces {
|
||||
response.ResponseProps.Content[producer] = &spec3.MediaType{
|
||||
MediaTypeProps: spec3.MediaTypeProps{
|
||||
Schema: ConvertSchema(v2Response.Schema),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
return response
|
||||
}
|
||||
|
||||
func ConvertParameter(v2Param spec.Parameter) *spec3.Parameter {
|
||||
param := &spec3.Parameter{
|
||||
Refable: ConvertRefableParameter(v2Param.Refable),
|
||||
VendorExtensible: v2Param.VendorExtensible,
|
||||
ParameterProps: spec3.ParameterProps{
|
||||
Name: v2Param.Name,
|
||||
Description: v2Param.Description,
|
||||
In: v2Param.In,
|
||||
Required: v2Param.Required,
|
||||
Schema: ConvertSchema(v2Param.Schema),
|
||||
AllowEmptyValue: v2Param.AllowEmptyValue,
|
||||
},
|
||||
}
|
||||
// Convert SimpleSchema into Schema
|
||||
if param.Schema == nil {
|
||||
param.Schema = &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{v2Param.Type},
|
||||
Format: v2Param.Format,
|
||||
UniqueItems: v2Param.UniqueItems,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return param
|
||||
}
|
||||
|
||||
func ConvertRefableParameter(refable spec.Refable) spec.Refable {
|
||||
if refable.Ref.String() != "" {
|
||||
return spec.Refable{Ref: spec.MustCreateRef(strings.Replace(refable.Ref.String(), "#/parameters/", "#/components/parameters/", 1))}
|
||||
}
|
||||
return refable
|
||||
}
|
||||
|
||||
func ConvertRefableResponse(refable spec.Refable) spec.Refable {
|
||||
if refable.Ref.String() != "" {
|
||||
return spec.Refable{Ref: spec.MustCreateRef(strings.Replace(refable.Ref.String(), "#/responses/", "#/components/responses/", 1))}
|
||||
}
|
||||
return refable
|
||||
}
|
||||
519
client/vendor/k8s.io/kube-openapi/pkg/schemamutation/walker.go
generated
vendored
Normal file
519
client/vendor/k8s.io/kube-openapi/pkg/schemamutation/walker.go
generated
vendored
Normal file
@@ -0,0 +1,519 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package schemamutation
|
||||
|
||||
import (
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
)
|
||||
|
||||
// Walker runs callback functions on all references of an OpenAPI spec,
|
||||
// replacing the values when visiting corresponding types.
|
||||
type Walker struct {
|
||||
// SchemaCallback will be called on each schema, taking the original schema,
|
||||
// and before any other callbacks of the Walker.
|
||||
// If the schema needs to be mutated, DO NOT mutate it in-place,
|
||||
// always create a copy, mutate, and return it.
|
||||
SchemaCallback func(schema *spec.Schema) *spec.Schema
|
||||
|
||||
// RefCallback will be called on each ref.
|
||||
// If the ref needs to be mutated, DO NOT mutate it in-place,
|
||||
// always create a copy, mutate, and return it.
|
||||
RefCallback func(ref *spec.Ref) *spec.Ref
|
||||
}
|
||||
|
||||
type SchemaCallbackFunc func(schema *spec.Schema) *spec.Schema
|
||||
type RefCallbackFunc func(ref *spec.Ref) *spec.Ref
|
||||
|
||||
var SchemaCallBackNoop SchemaCallbackFunc = func(schema *spec.Schema) *spec.Schema {
|
||||
return schema
|
||||
}
|
||||
var RefCallbackNoop RefCallbackFunc = func(ref *spec.Ref) *spec.Ref {
|
||||
return ref
|
||||
}
|
||||
|
||||
// ReplaceReferences rewrites the references without mutating the input.
|
||||
// The output might share data with the input.
|
||||
func ReplaceReferences(walkRef func(ref *spec.Ref) *spec.Ref, sp *spec.Swagger) *spec.Swagger {
|
||||
walker := &Walker{RefCallback: walkRef, SchemaCallback: SchemaCallBackNoop}
|
||||
return walker.WalkRoot(sp)
|
||||
}
|
||||
|
||||
func (w *Walker) WalkSchema(schema *spec.Schema) *spec.Schema {
|
||||
if schema == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
orig := schema
|
||||
clone := func() {
|
||||
if orig == schema {
|
||||
schema = &spec.Schema{}
|
||||
*schema = *orig
|
||||
}
|
||||
}
|
||||
|
||||
// Always run callback on the whole schema first
|
||||
// so that SchemaCallback can take the original schema as input.
|
||||
schema = w.SchemaCallback(schema)
|
||||
|
||||
if r := w.RefCallback(&schema.Ref); r != &schema.Ref {
|
||||
clone()
|
||||
schema.Ref = *r
|
||||
}
|
||||
|
||||
definitionsCloned := false
|
||||
for k, v := range schema.Definitions {
|
||||
if s := w.WalkSchema(&v); s != &v {
|
||||
if !definitionsCloned {
|
||||
definitionsCloned = true
|
||||
clone()
|
||||
schema.Definitions = make(spec.Definitions, len(orig.Definitions))
|
||||
for k2, v2 := range orig.Definitions {
|
||||
schema.Definitions[k2] = v2
|
||||
}
|
||||
}
|
||||
schema.Definitions[k] = *s
|
||||
}
|
||||
}
|
||||
|
||||
propertiesCloned := false
|
||||
for k, v := range schema.Properties {
|
||||
if s := w.WalkSchema(&v); s != &v {
|
||||
if !propertiesCloned {
|
||||
propertiesCloned = true
|
||||
clone()
|
||||
schema.Properties = make(map[string]spec.Schema, len(orig.Properties))
|
||||
for k2, v2 := range orig.Properties {
|
||||
schema.Properties[k2] = v2
|
||||
}
|
||||
}
|
||||
schema.Properties[k] = *s
|
||||
}
|
||||
}
|
||||
|
||||
patternPropertiesCloned := false
|
||||
for k, v := range schema.PatternProperties {
|
||||
if s := w.WalkSchema(&v); s != &v {
|
||||
if !patternPropertiesCloned {
|
||||
patternPropertiesCloned = true
|
||||
clone()
|
||||
schema.PatternProperties = make(map[string]spec.Schema, len(orig.PatternProperties))
|
||||
for k2, v2 := range orig.PatternProperties {
|
||||
schema.PatternProperties[k2] = v2
|
||||
}
|
||||
}
|
||||
schema.PatternProperties[k] = *s
|
||||
}
|
||||
}
|
||||
|
||||
allOfCloned := false
|
||||
for i := range schema.AllOf {
|
||||
if s := w.WalkSchema(&schema.AllOf[i]); s != &schema.AllOf[i] {
|
||||
if !allOfCloned {
|
||||
allOfCloned = true
|
||||
clone()
|
||||
schema.AllOf = make([]spec.Schema, len(orig.AllOf))
|
||||
copy(schema.AllOf, orig.AllOf)
|
||||
}
|
||||
schema.AllOf[i] = *s
|
||||
}
|
||||
}
|
||||
|
||||
anyOfCloned := false
|
||||
for i := range schema.AnyOf {
|
||||
if s := w.WalkSchema(&schema.AnyOf[i]); s != &schema.AnyOf[i] {
|
||||
if !anyOfCloned {
|
||||
anyOfCloned = true
|
||||
clone()
|
||||
schema.AnyOf = make([]spec.Schema, len(orig.AnyOf))
|
||||
copy(schema.AnyOf, orig.AnyOf)
|
||||
}
|
||||
schema.AnyOf[i] = *s
|
||||
}
|
||||
}
|
||||
|
||||
oneOfCloned := false
|
||||
for i := range schema.OneOf {
|
||||
if s := w.WalkSchema(&schema.OneOf[i]); s != &schema.OneOf[i] {
|
||||
if !oneOfCloned {
|
||||
oneOfCloned = true
|
||||
clone()
|
||||
schema.OneOf = make([]spec.Schema, len(orig.OneOf))
|
||||
copy(schema.OneOf, orig.OneOf)
|
||||
}
|
||||
schema.OneOf[i] = *s
|
||||
}
|
||||
}
|
||||
|
||||
if schema.Not != nil {
|
||||
if s := w.WalkSchema(schema.Not); s != schema.Not {
|
||||
clone()
|
||||
schema.Not = s
|
||||
}
|
||||
}
|
||||
|
||||
if schema.AdditionalProperties != nil && schema.AdditionalProperties.Schema != nil {
|
||||
if s := w.WalkSchema(schema.AdditionalProperties.Schema); s != schema.AdditionalProperties.Schema {
|
||||
clone()
|
||||
schema.AdditionalProperties = &spec.SchemaOrBool{Schema: s, Allows: schema.AdditionalProperties.Allows}
|
||||
}
|
||||
}
|
||||
|
||||
if schema.AdditionalItems != nil && schema.AdditionalItems.Schema != nil {
|
||||
if s := w.WalkSchema(schema.AdditionalItems.Schema); s != schema.AdditionalItems.Schema {
|
||||
clone()
|
||||
schema.AdditionalItems = &spec.SchemaOrBool{Schema: s, Allows: schema.AdditionalItems.Allows}
|
||||
}
|
||||
}
|
||||
|
||||
if schema.Items != nil {
|
||||
if schema.Items.Schema != nil {
|
||||
if s := w.WalkSchema(schema.Items.Schema); s != schema.Items.Schema {
|
||||
clone()
|
||||
schema.Items = &spec.SchemaOrArray{Schema: s}
|
||||
}
|
||||
} else {
|
||||
itemsCloned := false
|
||||
for i := range schema.Items.Schemas {
|
||||
if s := w.WalkSchema(&schema.Items.Schemas[i]); s != &schema.Items.Schemas[i] {
|
||||
if !itemsCloned {
|
||||
clone()
|
||||
schema.Items = &spec.SchemaOrArray{
|
||||
Schemas: make([]spec.Schema, len(orig.Items.Schemas)),
|
||||
}
|
||||
itemsCloned = true
|
||||
copy(schema.Items.Schemas, orig.Items.Schemas)
|
||||
}
|
||||
schema.Items.Schemas[i] = *s
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return schema
|
||||
}
|
||||
|
||||
func (w *Walker) walkParameter(param *spec.Parameter) *spec.Parameter {
|
||||
if param == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
orig := param
|
||||
cloned := false
|
||||
clone := func() {
|
||||
if !cloned {
|
||||
cloned = true
|
||||
param = &spec.Parameter{}
|
||||
*param = *orig
|
||||
}
|
||||
}
|
||||
|
||||
if r := w.RefCallback(¶m.Ref); r != ¶m.Ref {
|
||||
clone()
|
||||
param.Ref = *r
|
||||
}
|
||||
if s := w.WalkSchema(param.Schema); s != param.Schema {
|
||||
clone()
|
||||
param.Schema = s
|
||||
}
|
||||
if param.Items != nil {
|
||||
if r := w.RefCallback(¶m.Items.Ref); r != ¶m.Items.Ref {
|
||||
param.Items.Ref = *r
|
||||
}
|
||||
}
|
||||
|
||||
return param
|
||||
}
|
||||
|
||||
func (w *Walker) walkParameters(params []spec.Parameter) ([]spec.Parameter, bool) {
|
||||
if params == nil {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
orig := params
|
||||
cloned := false
|
||||
clone := func() {
|
||||
if !cloned {
|
||||
cloned = true
|
||||
params = make([]spec.Parameter, len(params))
|
||||
copy(params, orig)
|
||||
}
|
||||
}
|
||||
|
||||
for i := range params {
|
||||
if s := w.walkParameter(¶ms[i]); s != ¶ms[i] {
|
||||
clone()
|
||||
params[i] = *s
|
||||
}
|
||||
}
|
||||
|
||||
return params, cloned
|
||||
}
|
||||
|
||||
func (w *Walker) walkResponse(resp *spec.Response) *spec.Response {
|
||||
if resp == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
orig := resp
|
||||
cloned := false
|
||||
clone := func() {
|
||||
if !cloned {
|
||||
cloned = true
|
||||
resp = &spec.Response{}
|
||||
*resp = *orig
|
||||
}
|
||||
}
|
||||
|
||||
if r := w.RefCallback(&resp.Ref); r != &resp.Ref {
|
||||
clone()
|
||||
resp.Ref = *r
|
||||
}
|
||||
if s := w.WalkSchema(resp.Schema); s != resp.Schema {
|
||||
clone()
|
||||
resp.Schema = s
|
||||
}
|
||||
|
||||
return resp
|
||||
}
|
||||
|
||||
func (w *Walker) walkResponses(resps *spec.Responses) *spec.Responses {
|
||||
if resps == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
orig := resps
|
||||
cloned := false
|
||||
clone := func() {
|
||||
if !cloned {
|
||||
cloned = true
|
||||
resps = &spec.Responses{}
|
||||
*resps = *orig
|
||||
}
|
||||
}
|
||||
|
||||
if r := w.walkResponse(resps.ResponsesProps.Default); r != resps.ResponsesProps.Default {
|
||||
clone()
|
||||
resps.Default = r
|
||||
}
|
||||
|
||||
responsesCloned := false
|
||||
for k, v := range resps.ResponsesProps.StatusCodeResponses {
|
||||
if r := w.walkResponse(&v); r != &v {
|
||||
if !responsesCloned {
|
||||
responsesCloned = true
|
||||
clone()
|
||||
resps.ResponsesProps.StatusCodeResponses = make(map[int]spec.Response, len(orig.StatusCodeResponses))
|
||||
for k2, v2 := range orig.StatusCodeResponses {
|
||||
resps.ResponsesProps.StatusCodeResponses[k2] = v2
|
||||
}
|
||||
}
|
||||
resps.ResponsesProps.StatusCodeResponses[k] = *r
|
||||
}
|
||||
}
|
||||
|
||||
return resps
|
||||
}
|
||||
|
||||
func (w *Walker) walkOperation(op *spec.Operation) *spec.Operation {
|
||||
if op == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
orig := op
|
||||
cloned := false
|
||||
clone := func() {
|
||||
if !cloned {
|
||||
cloned = true
|
||||
op = &spec.Operation{}
|
||||
*op = *orig
|
||||
}
|
||||
}
|
||||
|
||||
parametersCloned := false
|
||||
for i := range op.Parameters {
|
||||
if s := w.walkParameter(&op.Parameters[i]); s != &op.Parameters[i] {
|
||||
if !parametersCloned {
|
||||
parametersCloned = true
|
||||
clone()
|
||||
op.Parameters = make([]spec.Parameter, len(orig.Parameters))
|
||||
copy(op.Parameters, orig.Parameters)
|
||||
}
|
||||
op.Parameters[i] = *s
|
||||
}
|
||||
}
|
||||
|
||||
if r := w.walkResponses(op.Responses); r != op.Responses {
|
||||
clone()
|
||||
op.Responses = r
|
||||
}
|
||||
|
||||
return op
|
||||
}
|
||||
|
||||
func (w *Walker) walkPathItem(pathItem *spec.PathItem) *spec.PathItem {
|
||||
if pathItem == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
orig := pathItem
|
||||
cloned := false
|
||||
clone := func() {
|
||||
if !cloned {
|
||||
cloned = true
|
||||
pathItem = &spec.PathItem{}
|
||||
*pathItem = *orig
|
||||
}
|
||||
}
|
||||
|
||||
if p, changed := w.walkParameters(pathItem.Parameters); changed {
|
||||
clone()
|
||||
pathItem.Parameters = p
|
||||
}
|
||||
if op := w.walkOperation(pathItem.Get); op != pathItem.Get {
|
||||
clone()
|
||||
pathItem.Get = op
|
||||
}
|
||||
if op := w.walkOperation(pathItem.Head); op != pathItem.Head {
|
||||
clone()
|
||||
pathItem.Head = op
|
||||
}
|
||||
if op := w.walkOperation(pathItem.Delete); op != pathItem.Delete {
|
||||
clone()
|
||||
pathItem.Delete = op
|
||||
}
|
||||
if op := w.walkOperation(pathItem.Options); op != pathItem.Options {
|
||||
clone()
|
||||
pathItem.Options = op
|
||||
}
|
||||
if op := w.walkOperation(pathItem.Patch); op != pathItem.Patch {
|
||||
clone()
|
||||
pathItem.Patch = op
|
||||
}
|
||||
if op := w.walkOperation(pathItem.Post); op != pathItem.Post {
|
||||
clone()
|
||||
pathItem.Post = op
|
||||
}
|
||||
if op := w.walkOperation(pathItem.Put); op != pathItem.Put {
|
||||
clone()
|
||||
pathItem.Put = op
|
||||
}
|
||||
|
||||
return pathItem
|
||||
}
|
||||
|
||||
func (w *Walker) walkPaths(paths *spec.Paths) *spec.Paths {
|
||||
if paths == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
orig := paths
|
||||
cloned := false
|
||||
clone := func() {
|
||||
if !cloned {
|
||||
cloned = true
|
||||
paths = &spec.Paths{}
|
||||
*paths = *orig
|
||||
}
|
||||
}
|
||||
|
||||
pathsCloned := false
|
||||
for k, v := range paths.Paths {
|
||||
if p := w.walkPathItem(&v); p != &v {
|
||||
if !pathsCloned {
|
||||
pathsCloned = true
|
||||
clone()
|
||||
paths.Paths = make(map[string]spec.PathItem, len(orig.Paths))
|
||||
for k2, v2 := range orig.Paths {
|
||||
paths.Paths[k2] = v2
|
||||
}
|
||||
}
|
||||
paths.Paths[k] = *p
|
||||
}
|
||||
}
|
||||
|
||||
return paths
|
||||
}
|
||||
|
||||
func (w *Walker) WalkRoot(swagger *spec.Swagger) *spec.Swagger {
|
||||
if swagger == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
orig := swagger
|
||||
cloned := false
|
||||
clone := func() {
|
||||
if !cloned {
|
||||
cloned = true
|
||||
swagger = &spec.Swagger{}
|
||||
*swagger = *orig
|
||||
}
|
||||
}
|
||||
|
||||
parametersCloned := false
|
||||
for k, v := range swagger.Parameters {
|
||||
if p := w.walkParameter(&v); p != &v {
|
||||
if !parametersCloned {
|
||||
parametersCloned = true
|
||||
clone()
|
||||
swagger.Parameters = make(map[string]spec.Parameter, len(orig.Parameters))
|
||||
for k2, v2 := range orig.Parameters {
|
||||
swagger.Parameters[k2] = v2
|
||||
}
|
||||
}
|
||||
swagger.Parameters[k] = *p
|
||||
}
|
||||
}
|
||||
|
||||
responsesCloned := false
|
||||
for k, v := range swagger.Responses {
|
||||
if r := w.walkResponse(&v); r != &v {
|
||||
if !responsesCloned {
|
||||
responsesCloned = true
|
||||
clone()
|
||||
swagger.Responses = make(map[string]spec.Response, len(orig.Responses))
|
||||
for k2, v2 := range orig.Responses {
|
||||
swagger.Responses[k2] = v2
|
||||
}
|
||||
}
|
||||
swagger.Responses[k] = *r
|
||||
}
|
||||
}
|
||||
|
||||
definitionsCloned := false
|
||||
for k, v := range swagger.Definitions {
|
||||
if s := w.WalkSchema(&v); s != &v {
|
||||
if !definitionsCloned {
|
||||
definitionsCloned = true
|
||||
clone()
|
||||
swagger.Definitions = make(spec.Definitions, len(orig.Definitions))
|
||||
for k2, v2 := range orig.Definitions {
|
||||
swagger.Definitions[k2] = v2
|
||||
}
|
||||
}
|
||||
swagger.Definitions[k] = *s
|
||||
}
|
||||
}
|
||||
|
||||
if swagger.Paths != nil {
|
||||
if p := w.walkPaths(swagger.Paths); p != swagger.Paths {
|
||||
clone()
|
||||
swagger.Paths = p
|
||||
}
|
||||
}
|
||||
|
||||
return swagger
|
||||
}
|
||||
47
client/vendor/k8s.io/kube-openapi/pkg/spec3/component.go
generated
vendored
Normal file
47
client/vendor/k8s.io/kube-openapi/pkg/spec3/component.go
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
Copyright 2021 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package spec3
|
||||
|
||||
import "k8s.io/kube-openapi/pkg/validation/spec"
|
||||
|
||||
// Components holds 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.
|
||||
//
|
||||
// more at https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#componentsObject
|
||||
type Components struct {
|
||||
// Schemas holds reusable Schema Objects
|
||||
Schemas map[string]*spec.Schema `json:"schemas,omitempty"`
|
||||
// SecuritySchemes holds reusable Security Scheme Objects, more at https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#securitySchemeObject
|
||||
SecuritySchemes SecuritySchemes `json:"securitySchemes,omitempty"`
|
||||
// Responses holds reusable Responses Objects
|
||||
Responses map[string]*Response `json:"responses,omitempty"`
|
||||
// Parameters holds reusable Parameters Objects
|
||||
Parameters map[string]*Parameter `json:"parameters,omitempty"`
|
||||
// Example holds reusable Example objects
|
||||
Examples map[string]*Example `json:"examples,omitempty"`
|
||||
// RequestBodies holds reusable Request Body objects
|
||||
RequestBodies map[string]*RequestBody `json:"requestBodies,omitempty"`
|
||||
// Links is a map of operations links that can be followed from the response
|
||||
Links map[string]*Link `json:"links,omitempty"`
|
||||
// Headers holds a maps of a headers name to its definition
|
||||
Headers map[string]*Header `json:"headers,omitempty"`
|
||||
// all fields are defined at https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#componentsObject
|
||||
}
|
||||
|
||||
// SecuritySchemes holds reusable Security Scheme Objects, more at https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#securitySchemeObject
|
||||
type SecuritySchemes map[string]*SecurityScheme
|
||||
64
client/vendor/k8s.io/kube-openapi/pkg/spec3/encoding.go
generated
vendored
Normal file
64
client/vendor/k8s.io/kube-openapi/pkg/spec3/encoding.go
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
Copyright 2021 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package spec3
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/go-openapi/swag"
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
)
|
||||
|
||||
type Encoding struct {
|
||||
EncodingProps
|
||||
spec.VendorExtensible
|
||||
}
|
||||
|
||||
// MarshalJSON is a custom marshal function that knows how to encode Encoding as JSON
|
||||
func (e *Encoding) MarshalJSON() ([]byte, error) {
|
||||
b1, err := json.Marshal(e.EncodingProps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(e.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return swag.ConcatJSON(b1, b2), nil
|
||||
}
|
||||
|
||||
func (e *Encoding) UnmarshalJSON(data []byte) error {
|
||||
if err := json.Unmarshal(data, &e.EncodingProps); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &e.VendorExtensible); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type EncodingProps struct {
|
||||
// Content Type for encoding a specific property
|
||||
ContentType string `json:"contentType,omitempty"`
|
||||
// A map allowing additional information to be provided as headers
|
||||
Headers map[string]*Header `json:"headers,omitempty"`
|
||||
// Describes how a specific property value will be serialized depending on its type
|
||||
Style string `json:"style,omitempty"`
|
||||
// When this is true, property 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 properties this property has no effect
|
||||
Explode string `json:"explode,omitempty"`
|
||||
// AllowReserved determines whether the parameter value SHOULD allow reserved characters, as defined by RFC3986
|
||||
AllowReserved bool `json:"allowReserved,omitempty"`
|
||||
}
|
||||
73
client/vendor/k8s.io/kube-openapi/pkg/spec3/example.go
generated
vendored
Normal file
73
client/vendor/k8s.io/kube-openapi/pkg/spec3/example.go
generated
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
Copyright 2021 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package spec3
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
"github.com/go-openapi/swag"
|
||||
)
|
||||
|
||||
// Example https://swagger.io/specification/#example-object
|
||||
|
||||
type Example struct {
|
||||
spec.Refable
|
||||
ExampleProps
|
||||
spec.VendorExtensible
|
||||
}
|
||||
|
||||
// MarshalJSON is a custom marshal function that knows how to encode RequestBody as JSON
|
||||
func (e *Example) MarshalJSON() ([]byte, error) {
|
||||
b1, err := json.Marshal(e.Refable)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(e.ExampleProps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b3, err := json.Marshal(e.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return swag.ConcatJSON(b1, b2, b3), nil
|
||||
}
|
||||
|
||||
func (e *Example) UnmarshalJSON(data []byte) error {
|
||||
if err := json.Unmarshal(data, &e.Refable); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &e.ExampleProps); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &e.VendorExtensible); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ExampleProps struct {
|
||||
// Summary holds a short description of the example
|
||||
Summary string `json:"summary,omitempty"`
|
||||
// Description holds a long description of the example
|
||||
Description string `json:"description,omitempty"`
|
||||
// Embedded literal example.
|
||||
Value interface{} `json:"value,omitempty"`
|
||||
// A URL that points to the literal example. This provides the capability to reference examples that cannot easily be included in JSON or YAML documents.
|
||||
ExternalValue string `json:"externalValue,omitempty"`
|
||||
}
|
||||
58
client/vendor/k8s.io/kube-openapi/pkg/spec3/external_documentation.go
generated
vendored
Normal file
58
client/vendor/k8s.io/kube-openapi/pkg/spec3/external_documentation.go
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
Copyright 2021 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package spec3
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
"github.com/go-openapi/swag"
|
||||
)
|
||||
|
||||
type ExternalDocumentation struct {
|
||||
ExternalDocumentationProps
|
||||
spec.VendorExtensible
|
||||
}
|
||||
|
||||
type ExternalDocumentationProps struct {
|
||||
// Description is a short description of the target documentation. CommonMark syntax MAY be used for rich text representation.
|
||||
Description string `json:"description,omitempty"`
|
||||
// URL is the URL for the target documentation.
|
||||
URL string `json:"url"`
|
||||
}
|
||||
|
||||
// MarshalJSON is a custom marshal function that knows how to encode Responses as JSON
|
||||
func (e *ExternalDocumentation) MarshalJSON() ([]byte, error) {
|
||||
b1, err := json.Marshal(e.ExternalDocumentationProps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(e.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return swag.ConcatJSON(b1, b2), nil
|
||||
}
|
||||
|
||||
func (e *ExternalDocumentation) UnmarshalJSON(data []byte) error {
|
||||
if err := json.Unmarshal(data, &e.ExternalDocumentationProps); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &e.VendorExtensible); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
90
client/vendor/k8s.io/kube-openapi/pkg/spec3/header.go
generated
vendored
Normal file
90
client/vendor/k8s.io/kube-openapi/pkg/spec3/header.go
generated
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
Copyright 2021 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package spec3
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/go-openapi/swag"
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
)
|
||||
|
||||
// Header a struct that describes a single operation parameter, more at https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#parameterObject
|
||||
//
|
||||
// Note that this struct is actually a thin wrapper around HeaderProps to make it referable and extensible
|
||||
type Header struct {
|
||||
spec.Refable
|
||||
HeaderProps
|
||||
spec.VendorExtensible
|
||||
}
|
||||
|
||||
// MarshalJSON is a custom marshal function that knows how to encode Header as JSON
|
||||
func (h *Header) MarshalJSON() ([]byte, error) {
|
||||
b1, err := json.Marshal(h.Refable)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(h.HeaderProps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b3, err := json.Marshal(h.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return swag.ConcatJSON(b1, b2, b3), nil
|
||||
}
|
||||
|
||||
func (h *Header) UnmarshalJSON(data []byte) error {
|
||||
if err := json.Unmarshal(data, &h.Refable); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &h.HeaderProps); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &h.VendorExtensible); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// HeaderProps a struct that describes a header object
|
||||
type HeaderProps struct {
|
||||
// Description holds a brief description of the parameter
|
||||
Description string `json:"description,omitempty"`
|
||||
// Required determines whether this parameter is mandatory
|
||||
Required bool `json:"required,omitempty"`
|
||||
// Deprecated declares this operation to be deprecated
|
||||
Deprecated bool `json:"deprecated,omitempty"`
|
||||
// AllowEmptyValue sets the ability to pass empty-valued parameters
|
||||
AllowEmptyValue bool `json:"allowEmptyValue,omitempty"`
|
||||
// Style describes how the parameter value will be serialized depending on the type of the parameter value
|
||||
Style string `json:"style,omitempty"`
|
||||
// Explode when true, parameter values of type array or object generate separate parameters for each value of the array or key-value pair of the map
|
||||
Explode bool `json:"explode,omitempty"`
|
||||
// AllowReserved determines whether the parameter value SHOULD allow reserved characters, as defined by RFC3986
|
||||
AllowReserved bool `json:"allowReserved,omitempty"`
|
||||
// Schema holds the schema defining the type used for the parameter
|
||||
Schema *spec.Schema `json:"schema,omitempty"`
|
||||
// Content holds a map containing the representations for the parameter
|
||||
Content map[string]*MediaType `json:"content,omitempty"`
|
||||
// Example of the header
|
||||
Example interface{} `json:"example,omitempty"`
|
||||
// Examples of the header
|
||||
Examples map[string]*Example `json:"examples,omitempty"`
|
||||
}
|
||||
66
client/vendor/k8s.io/kube-openapi/pkg/spec3/media_type.go
generated
vendored
Normal file
66
client/vendor/k8s.io/kube-openapi/pkg/spec3/media_type.go
generated
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
Copyright 2021 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package spec3
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/go-openapi/swag"
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
)
|
||||
|
||||
// MediaType a struct that allows you to specify content format, more at https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#mediaTypeObject
|
||||
//
|
||||
// Note that this struct is actually a thin wrapper around MediaTypeProps to make it referable and extensible
|
||||
type MediaType struct {
|
||||
MediaTypeProps
|
||||
spec.VendorExtensible
|
||||
}
|
||||
|
||||
// MarshalJSON is a custom marshal function that knows how to encode MediaType as JSON
|
||||
func (m *MediaType) MarshalJSON() ([]byte, error) {
|
||||
b1, err := json.Marshal(m.MediaTypeProps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(m.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return swag.ConcatJSON(b1, b2), nil
|
||||
}
|
||||
|
||||
func (m *MediaType) UnmarshalJSON(data []byte) error {
|
||||
if err := json.Unmarshal(data, &m.MediaTypeProps); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &m.VendorExtensible); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MediaTypeProps a struct that allows you to specify content format, more at https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#mediaTypeObject
|
||||
type MediaTypeProps struct {
|
||||
// Schema holds the schema defining the type used for the media type
|
||||
Schema *spec.Schema `json:"schema,omitempty"`
|
||||
// Example of the media type
|
||||
Example interface{} `json:"example,omitempty"`
|
||||
// Examples of the media type. Each example object should match the media type and specific schema if present
|
||||
Examples map[string]*Example `json:"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,omitempty"`
|
||||
}
|
||||
79
client/vendor/k8s.io/kube-openapi/pkg/spec3/operation.go
generated
vendored
Normal file
79
client/vendor/k8s.io/kube-openapi/pkg/spec3/operation.go
generated
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
Copyright 2021 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package spec3
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
"github.com/go-openapi/swag"
|
||||
)
|
||||
|
||||
// Operation describes a single API operation on a path, more at https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#operationObject
|
||||
//
|
||||
// Note that this struct is actually a thin wrapper around OperationProps to make it referable and extensible
|
||||
type Operation struct {
|
||||
OperationProps
|
||||
spec.VendorExtensible
|
||||
}
|
||||
|
||||
// MarshalJSON is a custom marshal function that knows how to encode Operation as JSON
|
||||
func (o *Operation) MarshalJSON() ([]byte, error) {
|
||||
b1, err := json.Marshal(o.OperationProps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(o.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return swag.ConcatJSON(b1, b2), nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON hydrates this items instance with the data from JSON
|
||||
func (o *Operation) UnmarshalJSON(data []byte) error {
|
||||
if err := json.Unmarshal(data, &o.OperationProps); err != nil {
|
||||
return err
|
||||
}
|
||||
return json.Unmarshal(data, &o.VendorExtensible)
|
||||
}
|
||||
|
||||
// OperationProps describes a single API operation on a path, more at https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#operationObject
|
||||
type OperationProps struct {
|
||||
// Tags holds a list of tags for API documentation control
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
// Summary holds a short summary of what the operation does
|
||||
Summary string `json:"summary,omitempty"`
|
||||
// Description holds a verbose explanation of the operation behavior
|
||||
Description string `json:"description,omitempty"`
|
||||
// ExternalDocs holds additional external documentation for this operation
|
||||
ExternalDocs *ExternalDocumentation `json:"externalDocs,omitempty"`
|
||||
// OperationId holds a unique string used to identify the operation
|
||||
OperationId string `json:"operationId,omitempty"`
|
||||
// Parameters a list of parameters that are applicable for this operation
|
||||
Parameters []*Parameter `json:"parameters,omitempty"`
|
||||
// RequestBody holds the request body applicable for this operation
|
||||
RequestBody *RequestBody `json:"requestBody,omitempty"`
|
||||
// Responses holds the list of possible responses as they are returned from executing this operation
|
||||
Responses *Responses `json:"responses,omitempty"`
|
||||
// Deprecated declares this operation to be deprecated
|
||||
Deprecated bool `json:"deprecated,omitempty"`
|
||||
// SecurityRequirement holds a declaration of which security mechanisms can be used for this operation
|
||||
SecurityRequirement []*SecurityRequirement `json:"security,omitempty"`
|
||||
// Servers contains an alternative server array to service this operation
|
||||
Servers []*Server `json:"servers,omitempty"`
|
||||
}
|
||||
94
client/vendor/k8s.io/kube-openapi/pkg/spec3/parameter.go
generated
vendored
Normal file
94
client/vendor/k8s.io/kube-openapi/pkg/spec3/parameter.go
generated
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
Copyright 2021 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package spec3
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/go-openapi/swag"
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
)
|
||||
|
||||
// Parameter a struct that describes a single operation parameter, more at https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#parameterObject
|
||||
//
|
||||
// Note that this struct is actually a thin wrapper around ParameterProps to make it referable and extensible
|
||||
type Parameter struct {
|
||||
spec.Refable
|
||||
ParameterProps
|
||||
spec.VendorExtensible
|
||||
}
|
||||
|
||||
// MarshalJSON is a custom marshal function that knows how to encode Parameter as JSON
|
||||
func (p *Parameter) MarshalJSON() ([]byte, error) {
|
||||
b1, err := json.Marshal(p.Refable)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(p.ParameterProps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b3, err := json.Marshal(p.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return swag.ConcatJSON(b1, b2, b3), nil
|
||||
}
|
||||
|
||||
func (p *Parameter) UnmarshalJSON(data []byte) error {
|
||||
if err := json.Unmarshal(data, &p.Refable); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &p.ParameterProps); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &p.VendorExtensible); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ParameterProps a struct that describes a single operation parameter, more at https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#parameterObject
|
||||
type ParameterProps struct {
|
||||
// Name holds the name of the parameter
|
||||
Name string `json:"name,omitempty"`
|
||||
// In holds the location of the parameter
|
||||
In string `json:"in,omitempty"`
|
||||
// Description holds a brief description of the parameter
|
||||
Description string `json:"description,omitempty"`
|
||||
// Required determines whether this parameter is mandatory
|
||||
Required bool `json:"required,omitempty"`
|
||||
// Deprecated declares this operation to be deprecated
|
||||
Deprecated bool `json:"deprecated,omitempty"`
|
||||
// AllowEmptyValue sets the ability to pass empty-valued parameters
|
||||
AllowEmptyValue bool `json:"allowEmptyValue,omitempty"`
|
||||
// Style describes how the parameter value will be serialized depending on the type of the parameter value
|
||||
Style string `json:"style,omitempty"`
|
||||
// Explode when true, parameter values of type array or object generate separate parameters for each value of the array or key-value pair of the map
|
||||
Explode bool `json:"explode,omitempty"`
|
||||
// AllowReserved determines whether the parameter value SHOULD allow reserved characters, as defined by RFC3986
|
||||
AllowReserved bool `json:"allowReserved,omitempty"`
|
||||
// Schema holds the schema defining the type used for the parameter
|
||||
Schema *spec.Schema `json:"schema,omitempty"`
|
||||
// Content holds a map containing the representations for the parameter
|
||||
Content map[string]*MediaType `json:"content,omitempty"`
|
||||
// Example of the parameter's potential value
|
||||
Example interface{} `json:"example,omitempty"`
|
||||
// Examples of the parameter's potential value. Each example SHOULD contain a value in the correct format as specified in the parameter encoding
|
||||
Examples map[string]*Example `json:"examples,omitempty"`
|
||||
}
|
||||
142
client/vendor/k8s.io/kube-openapi/pkg/spec3/path.go
generated
vendored
Normal file
142
client/vendor/k8s.io/kube-openapi/pkg/spec3/path.go
generated
vendored
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
Copyright 2021 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package spec3
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
"github.com/go-openapi/swag"
|
||||
)
|
||||
|
||||
// Paths describes the available paths and operations for the API, more at https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#pathsObject
|
||||
type Paths struct {
|
||||
Paths map[string]*Path
|
||||
spec.VendorExtensible
|
||||
}
|
||||
|
||||
// MarshalJSON is a custom marshal function that knows how to encode Paths as JSON
|
||||
func (p *Paths) MarshalJSON() ([]byte, error) {
|
||||
b1, err := json.Marshal(p.Paths)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(p.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return swag.ConcatJSON(b1, b2), nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON hydrates this items instance with the data from JSON
|
||||
func (p *Paths) UnmarshalJSON(data []byte) error {
|
||||
var res map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &res); err != nil {
|
||||
return err
|
||||
}
|
||||
for k, v := range res {
|
||||
if strings.HasPrefix(strings.ToLower(k), "x-") {
|
||||
if p.Extensions == nil {
|
||||
p.Extensions = make(map[string]interface{})
|
||||
}
|
||||
var d interface{}
|
||||
if err := json.Unmarshal(v, &d); err != nil {
|
||||
return err
|
||||
}
|
||||
p.Extensions[k] = d
|
||||
}
|
||||
if strings.HasPrefix(k, "/") {
|
||||
if p.Paths == nil {
|
||||
p.Paths = make(map[string]*Path)
|
||||
}
|
||||
var pi *Path
|
||||
if err := json.Unmarshal(v, &pi); err != nil {
|
||||
return err
|
||||
}
|
||||
p.Paths[k] = pi
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Path describes the operations available on a single path, more at https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#pathItemObject
|
||||
//
|
||||
// Note that this struct is actually a thin wrapper around PathProps to make it referable and extensible
|
||||
type Path struct {
|
||||
spec.Refable
|
||||
PathProps
|
||||
spec.VendorExtensible
|
||||
}
|
||||
|
||||
// MarshalJSON is a custom marshal function that knows how to encode Path as JSON
|
||||
func (p *Path) MarshalJSON() ([]byte, error) {
|
||||
b1, err := json.Marshal(p.Refable)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(p.PathProps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b3, err := json.Marshal(p.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return swag.ConcatJSON(b1, b2, b3), nil
|
||||
}
|
||||
|
||||
func (p *Path) UnmarshalJSON(data []byte) error {
|
||||
if err := json.Unmarshal(data, &p.Refable); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &p.PathProps); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &p.VendorExtensible); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// PathProps describes the operations available on a single path, more at https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#pathItemObject
|
||||
type PathProps struct {
|
||||
// Summary holds a summary for all operations in this path
|
||||
Summary string `json:"summary,omitempty"`
|
||||
// Description holds a description for all operations in this path
|
||||
Description string `json:"description,omitempty"`
|
||||
// Get defines GET operation
|
||||
Get *Operation `json:"get,omitempty"`
|
||||
// Put defines PUT operation
|
||||
Put *Operation `json:"put,omitempty"`
|
||||
// Post defines POST operation
|
||||
Post *Operation `json:"post,omitempty"`
|
||||
// Delete defines DELETE operation
|
||||
Delete *Operation `json:"delete,omitempty"`
|
||||
// Options defines OPTIONS operation
|
||||
Options *Operation `json:"options,omitempty"`
|
||||
// Head defines HEAD operation
|
||||
Head *Operation `json:"head,omitempty"`
|
||||
// Patch defines PATCH operation
|
||||
Patch *Operation `json:"patch,omitempty"`
|
||||
// Trace defines TRACE operation
|
||||
Trace *Operation `json:"trace,omitempty"`
|
||||
// Servers is an alternative server array to service all operations in this path
|
||||
Servers []*Server `json:"servers,omitempty"`
|
||||
// Parameters a list of parameters that are applicable for this operation
|
||||
Parameters []*Parameter `json:"parameters,omitempty"`
|
||||
}
|
||||
73
client/vendor/k8s.io/kube-openapi/pkg/spec3/request_body.go
generated
vendored
Normal file
73
client/vendor/k8s.io/kube-openapi/pkg/spec3/request_body.go
generated
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
Copyright 2021 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package spec3
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
"github.com/go-openapi/swag"
|
||||
)
|
||||
|
||||
// RequestBody describes a single request body, more at https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#requestBodyObject
|
||||
//
|
||||
// Note that this struct is actually a thin wrapper around RequestBodyProps to make it referable and extensible
|
||||
type RequestBody struct {
|
||||
spec.Refable
|
||||
RequestBodyProps
|
||||
spec.VendorExtensible
|
||||
}
|
||||
|
||||
// MarshalJSON is a custom marshal function that knows how to encode RequestBody as JSON
|
||||
func (r *RequestBody) MarshalJSON() ([]byte, error) {
|
||||
b1, err := json.Marshal(r.Refable)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(r.RequestBodyProps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b3, err := json.Marshal(r.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return swag.ConcatJSON(b1, b2, b3), nil
|
||||
}
|
||||
|
||||
func (r *RequestBody) UnmarshalJSON(data []byte) error {
|
||||
if err := json.Unmarshal(data, &r.Refable); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &r.RequestBodyProps); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &r.VendorExtensible); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RequestBodyProps describes a single request body, more at https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#requestBodyObject
|
||||
type RequestBodyProps struct {
|
||||
// Description holds a brief description of the request body
|
||||
Description string `json:"description,omitempty"`
|
||||
// Content is the content of the request body. The key is a media type or media type range and the value describes it
|
||||
Content map[string]*MediaType `json:"content,omitempty"`
|
||||
// Required determines if the request body is required in the request
|
||||
Required bool `json:"required,omitempty"`
|
||||
}
|
||||
203
client/vendor/k8s.io/kube-openapi/pkg/spec3/response.go
generated
vendored
Normal file
203
client/vendor/k8s.io/kube-openapi/pkg/spec3/response.go
generated
vendored
Normal file
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
Copyright 2021 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package spec3
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
"github.com/go-openapi/swag"
|
||||
)
|
||||
|
||||
// Responses holds the list of possible responses as they are returned from executing this operation
|
||||
//
|
||||
// Note that this struct is actually a thin wrapper around ResponsesProps to make it referable and extensible
|
||||
type Responses struct {
|
||||
ResponsesProps
|
||||
spec.VendorExtensible
|
||||
}
|
||||
|
||||
// MarshalJSON is a custom marshal function that knows how to encode Responses as JSON
|
||||
func (r *Responses) MarshalJSON() ([]byte, error) {
|
||||
b1, err := json.Marshal(r.ResponsesProps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(r.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return swag.ConcatJSON(b1, b2), nil
|
||||
}
|
||||
|
||||
func (r *Responses) UnmarshalJSON(data []byte) error {
|
||||
if err := json.Unmarshal(data, &r.ResponsesProps); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &r.VendorExtensible); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ResponsesProps holds the list of possible responses as they are returned from executing this operation
|
||||
type ResponsesProps struct {
|
||||
// Default holds the documentation of responses other than the ones declared for specific HTTP response codes. Use this field to cover undeclared responses
|
||||
Default *Response `json:"-"`
|
||||
// StatusCodeResponses holds a map of any HTTP status code to the response definition
|
||||
StatusCodeResponses map[int]*Response `json:"-"`
|
||||
}
|
||||
|
||||
// MarshalJSON is a custom marshal function that knows how to encode ResponsesProps as JSON
|
||||
func (r ResponsesProps) MarshalJSON() ([]byte, error) {
|
||||
toser := map[string]*Response{}
|
||||
if r.Default != nil {
|
||||
toser["default"] = r.Default
|
||||
}
|
||||
for k, v := range r.StatusCodeResponses {
|
||||
toser[strconv.Itoa(k)] = v
|
||||
}
|
||||
return json.Marshal(toser)
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshals responses from JSON
|
||||
func (r *ResponsesProps) UnmarshalJSON(data []byte) error {
|
||||
var res map[string]*Response
|
||||
if err := json.Unmarshal(data, &res); err != nil {
|
||||
return nil
|
||||
}
|
||||
if v, ok := res["default"]; ok {
|
||||
r.Default = v
|
||||
delete(res, "default")
|
||||
}
|
||||
for k, v := range res {
|
||||
if nk, err := strconv.Atoi(k); err == nil {
|
||||
if r.StatusCodeResponses == nil {
|
||||
r.StatusCodeResponses = map[int]*Response{}
|
||||
}
|
||||
r.StatusCodeResponses[nk] = v
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Response describes a single response from an API Operation, more at https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#responseObject
|
||||
//
|
||||
// Note that this struct is actually a thin wrapper around ResponseProps to make it referable and extensible
|
||||
type Response struct {
|
||||
spec.Refable
|
||||
ResponseProps
|
||||
spec.VendorExtensible
|
||||
}
|
||||
|
||||
// MarshalJSON is a custom marshal function that knows how to encode Response as JSON
|
||||
func (r *Response) MarshalJSON() ([]byte, error) {
|
||||
b1, err := json.Marshal(r.Refable)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(r.ResponseProps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b3, err := json.Marshal(r.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return swag.ConcatJSON(b1, b2, b3), nil
|
||||
}
|
||||
|
||||
func (r *Response) UnmarshalJSON(data []byte) error {
|
||||
if err := json.Unmarshal(data, &r.Refable); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &r.ResponseProps); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &r.VendorExtensible); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ResponseProps describes a single response from an API Operation, more at https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#responseObject
|
||||
type ResponseProps struct {
|
||||
// Description holds a short description of the response
|
||||
Description string `json:"description,omitempty"`
|
||||
// Headers holds a maps of a headers name to its definition
|
||||
Headers map[string]*Header `json:"headers,omitempty"`
|
||||
// Content holds a map containing descriptions of potential response payloads
|
||||
Content map[string]*MediaType `json:"content,omitempty"`
|
||||
// Links is a map of operations links that can be followed from the response
|
||||
Links map[string]*Link `json:"links,omitempty"`
|
||||
}
|
||||
|
||||
|
||||
// Link represents a possible design-time link for a response, more at https://swagger.io/specification/#link-object
|
||||
type Link struct {
|
||||
spec.Refable
|
||||
LinkProps
|
||||
spec.VendorExtensible
|
||||
}
|
||||
|
||||
// MarshalJSON is a custom marshal function that knows how to encode Link as JSON
|
||||
func (r *Link) MarshalJSON() ([]byte, error) {
|
||||
b1, err := json.Marshal(r.Refable)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(r.LinkProps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b3, err := json.Marshal(r.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return swag.ConcatJSON(b1, b2, b3), nil
|
||||
}
|
||||
|
||||
func (r *Link) UnmarshalJSON(data []byte) error {
|
||||
if err := json.Unmarshal(data, &r.Refable); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &r.LinkProps); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &r.VendorExtensible); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// LinkProps describes a single response from an API Operation, more at https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#responseObject
|
||||
type LinkProps struct {
|
||||
// OperationId is the name of an existing, resolvable OAS operation
|
||||
OperationId string `json:"operationId,omitempty"`
|
||||
// Parameters is a map representing parameters to pass to an operation as specified with operationId or identified via operationRef
|
||||
Parameters map[string]interface{} `json:"parameters,omitempty"`
|
||||
// Description holds a description of the link
|
||||
Description string `json:"description,omitempty"`
|
||||
// RequestBody is a literal value or expresion to use as a request body when calling the target operation
|
||||
RequestBody interface{} `json:"requestBody,omitempty"`
|
||||
// Server holds a server object used by the target operation
|
||||
Server *Server `json:"server,omitempty"`
|
||||
}
|
||||
56
client/vendor/k8s.io/kube-openapi/pkg/spec3/security_requirement.go
generated
vendored
Normal file
56
client/vendor/k8s.io/kube-openapi/pkg/spec3/security_requirement.go
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
Copyright 2021 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package spec3
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
"github.com/go-openapi/swag"
|
||||
)
|
||||
|
||||
// SecurityRequirementProps describes the required security schemes to execute an operation, more at https://swagger.io/specification/#security-requirement-object
|
||||
//
|
||||
// Note that this struct is actually a thin wrapper around SecurityRequirementProps to make it referable and extensible
|
||||
type SecurityRequirement struct {
|
||||
SecurityRequirementProps
|
||||
spec.VendorExtensible
|
||||
}
|
||||
|
||||
// MarshalJSON is a custom marshal function that knows how to encode SecurityRequirement as JSON
|
||||
func (s *SecurityRequirement) MarshalJSON() ([]byte, error) {
|
||||
b1, err := json.Marshal(s.SecurityRequirementProps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(s.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return swag.ConcatJSON(b1, b2), nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON hydrates this items instance with the data from JSON
|
||||
func (s *SecurityRequirement) UnmarshalJSON(data []byte) error {
|
||||
if err := json.Unmarshal(data, &s.SecurityRequirementProps); err != nil {
|
||||
return err
|
||||
}
|
||||
return json.Unmarshal(data, &s.VendorExtensible)
|
||||
}
|
||||
|
||||
// SecurityRequirementProps describes the required security schemes to execute an operation, more at https://swagger.io/specification/#security-requirement-object
|
||||
type SecurityRequirementProps map[string][]string
|
||||
118
client/vendor/k8s.io/kube-openapi/pkg/spec3/security_scheme.go
generated
vendored
Normal file
118
client/vendor/k8s.io/kube-openapi/pkg/spec3/security_scheme.go
generated
vendored
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
Copyright 2021 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package spec3
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
"github.com/go-openapi/swag"
|
||||
)
|
||||
|
||||
// SecurityScheme defines reusable Security Scheme Object, more at https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#securitySchemeObject
|
||||
type SecurityScheme struct {
|
||||
spec.Refable
|
||||
SecuritySchemeProps
|
||||
spec.VendorExtensible
|
||||
}
|
||||
|
||||
// MarshalJSON is a custom marshal function that knows how to encode SecurityScheme as JSON
|
||||
func (s *SecurityScheme) MarshalJSON() ([]byte, error) {
|
||||
b1, err := json.Marshal(s.SecuritySchemeProps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(s.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b3, err := json.Marshal(s.Refable)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return swag.ConcatJSON(b1, b2, b3), nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON hydrates this items instance with the data from JSON
|
||||
func (s *SecurityScheme) UnmarshalJSON(data []byte) error {
|
||||
if err := json.Unmarshal(data, &s.SecuritySchemeProps); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &s.VendorExtensible); err != nil {
|
||||
return err
|
||||
}
|
||||
return json.Unmarshal(data, &s.Refable)
|
||||
}
|
||||
|
||||
// SecuritySchemeProps defines a security scheme that can be used by the operations
|
||||
type SecuritySchemeProps struct {
|
||||
// Type of the security scheme
|
||||
Type string `json:"type,omitempty"`
|
||||
// Description holds a short description for security scheme
|
||||
Description string `json:"description,omitempty"`
|
||||
// Name holds the name of the header, query or cookie parameter to be used
|
||||
Name string `json:"name,omitempty"`
|
||||
// In holds the location of the API key
|
||||
In string `json:"in,omitempty"`
|
||||
// Scheme holds the name of the HTTP Authorization scheme to be used in the Authorization header
|
||||
Scheme string `json:"scheme,omitempty"`
|
||||
// BearerFormat holds a hint to the client to identify how the bearer token is formatted
|
||||
BearerFormat string `json:"bearerFormat,omitempty"`
|
||||
// Flows contains configuration information for the flow types supported.
|
||||
Flows map[string]*OAuthFlow `json:"flows,omitempty"`
|
||||
// OpenIdConnectUrl holds an url to discover OAuth2 configuration values from
|
||||
OpenIdConnectUrl string `json:"openIdConnectUrl,omitempty"`
|
||||
}
|
||||
|
||||
// OAuthFlow contains configuration information for the flow types supported.
|
||||
type OAuthFlow struct {
|
||||
OAuthFlowProps
|
||||
spec.VendorExtensible
|
||||
}
|
||||
|
||||
// MarshalJSON is a custom marshal function that knows how to encode OAuthFlow as JSON
|
||||
func (o *OAuthFlow) MarshalJSON() ([]byte, error) {
|
||||
b1, err := json.Marshal(o.OAuthFlowProps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(o.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return swag.ConcatJSON(b1, b2), nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON hydrates this items instance with the data from JSON
|
||||
func (o *OAuthFlow) UnmarshalJSON(data []byte) error {
|
||||
if err := json.Unmarshal(data, &o.OAuthFlowProps); err != nil {
|
||||
return err
|
||||
}
|
||||
return json.Unmarshal(data, &o.VendorExtensible)
|
||||
}
|
||||
|
||||
// OAuthFlowProps holds configuration details for a supported OAuth Flow
|
||||
type OAuthFlowProps struct {
|
||||
// AuthorizationUrl hold the authorization URL to be used for this flow
|
||||
AuthorizationUrl string `json:"authorizationUrl,omitempty"`
|
||||
// TokenUrl holds the token URL to be used for this flow
|
||||
TokenUrl string `json:"tokenUrl,omitempty"`
|
||||
// RefreshUrl holds the URL to be used for obtaining refresh tokens
|
||||
RefreshUrl string `json:"refreshUrl,omitempty"`
|
||||
// Scopes holds the available scopes for the OAuth2 security scheme
|
||||
Scopes map[string]string `json:"scopes,omitempty"`
|
||||
}
|
||||
98
client/vendor/k8s.io/kube-openapi/pkg/spec3/server.go
generated
vendored
Normal file
98
client/vendor/k8s.io/kube-openapi/pkg/spec3/server.go
generated
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
Copyright 2021 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package spec3
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
"github.com/go-openapi/swag"
|
||||
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
ServerProps
|
||||
spec.VendorExtensible
|
||||
}
|
||||
|
||||
type ServerProps struct {
|
||||
// Description is a short description of the target documentation. CommonMark syntax MAY be used for rich text representation.
|
||||
Description string `json:"description,omitempty"`
|
||||
// URL is the URL for the target documentation.
|
||||
URL string `json:"url"`
|
||||
// Variables contains a map between a variable name and its value. The value is used for substitution in the server's URL templeate
|
||||
Variables map[string]*ServerVariable `json:"variables,omitempty"`
|
||||
}
|
||||
|
||||
// MarshalJSON is a custom marshal function that knows how to encode Responses as JSON
|
||||
func (s *Server) MarshalJSON() ([]byte, error) {
|
||||
b1, err := json.Marshal(s.ServerProps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(s.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return swag.ConcatJSON(b1, b2), nil
|
||||
}
|
||||
|
||||
func (s *Server) UnmarshalJSON(data []byte) error {
|
||||
if err := json.Unmarshal(data, &s.ServerProps); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &s.VendorExtensible); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ServerVariable struct {
|
||||
ServerVariableProps
|
||||
spec.VendorExtensible
|
||||
}
|
||||
|
||||
type ServerVariableProps struct {
|
||||
// Enum is an enumeration of string values to be used if the substitution options are from a limited set
|
||||
Enum []string `json:"enum,omitempty"`
|
||||
// Default is the default value to use for substitution, which SHALL be sent if an alternate value is not supplied
|
||||
Default string `json:"default"`
|
||||
// Description is a description for the server variable
|
||||
Description string `json:"description,omitempty"`
|
||||
}
|
||||
|
||||
// MarshalJSON is a custom marshal function that knows how to encode Responses as JSON
|
||||
func (s *ServerVariable) MarshalJSON() ([]byte, error) {
|
||||
b1, err := json.Marshal(s.ServerVariableProps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(s.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return swag.ConcatJSON(b1, b2), nil
|
||||
}
|
||||
|
||||
func (s *ServerVariable) UnmarshalJSON(data []byte) error {
|
||||
if err := json.Unmarshal(data, &s.ServerVariableProps); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &s.VendorExtensible); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
37
client/vendor/k8s.io/kube-openapi/pkg/spec3/spec.go
generated
vendored
Normal file
37
client/vendor/k8s.io/kube-openapi/pkg/spec3/spec.go
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
Copyright 2021 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package spec3
|
||||
|
||||
import (
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
)
|
||||
|
||||
// OpenAPI is an object that describes an API and conforms to the OpenAPI Specification.
|
||||
type OpenAPI struct {
|
||||
// Version represents the semantic version number of the OpenAPI Specification that this document uses
|
||||
Version string `json:"openapi"`
|
||||
// Info provides metadata about the API
|
||||
Info *spec.Info `json:"info"`
|
||||
// Paths holds the available target and operations for the API
|
||||
Paths *Paths `json:"paths,omitempty"`
|
||||
// Servers is an array of Server objects which provide connectivity information to a target server
|
||||
Servers []*Server `json:"servers,omitempty"`
|
||||
// Components hold various schemas for the specification
|
||||
Components *Components `json:"components,omitempty"`
|
||||
// ExternalDocs holds additional external documentation
|
||||
ExternalDocs *ExternalDocumentation `json:"externalDocs,omitempty"`
|
||||
}
|
||||
2
client/vendor/k8s.io/kube-openapi/pkg/util/proto/OWNERS
generated
vendored
Normal file
2
client/vendor/k8s.io/kube-openapi/pkg/util/proto/OWNERS
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
approvers:
|
||||
- apelisse
|
||||
19
client/vendor/k8s.io/kube-openapi/pkg/util/proto/doc.go
generated
vendored
Normal file
19
client/vendor/k8s.io/kube-openapi/pkg/util/proto/doc.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package proto is a collection of libraries for parsing and indexing the type definitions.
|
||||
// The openapi spec contains the object model definitions and extensions metadata.
|
||||
package proto
|
||||
362
client/vendor/k8s.io/kube-openapi/pkg/util/proto/document.go
generated
vendored
Normal file
362
client/vendor/k8s.io/kube-openapi/pkg/util/proto/document.go
generated
vendored
Normal file
@@ -0,0 +1,362 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package proto
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
openapi_v2 "github.com/google/gnostic/openapiv2"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
func newSchemaError(path *Path, format string, a ...interface{}) error {
|
||||
err := fmt.Sprintf(format, a...)
|
||||
if path.Len() == 0 {
|
||||
return fmt.Errorf("SchemaError: %v", err)
|
||||
}
|
||||
return fmt.Errorf("SchemaError(%v): %v", path, err)
|
||||
}
|
||||
|
||||
// VendorExtensionToMap converts openapi VendorExtension to a map.
|
||||
func VendorExtensionToMap(e []*openapi_v2.NamedAny) map[string]interface{} {
|
||||
values := map[string]interface{}{}
|
||||
|
||||
for _, na := range e {
|
||||
if na.GetName() == "" || na.GetValue() == nil {
|
||||
continue
|
||||
}
|
||||
if na.GetValue().GetYaml() == "" {
|
||||
continue
|
||||
}
|
||||
var value interface{}
|
||||
err := yaml.Unmarshal([]byte(na.GetValue().GetYaml()), &value)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
values[na.GetName()] = value
|
||||
}
|
||||
|
||||
return values
|
||||
}
|
||||
|
||||
// Definitions is an implementation of `Models`. It looks for
|
||||
// models in an openapi Schema.
|
||||
type Definitions struct {
|
||||
models map[string]Schema
|
||||
}
|
||||
|
||||
var _ Models = &Definitions{}
|
||||
|
||||
// NewOpenAPIData creates a new `Models` out of the openapi document.
|
||||
func NewOpenAPIData(doc *openapi_v2.Document) (Models, error) {
|
||||
definitions := Definitions{
|
||||
models: map[string]Schema{},
|
||||
}
|
||||
|
||||
// Save the list of all models first. This will allow us to
|
||||
// validate that we don't have any dangling reference.
|
||||
for _, namedSchema := range doc.GetDefinitions().GetAdditionalProperties() {
|
||||
definitions.models[namedSchema.GetName()] = nil
|
||||
}
|
||||
|
||||
// Now, parse each model. We can validate that references exists.
|
||||
for _, namedSchema := range doc.GetDefinitions().GetAdditionalProperties() {
|
||||
path := NewPath(namedSchema.GetName())
|
||||
schema, err := definitions.ParseSchema(namedSchema.GetValue(), &path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
definitions.models[namedSchema.GetName()] = schema
|
||||
}
|
||||
|
||||
return &definitions, nil
|
||||
}
|
||||
|
||||
// We believe the schema is a reference, verify that and returns a new
|
||||
// Schema
|
||||
func (d *Definitions) parseReference(s *openapi_v2.Schema, path *Path) (Schema, error) {
|
||||
// TODO(wrong): a schema with a $ref can have properties. We can ignore them (would be incomplete), but we cannot return an error.
|
||||
if len(s.GetProperties().GetAdditionalProperties()) > 0 {
|
||||
return nil, newSchemaError(path, "unallowed embedded type definition")
|
||||
}
|
||||
// TODO(wrong): a schema with a $ref can have a type. We can ignore it (would be incomplete), but we cannot return an error.
|
||||
if len(s.GetType().GetValue()) > 0 {
|
||||
return nil, newSchemaError(path, "definition reference can't have a type")
|
||||
}
|
||||
|
||||
// TODO(wrong): $refs outside of the definitions are completely valid. We can ignore them (would be incomplete), but we cannot return an error.
|
||||
if !strings.HasPrefix(s.GetXRef(), "#/definitions/") {
|
||||
return nil, newSchemaError(path, "unallowed reference to non-definition %q", s.GetXRef())
|
||||
}
|
||||
reference := strings.TrimPrefix(s.GetXRef(), "#/definitions/")
|
||||
if _, ok := d.models[reference]; !ok {
|
||||
return nil, newSchemaError(path, "unknown model in reference: %q", reference)
|
||||
}
|
||||
base, err := d.parseBaseSchema(s, path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Ref{
|
||||
BaseSchema: base,
|
||||
reference: reference,
|
||||
definitions: d,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func parseDefault(def *openapi_v2.Any) (interface{}, error) {
|
||||
if def == nil {
|
||||
return nil, nil
|
||||
}
|
||||
var i interface{}
|
||||
if err := yaml.Unmarshal([]byte(def.Yaml), &i); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
|
||||
func (d *Definitions) parseBaseSchema(s *openapi_v2.Schema, path *Path) (BaseSchema, error) {
|
||||
def, err := parseDefault(s.GetDefault())
|
||||
if err != nil {
|
||||
return BaseSchema{}, err
|
||||
}
|
||||
return BaseSchema{
|
||||
Description: s.GetDescription(),
|
||||
Default: def,
|
||||
Extensions: VendorExtensionToMap(s.GetVendorExtension()),
|
||||
Path: *path,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// We believe the schema is a map, verify and return a new schema
|
||||
func (d *Definitions) parseMap(s *openapi_v2.Schema, path *Path) (Schema, error) {
|
||||
if len(s.GetType().GetValue()) != 0 && s.GetType().GetValue()[0] != object {
|
||||
return nil, newSchemaError(path, "invalid object type")
|
||||
}
|
||||
var sub Schema
|
||||
// TODO(incomplete): this misses the boolean case as AdditionalProperties is a bool+schema sum type.
|
||||
if s.GetAdditionalProperties().GetSchema() == nil {
|
||||
base, err := d.parseBaseSchema(s, path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sub = &Arbitrary{
|
||||
BaseSchema: base,
|
||||
}
|
||||
} else {
|
||||
var err error
|
||||
sub, err = d.ParseSchema(s.GetAdditionalProperties().GetSchema(), path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
base, err := d.parseBaseSchema(s, path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Map{
|
||||
BaseSchema: base,
|
||||
SubType: sub,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *Definitions) parsePrimitive(s *openapi_v2.Schema, path *Path) (Schema, error) {
|
||||
var t string
|
||||
if len(s.GetType().GetValue()) > 1 {
|
||||
return nil, newSchemaError(path, "primitive can't have more than 1 type")
|
||||
}
|
||||
if len(s.GetType().GetValue()) == 1 {
|
||||
t = s.GetType().GetValue()[0]
|
||||
}
|
||||
switch t {
|
||||
case String: // do nothing
|
||||
case Number: // do nothing
|
||||
case Integer: // do nothing
|
||||
case Boolean: // do nothing
|
||||
// TODO(wrong): this misses "null". Would skip the null case (would be incomplete), but we cannot return an error.
|
||||
default:
|
||||
return nil, newSchemaError(path, "Unknown primitive type: %q", t)
|
||||
}
|
||||
base, err := d.parseBaseSchema(s, path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Primitive{
|
||||
BaseSchema: base,
|
||||
Type: t,
|
||||
Format: s.GetFormat(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *Definitions) parseArray(s *openapi_v2.Schema, path *Path) (Schema, error) {
|
||||
if len(s.GetType().GetValue()) != 1 {
|
||||
return nil, newSchemaError(path, "array should have exactly one type")
|
||||
}
|
||||
if s.GetType().GetValue()[0] != array {
|
||||
return nil, newSchemaError(path, `array should have type "array"`)
|
||||
}
|
||||
if len(s.GetItems().GetSchema()) != 1 {
|
||||
// TODO(wrong): Items can have multiple elements. We can ignore Items then (would be incomplete), but we cannot return an error.
|
||||
// TODO(wrong): "type: array" witohut any items at all is completely valid.
|
||||
return nil, newSchemaError(path, "array should have exactly one sub-item")
|
||||
}
|
||||
sub, err := d.ParseSchema(s.GetItems().GetSchema()[0], path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
base, err := d.parseBaseSchema(s, path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Array{
|
||||
BaseSchema: base,
|
||||
SubType: sub,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *Definitions) parseKind(s *openapi_v2.Schema, path *Path) (Schema, error) {
|
||||
if len(s.GetType().GetValue()) != 0 && s.GetType().GetValue()[0] != object {
|
||||
return nil, newSchemaError(path, "invalid object type")
|
||||
}
|
||||
if s.GetProperties() == nil {
|
||||
return nil, newSchemaError(path, "object doesn't have properties")
|
||||
}
|
||||
|
||||
fields := map[string]Schema{}
|
||||
fieldOrder := []string{}
|
||||
|
||||
for _, namedSchema := range s.GetProperties().GetAdditionalProperties() {
|
||||
var err error
|
||||
name := namedSchema.GetName()
|
||||
path := path.FieldPath(name)
|
||||
fields[name], err = d.ParseSchema(namedSchema.GetValue(), &path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fieldOrder = append(fieldOrder, name)
|
||||
}
|
||||
|
||||
base, err := d.parseBaseSchema(s, path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Kind{
|
||||
BaseSchema: base,
|
||||
RequiredFields: s.GetRequired(),
|
||||
Fields: fields,
|
||||
FieldOrder: fieldOrder,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *Definitions) parseArbitrary(s *openapi_v2.Schema, path *Path) (Schema, error) {
|
||||
base, err := d.parseBaseSchema(s, path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Arbitrary{
|
||||
BaseSchema: base,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ParseSchema creates a walkable Schema from an openapi schema. While
|
||||
// this function is public, it doesn't leak through the interface.
|
||||
func (d *Definitions) ParseSchema(s *openapi_v2.Schema, path *Path) (Schema, error) {
|
||||
if s.GetXRef() != "" {
|
||||
// TODO(incomplete): ignoring the rest of s is wrong. As long as there are no conflict, everything from s must be considered
|
||||
// Reference: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#path-item-object
|
||||
return d.parseReference(s, path)
|
||||
}
|
||||
objectTypes := s.GetType().GetValue()
|
||||
switch len(objectTypes) {
|
||||
case 0:
|
||||
// in the OpenAPI schema served by older k8s versions, object definitions created from structs did not include
|
||||
// the type:object property (they only included the "properties" property), so we need to handle this case
|
||||
// TODO: validate that we ever published empty, non-nil properties. JSON roundtripping nils them.
|
||||
if s.GetProperties() != nil {
|
||||
// TODO(wrong): when verifying a non-object later against this, it will be rejected as invalid type.
|
||||
// TODO(CRD validation schema publishing): we have to filter properties (empty or not) if type=object is not given
|
||||
return d.parseKind(s, path)
|
||||
} else {
|
||||
// Definition has no type and no properties. Treat it as an arbitrary value
|
||||
// TODO(incomplete): what if it has additionalProperties=false or patternProperties?
|
||||
// ANSWER: parseArbitrary is less strict than it has to be with patternProperties (which is ignored). So this is correct (of course not complete).
|
||||
return d.parseArbitrary(s, path)
|
||||
}
|
||||
case 1:
|
||||
t := objectTypes[0]
|
||||
switch t {
|
||||
case object:
|
||||
if s.GetProperties() != nil {
|
||||
return d.parseKind(s, path)
|
||||
} else {
|
||||
return d.parseMap(s, path)
|
||||
}
|
||||
case array:
|
||||
return d.parseArray(s, path)
|
||||
}
|
||||
return d.parsePrimitive(s, path)
|
||||
default:
|
||||
// the OpenAPI generator never generates (nor it ever did in the past) OpenAPI type definitions with multiple types
|
||||
// TODO(wrong): this is rejecting a completely valid OpenAPI spec
|
||||
// TODO(CRD validation schema publishing): filter these out
|
||||
return nil, newSchemaError(path, "definitions with multiple types aren't supported")
|
||||
}
|
||||
}
|
||||
|
||||
// LookupModel is public through the interface of Models. It
|
||||
// returns a visitable schema from the given model name.
|
||||
func (d *Definitions) LookupModel(model string) Schema {
|
||||
return d.models[model]
|
||||
}
|
||||
|
||||
func (d *Definitions) ListModels() []string {
|
||||
models := []string{}
|
||||
|
||||
for model := range d.models {
|
||||
models = append(models, model)
|
||||
}
|
||||
|
||||
sort.Strings(models)
|
||||
return models
|
||||
}
|
||||
|
||||
type Ref struct {
|
||||
BaseSchema
|
||||
|
||||
reference string
|
||||
definitions *Definitions
|
||||
}
|
||||
|
||||
var _ Reference = &Ref{}
|
||||
|
||||
func (r *Ref) Reference() string {
|
||||
return r.reference
|
||||
}
|
||||
|
||||
func (r *Ref) SubSchema() Schema {
|
||||
return r.definitions.models[r.reference]
|
||||
}
|
||||
|
||||
func (r *Ref) Accept(v SchemaVisitor) {
|
||||
v.VisitReference(r)
|
||||
}
|
||||
|
||||
func (r *Ref) GetName() string {
|
||||
return fmt.Sprintf("Reference to %q", r.reference)
|
||||
}
|
||||
324
client/vendor/k8s.io/kube-openapi/pkg/util/proto/document_v3.go
generated
vendored
Normal file
324
client/vendor/k8s.io/kube-openapi/pkg/util/proto/document_v3.go
generated
vendored
Normal file
@@ -0,0 +1,324 @@
|
||||
/*
|
||||
Copyright 2022 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package proto
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
openapi_v3 "github.com/google/gnostic/openapiv3"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// Temporary parse implementation to be used until gnostic->kube-openapi conversion
|
||||
// is possible.
|
||||
func NewOpenAPIV3Data(doc *openapi_v3.Document) (Models, error) {
|
||||
definitions := Definitions{
|
||||
models: map[string]Schema{},
|
||||
}
|
||||
|
||||
schemas := doc.GetComponents().GetSchemas()
|
||||
if schemas == nil {
|
||||
return &definitions, nil
|
||||
}
|
||||
|
||||
// Save the list of all models first. This will allow us to
|
||||
// validate that we don't have any dangling reference.
|
||||
for _, namedSchema := range schemas.GetAdditionalProperties() {
|
||||
definitions.models[namedSchema.GetName()] = nil
|
||||
}
|
||||
|
||||
// Now, parse each model. We can validate that references exists.
|
||||
for _, namedSchema := range schemas.GetAdditionalProperties() {
|
||||
path := NewPath(namedSchema.GetName())
|
||||
val := namedSchema.GetValue()
|
||||
|
||||
if val == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if schema, err := definitions.ParseV3SchemaOrReference(namedSchema.GetValue(), &path); err != nil {
|
||||
return nil, err
|
||||
} else if schema != nil {
|
||||
// Schema may be nil if we hit incompleteness in the conversion,
|
||||
// but not a fatal error
|
||||
definitions.models[namedSchema.GetName()] = schema
|
||||
}
|
||||
}
|
||||
|
||||
return &definitions, nil
|
||||
}
|
||||
|
||||
func (d *Definitions) ParseV3SchemaReference(s *openapi_v3.Reference, path *Path) (Schema, error) {
|
||||
base := &BaseSchema{
|
||||
Description: s.Description,
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(s.GetXRef(), "#/components/schemas") {
|
||||
// Only resolve references to components/schemas. We may add support
|
||||
// later for other in-spec paths, but otherwise treat unrecognized
|
||||
// refs as arbitrary/unknown values.
|
||||
return &Arbitrary{
|
||||
BaseSchema: *base,
|
||||
}, nil
|
||||
}
|
||||
|
||||
reference := strings.TrimPrefix(s.GetXRef(), "#/components/schemas/")
|
||||
if _, ok := d.models[reference]; !ok {
|
||||
return nil, newSchemaError(path, "unknown model in reference: %q", reference)
|
||||
}
|
||||
|
||||
return &Ref{
|
||||
BaseSchema: BaseSchema{
|
||||
Description: s.Description,
|
||||
},
|
||||
reference: reference,
|
||||
definitions: d,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *Definitions) ParseV3SchemaOrReference(s *openapi_v3.SchemaOrReference, path *Path) (Schema, error) {
|
||||
var schema Schema
|
||||
var err error
|
||||
|
||||
switch v := s.GetOneof().(type) {
|
||||
case *openapi_v3.SchemaOrReference_Reference:
|
||||
// Any references stored in #!/components/... are bound to refer
|
||||
// to external documents. This API does not support such a
|
||||
// feature.
|
||||
//
|
||||
// In the weird case that this is a reference to a schema that is
|
||||
// not external, we attempt to parse anyway
|
||||
schema, err = d.ParseV3SchemaReference(v.Reference, path)
|
||||
case *openapi_v3.SchemaOrReference_Schema:
|
||||
schema, err = d.ParseSchemaV3(v.Schema, path)
|
||||
default:
|
||||
panic("unexpected type")
|
||||
}
|
||||
|
||||
return schema, err
|
||||
}
|
||||
|
||||
// ParseSchema creates a walkable Schema from an openapi v3 schema. While
|
||||
// this function is public, it doesn't leak through the interface.
|
||||
func (d *Definitions) ParseSchemaV3(s *openapi_v3.Schema, path *Path) (Schema, error) {
|
||||
switch s.GetType() {
|
||||
case object:
|
||||
for _, extension := range s.GetSpecificationExtension() {
|
||||
if extension.Name == "x-kuberentes-group-version-kind" {
|
||||
// Objects with x-kubernetes-group-version-kind are always top
|
||||
// level types.
|
||||
return d.parseV3Kind(s, path)
|
||||
}
|
||||
}
|
||||
|
||||
if len(s.GetProperties().GetAdditionalProperties()) > 0 {
|
||||
return d.parseV3Kind(s, path)
|
||||
}
|
||||
return d.parseV3Map(s, path)
|
||||
case array:
|
||||
return d.parseV3Array(s, path)
|
||||
case String, Number, Integer, Boolean:
|
||||
return d.parseV3Primitive(s, path)
|
||||
default:
|
||||
return d.parseV3Arbitrary(s, path)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Definitions) parseV3Kind(s *openapi_v3.Schema, path *Path) (Schema, error) {
|
||||
if s.GetType() != object {
|
||||
return nil, newSchemaError(path, "invalid object type")
|
||||
} else if s.GetProperties() == nil {
|
||||
return nil, newSchemaError(path, "object doesn't have properties")
|
||||
}
|
||||
|
||||
fields := map[string]Schema{}
|
||||
fieldOrder := []string{}
|
||||
|
||||
for _, namedSchema := range s.GetProperties().GetAdditionalProperties() {
|
||||
var err error
|
||||
name := namedSchema.GetName()
|
||||
path := path.FieldPath(name)
|
||||
fields[name], err = d.ParseV3SchemaOrReference(namedSchema.GetValue(), &path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fieldOrder = append(fieldOrder, name)
|
||||
}
|
||||
|
||||
base, err := d.parseV3BaseSchema(s, path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Kind{
|
||||
BaseSchema: *base,
|
||||
RequiredFields: s.GetRequired(),
|
||||
Fields: fields,
|
||||
FieldOrder: fieldOrder,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *Definitions) parseV3Arbitrary(s *openapi_v3.Schema, path *Path) (Schema, error) {
|
||||
base, err := d.parseV3BaseSchema(s, path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Arbitrary{
|
||||
BaseSchema: *base,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *Definitions) parseV3Primitive(s *openapi_v3.Schema, path *Path) (Schema, error) {
|
||||
switch s.GetType() {
|
||||
case String: // do nothing
|
||||
case Number: // do nothing
|
||||
case Integer: // do nothing
|
||||
case Boolean: // do nothing
|
||||
default:
|
||||
// Unsupported primitive type. Treat as arbitrary type
|
||||
return d.parseV3Arbitrary(s, path)
|
||||
}
|
||||
|
||||
base, err := d.parseV3BaseSchema(s, path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Primitive{
|
||||
BaseSchema: *base,
|
||||
Type: s.GetType(),
|
||||
Format: s.GetFormat(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *Definitions) parseV3Array(s *openapi_v3.Schema, path *Path) (Schema, error) {
|
||||
if s.GetType() != array {
|
||||
return nil, newSchemaError(path, `array should have type "array"`)
|
||||
} else if len(s.GetItems().GetSchemaOrReference()) != 1 {
|
||||
// This array can have multiple types in it (or no types at all)
|
||||
// This is not supported by this conversion.
|
||||
// Just return an arbitrary type
|
||||
return d.parseV3Arbitrary(s, path)
|
||||
}
|
||||
|
||||
sub, err := d.ParseV3SchemaOrReference(s.GetItems().GetSchemaOrReference()[0], path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
base, err := d.parseV3BaseSchema(s, path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Array{
|
||||
BaseSchema: *base,
|
||||
SubType: sub,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// We believe the schema is a map, verify and return a new schema
|
||||
func (d *Definitions) parseV3Map(s *openapi_v3.Schema, path *Path) (Schema, error) {
|
||||
if s.GetType() != object {
|
||||
return nil, newSchemaError(path, "invalid object type")
|
||||
}
|
||||
var sub Schema
|
||||
|
||||
switch p := s.GetAdditionalProperties().GetOneof().(type) {
|
||||
case *openapi_v3.AdditionalPropertiesItem_Boolean:
|
||||
// What does this boolean even mean?
|
||||
base, err := d.parseV3BaseSchema(s, path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sub = &Arbitrary{
|
||||
BaseSchema: *base,
|
||||
}
|
||||
case *openapi_v3.AdditionalPropertiesItem_SchemaOrReference:
|
||||
if schema, err := d.ParseV3SchemaOrReference(p.SchemaOrReference, path); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
sub = schema
|
||||
}
|
||||
case nil:
|
||||
// no subtype?
|
||||
sub = &Arbitrary{}
|
||||
default:
|
||||
panic("unrecognized type " + reflect.TypeOf(p).Name())
|
||||
}
|
||||
|
||||
base, err := d.parseV3BaseSchema(s, path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Map{
|
||||
BaseSchema: *base,
|
||||
SubType: sub,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func parseV3Interface(def *yaml.Node) (interface{}, error) {
|
||||
if def == nil {
|
||||
return nil, nil
|
||||
}
|
||||
var i interface{}
|
||||
if err := def.Decode(&i); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
|
||||
func (d *Definitions) parseV3BaseSchema(s *openapi_v3.Schema, path *Path) (*BaseSchema, error) {
|
||||
if s == nil {
|
||||
return nil, fmt.Errorf("cannot initializae BaseSchema from nil")
|
||||
}
|
||||
|
||||
def, err := parseV3Interface(s.GetDefault().ToRawInfo())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &BaseSchema{
|
||||
Description: s.GetDescription(),
|
||||
Default: def,
|
||||
Extensions: SpecificationExtensionToMap(s.GetSpecificationExtension()),
|
||||
Path: *path,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func SpecificationExtensionToMap(e []*openapi_v3.NamedAny) map[string]interface{} {
|
||||
values := map[string]interface{}{}
|
||||
|
||||
for _, na := range e {
|
||||
if na.GetName() == "" || na.GetValue() == nil {
|
||||
continue
|
||||
}
|
||||
if na.GetValue().GetYaml() == "" {
|
||||
continue
|
||||
}
|
||||
var value interface{}
|
||||
err := yaml.Unmarshal([]byte(na.GetValue().GetYaml()), &value)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
values[na.GetName()] = value
|
||||
}
|
||||
|
||||
return values
|
||||
}
|
||||
285
client/vendor/k8s.io/kube-openapi/pkg/util/proto/openapi.go
generated
vendored
Normal file
285
client/vendor/k8s.io/kube-openapi/pkg/util/proto/openapi.go
generated
vendored
Normal file
@@ -0,0 +1,285 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package proto
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Defines openapi types.
|
||||
const (
|
||||
Integer = "integer"
|
||||
Number = "number"
|
||||
String = "string"
|
||||
Boolean = "boolean"
|
||||
|
||||
// These types are private as they should never leak, and are
|
||||
// represented by actual structs.
|
||||
array = "array"
|
||||
object = "object"
|
||||
)
|
||||
|
||||
// Models interface describe a model provider. They can give you the
|
||||
// schema for a specific model.
|
||||
type Models interface {
|
||||
LookupModel(string) Schema
|
||||
ListModels() []string
|
||||
}
|
||||
|
||||
// SchemaVisitor is an interface that you need to implement if you want
|
||||
// to "visit" an openapi schema. A dispatch on the Schema type will call
|
||||
// the appropriate function based on its actual type:
|
||||
// - Array is a list of one and only one given subtype
|
||||
// - Map is a map of string to one and only one given subtype
|
||||
// - Primitive can be string, integer, number and boolean.
|
||||
// - Kind is an object with specific fields mapping to specific types.
|
||||
// - Reference is a link to another definition.
|
||||
type SchemaVisitor interface {
|
||||
VisitArray(*Array)
|
||||
VisitMap(*Map)
|
||||
VisitPrimitive(*Primitive)
|
||||
VisitKind(*Kind)
|
||||
VisitReference(Reference)
|
||||
}
|
||||
|
||||
// SchemaVisitorArbitrary is an additional visitor interface which handles
|
||||
// arbitrary types. For backwards compatibility, it's a separate interface
|
||||
// which is checked for at runtime.
|
||||
type SchemaVisitorArbitrary interface {
|
||||
SchemaVisitor
|
||||
VisitArbitrary(*Arbitrary)
|
||||
}
|
||||
|
||||
// Schema is the base definition of an openapi type.
|
||||
type Schema interface {
|
||||
// Giving a visitor here will let you visit the actual type.
|
||||
Accept(SchemaVisitor)
|
||||
|
||||
// Pretty print the name of the type.
|
||||
GetName() string
|
||||
// Describes how to access this field.
|
||||
GetPath() *Path
|
||||
// Describes the field.
|
||||
GetDescription() string
|
||||
// Default for that schema.
|
||||
GetDefault() interface{}
|
||||
// Returns type extensions.
|
||||
GetExtensions() map[string]interface{}
|
||||
}
|
||||
|
||||
// Path helps us keep track of type paths
|
||||
type Path struct {
|
||||
parent *Path
|
||||
key string
|
||||
}
|
||||
|
||||
func NewPath(key string) Path {
|
||||
return Path{key: key}
|
||||
}
|
||||
|
||||
func (p *Path) Get() []string {
|
||||
if p == nil {
|
||||
return []string{}
|
||||
}
|
||||
if p.key == "" {
|
||||
return p.parent.Get()
|
||||
}
|
||||
return append(p.parent.Get(), p.key)
|
||||
}
|
||||
|
||||
func (p *Path) Len() int {
|
||||
return len(p.Get())
|
||||
}
|
||||
|
||||
func (p *Path) String() string {
|
||||
return strings.Join(p.Get(), "")
|
||||
}
|
||||
|
||||
// ArrayPath appends an array index and creates a new path
|
||||
func (p *Path) ArrayPath(i int) Path {
|
||||
return Path{
|
||||
parent: p,
|
||||
key: fmt.Sprintf("[%d]", i),
|
||||
}
|
||||
}
|
||||
|
||||
// FieldPath appends a field name and creates a new path
|
||||
func (p *Path) FieldPath(field string) Path {
|
||||
return Path{
|
||||
parent: p,
|
||||
key: fmt.Sprintf(".%s", field),
|
||||
}
|
||||
}
|
||||
|
||||
// BaseSchema holds data used by each types of schema.
|
||||
type BaseSchema struct {
|
||||
Description string
|
||||
Extensions map[string]interface{}
|
||||
Default interface{}
|
||||
|
||||
Path Path
|
||||
}
|
||||
|
||||
func (b *BaseSchema) GetDescription() string {
|
||||
return b.Description
|
||||
}
|
||||
|
||||
func (b *BaseSchema) GetExtensions() map[string]interface{} {
|
||||
return b.Extensions
|
||||
}
|
||||
|
||||
func (b *BaseSchema) GetDefault() interface{} {
|
||||
return b.Default
|
||||
}
|
||||
|
||||
func (b *BaseSchema) GetPath() *Path {
|
||||
return &b.Path
|
||||
}
|
||||
|
||||
// Array must have all its element of the same `SubType`.
|
||||
type Array struct {
|
||||
BaseSchema
|
||||
|
||||
SubType Schema
|
||||
}
|
||||
|
||||
var _ Schema = &Array{}
|
||||
|
||||
func (a *Array) Accept(v SchemaVisitor) {
|
||||
v.VisitArray(a)
|
||||
}
|
||||
|
||||
func (a *Array) GetName() string {
|
||||
return fmt.Sprintf("Array of %s", a.SubType.GetName())
|
||||
}
|
||||
|
||||
// Kind is a complex object. It can have multiple different
|
||||
// subtypes for each field, as defined in the `Fields` field. Mandatory
|
||||
// fields are listed in `RequiredFields`. The key of the object is
|
||||
// always of type `string`.
|
||||
type Kind struct {
|
||||
BaseSchema
|
||||
|
||||
// Lists names of required fields.
|
||||
RequiredFields []string
|
||||
// Maps field names to types.
|
||||
Fields map[string]Schema
|
||||
// FieldOrder reports the canonical order for the fields.
|
||||
FieldOrder []string
|
||||
}
|
||||
|
||||
var _ Schema = &Kind{}
|
||||
|
||||
func (k *Kind) Accept(v SchemaVisitor) {
|
||||
v.VisitKind(k)
|
||||
}
|
||||
|
||||
func (k *Kind) GetName() string {
|
||||
properties := []string{}
|
||||
for key := range k.Fields {
|
||||
properties = append(properties, key)
|
||||
}
|
||||
return fmt.Sprintf("Kind(%v)", properties)
|
||||
}
|
||||
|
||||
// IsRequired returns true if `field` is a required field for this type.
|
||||
func (k *Kind) IsRequired(field string) bool {
|
||||
for _, f := range k.RequiredFields {
|
||||
if f == field {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Keys returns a alphabetically sorted list of keys.
|
||||
func (k *Kind) Keys() []string {
|
||||
keys := make([]string, 0)
|
||||
for key := range k.Fields {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
return keys
|
||||
}
|
||||
|
||||
// Map is an object who values must all be of the same `SubType`.
|
||||
// The key of the object is always of type `string`.
|
||||
type Map struct {
|
||||
BaseSchema
|
||||
|
||||
SubType Schema
|
||||
}
|
||||
|
||||
var _ Schema = &Map{}
|
||||
|
||||
func (m *Map) Accept(v SchemaVisitor) {
|
||||
v.VisitMap(m)
|
||||
}
|
||||
|
||||
func (m *Map) GetName() string {
|
||||
return fmt.Sprintf("Map of %s", m.SubType.GetName())
|
||||
}
|
||||
|
||||
// Primitive is a literal. There can be multiple types of primitives,
|
||||
// and this subtype can be visited through the `subType` field.
|
||||
type Primitive struct {
|
||||
BaseSchema
|
||||
|
||||
// Type of a primitive must be one of: integer, number, string, boolean.
|
||||
Type string
|
||||
Format string
|
||||
}
|
||||
|
||||
var _ Schema = &Primitive{}
|
||||
|
||||
func (p *Primitive) Accept(v SchemaVisitor) {
|
||||
v.VisitPrimitive(p)
|
||||
}
|
||||
|
||||
func (p *Primitive) GetName() string {
|
||||
if p.Format == "" {
|
||||
return p.Type
|
||||
}
|
||||
return fmt.Sprintf("%s (%s)", p.Type, p.Format)
|
||||
}
|
||||
|
||||
// Arbitrary is a value of any type (primitive, object or array)
|
||||
type Arbitrary struct {
|
||||
BaseSchema
|
||||
}
|
||||
|
||||
var _ Schema = &Arbitrary{}
|
||||
|
||||
func (a *Arbitrary) Accept(v SchemaVisitor) {
|
||||
if visitor, ok := v.(SchemaVisitorArbitrary); ok {
|
||||
visitor.VisitArbitrary(a)
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Arbitrary) GetName() string {
|
||||
return "Arbitrary value (primitive, object or array)"
|
||||
}
|
||||
|
||||
// Reference implementation depends on the type of document.
|
||||
type Reference interface {
|
||||
Schema
|
||||
|
||||
Reference() string
|
||||
SubSchema() Schema
|
||||
}
|
||||
27
client/vendor/k8s.io/kube-openapi/pkg/util/sets/empty.go
generated
vendored
Normal file
27
client/vendor/k8s.io/kube-openapi/pkg/util/sets/empty.go
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
Copyright The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Code generated by set-gen. DO NOT EDIT.
|
||||
|
||||
// NOTE: This file is copied from k8s.io/kubernetes/vendor/k8s.io/apimachinery/pkg/util/sets/empty.go
|
||||
// because in Kubernetes we don't allowed vendor code to import staging code. See
|
||||
// https://github.com/kubernetes/kube-openapi/pull/90 for more details.
|
||||
|
||||
package sets
|
||||
|
||||
// Empty is public since it is used by some internal API objects for conversions between external
|
||||
// string arrays and internal sets, and conversion logic requires public types today.
|
||||
type Empty struct{}
|
||||
207
client/vendor/k8s.io/kube-openapi/pkg/util/sets/string.go
generated
vendored
Normal file
207
client/vendor/k8s.io/kube-openapi/pkg/util/sets/string.go
generated
vendored
Normal file
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
Copyright The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Code generated by set-gen. DO NOT EDIT.
|
||||
|
||||
// NOTE: This file is copied from k8s.io/kubernetes/vendor/k8s.io/apimachinery/pkg/util/sets/string.go
|
||||
// because in Kubernetes we don't allowed vendor code to import staging code. See
|
||||
// https://github.com/kubernetes/kube-openapi/pull/90 for more details.
|
||||
|
||||
package sets
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// sets.String is a set of strings, implemented via map[string]struct{} for minimal memory consumption.
|
||||
type String map[string]Empty
|
||||
|
||||
// NewString creates a String from a list of values.
|
||||
func NewString(items ...string) String {
|
||||
ss := String{}
|
||||
ss.Insert(items...)
|
||||
return ss
|
||||
}
|
||||
|
||||
// StringKeySet creates a String from a keys of a map[string](? extends interface{}).
|
||||
// If the value passed in is not actually a map, this will panic.
|
||||
func StringKeySet(theMap interface{}) String {
|
||||
v := reflect.ValueOf(theMap)
|
||||
ret := String{}
|
||||
|
||||
for _, keyValue := range v.MapKeys() {
|
||||
ret.Insert(keyValue.Interface().(string))
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// Insert adds items to the set.
|
||||
func (s String) Insert(items ...string) {
|
||||
for _, item := range items {
|
||||
s[item] = Empty{}
|
||||
}
|
||||
}
|
||||
|
||||
// Delete removes all items from the set.
|
||||
func (s String) Delete(items ...string) {
|
||||
for _, item := range items {
|
||||
delete(s, item)
|
||||
}
|
||||
}
|
||||
|
||||
// Has returns true if and only if item is contained in the set.
|
||||
func (s String) Has(item string) bool {
|
||||
_, contained := s[item]
|
||||
return contained
|
||||
}
|
||||
|
||||
// HasAll returns true if and only if all items are contained in the set.
|
||||
func (s String) HasAll(items ...string) bool {
|
||||
for _, item := range items {
|
||||
if !s.Has(item) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// HasAny returns true if any items are contained in the set.
|
||||
func (s String) HasAny(items ...string) bool {
|
||||
for _, item := range items {
|
||||
if s.Has(item) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Difference returns a set of objects that are not in s2
|
||||
// For example:
|
||||
// s1 = {a1, a2, a3}
|
||||
// s2 = {a1, a2, a4, a5}
|
||||
// s1.Difference(s2) = {a3}
|
||||
// s2.Difference(s1) = {a4, a5}
|
||||
func (s String) Difference(s2 String) String {
|
||||
result := NewString()
|
||||
for key := range s {
|
||||
if !s2.Has(key) {
|
||||
result.Insert(key)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Union returns a new set which includes items in either s1 or s2.
|
||||
// For example:
|
||||
// s1 = {a1, a2}
|
||||
// s2 = {a3, a4}
|
||||
// s1.Union(s2) = {a1, a2, a3, a4}
|
||||
// s2.Union(s1) = {a1, a2, a3, a4}
|
||||
func (s1 String) Union(s2 String) String {
|
||||
result := NewString()
|
||||
for key := range s1 {
|
||||
result.Insert(key)
|
||||
}
|
||||
for key := range s2 {
|
||||
result.Insert(key)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Intersection returns a new set which includes the item in BOTH s1 and s2
|
||||
// For example:
|
||||
// s1 = {a1, a2}
|
||||
// s2 = {a2, a3}
|
||||
// s1.Intersection(s2) = {a2}
|
||||
func (s1 String) Intersection(s2 String) String {
|
||||
var walk, other String
|
||||
result := NewString()
|
||||
if s1.Len() < s2.Len() {
|
||||
walk = s1
|
||||
other = s2
|
||||
} else {
|
||||
walk = s2
|
||||
other = s1
|
||||
}
|
||||
for key := range walk {
|
||||
if other.Has(key) {
|
||||
result.Insert(key)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// IsSuperset returns true if and only if s1 is a superset of s2.
|
||||
func (s1 String) IsSuperset(s2 String) bool {
|
||||
for item := range s2 {
|
||||
if !s1.Has(item) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Equal returns true if and only if s1 is equal (as a set) to s2.
|
||||
// Two sets are equal if their membership is identical.
|
||||
// (In practice, this means same elements, order doesn't matter)
|
||||
func (s1 String) Equal(s2 String) bool {
|
||||
return len(s1) == len(s2) && s1.IsSuperset(s2)
|
||||
}
|
||||
|
||||
type sortableSliceOfString []string
|
||||
|
||||
func (s sortableSliceOfString) Len() int { return len(s) }
|
||||
func (s sortableSliceOfString) Less(i, j int) bool { return lessString(s[i], s[j]) }
|
||||
func (s sortableSliceOfString) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
|
||||
// List returns the contents as a sorted string slice.
|
||||
func (s String) List() []string {
|
||||
res := make(sortableSliceOfString, 0, len(s))
|
||||
for key := range s {
|
||||
res = append(res, key)
|
||||
}
|
||||
sort.Sort(res)
|
||||
return []string(res)
|
||||
}
|
||||
|
||||
// UnsortedList returns the slice with contents in random order.
|
||||
func (s String) UnsortedList() []string {
|
||||
res := make([]string, 0, len(s))
|
||||
for key := range s {
|
||||
res = append(res, key)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// Returns a single element from the set.
|
||||
func (s String) PopAny() (string, bool) {
|
||||
for key := range s {
|
||||
s.Delete(key)
|
||||
return key, true
|
||||
}
|
||||
var zeroValue string
|
||||
return zeroValue, false
|
||||
}
|
||||
|
||||
// Len returns the size of the set.
|
||||
func (s String) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
func lessString(lhs, rhs string) bool {
|
||||
return lhs < rhs
|
||||
}
|
||||
2
client/vendor/k8s.io/kube-openapi/pkg/validation/spec/.gitignore
generated
vendored
Normal file
2
client/vendor/k8s.io/kube-openapi/pkg/validation/spec/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
secrets.yml
|
||||
coverage.out
|
||||
202
client/vendor/k8s.io/kube-openapi/pkg/validation/spec/LICENSE
generated
vendored
Normal file
202
client/vendor/k8s.io/kube-openapi/pkg/validation/spec/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
24
client/vendor/k8s.io/kube-openapi/pkg/validation/spec/contact_info.go
generated
vendored
Normal file
24
client/vendor/k8s.io/kube-openapi/pkg/validation/spec/contact_info.go
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package spec
|
||||
|
||||
// ContactInfo contact information for the exposed API.
|
||||
//
|
||||
// For more information: http://goo.gl/8us55a#contactObject
|
||||
type ContactInfo struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
URL string `json:"url,omitempty"`
|
||||
Email string `json:"email,omitempty"`
|
||||
}
|
||||
24
client/vendor/k8s.io/kube-openapi/pkg/validation/spec/external_docs.go
generated
vendored
Normal file
24
client/vendor/k8s.io/kube-openapi/pkg/validation/spec/external_docs.go
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package spec
|
||||
|
||||
// ExternalDocumentation allows referencing an external resource for
|
||||
// extended documentation.
|
||||
//
|
||||
// For more information: http://goo.gl/8us55a#externalDocumentationObject
|
||||
type ExternalDocumentation struct {
|
||||
Description string `json:"description,omitempty"`
|
||||
URL string `json:"url,omitempty"`
|
||||
}
|
||||
502
client/vendor/k8s.io/kube-openapi/pkg/validation/spec/fuzz.go
generated
vendored
Normal file
502
client/vendor/k8s.io/kube-openapi/pkg/validation/spec/fuzz.go
generated
vendored
Normal file
@@ -0,0 +1,502 @@
|
||||
/*
|
||||
Copyright 2022 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package spec
|
||||
|
||||
import (
|
||||
"github.com/go-openapi/jsonreference"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
fuzz "github.com/google/gofuzz"
|
||||
)
|
||||
|
||||
var SwaggerFuzzFuncs []interface{} = []interface{}{
|
||||
func(v *Responses, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(v)
|
||||
if v.Default != nil {
|
||||
// Check if we hit maxDepth and left an incomplete value
|
||||
if v.Default.Description == "" {
|
||||
v.Default = nil
|
||||
v.StatusCodeResponses = nil
|
||||
}
|
||||
}
|
||||
|
||||
// conversion has no way to discern empty statusCodeResponses from
|
||||
// nil, since "default" is always included in the map.
|
||||
// So avoid empty responses list
|
||||
if len(v.StatusCodeResponses) == 0 {
|
||||
v.StatusCodeResponses = nil
|
||||
}
|
||||
},
|
||||
func(v *Operation, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(v)
|
||||
|
||||
if v != nil {
|
||||
// force non-nil
|
||||
v.Responses = &Responses{}
|
||||
c.Fuzz(v.Responses)
|
||||
|
||||
v.Schemes = nil
|
||||
if c.RandBool() {
|
||||
v.Schemes = append(v.Schemes, "http")
|
||||
}
|
||||
|
||||
if c.RandBool() {
|
||||
v.Schemes = append(v.Schemes, "https")
|
||||
}
|
||||
|
||||
if c.RandBool() {
|
||||
v.Schemes = append(v.Schemes, "ws")
|
||||
}
|
||||
|
||||
if c.RandBool() {
|
||||
v.Schemes = append(v.Schemes, "wss")
|
||||
}
|
||||
|
||||
// Gnostic unconditionally makes security values non-null
|
||||
// So do not fuzz null values into the array.
|
||||
for i, val := range v.Security {
|
||||
if val == nil {
|
||||
v.Security[i] = make(map[string][]string)
|
||||
}
|
||||
|
||||
for k, v := range val {
|
||||
if v == nil {
|
||||
val[k] = make([]string, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
func(v map[int]Response, c fuzz.Continue) {
|
||||
n := 0
|
||||
c.Fuzz(&n)
|
||||
if n == 0 {
|
||||
// Test that fuzzer is not at maxDepth so we do not
|
||||
// end up with empty elements
|
||||
return
|
||||
}
|
||||
|
||||
// Prevent negative numbers
|
||||
num := c.Intn(4)
|
||||
for i := 0; i < num+2; i++ {
|
||||
val := Response{}
|
||||
c.Fuzz(&val)
|
||||
|
||||
val.Description = c.RandString() + "x"
|
||||
v[100*(i+1)+c.Intn(100)] = val
|
||||
}
|
||||
},
|
||||
func(v map[string]PathItem, c fuzz.Continue) {
|
||||
n := 0
|
||||
c.Fuzz(&n)
|
||||
if n == 0 {
|
||||
// Test that fuzzer is not at maxDepth so we do not
|
||||
// end up with empty elements
|
||||
return
|
||||
}
|
||||
|
||||
num := c.Intn(5)
|
||||
for i := 0; i < num+2; i++ {
|
||||
val := PathItem{}
|
||||
c.Fuzz(&val)
|
||||
|
||||
// Ref params are only allowed in certain locations, so
|
||||
// possibly add a few to PathItems
|
||||
numRefsToAdd := c.Intn(5)
|
||||
for i := 0; i < numRefsToAdd; i++ {
|
||||
theRef := Parameter{}
|
||||
c.Fuzz(&theRef.Refable)
|
||||
|
||||
val.Parameters = append(val.Parameters, theRef)
|
||||
}
|
||||
|
||||
v["/"+c.RandString()] = val
|
||||
}
|
||||
},
|
||||
func(v *SchemaOrArray, c fuzz.Continue) {
|
||||
*v = SchemaOrArray{}
|
||||
// gnostic parser just doesn't support more
|
||||
// than one Schema here
|
||||
v.Schema = &Schema{}
|
||||
c.Fuzz(&v.Schema)
|
||||
|
||||
},
|
||||
func(v *SchemaOrBool, c fuzz.Continue) {
|
||||
*v = SchemaOrBool{}
|
||||
|
||||
if c.RandBool() {
|
||||
v.Allows = c.RandBool()
|
||||
} else {
|
||||
v.Schema = &Schema{}
|
||||
v.Allows = true
|
||||
c.Fuzz(&v.Schema)
|
||||
}
|
||||
},
|
||||
func(v map[string]Response, c fuzz.Continue) {
|
||||
n := 0
|
||||
c.Fuzz(&n)
|
||||
if n == 0 {
|
||||
// Test that fuzzer is not at maxDepth so we do not
|
||||
// end up with empty elements
|
||||
return
|
||||
}
|
||||
|
||||
// Response definitions are not allowed to
|
||||
// be refs
|
||||
for i := 0; i < c.Intn(5)+1; i++ {
|
||||
resp := &Response{}
|
||||
|
||||
c.Fuzz(resp)
|
||||
resp.Ref = Ref{}
|
||||
resp.Description = c.RandString() + "x"
|
||||
|
||||
// Response refs are not vendor extensible by gnostic
|
||||
resp.VendorExtensible.Extensions = nil
|
||||
v[c.RandString()+"x"] = *resp
|
||||
}
|
||||
},
|
||||
func(v *Header, c fuzz.Continue) {
|
||||
if v != nil {
|
||||
c.FuzzNoCustom(v)
|
||||
|
||||
// descendant Items of Header may not be refs
|
||||
cur := v.Items
|
||||
for cur != nil {
|
||||
cur.Ref = Ref{}
|
||||
cur = cur.Items
|
||||
}
|
||||
}
|
||||
},
|
||||
func(v *Ref, c fuzz.Continue) {
|
||||
*v = Ref{}
|
||||
v.Ref, _ = jsonreference.New("http://asd.com/" + c.RandString())
|
||||
},
|
||||
func(v *Response, c fuzz.Continue) {
|
||||
*v = Response{}
|
||||
if c.RandBool() {
|
||||
v.Ref = Ref{}
|
||||
v.Ref.Ref, _ = jsonreference.New("http://asd.com/" + c.RandString())
|
||||
} else {
|
||||
c.Fuzz(&v.VendorExtensible)
|
||||
c.Fuzz(&v.Schema)
|
||||
c.Fuzz(&v.ResponseProps)
|
||||
|
||||
v.Headers = nil
|
||||
v.Ref = Ref{}
|
||||
|
||||
n := 0
|
||||
c.Fuzz(&n)
|
||||
if n != 0 {
|
||||
// Test that fuzzer is not at maxDepth so we do not
|
||||
// end up with empty elements
|
||||
num := c.Intn(4)
|
||||
for i := 0; i < num; i++ {
|
||||
if v.Headers == nil {
|
||||
v.Headers = make(map[string]Header)
|
||||
}
|
||||
hdr := Header{}
|
||||
c.Fuzz(&hdr)
|
||||
if hdr.Type == "" {
|
||||
// hit maxDepth, just abort trying to make haders
|
||||
v.Headers = nil
|
||||
break
|
||||
}
|
||||
v.Headers[c.RandString()+"x"] = hdr
|
||||
}
|
||||
} else {
|
||||
v.Headers = nil
|
||||
}
|
||||
}
|
||||
|
||||
v.Description = c.RandString() + "x"
|
||||
|
||||
// Gnostic parses empty as nil, so to keep avoid putting empty
|
||||
if len(v.Headers) == 0 {
|
||||
v.Headers = nil
|
||||
}
|
||||
},
|
||||
func(v **Info, c fuzz.Continue) {
|
||||
// Info is never nil
|
||||
*v = &Info{}
|
||||
c.FuzzNoCustom(*v)
|
||||
|
||||
(*v).Title = c.RandString() + "x"
|
||||
},
|
||||
func(v *Extensions, c fuzz.Continue) {
|
||||
// gnostic parser only picks up x- vendor extensions
|
||||
numChildren := c.Intn(5)
|
||||
for i := 0; i < numChildren; i++ {
|
||||
if *v == nil {
|
||||
*v = Extensions{}
|
||||
}
|
||||
(*v)["x-"+c.RandString()] = c.RandString()
|
||||
}
|
||||
},
|
||||
func(v *Swagger, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(v)
|
||||
|
||||
if v.Paths == nil {
|
||||
// Force paths non-nil since it does not have omitempty in json tag.
|
||||
// This means a perfect roundtrip (via json) is impossible,
|
||||
// since we can't tell the difference between empty/unspecified paths
|
||||
v.Paths = &Paths{}
|
||||
c.Fuzz(v.Paths)
|
||||
}
|
||||
|
||||
v.Swagger = "2.0"
|
||||
|
||||
// Gnostic support serializing ID at all
|
||||
// unavoidable data loss
|
||||
v.ID = ""
|
||||
|
||||
v.Schemes = nil
|
||||
if c.RandUint64()%2 == 1 {
|
||||
v.Schemes = append(v.Schemes, "http")
|
||||
}
|
||||
|
||||
if c.RandUint64()%2 == 1 {
|
||||
v.Schemes = append(v.Schemes, "https")
|
||||
}
|
||||
|
||||
if c.RandUint64()%2 == 1 {
|
||||
v.Schemes = append(v.Schemes, "ws")
|
||||
}
|
||||
|
||||
if c.RandUint64()%2 == 1 {
|
||||
v.Schemes = append(v.Schemes, "wss")
|
||||
}
|
||||
|
||||
// Gnostic unconditionally makes security values non-null
|
||||
// So do not fuzz null values into the array.
|
||||
for i, val := range v.Security {
|
||||
if val == nil {
|
||||
v.Security[i] = make(map[string][]string)
|
||||
}
|
||||
|
||||
for k, v := range val {
|
||||
if v == nil {
|
||||
val[k] = make([]string, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
func(v *SecurityScheme, c fuzz.Continue) {
|
||||
v.Description = c.RandString() + "x"
|
||||
c.Fuzz(&v.VendorExtensible)
|
||||
|
||||
switch c.Intn(3) {
|
||||
case 0:
|
||||
v.Type = "basic"
|
||||
case 1:
|
||||
v.Type = "apiKey"
|
||||
switch c.Intn(2) {
|
||||
case 0:
|
||||
v.In = "header"
|
||||
case 1:
|
||||
v.In = "query"
|
||||
default:
|
||||
panic("unreachable")
|
||||
}
|
||||
v.Name = "x" + c.RandString()
|
||||
case 2:
|
||||
v.Type = "oauth2"
|
||||
|
||||
switch c.Intn(4) {
|
||||
case 0:
|
||||
v.Flow = "accessCode"
|
||||
v.TokenURL = "https://" + c.RandString()
|
||||
v.AuthorizationURL = "https://" + c.RandString()
|
||||
case 1:
|
||||
v.Flow = "application"
|
||||
v.TokenURL = "https://" + c.RandString()
|
||||
case 2:
|
||||
v.Flow = "implicit"
|
||||
v.AuthorizationURL = "https://" + c.RandString()
|
||||
case 3:
|
||||
v.Flow = "password"
|
||||
v.TokenURL = "https://" + c.RandString()
|
||||
default:
|
||||
panic("unreachable")
|
||||
}
|
||||
c.Fuzz(&v.Scopes)
|
||||
default:
|
||||
panic("unreachable")
|
||||
}
|
||||
},
|
||||
func(v *interface{}, c fuzz.Continue) {
|
||||
*v = c.RandString() + "x"
|
||||
},
|
||||
func(v *string, c fuzz.Continue) {
|
||||
*v = c.RandString() + "x"
|
||||
},
|
||||
func(v *ExternalDocumentation, c fuzz.Continue) {
|
||||
v.Description = c.RandString() + "x"
|
||||
v.URL = c.RandString() + "x"
|
||||
},
|
||||
func(v *SimpleSchema, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(v)
|
||||
|
||||
switch c.Intn(5) {
|
||||
case 0:
|
||||
v.Type = "string"
|
||||
case 1:
|
||||
v.Type = "number"
|
||||
case 2:
|
||||
v.Type = "boolean"
|
||||
case 3:
|
||||
v.Type = "integer"
|
||||
case 4:
|
||||
v.Type = "array"
|
||||
default:
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
switch c.Intn(5) {
|
||||
case 0:
|
||||
v.CollectionFormat = "csv"
|
||||
case 1:
|
||||
v.CollectionFormat = "ssv"
|
||||
case 2:
|
||||
v.CollectionFormat = "tsv"
|
||||
case 3:
|
||||
v.CollectionFormat = "pipes"
|
||||
case 4:
|
||||
v.CollectionFormat = ""
|
||||
default:
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// None of the types which include SimpleSchema in our definitions
|
||||
// actually support "example" in the official spec
|
||||
v.Example = nil
|
||||
|
||||
// unsupported by openapi
|
||||
v.Nullable = false
|
||||
},
|
||||
func(v *int64, c fuzz.Continue) {
|
||||
c.Fuzz(v)
|
||||
|
||||
// Gnostic does not differentiate between 0 and non-specified
|
||||
// so avoid using 0 for fuzzer
|
||||
if *v == 0 {
|
||||
*v = 1
|
||||
}
|
||||
},
|
||||
func(v *float64, c fuzz.Continue) {
|
||||
c.Fuzz(v)
|
||||
|
||||
// Gnostic does not differentiate between 0 and non-specified
|
||||
// so avoid using 0 for fuzzer
|
||||
if *v == 0.0 {
|
||||
*v = 1.0
|
||||
}
|
||||
},
|
||||
func(v *Parameter, c fuzz.Continue) {
|
||||
if v == nil {
|
||||
return
|
||||
}
|
||||
c.Fuzz(&v.VendorExtensible)
|
||||
if c.RandBool() {
|
||||
// body param
|
||||
v.Description = c.RandString() + "x"
|
||||
v.Name = c.RandString() + "x"
|
||||
v.In = "body"
|
||||
c.Fuzz(&v.Description)
|
||||
c.Fuzz(&v.Required)
|
||||
|
||||
v.Schema = &Schema{}
|
||||
c.Fuzz(&v.Schema)
|
||||
|
||||
} else {
|
||||
c.Fuzz(&v.SimpleSchema)
|
||||
c.Fuzz(&v.CommonValidations)
|
||||
v.AllowEmptyValue = false
|
||||
v.Description = c.RandString() + "x"
|
||||
v.Name = c.RandString() + "x"
|
||||
|
||||
switch c.Intn(4) {
|
||||
case 0:
|
||||
// Header param
|
||||
v.In = "header"
|
||||
case 1:
|
||||
// Form data param
|
||||
v.In = "formData"
|
||||
v.AllowEmptyValue = c.RandBool()
|
||||
case 2:
|
||||
// Query param
|
||||
v.In = "query"
|
||||
v.AllowEmptyValue = c.RandBool()
|
||||
case 3:
|
||||
// Path param
|
||||
v.In = "path"
|
||||
v.Required = true
|
||||
default:
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// descendant Items of Parameter may not be refs
|
||||
cur := v.Items
|
||||
for cur != nil {
|
||||
cur.Ref = Ref{}
|
||||
cur = cur.Items
|
||||
}
|
||||
}
|
||||
},
|
||||
func(v *Schema, c fuzz.Continue) {
|
||||
if c.RandBool() {
|
||||
// file schema
|
||||
c.Fuzz(&v.Default)
|
||||
c.Fuzz(&v.Description)
|
||||
c.Fuzz(&v.Example)
|
||||
c.Fuzz(&v.ExternalDocs)
|
||||
|
||||
c.Fuzz(&v.Format)
|
||||
c.Fuzz(&v.ReadOnly)
|
||||
c.Fuzz(&v.Required)
|
||||
c.Fuzz(&v.Title)
|
||||
v.Type = StringOrArray{"file"}
|
||||
|
||||
} else {
|
||||
// normal schema
|
||||
c.Fuzz(&v.SchemaProps)
|
||||
c.Fuzz(&v.SwaggerSchemaProps)
|
||||
c.Fuzz(&v.VendorExtensible)
|
||||
// c.Fuzz(&v.ExtraProps)
|
||||
// ExtraProps will not roundtrip - gnostic throws out
|
||||
// unrecognized keys
|
||||
}
|
||||
|
||||
// Not supported by official openapi v2 spec
|
||||
// and stripped by k8s apiserver
|
||||
v.ID = ""
|
||||
v.AnyOf = nil
|
||||
v.OneOf = nil
|
||||
v.Not = nil
|
||||
v.Nullable = false
|
||||
v.AdditionalItems = nil
|
||||
v.Schema = ""
|
||||
v.PatternProperties = nil
|
||||
v.Definitions = nil
|
||||
v.Dependencies = nil
|
||||
},
|
||||
}
|
||||
|
||||
var SwaggerDiffOptions = []cmp.Option{
|
||||
// cmp.Diff panics on Ref since jsonreference.Ref uses unexported fields
|
||||
cmp.Comparer(func(a Ref, b Ref) bool {
|
||||
return a.String() == b.String()
|
||||
}),
|
||||
}
|
||||
1517
client/vendor/k8s.io/kube-openapi/pkg/validation/spec/gnostic.go
generated
vendored
Normal file
1517
client/vendor/k8s.io/kube-openapi/pkg/validation/spec/gnostic.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
105
client/vendor/k8s.io/kube-openapi/pkg/validation/spec/header.go
generated
vendored
Normal file
105
client/vendor/k8s.io/kube-openapi/pkg/validation/spec/header.go
generated
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package spec
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/go-openapi/swag"
|
||||
"k8s.io/kube-openapi/pkg/internal"
|
||||
jsonv2 "k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json"
|
||||
)
|
||||
|
||||
const (
|
||||
jsonArray = "array"
|
||||
)
|
||||
|
||||
// HeaderProps describes a response header
|
||||
type HeaderProps struct {
|
||||
Description string `json:"description,omitempty"`
|
||||
}
|
||||
|
||||
// Header describes a header for a response of the API
|
||||
//
|
||||
// For more information: http://goo.gl/8us55a#headerObject
|
||||
type Header struct {
|
||||
CommonValidations
|
||||
SimpleSchema
|
||||
VendorExtensible
|
||||
HeaderProps
|
||||
}
|
||||
|
||||
// MarshalJSON marshal this to JSON
|
||||
func (h Header) MarshalJSON() ([]byte, error) {
|
||||
b1, err := json.Marshal(h.CommonValidations)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(h.SimpleSchema)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b3, err := json.Marshal(h.HeaderProps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b4, err := json.Marshal(h.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return swag.ConcatJSON(b1, b2, b3, b4), nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshals this header from JSON
|
||||
func (h *Header) UnmarshalJSON(data []byte) error {
|
||||
if internal.UseOptimizedJSONUnmarshaling {
|
||||
return jsonv2.Unmarshal(data, h)
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(data, &h.CommonValidations); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &h.SimpleSchema); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &h.VendorExtensible); err != nil {
|
||||
return err
|
||||
}
|
||||
return json.Unmarshal(data, &h.HeaderProps)
|
||||
}
|
||||
|
||||
func (h *Header) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) error {
|
||||
var x struct {
|
||||
CommonValidations
|
||||
SimpleSchema
|
||||
Extensions
|
||||
HeaderProps
|
||||
}
|
||||
|
||||
if err := opts.UnmarshalNext(dec, &x); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
h.CommonValidations = x.CommonValidations
|
||||
h.SimpleSchema = x.SimpleSchema
|
||||
h.Extensions = x.Extensions
|
||||
h.HeaderProps = x.HeaderProps
|
||||
|
||||
h.Extensions.sanitize()
|
||||
if len(h.Extensions) == 0 {
|
||||
h.Extensions = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
222
client/vendor/k8s.io/kube-openapi/pkg/validation/spec/info.go
generated
vendored
Normal file
222
client/vendor/k8s.io/kube-openapi/pkg/validation/spec/info.go
generated
vendored
Normal file
@@ -0,0 +1,222 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package spec
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
"github.com/go-openapi/swag"
|
||||
"k8s.io/kube-openapi/pkg/internal"
|
||||
jsonv2 "k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json"
|
||||
)
|
||||
|
||||
// Extensions vendor specific extensions
|
||||
type Extensions map[string]interface{}
|
||||
|
||||
// Add adds a value to these extensions
|
||||
func (e Extensions) Add(key string, value interface{}) {
|
||||
realKey := strings.ToLower(key)
|
||||
e[realKey] = value
|
||||
}
|
||||
|
||||
// GetString gets a string value from the extensions
|
||||
func (e Extensions) GetString(key string) (string, bool) {
|
||||
if v, ok := e[strings.ToLower(key)]; ok {
|
||||
str, ok := v.(string)
|
||||
return str, ok
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
// GetBool gets a string value from the extensions
|
||||
func (e Extensions) GetBool(key string) (bool, bool) {
|
||||
if v, ok := e[strings.ToLower(key)]; ok {
|
||||
str, ok := v.(bool)
|
||||
return str, ok
|
||||
}
|
||||
return false, false
|
||||
}
|
||||
|
||||
// GetStringSlice gets a string value from the extensions
|
||||
func (e Extensions) GetStringSlice(key string) ([]string, bool) {
|
||||
if v, ok := e[strings.ToLower(key)]; ok {
|
||||
arr, isSlice := v.([]interface{})
|
||||
if !isSlice {
|
||||
return nil, false
|
||||
}
|
||||
var strs []string
|
||||
for _, iface := range arr {
|
||||
str, isString := iface.(string)
|
||||
if !isString {
|
||||
return nil, false
|
||||
}
|
||||
strs = append(strs, str)
|
||||
}
|
||||
return strs, ok
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// GetObject gets the object value from the extensions.
|
||||
// out must be a json serializable type; the json go struct
|
||||
// tags of out are used to populate it.
|
||||
func (e Extensions) GetObject(key string, out interface{}) error {
|
||||
// This json serialization/deserialization could be replaced with
|
||||
// an approach using reflection if the optimization becomes justified.
|
||||
if v, ok := e[strings.ToLower(key)]; ok {
|
||||
b, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = json.Unmarshal(b, out)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e Extensions) sanitize() {
|
||||
for k := range e {
|
||||
if !isExtensionKey(k) {
|
||||
delete(e, k)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (e Extensions) sanitizeWithExtra() (extra map[string]any) {
|
||||
for k, v := range e {
|
||||
if !isExtensionKey(k) {
|
||||
if extra == nil {
|
||||
extra = make(map[string]any)
|
||||
}
|
||||
extra[k] = v
|
||||
delete(e, k)
|
||||
}
|
||||
}
|
||||
return extra
|
||||
}
|
||||
|
||||
func isExtensionKey(k string) bool {
|
||||
return len(k) > 1 && (k[0] == 'x' || k[0] == 'X') && k[1] == '-'
|
||||
}
|
||||
|
||||
// VendorExtensible composition block.
|
||||
type VendorExtensible struct {
|
||||
Extensions Extensions
|
||||
}
|
||||
|
||||
// AddExtension adds an extension to this extensible object
|
||||
func (v *VendorExtensible) AddExtension(key string, value interface{}) {
|
||||
if value == nil {
|
||||
return
|
||||
}
|
||||
if v.Extensions == nil {
|
||||
v.Extensions = make(map[string]interface{})
|
||||
}
|
||||
v.Extensions.Add(key, value)
|
||||
}
|
||||
|
||||
// MarshalJSON marshals the extensions to json
|
||||
func (v VendorExtensible) MarshalJSON() ([]byte, error) {
|
||||
toser := make(map[string]interface{})
|
||||
for k, v := range v.Extensions {
|
||||
lk := strings.ToLower(k)
|
||||
if strings.HasPrefix(lk, "x-") {
|
||||
toser[k] = v
|
||||
}
|
||||
}
|
||||
return json.Marshal(toser)
|
||||
}
|
||||
|
||||
// UnmarshalJSON for this extensible object
|
||||
func (v *VendorExtensible) UnmarshalJSON(data []byte) error {
|
||||
var d map[string]interface{}
|
||||
if err := json.Unmarshal(data, &d); err != nil {
|
||||
return err
|
||||
}
|
||||
for k, vv := range d {
|
||||
lk := strings.ToLower(k)
|
||||
if strings.HasPrefix(lk, "x-") {
|
||||
if v.Extensions == nil {
|
||||
v.Extensions = map[string]interface{}{}
|
||||
}
|
||||
v.Extensions[k] = vv
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// InfoProps the properties for an info definition
|
||||
type InfoProps struct {
|
||||
Description string `json:"description,omitempty"`
|
||||
Title string `json:"title,omitempty"`
|
||||
TermsOfService string `json:"termsOfService,omitempty"`
|
||||
Contact *ContactInfo `json:"contact,omitempty"`
|
||||
License *License `json:"license,omitempty"`
|
||||
Version string `json:"version,omitempty"`
|
||||
}
|
||||
|
||||
// Info object provides metadata about the API.
|
||||
// The metadata can be used by the clients if needed, and can be presented in the Swagger-UI for convenience.
|
||||
//
|
||||
// For more information: http://goo.gl/8us55a#infoObject
|
||||
type Info struct {
|
||||
VendorExtensible
|
||||
InfoProps
|
||||
}
|
||||
|
||||
// MarshalJSON marshal this to JSON
|
||||
func (i Info) MarshalJSON() ([]byte, error) {
|
||||
b1, err := json.Marshal(i.InfoProps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(i.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return swag.ConcatJSON(b1, b2), nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON marshal this from JSON
|
||||
func (i *Info) UnmarshalJSON(data []byte) error {
|
||||
if internal.UseOptimizedJSONUnmarshaling {
|
||||
return jsonv2.Unmarshal(data, i)
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(data, &i.InfoProps); err != nil {
|
||||
return err
|
||||
}
|
||||
return json.Unmarshal(data, &i.VendorExtensible)
|
||||
}
|
||||
|
||||
func (i *Info) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) error {
|
||||
var x struct {
|
||||
Extensions
|
||||
InfoProps
|
||||
}
|
||||
if err := opts.UnmarshalNext(dec, &x); err != nil {
|
||||
return err
|
||||
}
|
||||
x.Extensions.sanitize()
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
i.VendorExtensible.Extensions = x.Extensions
|
||||
i.InfoProps = x.InfoProps
|
||||
return nil
|
||||
}
|
||||
137
client/vendor/k8s.io/kube-openapi/pkg/validation/spec/items.go
generated
vendored
Normal file
137
client/vendor/k8s.io/kube-openapi/pkg/validation/spec/items.go
generated
vendored
Normal file
@@ -0,0 +1,137 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package spec
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/go-openapi/swag"
|
||||
"k8s.io/kube-openapi/pkg/internal"
|
||||
jsonv2 "k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json"
|
||||
)
|
||||
|
||||
const (
|
||||
jsonRef = "$ref"
|
||||
)
|
||||
|
||||
// SimpleSchema describe swagger simple schemas for parameters and headers
|
||||
type SimpleSchema struct {
|
||||
Type string `json:"type,omitempty"`
|
||||
Nullable bool `json:"nullable,omitempty"`
|
||||
Format string `json:"format,omitempty"`
|
||||
Items *Items `json:"items,omitempty"`
|
||||
CollectionFormat string `json:"collectionFormat,omitempty"`
|
||||
Default interface{} `json:"default,omitempty"`
|
||||
Example interface{} `json:"example,omitempty"`
|
||||
}
|
||||
|
||||
// CommonValidations describe common JSON-schema validations
|
||||
type CommonValidations struct {
|
||||
Maximum *float64 `json:"maximum,omitempty"`
|
||||
ExclusiveMaximum bool `json:"exclusiveMaximum,omitempty"`
|
||||
Minimum *float64 `json:"minimum,omitempty"`
|
||||
ExclusiveMinimum bool `json:"exclusiveMinimum,omitempty"`
|
||||
MaxLength *int64 `json:"maxLength,omitempty"`
|
||||
MinLength *int64 `json:"minLength,omitempty"`
|
||||
Pattern string `json:"pattern,omitempty"`
|
||||
MaxItems *int64 `json:"maxItems,omitempty"`
|
||||
MinItems *int64 `json:"minItems,omitempty"`
|
||||
UniqueItems bool `json:"uniqueItems,omitempty"`
|
||||
MultipleOf *float64 `json:"multipleOf,omitempty"`
|
||||
Enum []interface{} `json:"enum,omitempty"`
|
||||
}
|
||||
|
||||
// Items a limited subset of JSON-Schema's items object.
|
||||
// It is used by parameter definitions that are not located in "body".
|
||||
//
|
||||
// For more information: http://goo.gl/8us55a#items-object
|
||||
type Items struct {
|
||||
Refable
|
||||
CommonValidations
|
||||
SimpleSchema
|
||||
VendorExtensible
|
||||
}
|
||||
|
||||
// UnmarshalJSON hydrates this items instance with the data from JSON
|
||||
func (i *Items) UnmarshalJSON(data []byte) error {
|
||||
if internal.UseOptimizedJSONUnmarshaling {
|
||||
return jsonv2.Unmarshal(data, i)
|
||||
}
|
||||
|
||||
var validations CommonValidations
|
||||
if err := json.Unmarshal(data, &validations); err != nil {
|
||||
return err
|
||||
}
|
||||
var ref Refable
|
||||
if err := json.Unmarshal(data, &ref); err != nil {
|
||||
return err
|
||||
}
|
||||
var simpleSchema SimpleSchema
|
||||
if err := json.Unmarshal(data, &simpleSchema); err != nil {
|
||||
return err
|
||||
}
|
||||
var vendorExtensible VendorExtensible
|
||||
if err := json.Unmarshal(data, &vendorExtensible); err != nil {
|
||||
return err
|
||||
}
|
||||
i.Refable = ref
|
||||
i.CommonValidations = validations
|
||||
i.SimpleSchema = simpleSchema
|
||||
i.VendorExtensible = vendorExtensible
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *Items) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) error {
|
||||
var x struct {
|
||||
CommonValidations
|
||||
SimpleSchema
|
||||
Extensions
|
||||
}
|
||||
if err := opts.UnmarshalNext(dec, &x); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := i.Refable.Ref.fromMap(x.Extensions); err != nil {
|
||||
return err
|
||||
}
|
||||
x.Extensions.sanitize()
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
i.CommonValidations = x.CommonValidations
|
||||
i.SimpleSchema = x.SimpleSchema
|
||||
i.VendorExtensible.Extensions = x.Extensions
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON converts this items object to JSON
|
||||
func (i Items) MarshalJSON() ([]byte, error) {
|
||||
b1, err := json.Marshal(i.CommonValidations)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(i.SimpleSchema)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b3, err := json.Marshal(i.Refable)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b4, err := json.Marshal(i.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return swag.ConcatJSON(b4, b3, b1, b2), nil
|
||||
}
|
||||
23
client/vendor/k8s.io/kube-openapi/pkg/validation/spec/license.go
generated
vendored
Normal file
23
client/vendor/k8s.io/kube-openapi/pkg/validation/spec/license.go
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package spec
|
||||
|
||||
// License information for the exposed API.
|
||||
//
|
||||
// For more information: http://goo.gl/8us55a#licenseObject
|
||||
type License struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
URL string `json:"url,omitempty"`
|
||||
}
|
||||
120
client/vendor/k8s.io/kube-openapi/pkg/validation/spec/operation.go
generated
vendored
Normal file
120
client/vendor/k8s.io/kube-openapi/pkg/validation/spec/operation.go
generated
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package spec
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/go-openapi/swag"
|
||||
"k8s.io/kube-openapi/pkg/internal"
|
||||
jsonv2 "k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json"
|
||||
)
|
||||
|
||||
// OperationProps describes an operation
|
||||
//
|
||||
// NOTES:
|
||||
// - schemes, when present must be from [http, https, ws, wss]: see validate
|
||||
// - Security is handled as a special case: see MarshalJSON function
|
||||
type OperationProps struct {
|
||||
Description string `json:"description,omitempty"`
|
||||
Consumes []string `json:"consumes,omitempty"`
|
||||
Produces []string `json:"produces,omitempty"`
|
||||
Schemes []string `json:"schemes,omitempty"`
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
Summary string `json:"summary,omitempty"`
|
||||
ExternalDocs *ExternalDocumentation `json:"externalDocs,omitempty"`
|
||||
ID string `json:"operationId,omitempty"`
|
||||
Deprecated bool `json:"deprecated,omitempty"`
|
||||
Security []map[string][]string `json:"security,omitempty"`
|
||||
Parameters []Parameter `json:"parameters,omitempty"`
|
||||
Responses *Responses `json:"responses,omitempty"`
|
||||
}
|
||||
|
||||
// MarshalJSON takes care of serializing operation properties to JSON
|
||||
//
|
||||
// We use a custom marhaller here to handle a special cases related to
|
||||
// the Security field. We need to preserve zero length slice
|
||||
// while omitting the field when the value is nil/unset.
|
||||
func (op OperationProps) MarshalJSON() ([]byte, error) {
|
||||
type Alias OperationProps
|
||||
if op.Security == nil {
|
||||
return json.Marshal(&struct {
|
||||
Security []map[string][]string `json:"security,omitempty"`
|
||||
*Alias
|
||||
}{
|
||||
Security: op.Security,
|
||||
Alias: (*Alias)(&op),
|
||||
})
|
||||
}
|
||||
return json.Marshal(&struct {
|
||||
Security []map[string][]string `json:"security"`
|
||||
*Alias
|
||||
}{
|
||||
Security: op.Security,
|
||||
Alias: (*Alias)(&op),
|
||||
})
|
||||
}
|
||||
|
||||
// Operation describes a single API operation on a path.
|
||||
//
|
||||
// For more information: http://goo.gl/8us55a#operationObject
|
||||
type Operation struct {
|
||||
VendorExtensible
|
||||
OperationProps
|
||||
}
|
||||
|
||||
// UnmarshalJSON hydrates this items instance with the data from JSON
|
||||
func (o *Operation) UnmarshalJSON(data []byte) error {
|
||||
if internal.UseOptimizedJSONUnmarshaling {
|
||||
return jsonv2.Unmarshal(data, o)
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(data, &o.OperationProps); err != nil {
|
||||
return err
|
||||
}
|
||||
return json.Unmarshal(data, &o.VendorExtensible)
|
||||
}
|
||||
|
||||
func (o *Operation) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) error {
|
||||
type OperationPropsNoMethods OperationProps // strip MarshalJSON method
|
||||
var x struct {
|
||||
Extensions
|
||||
OperationPropsNoMethods
|
||||
}
|
||||
if err := opts.UnmarshalNext(dec, &x); err != nil {
|
||||
return err
|
||||
}
|
||||
x.Extensions.sanitize()
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
o.VendorExtensible.Extensions = x.Extensions
|
||||
o.OperationProps = OperationProps(x.OperationPropsNoMethods)
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON converts this items object to JSON
|
||||
func (o Operation) MarshalJSON() ([]byte, error) {
|
||||
b1, err := json.Marshal(o.OperationProps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(o.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
concated := swag.ConcatJSON(b1, b2)
|
||||
return concated, nil
|
||||
}
|
||||
146
client/vendor/k8s.io/kube-openapi/pkg/validation/spec/parameter.go
generated
vendored
Normal file
146
client/vendor/k8s.io/kube-openapi/pkg/validation/spec/parameter.go
generated
vendored
Normal file
@@ -0,0 +1,146 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package spec
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/go-openapi/swag"
|
||||
"k8s.io/kube-openapi/pkg/internal"
|
||||
jsonv2 "k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json"
|
||||
)
|
||||
|
||||
// ParamProps describes the specific attributes of an operation parameter
|
||||
//
|
||||
// NOTE:
|
||||
// - Schema is defined when "in" == "body": see validate
|
||||
// - AllowEmptyValue is allowed where "in" == "query" || "formData"
|
||||
type ParamProps struct {
|
||||
Description string `json:"description,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
In string `json:"in,omitempty"`
|
||||
Required bool `json:"required,omitempty"`
|
||||
Schema *Schema `json:"schema,omitempty"`
|
||||
AllowEmptyValue bool `json:"allowEmptyValue,omitempty"`
|
||||
}
|
||||
|
||||
// Parameter a unique parameter is defined by a combination of a [name](#parameterName) and [location](#parameterIn).
|
||||
//
|
||||
// There are five possible parameter types.
|
||||
// * Path - Used together with [Path Templating](#pathTemplating), where the parameter value is actually part
|
||||
//
|
||||
// of the operation's URL. This does not include the host or base path of the API. For example, in `/items/{itemId}`,
|
||||
// the path parameter is `itemId`.
|
||||
//
|
||||
// * Query - Parameters that are appended to the URL. For example, in `/items?id=###`, the query parameter is `id`.
|
||||
// * Header - Custom headers that are expected as part of the request.
|
||||
// * Body - The payload that's appended to the HTTP request. Since there can only be one payload, there can only be
|
||||
//
|
||||
// _one_ body parameter. The name of the body parameter has no effect on the parameter itself and is used for
|
||||
// documentation purposes only. Since Form parameters are also in the payload, body and form parameters cannot exist
|
||||
// together for the same operation.
|
||||
//
|
||||
// * Form - Used to describe the payload of an HTTP request when either `application/x-www-form-urlencoded` or
|
||||
//
|
||||
// `multipart/form-data` are used as the content type of the request (in Swagger's definition,
|
||||
// the [`consumes`](#operationConsumes) property of an operation). This is the only parameter type that can be used
|
||||
// to send files, thus supporting the `file` type. Since form parameters are sent in the payload, they cannot be
|
||||
// declared together with a body parameter for the same operation. Form parameters have a different format based on
|
||||
// the content-type used (for further details, consult http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4).
|
||||
// * `application/x-www-form-urlencoded` - Similar to the format of Query parameters but as a payload.
|
||||
// For example, `foo=1&bar=swagger` - both `foo` and `bar` are form parameters. This is normally used for simple
|
||||
// parameters that are being transferred.
|
||||
// * `multipart/form-data` - each parameter takes a section in the payload with an internal header.
|
||||
// For example, for the header `Content-Disposition: form-data; name="submit-name"` the name of the parameter is
|
||||
// `submit-name`. This type of form parameters is more commonly used for file transfers.
|
||||
//
|
||||
// For more information: http://goo.gl/8us55a#parameterObject
|
||||
type Parameter struct {
|
||||
Refable
|
||||
CommonValidations
|
||||
SimpleSchema
|
||||
VendorExtensible
|
||||
ParamProps
|
||||
}
|
||||
|
||||
// UnmarshalJSON hydrates this items instance with the data from JSON
|
||||
func (p *Parameter) UnmarshalJSON(data []byte) error {
|
||||
if internal.UseOptimizedJSONUnmarshaling {
|
||||
return jsonv2.Unmarshal(data, p)
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(data, &p.CommonValidations); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &p.Refable); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &p.SimpleSchema); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &p.VendorExtensible); err != nil {
|
||||
return err
|
||||
}
|
||||
return json.Unmarshal(data, &p.ParamProps)
|
||||
}
|
||||
|
||||
func (p *Parameter) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) error {
|
||||
var x struct {
|
||||
CommonValidations
|
||||
SimpleSchema
|
||||
Extensions
|
||||
ParamProps
|
||||
}
|
||||
if err := opts.UnmarshalNext(dec, &x); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := p.Refable.Ref.fromMap(x.Extensions); err != nil {
|
||||
return err
|
||||
}
|
||||
x.Extensions.sanitize()
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
p.CommonValidations = x.CommonValidations
|
||||
p.SimpleSchema = x.SimpleSchema
|
||||
p.VendorExtensible.Extensions = x.Extensions
|
||||
p.ParamProps = x.ParamProps
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON converts this items object to JSON
|
||||
func (p Parameter) MarshalJSON() ([]byte, error) {
|
||||
b1, err := json.Marshal(p.CommonValidations)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(p.SimpleSchema)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b3, err := json.Marshal(p.Refable)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b4, err := json.Marshal(p.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b5, err := json.Marshal(p.ParamProps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return swag.ConcatJSON(b3, b1, b2, b4, b5), nil
|
||||
}
|
||||
105
client/vendor/k8s.io/kube-openapi/pkg/validation/spec/path_item.go
generated
vendored
Normal file
105
client/vendor/k8s.io/kube-openapi/pkg/validation/spec/path_item.go
generated
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package spec
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/go-openapi/swag"
|
||||
"k8s.io/kube-openapi/pkg/internal"
|
||||
jsonv2 "k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json"
|
||||
)
|
||||
|
||||
// PathItemProps the path item specific properties
|
||||
type PathItemProps struct {
|
||||
Get *Operation `json:"get,omitempty"`
|
||||
Put *Operation `json:"put,omitempty"`
|
||||
Post *Operation `json:"post,omitempty"`
|
||||
Delete *Operation `json:"delete,omitempty"`
|
||||
Options *Operation `json:"options,omitempty"`
|
||||
Head *Operation `json:"head,omitempty"`
|
||||
Patch *Operation `json:"patch,omitempty"`
|
||||
Parameters []Parameter `json:"parameters,omitempty"`
|
||||
}
|
||||
|
||||
// PathItem describes the operations available on a single path.
|
||||
// A Path Item may be empty, due to [ACL constraints](http://goo.gl/8us55a#securityFiltering).
|
||||
// The path itself is still exposed to the documentation viewer but they will
|
||||
// not know which operations and parameters are available.
|
||||
//
|
||||
// For more information: http://goo.gl/8us55a#pathItemObject
|
||||
type PathItem struct {
|
||||
Refable
|
||||
VendorExtensible
|
||||
PathItemProps
|
||||
}
|
||||
|
||||
// UnmarshalJSON hydrates this items instance with the data from JSON
|
||||
func (p *PathItem) UnmarshalJSON(data []byte) error {
|
||||
if internal.UseOptimizedJSONUnmarshaling {
|
||||
return jsonv2.Unmarshal(data, p)
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(data, &p.Refable); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &p.VendorExtensible); err != nil {
|
||||
return err
|
||||
}
|
||||
return json.Unmarshal(data, &p.PathItemProps)
|
||||
}
|
||||
|
||||
func (p *PathItem) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) error {
|
||||
var x struct {
|
||||
Extensions
|
||||
PathItemProps
|
||||
}
|
||||
|
||||
if err := opts.UnmarshalNext(dec, &x); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p.Extensions = x.Extensions
|
||||
p.PathItemProps = x.PathItemProps
|
||||
|
||||
if err := p.Refable.Ref.fromMap(p.Extensions); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p.Extensions.sanitize()
|
||||
if len(p.Extensions) == 0 {
|
||||
p.Extensions = nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON converts this items object to JSON
|
||||
func (p PathItem) MarshalJSON() ([]byte, error) {
|
||||
b3, err := json.Marshal(p.Refable)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b4, err := json.Marshal(p.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b5, err := json.Marshal(p.PathItemProps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
concated := swag.ConcatJSON(b3, b4, b5)
|
||||
return concated, nil
|
||||
}
|
||||
144
client/vendor/k8s.io/kube-openapi/pkg/validation/spec/paths.go
generated
vendored
Normal file
144
client/vendor/k8s.io/kube-openapi/pkg/validation/spec/paths.go
generated
vendored
Normal file
@@ -0,0 +1,144 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package spec
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/go-openapi/swag"
|
||||
"k8s.io/kube-openapi/pkg/internal"
|
||||
jsonv2 "k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json"
|
||||
)
|
||||
|
||||
// Paths holds the relative paths to the individual endpoints.
|
||||
// The path is appended to the [`basePath`](http://goo.gl/8us55a#swaggerBasePath) in order
|
||||
// to construct the full URL.
|
||||
// The Paths may be empty, due to [ACL constraints](http://goo.gl/8us55a#securityFiltering).
|
||||
//
|
||||
// For more information: http://goo.gl/8us55a#pathsObject
|
||||
type Paths struct {
|
||||
VendorExtensible
|
||||
Paths map[string]PathItem `json:"-"` // custom serializer to flatten this, each entry must start with "/"
|
||||
}
|
||||
|
||||
// UnmarshalJSON hydrates this items instance with the data from JSON
|
||||
func (p *Paths) UnmarshalJSON(data []byte) error {
|
||||
if internal.UseOptimizedJSONUnmarshaling {
|
||||
return jsonv2.Unmarshal(data, p)
|
||||
}
|
||||
|
||||
var res map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &res); err != nil {
|
||||
return err
|
||||
}
|
||||
for k, v := range res {
|
||||
if strings.HasPrefix(strings.ToLower(k), "x-") {
|
||||
if p.Extensions == nil {
|
||||
p.Extensions = make(map[string]interface{})
|
||||
}
|
||||
var d interface{}
|
||||
if err := json.Unmarshal(v, &d); err != nil {
|
||||
return err
|
||||
}
|
||||
p.Extensions[k] = d
|
||||
}
|
||||
if strings.HasPrefix(k, "/") {
|
||||
if p.Paths == nil {
|
||||
p.Paths = make(map[string]PathItem)
|
||||
}
|
||||
var pi PathItem
|
||||
if err := json.Unmarshal(v, &pi); err != nil {
|
||||
return err
|
||||
}
|
||||
p.Paths[k] = pi
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Paths) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) error {
|
||||
tok, err := dec.ReadToken()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var ext any
|
||||
var pi PathItem
|
||||
switch k := tok.Kind(); k {
|
||||
case 'n':
|
||||
return nil // noop
|
||||
case '{':
|
||||
for {
|
||||
tok, err := dec.ReadToken()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if tok.Kind() == '}' {
|
||||
return nil
|
||||
}
|
||||
|
||||
switch k := tok.String(); {
|
||||
case isExtensionKey(k):
|
||||
ext = nil
|
||||
if err := opts.UnmarshalNext(dec, &ext); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if p.Extensions == nil {
|
||||
p.Extensions = make(map[string]any)
|
||||
}
|
||||
p.Extensions[k] = ext
|
||||
case len(k) > 0 && k[0] == '/':
|
||||
pi = PathItem{}
|
||||
if err := opts.UnmarshalNext(dec, &pi); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if p.Paths == nil {
|
||||
p.Paths = make(map[string]PathItem)
|
||||
}
|
||||
p.Paths[k] = pi
|
||||
default:
|
||||
_, err := dec.ReadValue() // skip value
|
||||
return err
|
||||
}
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unknown JSON kind: %v", k)
|
||||
}
|
||||
}
|
||||
|
||||
// MarshalJSON converts this items object to JSON
|
||||
func (p Paths) MarshalJSON() ([]byte, error) {
|
||||
b1, err := json.Marshal(p.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pths := make(map[string]PathItem)
|
||||
for k, v := range p.Paths {
|
||||
if strings.HasPrefix(k, "/") {
|
||||
pths[k] = v
|
||||
}
|
||||
}
|
||||
b2, err := json.Marshal(pths)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
concated := swag.ConcatJSON(b1, b2)
|
||||
return concated, nil
|
||||
}
|
||||
167
client/vendor/k8s.io/kube-openapi/pkg/validation/spec/ref.go
generated
vendored
Normal file
167
client/vendor/k8s.io/kube-openapi/pkg/validation/spec/ref.go
generated
vendored
Normal file
@@ -0,0 +1,167 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package spec
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/go-openapi/jsonreference"
|
||||
)
|
||||
|
||||
// Refable is a struct for things that accept a $ref property
|
||||
type Refable struct {
|
||||
Ref Ref
|
||||
}
|
||||
|
||||
// MarshalJSON marshals the ref to json
|
||||
func (r Refable) MarshalJSON() ([]byte, error) {
|
||||
return r.Ref.MarshalJSON()
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshalss the ref from json
|
||||
func (r *Refable) UnmarshalJSON(d []byte) error {
|
||||
return json.Unmarshal(d, &r.Ref)
|
||||
}
|
||||
|
||||
// Ref represents a json reference that is potentially resolved
|
||||
type Ref struct {
|
||||
jsonreference.Ref
|
||||
}
|
||||
|
||||
// RemoteURI gets the remote uri part of the ref
|
||||
func (r *Ref) RemoteURI() string {
|
||||
if r.String() == "" {
|
||||
return r.String()
|
||||
}
|
||||
|
||||
u := *r.GetURL()
|
||||
u.Fragment = ""
|
||||
return u.String()
|
||||
}
|
||||
|
||||
// IsValidURI returns true when the url the ref points to can be found
|
||||
func (r *Ref) IsValidURI(basepaths ...string) bool {
|
||||
if r.String() == "" {
|
||||
return true
|
||||
}
|
||||
|
||||
v := r.RemoteURI()
|
||||
if v == "" {
|
||||
return true
|
||||
}
|
||||
|
||||
if r.HasFullURL {
|
||||
rr, err := http.Get(v)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return rr.StatusCode/100 == 2
|
||||
}
|
||||
|
||||
if !(r.HasFileScheme || r.HasFullFilePath || r.HasURLPathOnly) {
|
||||
return false
|
||||
}
|
||||
|
||||
// check for local file
|
||||
pth := v
|
||||
if r.HasURLPathOnly {
|
||||
base := "."
|
||||
if len(basepaths) > 0 {
|
||||
base = filepath.Dir(filepath.Join(basepaths...))
|
||||
}
|
||||
p, e := filepath.Abs(filepath.ToSlash(filepath.Join(base, pth)))
|
||||
if e != nil {
|
||||
return false
|
||||
}
|
||||
pth = p
|
||||
}
|
||||
|
||||
fi, err := os.Stat(filepath.ToSlash(pth))
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return !fi.IsDir()
|
||||
}
|
||||
|
||||
// Inherits creates a new reference from a parent and a child
|
||||
// If the child cannot inherit from the parent, an error is returned
|
||||
func (r *Ref) Inherits(child Ref) (*Ref, error) {
|
||||
ref, err := r.Ref.Inherits(child.Ref)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Ref{Ref: *ref}, nil
|
||||
}
|
||||
|
||||
// NewRef creates a new instance of a ref object
|
||||
// returns an error when the reference uri is an invalid uri
|
||||
func NewRef(refURI string) (Ref, error) {
|
||||
ref, err := jsonreference.New(refURI)
|
||||
if err != nil {
|
||||
return Ref{}, err
|
||||
}
|
||||
return Ref{Ref: ref}, nil
|
||||
}
|
||||
|
||||
// MustCreateRef creates a ref object but panics when refURI is invalid.
|
||||
// Use the NewRef method for a version that returns an error.
|
||||
func MustCreateRef(refURI string) Ref {
|
||||
return Ref{Ref: jsonreference.MustCreateRef(refURI)}
|
||||
}
|
||||
|
||||
// MarshalJSON marshals this ref into a JSON object
|
||||
func (r Ref) MarshalJSON() ([]byte, error) {
|
||||
str := r.String()
|
||||
if str == "" {
|
||||
if r.IsRoot() {
|
||||
return []byte(`{"$ref":""}`), nil
|
||||
}
|
||||
return []byte("{}"), nil
|
||||
}
|
||||
v := map[string]interface{}{"$ref": str}
|
||||
return json.Marshal(v)
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshals this ref from a JSON object
|
||||
func (r *Ref) UnmarshalJSON(d []byte) error {
|
||||
var v map[string]interface{}
|
||||
if err := json.Unmarshal(d, &v); err != nil {
|
||||
return err
|
||||
}
|
||||
return r.fromMap(v)
|
||||
}
|
||||
|
||||
func (r *Ref) fromMap(v map[string]interface{}) error {
|
||||
if v == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if vv, ok := v["$ref"]; ok {
|
||||
if str, ok := vv.(string); ok {
|
||||
ref, err := jsonreference.New(str)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*r = Ref{Ref: ref}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
113
client/vendor/k8s.io/kube-openapi/pkg/validation/spec/response.go
generated
vendored
Normal file
113
client/vendor/k8s.io/kube-openapi/pkg/validation/spec/response.go
generated
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package spec
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/go-openapi/swag"
|
||||
"k8s.io/kube-openapi/pkg/internal"
|
||||
jsonv2 "k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json"
|
||||
)
|
||||
|
||||
// ResponseProps properties specific to a response
|
||||
type ResponseProps struct {
|
||||
Description string `json:"description,omitempty"`
|
||||
Schema *Schema `json:"schema,omitempty"`
|
||||
Headers map[string]Header `json:"headers,omitempty"`
|
||||
Examples map[string]interface{} `json:"examples,omitempty"`
|
||||
}
|
||||
|
||||
// Response describes a single response from an API Operation.
|
||||
//
|
||||
// For more information: http://goo.gl/8us55a#responseObject
|
||||
type Response struct {
|
||||
Refable
|
||||
ResponseProps
|
||||
VendorExtensible
|
||||
}
|
||||
|
||||
// UnmarshalJSON hydrates this items instance with the data from JSON
|
||||
func (r *Response) UnmarshalJSON(data []byte) error {
|
||||
if internal.UseOptimizedJSONUnmarshaling {
|
||||
return jsonv2.Unmarshal(data, r)
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(data, &r.ResponseProps); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &r.Refable); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &r.VendorExtensible); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Response) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) error {
|
||||
var x struct {
|
||||
ResponseProps
|
||||
Extensions
|
||||
}
|
||||
|
||||
if err := opts.UnmarshalNext(dec, &x); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
r.Extensions = x.Extensions
|
||||
r.ResponseProps = x.ResponseProps
|
||||
|
||||
if err := r.Refable.Ref.fromMap(r.Extensions); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
r.Extensions.sanitize()
|
||||
if len(r.Extensions) == 0 {
|
||||
r.Extensions = nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON converts this items object to JSON
|
||||
func (r Response) MarshalJSON() ([]byte, error) {
|
||||
b1, err := json.Marshal(r.ResponseProps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(r.Refable)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b3, err := json.Marshal(r.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return swag.ConcatJSON(b1, b2, b3), nil
|
||||
}
|
||||
|
||||
// NewResponse creates a new response instance
|
||||
func NewResponse() *Response {
|
||||
return new(Response)
|
||||
}
|
||||
|
||||
// ResponseRef creates a response as a json reference
|
||||
func ResponseRef(url string) *Response {
|
||||
resp := NewResponse()
|
||||
resp.Ref = MustCreateRef(url)
|
||||
return resp
|
||||
}
|
||||
186
client/vendor/k8s.io/kube-openapi/pkg/validation/spec/responses.go
generated
vendored
Normal file
186
client/vendor/k8s.io/kube-openapi/pkg/validation/spec/responses.go
generated
vendored
Normal file
@@ -0,0 +1,186 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package spec
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
|
||||
"github.com/go-openapi/swag"
|
||||
"k8s.io/kube-openapi/pkg/internal"
|
||||
jsonv2 "k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json"
|
||||
)
|
||||
|
||||
// Responses is a container for the expected responses of an operation.
|
||||
// The container maps a HTTP response code to the expected response.
|
||||
// It is not expected from the documentation to necessarily cover all possible HTTP response codes,
|
||||
// since they may not be known in advance. However, it is expected from the documentation to cover
|
||||
// a successful operation response and any known errors.
|
||||
//
|
||||
// The `default` can be used a default response object for all HTTP codes that are not covered
|
||||
// individually by the specification.
|
||||
//
|
||||
// The `Responses Object` MUST contain at least one response code, and it SHOULD be the response
|
||||
// for a successful operation call.
|
||||
//
|
||||
// For more information: http://goo.gl/8us55a#responsesObject
|
||||
type Responses struct {
|
||||
VendorExtensible
|
||||
ResponsesProps
|
||||
}
|
||||
|
||||
// UnmarshalJSON hydrates this items instance with the data from JSON
|
||||
func (r *Responses) UnmarshalJSON(data []byte) error {
|
||||
if internal.UseOptimizedJSONUnmarshaling {
|
||||
return jsonv2.Unmarshal(data, r)
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(data, &r.ResponsesProps); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &r.VendorExtensible); err != nil {
|
||||
return err
|
||||
}
|
||||
if reflect.DeepEqual(ResponsesProps{}, r.ResponsesProps) {
|
||||
r.ResponsesProps = ResponsesProps{}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON converts this items object to JSON
|
||||
func (r Responses) MarshalJSON() ([]byte, error) {
|
||||
b1, err := json.Marshal(r.ResponsesProps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(r.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
concated := swag.ConcatJSON(b1, b2)
|
||||
return concated, nil
|
||||
}
|
||||
|
||||
// ResponsesProps describes all responses for an operation.
|
||||
// It tells what is the default response and maps all responses with a
|
||||
// HTTP status code.
|
||||
type ResponsesProps struct {
|
||||
Default *Response
|
||||
StatusCodeResponses map[int]Response
|
||||
}
|
||||
|
||||
// MarshalJSON marshals responses as JSON
|
||||
func (r ResponsesProps) MarshalJSON() ([]byte, error) {
|
||||
toser := map[string]Response{}
|
||||
if r.Default != nil {
|
||||
toser["default"] = *r.Default
|
||||
}
|
||||
for k, v := range r.StatusCodeResponses {
|
||||
toser[strconv.Itoa(k)] = v
|
||||
}
|
||||
return json.Marshal(toser)
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshals responses from JSON
|
||||
func (r *ResponsesProps) UnmarshalJSON(data []byte) error {
|
||||
if internal.UseOptimizedJSONUnmarshaling {
|
||||
return jsonv2.Unmarshal(data, r)
|
||||
}
|
||||
var res map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &res); err != nil {
|
||||
return err
|
||||
}
|
||||
if v, ok := res["default"]; ok {
|
||||
value := Response{}
|
||||
if err := json.Unmarshal(v, &value); err != nil {
|
||||
return err
|
||||
}
|
||||
r.Default = &value
|
||||
delete(res, "default")
|
||||
}
|
||||
for k, v := range res {
|
||||
// Take all integral keys
|
||||
if nk, err := strconv.Atoi(k); err == nil {
|
||||
if r.StatusCodeResponses == nil {
|
||||
r.StatusCodeResponses = map[int]Response{}
|
||||
}
|
||||
value := Response{}
|
||||
if err := json.Unmarshal(v, &value); err != nil {
|
||||
return err
|
||||
}
|
||||
r.StatusCodeResponses[nk] = value
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Responses) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) (err error) {
|
||||
tok, err := dec.ReadToken()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var ext any
|
||||
var resp Response
|
||||
switch k := tok.Kind(); k {
|
||||
case 'n':
|
||||
return nil // noop
|
||||
case '{':
|
||||
for {
|
||||
tok, err := dec.ReadToken()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if tok.Kind() == '}' {
|
||||
return nil
|
||||
}
|
||||
switch k := tok.String(); {
|
||||
case isExtensionKey(k):
|
||||
ext = nil
|
||||
if err := opts.UnmarshalNext(dec, &ext); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if r.Extensions == nil {
|
||||
r.Extensions = make(map[string]any)
|
||||
}
|
||||
r.Extensions[k] = ext
|
||||
case k == "default":
|
||||
resp = Response{}
|
||||
if err := opts.UnmarshalNext(dec, &resp); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
respCopy := resp
|
||||
r.ResponsesProps.Default = &respCopy
|
||||
default:
|
||||
if nk, err := strconv.Atoi(k); err == nil {
|
||||
resp = Response{}
|
||||
if err := opts.UnmarshalNext(dec, &resp); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if r.StatusCodeResponses == nil {
|
||||
r.StatusCodeResponses = map[int]Response{}
|
||||
}
|
||||
r.StatusCodeResponses[nk] = resp
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unknown JSON kind: %v", k)
|
||||
}
|
||||
}
|
||||
554
client/vendor/k8s.io/kube-openapi/pkg/validation/spec/schema.go
generated
vendored
Normal file
554
client/vendor/k8s.io/kube-openapi/pkg/validation/spec/schema.go
generated
vendored
Normal file
@@ -0,0 +1,554 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package spec
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/go-openapi/swag"
|
||||
"k8s.io/kube-openapi/pkg/internal"
|
||||
jsonv2 "k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json"
|
||||
)
|
||||
|
||||
// BooleanProperty creates a boolean property
|
||||
func BooleanProperty() *Schema {
|
||||
return &Schema{SchemaProps: SchemaProps{Type: []string{"boolean"}}}
|
||||
}
|
||||
|
||||
// BoolProperty creates a boolean property
|
||||
func BoolProperty() *Schema { return BooleanProperty() }
|
||||
|
||||
// StringProperty creates a string property
|
||||
func StringProperty() *Schema {
|
||||
return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}}}
|
||||
}
|
||||
|
||||
// CharProperty creates a string property
|
||||
func CharProperty() *Schema {
|
||||
return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}}}
|
||||
}
|
||||
|
||||
// Float64Property creates a float64/double property
|
||||
func Float64Property() *Schema {
|
||||
return &Schema{SchemaProps: SchemaProps{Type: []string{"number"}, Format: "double"}}
|
||||
}
|
||||
|
||||
// Float32Property creates a float32/float property
|
||||
func Float32Property() *Schema {
|
||||
return &Schema{SchemaProps: SchemaProps{Type: []string{"number"}, Format: "float"}}
|
||||
}
|
||||
|
||||
// Int8Property creates an int8 property
|
||||
func Int8Property() *Schema {
|
||||
return &Schema{SchemaProps: SchemaProps{Type: []string{"integer"}, Format: "int8"}}
|
||||
}
|
||||
|
||||
// Int16Property creates an int16 property
|
||||
func Int16Property() *Schema {
|
||||
return &Schema{SchemaProps: SchemaProps{Type: []string{"integer"}, Format: "int16"}}
|
||||
}
|
||||
|
||||
// Int32Property creates an int32 property
|
||||
func Int32Property() *Schema {
|
||||
return &Schema{SchemaProps: SchemaProps{Type: []string{"integer"}, Format: "int32"}}
|
||||
}
|
||||
|
||||
// Int64Property creates an int64 property
|
||||
func Int64Property() *Schema {
|
||||
return &Schema{SchemaProps: SchemaProps{Type: []string{"integer"}, Format: "int64"}}
|
||||
}
|
||||
|
||||
// StrFmtProperty creates a property for the named string format
|
||||
func StrFmtProperty(format string) *Schema {
|
||||
return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}, Format: format}}
|
||||
}
|
||||
|
||||
// DateProperty creates a date property
|
||||
func DateProperty() *Schema {
|
||||
return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}, Format: "date"}}
|
||||
}
|
||||
|
||||
// DateTimeProperty creates a date time property
|
||||
func DateTimeProperty() *Schema {
|
||||
return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}, Format: "date-time"}}
|
||||
}
|
||||
|
||||
// MapProperty creates a map property
|
||||
func MapProperty(property *Schema) *Schema {
|
||||
return &Schema{SchemaProps: SchemaProps{Type: []string{"object"},
|
||||
AdditionalProperties: &SchemaOrBool{Allows: true, Schema: property}}}
|
||||
}
|
||||
|
||||
// RefProperty creates a ref property
|
||||
func RefProperty(name string) *Schema {
|
||||
return &Schema{SchemaProps: SchemaProps{Ref: MustCreateRef(name)}}
|
||||
}
|
||||
|
||||
// RefSchema creates a ref property
|
||||
func RefSchema(name string) *Schema {
|
||||
return &Schema{SchemaProps: SchemaProps{Ref: MustCreateRef(name)}}
|
||||
}
|
||||
|
||||
// ArrayProperty creates an array property
|
||||
func ArrayProperty(items *Schema) *Schema {
|
||||
if items == nil {
|
||||
return &Schema{SchemaProps: SchemaProps{Type: []string{"array"}}}
|
||||
}
|
||||
return &Schema{SchemaProps: SchemaProps{Items: &SchemaOrArray{Schema: items}, Type: []string{"array"}}}
|
||||
}
|
||||
|
||||
// ComposedSchema creates a schema with allOf
|
||||
func ComposedSchema(schemas ...Schema) *Schema {
|
||||
s := new(Schema)
|
||||
s.AllOf = schemas
|
||||
return s
|
||||
}
|
||||
|
||||
// SchemaURL represents a schema url
|
||||
type SchemaURL string
|
||||
|
||||
// MarshalJSON marshal this to JSON
|
||||
func (r SchemaURL) MarshalJSON() ([]byte, error) {
|
||||
if r == "" {
|
||||
return []byte("{}"), nil
|
||||
}
|
||||
v := map[string]interface{}{"$schema": string(r)}
|
||||
return json.Marshal(v)
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshal this from JSON
|
||||
func (r *SchemaURL) UnmarshalJSON(data []byte) error {
|
||||
var v map[string]interface{}
|
||||
if err := json.Unmarshal(data, &v); err != nil {
|
||||
return err
|
||||
}
|
||||
return r.fromMap(v)
|
||||
}
|
||||
|
||||
func (r *SchemaURL) fromMap(v map[string]interface{}) error {
|
||||
if v == nil {
|
||||
return nil
|
||||
}
|
||||
if vv, ok := v["$schema"]; ok {
|
||||
if str, ok := vv.(string); ok {
|
||||
u, err := url.Parse(str)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*r = SchemaURL(u.String())
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SchemaProps describes a JSON schema (draft 4)
|
||||
type SchemaProps struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Ref Ref `json:"-"`
|
||||
Schema SchemaURL `json:"-"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Type StringOrArray `json:"type,omitempty"`
|
||||
Nullable bool `json:"nullable,omitempty"`
|
||||
Format string `json:"format,omitempty"`
|
||||
Title string `json:"title,omitempty"`
|
||||
Default interface{} `json:"default,omitempty"`
|
||||
Maximum *float64 `json:"maximum,omitempty"`
|
||||
ExclusiveMaximum bool `json:"exclusiveMaximum,omitempty"`
|
||||
Minimum *float64 `json:"minimum,omitempty"`
|
||||
ExclusiveMinimum bool `json:"exclusiveMinimum,omitempty"`
|
||||
MaxLength *int64 `json:"maxLength,omitempty"`
|
||||
MinLength *int64 `json:"minLength,omitempty"`
|
||||
Pattern string `json:"pattern,omitempty"`
|
||||
MaxItems *int64 `json:"maxItems,omitempty"`
|
||||
MinItems *int64 `json:"minItems,omitempty"`
|
||||
UniqueItems bool `json:"uniqueItems,omitempty"`
|
||||
MultipleOf *float64 `json:"multipleOf,omitempty"`
|
||||
Enum []interface{} `json:"enum,omitempty"`
|
||||
MaxProperties *int64 `json:"maxProperties,omitempty"`
|
||||
MinProperties *int64 `json:"minProperties,omitempty"`
|
||||
Required []string `json:"required,omitempty"`
|
||||
Items *SchemaOrArray `json:"items,omitempty"`
|
||||
AllOf []Schema `json:"allOf,omitempty"`
|
||||
OneOf []Schema `json:"oneOf,omitempty"`
|
||||
AnyOf []Schema `json:"anyOf,omitempty"`
|
||||
Not *Schema `json:"not,omitempty"`
|
||||
Properties map[string]Schema `json:"properties,omitempty"`
|
||||
AdditionalProperties *SchemaOrBool `json:"additionalProperties,omitempty"`
|
||||
PatternProperties map[string]Schema `json:"patternProperties,omitempty"`
|
||||
Dependencies Dependencies `json:"dependencies,omitempty"`
|
||||
AdditionalItems *SchemaOrBool `json:"additionalItems,omitempty"`
|
||||
Definitions Definitions `json:"definitions,omitempty"`
|
||||
}
|
||||
|
||||
// SwaggerSchemaProps are additional properties supported by swagger schemas, but not JSON-schema (draft 4)
|
||||
type SwaggerSchemaProps struct {
|
||||
Discriminator string `json:"discriminator,omitempty"`
|
||||
ReadOnly bool `json:"readOnly,omitempty"`
|
||||
ExternalDocs *ExternalDocumentation `json:"externalDocs,omitempty"`
|
||||
Example interface{} `json:"example,omitempty"`
|
||||
}
|
||||
|
||||
// Schema the schema object allows the definition of input and output data types.
|
||||
// These types can be objects, but also primitives and arrays.
|
||||
// This object is based on the [JSON Schema Specification Draft 4](http://json-schema.org/)
|
||||
// and uses a predefined subset of it.
|
||||
// On top of this subset, there are extensions provided by this specification to allow for more complete documentation.
|
||||
//
|
||||
// For more information: http://goo.gl/8us55a#schemaObject
|
||||
type Schema struct {
|
||||
VendorExtensible
|
||||
SchemaProps
|
||||
SwaggerSchemaProps
|
||||
ExtraProps map[string]interface{} `json:"-"`
|
||||
}
|
||||
|
||||
// WithID sets the id for this schema, allows for chaining
|
||||
func (s *Schema) WithID(id string) *Schema {
|
||||
s.ID = id
|
||||
return s
|
||||
}
|
||||
|
||||
// WithTitle sets the title for this schema, allows for chaining
|
||||
func (s *Schema) WithTitle(title string) *Schema {
|
||||
s.Title = title
|
||||
return s
|
||||
}
|
||||
|
||||
// WithDescription sets the description for this schema, allows for chaining
|
||||
func (s *Schema) WithDescription(description string) *Schema {
|
||||
s.Description = description
|
||||
return s
|
||||
}
|
||||
|
||||
// WithProperties sets the properties for this schema
|
||||
func (s *Schema) WithProperties(schemas map[string]Schema) *Schema {
|
||||
s.Properties = schemas
|
||||
return s
|
||||
}
|
||||
|
||||
// SetProperty sets a property on this schema
|
||||
func (s *Schema) SetProperty(name string, schema Schema) *Schema {
|
||||
if s.Properties == nil {
|
||||
s.Properties = make(map[string]Schema)
|
||||
}
|
||||
s.Properties[name] = schema
|
||||
return s
|
||||
}
|
||||
|
||||
// WithAllOf sets the all of property
|
||||
func (s *Schema) WithAllOf(schemas ...Schema) *Schema {
|
||||
s.AllOf = schemas
|
||||
return s
|
||||
}
|
||||
|
||||
// WithMaxProperties sets the max number of properties an object can have
|
||||
func (s *Schema) WithMaxProperties(max int64) *Schema {
|
||||
s.MaxProperties = &max
|
||||
return s
|
||||
}
|
||||
|
||||
// WithMinProperties sets the min number of properties an object must have
|
||||
func (s *Schema) WithMinProperties(min int64) *Schema {
|
||||
s.MinProperties = &min
|
||||
return s
|
||||
}
|
||||
|
||||
// Typed sets the type of this schema for a single value item
|
||||
func (s *Schema) Typed(tpe, format string) *Schema {
|
||||
s.Type = []string{tpe}
|
||||
s.Format = format
|
||||
return s
|
||||
}
|
||||
|
||||
// AddType adds a type with potential format to the types for this schema
|
||||
func (s *Schema) AddType(tpe, format string) *Schema {
|
||||
s.Type = append(s.Type, tpe)
|
||||
if format != "" {
|
||||
s.Format = format
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// AsNullable flags this schema as nullable.
|
||||
func (s *Schema) AsNullable() *Schema {
|
||||
s.Nullable = true
|
||||
return s
|
||||
}
|
||||
|
||||
// CollectionOf a fluent builder method for an array parameter
|
||||
func (s *Schema) CollectionOf(items Schema) *Schema {
|
||||
s.Type = []string{jsonArray}
|
||||
s.Items = &SchemaOrArray{Schema: &items}
|
||||
return s
|
||||
}
|
||||
|
||||
// WithDefault sets the default value on this parameter
|
||||
func (s *Schema) WithDefault(defaultValue interface{}) *Schema {
|
||||
s.Default = defaultValue
|
||||
return s
|
||||
}
|
||||
|
||||
// WithRequired flags this parameter as required
|
||||
func (s *Schema) WithRequired(items ...string) *Schema {
|
||||
s.Required = items
|
||||
return s
|
||||
}
|
||||
|
||||
// AddRequired adds field names to the required properties array
|
||||
func (s *Schema) AddRequired(items ...string) *Schema {
|
||||
s.Required = append(s.Required, items...)
|
||||
return s
|
||||
}
|
||||
|
||||
// WithMaxLength sets a max length value
|
||||
func (s *Schema) WithMaxLength(max int64) *Schema {
|
||||
s.MaxLength = &max
|
||||
return s
|
||||
}
|
||||
|
||||
// WithMinLength sets a min length value
|
||||
func (s *Schema) WithMinLength(min int64) *Schema {
|
||||
s.MinLength = &min
|
||||
return s
|
||||
}
|
||||
|
||||
// WithPattern sets a pattern value
|
||||
func (s *Schema) WithPattern(pattern string) *Schema {
|
||||
s.Pattern = pattern
|
||||
return s
|
||||
}
|
||||
|
||||
// WithMultipleOf sets a multiple of value
|
||||
func (s *Schema) WithMultipleOf(number float64) *Schema {
|
||||
s.MultipleOf = &number
|
||||
return s
|
||||
}
|
||||
|
||||
// WithMaximum sets a maximum number value
|
||||
func (s *Schema) WithMaximum(max float64, exclusive bool) *Schema {
|
||||
s.Maximum = &max
|
||||
s.ExclusiveMaximum = exclusive
|
||||
return s
|
||||
}
|
||||
|
||||
// WithMinimum sets a minimum number value
|
||||
func (s *Schema) WithMinimum(min float64, exclusive bool) *Schema {
|
||||
s.Minimum = &min
|
||||
s.ExclusiveMinimum = exclusive
|
||||
return s
|
||||
}
|
||||
|
||||
// WithEnum sets a the enum values (replace)
|
||||
func (s *Schema) WithEnum(values ...interface{}) *Schema {
|
||||
s.Enum = append([]interface{}{}, values...)
|
||||
return s
|
||||
}
|
||||
|
||||
// WithMaxItems sets the max items
|
||||
func (s *Schema) WithMaxItems(size int64) *Schema {
|
||||
s.MaxItems = &size
|
||||
return s
|
||||
}
|
||||
|
||||
// WithMinItems sets the min items
|
||||
func (s *Schema) WithMinItems(size int64) *Schema {
|
||||
s.MinItems = &size
|
||||
return s
|
||||
}
|
||||
|
||||
// UniqueValues dictates that this array can only have unique items
|
||||
func (s *Schema) UniqueValues() *Schema {
|
||||
s.UniqueItems = true
|
||||
return s
|
||||
}
|
||||
|
||||
// AllowDuplicates this array can have duplicates
|
||||
func (s *Schema) AllowDuplicates() *Schema {
|
||||
s.UniqueItems = false
|
||||
return s
|
||||
}
|
||||
|
||||
// AddToAllOf adds a schema to the allOf property
|
||||
func (s *Schema) AddToAllOf(schemas ...Schema) *Schema {
|
||||
s.AllOf = append(s.AllOf, schemas...)
|
||||
return s
|
||||
}
|
||||
|
||||
// WithDiscriminator sets the name of the discriminator field
|
||||
func (s *Schema) WithDiscriminator(discriminator string) *Schema {
|
||||
s.Discriminator = discriminator
|
||||
return s
|
||||
}
|
||||
|
||||
// AsReadOnly flags this schema as readonly
|
||||
func (s *Schema) AsReadOnly() *Schema {
|
||||
s.ReadOnly = true
|
||||
return s
|
||||
}
|
||||
|
||||
// AsWritable flags this schema as writeable (not read-only)
|
||||
func (s *Schema) AsWritable() *Schema {
|
||||
s.ReadOnly = false
|
||||
return s
|
||||
}
|
||||
|
||||
// WithExample sets the example for this schema
|
||||
func (s *Schema) WithExample(example interface{}) *Schema {
|
||||
s.Example = example
|
||||
return s
|
||||
}
|
||||
|
||||
// WithExternalDocs sets/removes the external docs for/from this schema.
|
||||
// When you pass empty strings as params the external documents will be removed.
|
||||
// When you pass non-empty string as one value then those values will be used on the external docs object.
|
||||
// So when you pass a non-empty description, you should also pass the url and vice versa.
|
||||
func (s *Schema) WithExternalDocs(description, url string) *Schema {
|
||||
if description == "" && url == "" {
|
||||
s.ExternalDocs = nil
|
||||
return s
|
||||
}
|
||||
|
||||
if s.ExternalDocs == nil {
|
||||
s.ExternalDocs = &ExternalDocumentation{}
|
||||
}
|
||||
s.ExternalDocs.Description = description
|
||||
s.ExternalDocs.URL = url
|
||||
return s
|
||||
}
|
||||
|
||||
// MarshalJSON marshal this to JSON
|
||||
func (s Schema) MarshalJSON() ([]byte, error) {
|
||||
b1, err := json.Marshal(s.SchemaProps)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("schema props %v", err)
|
||||
}
|
||||
b2, err := json.Marshal(s.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("vendor props %v", err)
|
||||
}
|
||||
b3, err := s.Ref.MarshalJSON()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ref prop %v", err)
|
||||
}
|
||||
b4, err := s.Schema.MarshalJSON()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("schema prop %v", err)
|
||||
}
|
||||
b5, err := json.Marshal(s.SwaggerSchemaProps)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("common validations %v", err)
|
||||
}
|
||||
var b6 []byte
|
||||
if s.ExtraProps != nil {
|
||||
jj, err := json.Marshal(s.ExtraProps)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("extra props %v", err)
|
||||
}
|
||||
b6 = jj
|
||||
}
|
||||
return swag.ConcatJSON(b1, b2, b3, b4, b5, b6), nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON marshal this from JSON
|
||||
func (s *Schema) UnmarshalJSON(data []byte) error {
|
||||
if internal.UseOptimizedJSONUnmarshaling {
|
||||
return jsonv2.Unmarshal(data, s)
|
||||
}
|
||||
|
||||
props := struct {
|
||||
SchemaProps
|
||||
SwaggerSchemaProps
|
||||
}{}
|
||||
if err := json.Unmarshal(data, &props); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sch := Schema{
|
||||
SchemaProps: props.SchemaProps,
|
||||
SwaggerSchemaProps: props.SwaggerSchemaProps,
|
||||
}
|
||||
|
||||
var d map[string]interface{}
|
||||
if err := json.Unmarshal(data, &d); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_ = sch.Ref.fromMap(d)
|
||||
_ = sch.Schema.fromMap(d)
|
||||
|
||||
delete(d, "$ref")
|
||||
delete(d, "$schema")
|
||||
for _, pn := range swag.DefaultJSONNameProvider.GetJSONNames(s) {
|
||||
delete(d, pn)
|
||||
}
|
||||
|
||||
for k, vv := range d {
|
||||
lk := strings.ToLower(k)
|
||||
if strings.HasPrefix(lk, "x-") {
|
||||
if sch.Extensions == nil {
|
||||
sch.Extensions = map[string]interface{}{}
|
||||
}
|
||||
sch.Extensions[k] = vv
|
||||
continue
|
||||
}
|
||||
if sch.ExtraProps == nil {
|
||||
sch.ExtraProps = map[string]interface{}{}
|
||||
}
|
||||
sch.ExtraProps[k] = vv
|
||||
}
|
||||
|
||||
*s = sch
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Schema) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) error {
|
||||
var x struct {
|
||||
Extensions
|
||||
SchemaProps
|
||||
SwaggerSchemaProps
|
||||
}
|
||||
if err := opts.UnmarshalNext(dec, &x); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := x.Ref.fromMap(x.Extensions); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := x.Schema.fromMap(x.Extensions); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
delete(x.Extensions, "$ref")
|
||||
delete(x.Extensions, "$schema")
|
||||
|
||||
for _, pn := range swag.DefaultJSONNameProvider.GetJSONNames(s) {
|
||||
delete(x.Extensions, pn)
|
||||
}
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
|
||||
s.ExtraProps = x.Extensions.sanitizeWithExtra()
|
||||
s.VendorExtensible.Extensions = x.Extensions
|
||||
s.SchemaProps = x.SchemaProps
|
||||
s.SwaggerSchemaProps = x.SwaggerSchemaProps
|
||||
return nil
|
||||
}
|
||||
82
client/vendor/k8s.io/kube-openapi/pkg/validation/spec/security_scheme.go
generated
vendored
Normal file
82
client/vendor/k8s.io/kube-openapi/pkg/validation/spec/security_scheme.go
generated
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package spec
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/go-openapi/swag"
|
||||
jsonv2 "k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json"
|
||||
)
|
||||
|
||||
// SecuritySchemeProps describes a swagger security scheme in the securityDefinitions section
|
||||
type SecuritySchemeProps struct {
|
||||
Description string `json:"description,omitempty"`
|
||||
Type string `json:"type"`
|
||||
Name string `json:"name,omitempty"` // api key
|
||||
In string `json:"in,omitempty"` // api key
|
||||
Flow string `json:"flow,omitempty"` // oauth2
|
||||
AuthorizationURL string `json:"authorizationUrl,omitempty"` // oauth2
|
||||
TokenURL string `json:"tokenUrl,omitempty"` // oauth2
|
||||
Scopes map[string]string `json:"scopes,omitempty"` // oauth2
|
||||
}
|
||||
|
||||
// SecurityScheme allows the definition of a security scheme that can be used by the operations.
|
||||
// Supported schemes are basic authentication, an API key (either as a header or as a query parameter)
|
||||
// and OAuth2's common flows (implicit, password, application and access code).
|
||||
//
|
||||
// For more information: http://goo.gl/8us55a#securitySchemeObject
|
||||
type SecurityScheme struct {
|
||||
VendorExtensible
|
||||
SecuritySchemeProps
|
||||
}
|
||||
|
||||
// MarshalJSON marshal this to JSON
|
||||
func (s SecurityScheme) MarshalJSON() ([]byte, error) {
|
||||
b1, err := json.Marshal(s.SecuritySchemeProps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(s.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return swag.ConcatJSON(b1, b2), nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON marshal this from JSON
|
||||
func (s *SecurityScheme) UnmarshalJSON(data []byte) error {
|
||||
if err := json.Unmarshal(data, &s.SecuritySchemeProps); err != nil {
|
||||
return err
|
||||
}
|
||||
return json.Unmarshal(data, &s.VendorExtensible)
|
||||
}
|
||||
|
||||
func (s *SecurityScheme) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) error {
|
||||
var x struct {
|
||||
Extensions
|
||||
SecuritySchemeProps
|
||||
}
|
||||
if err := opts.UnmarshalNext(dec, &x); err != nil {
|
||||
return err
|
||||
}
|
||||
x.Extensions.sanitize()
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
s.VendorExtensible.Extensions = x.Extensions
|
||||
s.SecuritySchemeProps = x.SecuritySchemeProps
|
||||
return nil
|
||||
}
|
||||
393
client/vendor/k8s.io/kube-openapi/pkg/validation/spec/swagger.go
generated
vendored
Normal file
393
client/vendor/k8s.io/kube-openapi/pkg/validation/spec/swagger.go
generated
vendored
Normal file
@@ -0,0 +1,393 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package spec
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/go-openapi/swag"
|
||||
"k8s.io/kube-openapi/pkg/internal"
|
||||
jsonv2 "k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json"
|
||||
)
|
||||
|
||||
// Swagger this is the root document object for the API specification.
|
||||
// It combines what previously was the Resource Listing and API Declaration (version 1.2 and earlier)
|
||||
// together into one document.
|
||||
//
|
||||
// For more information: http://goo.gl/8us55a#swagger-object-
|
||||
type Swagger struct {
|
||||
VendorExtensible
|
||||
SwaggerProps
|
||||
}
|
||||
|
||||
// MarshalJSON marshals this swagger structure to json
|
||||
func (s Swagger) MarshalJSON() ([]byte, error) {
|
||||
b1, err := json.Marshal(s.SwaggerProps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(s.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return swag.ConcatJSON(b1, b2), nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshals a swagger spec from json
|
||||
func (s *Swagger) UnmarshalJSON(data []byte) error {
|
||||
if internal.UseOptimizedJSONUnmarshaling {
|
||||
return jsonv2.Unmarshal(data, s)
|
||||
}
|
||||
|
||||
var sw Swagger
|
||||
if err := json.Unmarshal(data, &sw.SwaggerProps); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &sw.VendorExtensible); err != nil {
|
||||
return err
|
||||
}
|
||||
*s = sw
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Swagger) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) error {
|
||||
// Note: If you're willing to make breaking changes, it is possible to
|
||||
// optimize this and other usages of this pattern:
|
||||
// https://github.com/kubernetes/kube-openapi/pull/319#discussion_r983165948
|
||||
var x struct {
|
||||
Extensions
|
||||
SwaggerProps
|
||||
}
|
||||
|
||||
if err := opts.UnmarshalNext(dec, &x); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.Extensions = x.Extensions
|
||||
s.SwaggerProps = x.SwaggerProps
|
||||
|
||||
s.Extensions.sanitize()
|
||||
if len(s.Extensions) == 0 {
|
||||
s.Extensions = nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SwaggerProps captures the top-level properties of an Api specification
|
||||
//
|
||||
// NOTE: validation rules
|
||||
// - the scheme, when present must be from [http, https, ws, wss]
|
||||
// - BasePath must start with a leading "/"
|
||||
// - Paths is required
|
||||
type SwaggerProps struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Consumes []string `json:"consumes,omitempty"`
|
||||
Produces []string `json:"produces,omitempty"`
|
||||
Schemes []string `json:"schemes,omitempty"`
|
||||
Swagger string `json:"swagger,omitempty"`
|
||||
Info *Info `json:"info,omitempty"`
|
||||
Host string `json:"host,omitempty"`
|
||||
BasePath string `json:"basePath,omitempty"`
|
||||
Paths *Paths `json:"paths"`
|
||||
Definitions Definitions `json:"definitions,omitempty"`
|
||||
Parameters map[string]Parameter `json:"parameters,omitempty"`
|
||||
Responses map[string]Response `json:"responses,omitempty"`
|
||||
SecurityDefinitions SecurityDefinitions `json:"securityDefinitions,omitempty"`
|
||||
Security []map[string][]string `json:"security,omitempty"`
|
||||
Tags []Tag `json:"tags,omitempty"`
|
||||
ExternalDocs *ExternalDocumentation `json:"externalDocs,omitempty"`
|
||||
}
|
||||
|
||||
// Dependencies represent a dependencies property
|
||||
type Dependencies map[string]SchemaOrStringArray
|
||||
|
||||
// SchemaOrBool represents a schema or boolean value, is biased towards true for the boolean property
|
||||
type SchemaOrBool struct {
|
||||
Allows bool
|
||||
Schema *Schema
|
||||
}
|
||||
|
||||
var jsTrue = []byte("true")
|
||||
var jsFalse = []byte("false")
|
||||
|
||||
// MarshalJSON convert this object to JSON
|
||||
func (s SchemaOrBool) MarshalJSON() ([]byte, error) {
|
||||
if s.Schema != nil {
|
||||
return json.Marshal(s.Schema)
|
||||
}
|
||||
|
||||
if s.Schema == nil && !s.Allows {
|
||||
return jsFalse, nil
|
||||
}
|
||||
return jsTrue, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON converts this bool or schema object from a JSON structure
|
||||
func (s *SchemaOrBool) UnmarshalJSON(data []byte) error {
|
||||
if internal.UseOptimizedJSONUnmarshaling {
|
||||
return jsonv2.Unmarshal(data, s)
|
||||
}
|
||||
|
||||
var nw SchemaOrBool
|
||||
if len(data) >= 4 {
|
||||
if data[0] == '{' {
|
||||
var sch Schema
|
||||
if err := json.Unmarshal(data, &sch); err != nil {
|
||||
return err
|
||||
}
|
||||
nw.Schema = &sch
|
||||
}
|
||||
nw.Allows = !(data[0] == 'f' && data[1] == 'a' && data[2] == 'l' && data[3] == 's' && data[4] == 'e')
|
||||
}
|
||||
*s = nw
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SchemaOrBool) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) error {
|
||||
switch k := dec.PeekKind(); k {
|
||||
case '{':
|
||||
err := opts.UnmarshalNext(dec, &s.Schema)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.Allows = true
|
||||
return nil
|
||||
case 't', 'f':
|
||||
err := opts.UnmarshalNext(dec, &s.Allows)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("expected object or bool, not '%v'", k.String())
|
||||
}
|
||||
}
|
||||
|
||||
// SchemaOrStringArray represents a schema or a string array
|
||||
type SchemaOrStringArray struct {
|
||||
Schema *Schema
|
||||
Property []string
|
||||
}
|
||||
|
||||
// MarshalJSON converts this schema object or array into JSON structure
|
||||
func (s SchemaOrStringArray) MarshalJSON() ([]byte, error) {
|
||||
if len(s.Property) > 0 {
|
||||
return json.Marshal(s.Property)
|
||||
}
|
||||
if s.Schema != nil {
|
||||
return json.Marshal(s.Schema)
|
||||
}
|
||||
return []byte("null"), nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON converts this schema object or array from a JSON structure
|
||||
func (s *SchemaOrStringArray) UnmarshalJSON(data []byte) error {
|
||||
if internal.UseOptimizedJSONUnmarshaling {
|
||||
return jsonv2.Unmarshal(data, s)
|
||||
}
|
||||
|
||||
var first byte
|
||||
if len(data) > 1 {
|
||||
first = data[0]
|
||||
}
|
||||
var nw SchemaOrStringArray
|
||||
if first == '{' {
|
||||
var sch Schema
|
||||
if err := json.Unmarshal(data, &sch); err != nil {
|
||||
return err
|
||||
}
|
||||
nw.Schema = &sch
|
||||
}
|
||||
if first == '[' {
|
||||
if err := json.Unmarshal(data, &nw.Property); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
*s = nw
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SchemaOrStringArray) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) error {
|
||||
switch dec.PeekKind() {
|
||||
case '{':
|
||||
return opts.UnmarshalNext(dec, &s.Schema)
|
||||
case '[':
|
||||
return opts.UnmarshalNext(dec, &s.Property)
|
||||
default:
|
||||
_, err := dec.ReadValue()
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Definitions contains the models explicitly defined in this spec
|
||||
// An object to hold data types that can be consumed and produced by operations.
|
||||
// These data types can be primitives, arrays or models.
|
||||
//
|
||||
// For more information: http://goo.gl/8us55a#definitionsObject
|
||||
type Definitions map[string]Schema
|
||||
|
||||
// SecurityDefinitions a declaration of the security schemes available to be used in the specification.
|
||||
// This does not enforce the security schemes on the operations and only serves to provide
|
||||
// the relevant details for each scheme.
|
||||
//
|
||||
// For more information: http://goo.gl/8us55a#securityDefinitionsObject
|
||||
type SecurityDefinitions map[string]*SecurityScheme
|
||||
|
||||
// StringOrArray represents a value that can either be a string
|
||||
// or an array of strings. Mainly here for serialization purposes
|
||||
type StringOrArray []string
|
||||
|
||||
// Contains returns true when the value is contained in the slice
|
||||
func (s StringOrArray) Contains(value string) bool {
|
||||
for _, str := range s {
|
||||
if str == value {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshals this string or array object from a JSON array or JSON string
|
||||
func (s *StringOrArray) UnmarshalJSON(data []byte) error {
|
||||
if internal.UseOptimizedJSONUnmarshaling {
|
||||
return jsonv2.Unmarshal(data, s)
|
||||
}
|
||||
|
||||
var first byte
|
||||
if len(data) > 1 {
|
||||
first = data[0]
|
||||
}
|
||||
|
||||
if first == '[' {
|
||||
var parsed []string
|
||||
if err := json.Unmarshal(data, &parsed); err != nil {
|
||||
return err
|
||||
}
|
||||
*s = StringOrArray(parsed)
|
||||
return nil
|
||||
}
|
||||
|
||||
var single interface{}
|
||||
if err := json.Unmarshal(data, &single); err != nil {
|
||||
return err
|
||||
}
|
||||
if single == nil {
|
||||
return nil
|
||||
}
|
||||
switch v := single.(type) {
|
||||
case string:
|
||||
*s = StringOrArray([]string{v})
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("only string or array is allowed, not %T", single)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *StringOrArray) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) error {
|
||||
switch k := dec.PeekKind(); k {
|
||||
case '[':
|
||||
*s = StringOrArray{}
|
||||
return opts.UnmarshalNext(dec, (*[]string)(s))
|
||||
case '"':
|
||||
*s = StringOrArray{""}
|
||||
return opts.UnmarshalNext(dec, &(*s)[0])
|
||||
case 'n':
|
||||
// Throw out null token
|
||||
_, _ = dec.ReadToken()
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("expected string or array, not '%v'", k.String())
|
||||
}
|
||||
}
|
||||
|
||||
// MarshalJSON converts this string or array to a JSON array or JSON string
|
||||
func (s StringOrArray) MarshalJSON() ([]byte, error) {
|
||||
if len(s) == 1 {
|
||||
return json.Marshal([]string(s)[0])
|
||||
}
|
||||
return json.Marshal([]string(s))
|
||||
}
|
||||
|
||||
// SchemaOrArray represents a value that can either be a Schema
|
||||
// or an array of Schema. Mainly here for serialization purposes
|
||||
type SchemaOrArray struct {
|
||||
Schema *Schema
|
||||
Schemas []Schema
|
||||
}
|
||||
|
||||
// Len returns the number of schemas in this property
|
||||
func (s SchemaOrArray) Len() int {
|
||||
if s.Schema != nil {
|
||||
return 1
|
||||
}
|
||||
return len(s.Schemas)
|
||||
}
|
||||
|
||||
// ContainsType returns true when one of the schemas is of the specified type
|
||||
func (s *SchemaOrArray) ContainsType(name string) bool {
|
||||
if s.Schema != nil {
|
||||
return s.Schema.Type != nil && s.Schema.Type.Contains(name)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// MarshalJSON converts this schema object or array into JSON structure
|
||||
func (s SchemaOrArray) MarshalJSON() ([]byte, error) {
|
||||
if len(s.Schemas) > 0 {
|
||||
return json.Marshal(s.Schemas)
|
||||
}
|
||||
return json.Marshal(s.Schema)
|
||||
}
|
||||
|
||||
// UnmarshalJSON converts this schema object or array from a JSON structure
|
||||
func (s *SchemaOrArray) UnmarshalJSON(data []byte) error {
|
||||
if internal.UseOptimizedJSONUnmarshaling {
|
||||
return jsonv2.Unmarshal(data, s)
|
||||
}
|
||||
|
||||
var nw SchemaOrArray
|
||||
var first byte
|
||||
if len(data) > 1 {
|
||||
first = data[0]
|
||||
}
|
||||
if first == '{' {
|
||||
var sch Schema
|
||||
if err := json.Unmarshal(data, &sch); err != nil {
|
||||
return err
|
||||
}
|
||||
nw.Schema = &sch
|
||||
}
|
||||
if first == '[' {
|
||||
if err := json.Unmarshal(data, &nw.Schemas); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
*s = nw
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SchemaOrArray) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) error {
|
||||
switch dec.PeekKind() {
|
||||
case '{':
|
||||
return opts.UnmarshalNext(dec, &s.Schema)
|
||||
case '[':
|
||||
return opts.UnmarshalNext(dec, &s.Schemas)
|
||||
default:
|
||||
_, err := dec.ReadValue()
|
||||
return err
|
||||
}
|
||||
}
|
||||
82
client/vendor/k8s.io/kube-openapi/pkg/validation/spec/tag.go
generated
vendored
Normal file
82
client/vendor/k8s.io/kube-openapi/pkg/validation/spec/tag.go
generated
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package spec
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/go-openapi/swag"
|
||||
"k8s.io/kube-openapi/pkg/internal"
|
||||
jsonv2 "k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json"
|
||||
)
|
||||
|
||||
// TagProps describe a tag entry in the top level tags section of a swagger spec
|
||||
type TagProps struct {
|
||||
Description string `json:"description,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
ExternalDocs *ExternalDocumentation `json:"externalDocs,omitempty"`
|
||||
}
|
||||
|
||||
// Tag allows adding meta data to a single tag that is used by the
|
||||
// [Operation Object](http://goo.gl/8us55a#operationObject).
|
||||
// It is not mandatory to have a Tag Object per tag used there.
|
||||
//
|
||||
// For more information: http://goo.gl/8us55a#tagObject
|
||||
type Tag struct {
|
||||
VendorExtensible
|
||||
TagProps
|
||||
}
|
||||
|
||||
// MarshalJSON marshal this to JSON
|
||||
func (t Tag) MarshalJSON() ([]byte, error) {
|
||||
b1, err := json.Marshal(t.TagProps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(t.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return swag.ConcatJSON(b1, b2), nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON marshal this from JSON
|
||||
func (t *Tag) UnmarshalJSON(data []byte) error {
|
||||
if internal.UseOptimizedJSONUnmarshaling {
|
||||
return jsonv2.Unmarshal(data, t)
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(data, &t.TagProps); err != nil {
|
||||
return err
|
||||
}
|
||||
return json.Unmarshal(data, &t.VendorExtensible)
|
||||
}
|
||||
|
||||
func (t *Tag) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) error {
|
||||
var x struct {
|
||||
Extensions
|
||||
TagProps
|
||||
}
|
||||
if err := opts.UnmarshalNext(dec, &x); err != nil {
|
||||
return err
|
||||
}
|
||||
x.Extensions.sanitize()
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
t.VendorExtensible.Extensions = x.Extensions
|
||||
t.TagProps = x.TagProps
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user