diff --git a/processor/processor.go b/processor/processor.go index 6956539..cc25b64 100644 --- a/processor/processor.go +++ b/processor/processor.go @@ -64,6 +64,8 @@ func Process(config *config.Config) ([]types.GroupVersionDetails, error) { } p.types.InlineTypes(p.propagateReference) + p.types.PropagateMarkers() + p.parseMarkers() // collect references between types for typeName, refs := range p.references { @@ -494,3 +496,54 @@ func mkRegistry() (*markers.Registry, error) { return registry, nil } + +func parseMarkers(markers markers.MarkerValues) (string, []string) { + defaultValue := "" + validation := []string{} + + markerNames := make([]string, 0, len(markers)) + for name := range markers { + markerNames = append(markerNames, name) + } + sort.Strings(markerNames) + + for _, name := range markerNames { + value := markers[name][len(markers[name])-1] + + if strings.HasPrefix(name, "kubebuilder:validation:") { + name := strings.TrimPrefix(name, "kubebuilder:validation:") + + switch name { + case "Pattern": + value = fmt.Sprintf("`%s`", value) + // FIXME: XValidation currently removed due to being long and difficult to read. + // E.g. "XValidation: {self.page < 200 Please start a new book.}" + case "XValidation": + continue + } + validation = append(validation, fmt.Sprintf("%s: %v", name, value)) + } + + if name == "kubebuilder:default" { + if value, ok := value.(crdmarkers.Default); ok { + defaultValue = fmt.Sprintf("%v", value.Value) + if strings.HasPrefix(defaultValue, "map[") { + defaultValue = strings.TrimPrefix(defaultValue, "map[") + defaultValue = strings.TrimSuffix(defaultValue, "]") + defaultValue = fmt.Sprintf("{ %s }", defaultValue) + } + } + } + } + + return defaultValue, validation +} + +func (p *processor) parseMarkers() { + for _, t := range p.types { + t.Default, t.Validation = parseMarkers(t.Markers) + for _, f := range t.Fields { + f.Default, f.Validation = parseMarkers(f.Markers) + } + } +} diff --git a/renderer/markdown.go b/renderer/markdown.go index ac41bde..34b2f88 100644 --- a/renderer/markdown.go +++ b/renderer/markdown.go @@ -79,6 +79,7 @@ func (m *MarkdownRenderer) ToFuncMap() template.FuncMap { "ShouldRenderType": m.ShouldRenderType, "TypeID": m.TypeID, "RenderFieldDoc": m.RenderFieldDoc, + "RenderDefault": m.RenderDefault, } } @@ -138,6 +139,13 @@ func (m *MarkdownRenderer) RenderExternalLink(link, text string) string { return fmt.Sprintf("[%s](%s)", text, link) } +func (m *MarkdownRenderer) RenderDefault(text string) string { + return strings.NewReplacer( + "{", "\\{", + "}", "\\}", + ).Replace(text) +} + func (m *MarkdownRenderer) RenderGVLink(gv types.GroupVersionDetails) string { return m.RenderLocalLink(gv.GroupVersionString()) } diff --git a/templates/asciidoctor/type.tpl b/templates/asciidoctor/type.tpl index 78eae46..7b72b29 100644 --- a/templates/asciidoctor/type.tpl +++ b/templates/asciidoctor/type.tpl @@ -9,6 +9,13 @@ {{ $type.Doc }} +{{ if $type.Validation -}} +.Validation: +{{- range $type.Validation }} +- {{ . }} +{{- end }} +{{- end }} + {{ if $type.References -}} .Appears In: **** @@ -19,16 +26,17 @@ {{- end }} {{ if $type.Members -}} -[cols="25a,75a", options="header"] +[cols="20a,50a,15a,15a", options="header"] |=== -| Field | Description +| Field | Description | Default | Validation {{ if $type.GVK -}} -| *`apiVersion`* __string__ | `{{ $type.GVK.Group }}/{{ $type.GVK.Version }}` -| *`kind`* __string__ | `{{ $type.GVK.Kind }}` +| *`apiVersion`* __string__ | `{{ $type.GVK.Group }}/{{ $type.GVK.Version }}` | | +| *`kind`* __string__ | `{{ $type.GVK.Kind }}` | | {{ end -}} {{ range $type.Members -}} -| *`{{ .Name }}`* __{{ asciidocRenderType .Type }}__ | {{ template "type_members" . }} +| *`{{ .Name }}`* __{{ asciidocRenderType .Type }}__ | {{ template "type_members" . }} | {{ .Default }} | {{ range .Validation -}} {{ . }} + +{{ end }} {{ end -}} |=== {{ end -}} diff --git a/templates/markdown/type.tpl b/templates/markdown/type.tpl index 9f61b19..405a32a 100644 --- a/templates/markdown/type.tpl +++ b/templates/markdown/type.tpl @@ -8,6 +8,13 @@ {{ $type.Doc }} +{{ if $type.Validation -}} +_Validation:_ +{{- range $type.Validation }} +- {{ . }} +{{- end }} +{{- end }} + {{ if $type.References -}} _Appears in:_ {{- range $type.SortedReferences }} @@ -16,15 +23,15 @@ _Appears in:_ {{- end }} {{ if $type.Members -}} -| Field | Description | -| --- | --- | +| Field | Description | Default | Validation | +| --- | --- | --- | --- | {{ if $type.GVK -}} -| `apiVersion` _string_ | `{{ $type.GVK.Group }}/{{ $type.GVK.Version }}` -| `kind` _string_ | `{{ $type.GVK.Kind }}` +| `apiVersion` _string_ | `{{ $type.GVK.Group }}/{{ $type.GVK.Version }}` | | | +| `kind` _string_ | `{{ $type.GVK.Kind }}` | | | {{ end -}} {{ range $type.Members -}} -| `{{ .Name }}` _{{ markdownRenderType .Type }}_ | {{ template "type_members" . }} | +| `{{ .Name }}` _{{ markdownRenderType .Type }}_ | {{ template "type_members" . }} | {{ markdownRenderDefault .Default }} | {{ range .Validation -}} {{ . }}
{{ end }} | {{ end -}} {{ end -}} diff --git a/test/api/v1/guestbook_types.go b/test/api/v1/guestbook_types.go index 6db3a12..c142576 100644 --- a/test/api/v1/guestbook_types.go +++ b/test/api/v1/guestbook_types.go @@ -54,6 +54,9 @@ type EmbeddedX struct { // Underlying tests that Underlying1's underlying type is Underlying2 instead of string. // +kubebuilder:object:root=true type Underlying struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + // +kubebuilder:default="b" A Underlying1 `json:"a,omitempty"` } @@ -62,40 +65,51 @@ type Underlying struct { type Underlying1 Underlying2 // Underlying2 is a string alias +// +kubebuilder:validation:MaxLength=10 type Underlying2 string // NOTE: Rating is placed here to ensure that it is parsed as a standalone type // before it is parsed as a struct field. // Rating is the rating provided by a guest. +// +kubebuilder:validation:Maximum=4 // +kubebuilder:validation:Minimum=1 // +kubebuilder:validation:Maximum=5 type Rating int // GuestbookSpec defines the desired state of Guestbook. +// +kubebuilder:validation:XValidation:rule="self.page < 200", message="Please start a new book." type GuestbookSpec struct { // Page indicates the page number // +kubebuilder:default=1 - Page *int `json:"page,omitempty"` + // +kubebuilder:example=3 + Page *PositiveInt `json:"page,omitempty"` // Entries contain guest book entries for the page Entries []GuestbookEntry `json:"entries,omitempty"` // Selector selects something Selector metav1.LabelSelector `json:"selector,omitempty"` // Headers contains a list of header items to include in the page + // +kubebuilder:validation:MaxItems=10 + // +kubebuilder:validation:UniqueItems=true Headers []GuestbookHeader `json:"headers,omitempty"` // CertificateRef is a reference to a secret containing a certificate CertificateRef gwapiv1b1.SecretObjectReference `json:"certificateRef"` } +// +kubebuilder:validation:Minimum=1 +type PositiveInt int + // GuestbookEntry defines an entry in a guest book. type GuestbookEntry struct { // Name of the guest (pipe | should be escaped) + // +kubebuilder:validation:MaxLength=80 Name string `json:"name,omitempty"` // Time of entry Time metav1.Time `json:"time,omitempty"` // Comment by guest. This can be a multi-line comment. // // Just like this one. + // +kubebuilder:validation:Pattern=`[a-z0-9]` Comment string `json:"comment,omitempty"` // Rating provided by the guest Rating Rating `json:"rating,omitempty"` @@ -103,9 +117,13 @@ type GuestbookEntry struct { // GuestbookStatus defines the observed state of Guestbook. type GuestbookStatus struct { - Status string `json:"status"` + // +kubebuilder:validation:Enum={OK, Error} + Status Status `json:"status"` } +// +kubebuilder:validation:Enum={OK, Unknown, Error} +type Status string + // GuestbookHeaders are strings to include at the top of a page. type GuestbookHeader string @@ -117,6 +135,7 @@ type Guestbook struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` + // +kubebuilder:default={page: 1} Spec GuestbookSpec `json:"spec,omitempty"` Status GuestbookStatus `json:"status,omitempty"` } diff --git a/test/api/v1/zz_generated.deepcopy.go b/test/api/v1/zz_generated.deepcopy.go index 642477e..fef1ace 100644 --- a/test/api/v1/zz_generated.deepcopy.go +++ b/test/api/v1/zz_generated.deepcopy.go @@ -211,7 +211,7 @@ func (in *GuestbookSpec) DeepCopyInto(out *GuestbookSpec) { *out = *in if in.Page != nil { in, out := &in.Page, &out.Page - *out = new(int) + *out = new(PositiveInt) **out = **in } if in.Entries != nil { @@ -254,3 +254,28 @@ func (in *GuestbookStatus) DeepCopy() *GuestbookStatus { in.DeepCopyInto(out) return out } + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Underlying) DeepCopyInto(out *Underlying) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Underlying. +func (in *Underlying) DeepCopy() *Underlying { + if in == nil { + return nil + } + out := new(Underlying) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Underlying) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} diff --git a/test/expected.asciidoc b/test/expected.asciidoc index 9868592..d367b2e 100644 --- a/test/expected.asciidoc +++ b/test/expected.asciidoc @@ -30,19 +30,21 @@ Package v1 contains API Schema definitions for the webapp v1 API group -[cols="25a,75a", options="header"] + + +[cols="20a,50a,15a,15a", options="header"] |=== -| Field | Description -| *`apiVersion`* __string__ | `webapp.test.k8s.elastic.co/v1` -| *`kind`* __string__ | `Embedded` +| Field | Description | Default | Validation +| *`apiVersion`* __string__ | `webapp.test.k8s.elastic.co/v1` | | +| *`kind`* __string__ | `Embedded` | | | *`metadata`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#objectmeta-v1-meta[$$ObjectMeta$$]__ | Refer to Kubernetes API documentation for fields of `metadata`. - -| *`a`* __string__ | -| *`b`* __string__ | -| *`c`* __string__ | -| *`x`* __string__ | -| *`d`* __string__ | -| *`e`* __string__ | + | | +| *`a`* __string__ | | | +| *`b`* __string__ | | | +| *`c`* __string__ | | | +| *`x`* __string__ | | | +| *`d`* __string__ | | | +| *`e`* __string__ | | | |=== @@ -53,6 +55,8 @@ Package v1 contains API Schema definitions for the webapp v1 API group + + .Appears In: **** - xref:{anchor_prefix}-github-com-elastic-crd-ref-docs-api-v1-embedded[$$Embedded$$] @@ -62,10 +66,10 @@ Package v1 contains API Schema definitions for the webapp v1 API group - xref:{anchor_prefix}-github-com-elastic-crd-ref-docs-api-v1-embedded4[$$Embedded4$$] **** -[cols="25a,75a", options="header"] +[cols="20a,50a,15a,15a", options="header"] |=== -| Field | Description -| *`x`* __string__ | +| Field | Description | Default | Validation +| *`x`* __string__ | | | |=== @@ -76,19 +80,21 @@ Package v1 contains API Schema definitions for the webapp v1 API group Guestbook is the Schema for the guestbooks API. + + .Appears In: **** - xref:{anchor_prefix}-github-com-elastic-crd-ref-docs-api-v1-guestbooklist[$$GuestbookList$$] **** -[cols="25a,75a", options="header"] +[cols="20a,50a,15a,15a", options="header"] |=== -| Field | Description -| *`apiVersion`* __string__ | `webapp.test.k8s.elastic.co/v1` -| *`kind`* __string__ | `Guestbook` +| Field | Description | Default | Validation +| *`apiVersion`* __string__ | `webapp.test.k8s.elastic.co/v1` | | +| *`kind`* __string__ | `Guestbook` | | | *`metadata`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#objectmeta-v1-meta[$$ObjectMeta$$]__ | Refer to Kubernetes API documentation for fields of `metadata`. - -| *`spec`* __xref:{anchor_prefix}-github-com-elastic-crd-ref-docs-api-v1-guestbookspec[$$GuestbookSpec$$]__ | + | | +| *`spec`* __xref:{anchor_prefix}-github-com-elastic-crd-ref-docs-api-v1-guestbookspec[$$GuestbookSpec$$]__ | | { page:1 } | |=== @@ -99,20 +105,26 @@ Guestbook is the Schema for the guestbooks API. GuestbookEntry defines an entry in a guest book. + + .Appears In: **** - xref:{anchor_prefix}-github-com-elastic-crd-ref-docs-api-v1-guestbookspec[$$GuestbookSpec$$] **** -[cols="25a,75a", options="header"] +[cols="20a,50a,15a,15a", options="header"] |=== -| Field | Description -| *`name`* __string__ | Name of the guest (pipe \| should be escaped) -| *`time`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#time-v1-meta[$$Time$$]__ | Time of entry +| Field | Description | Default | Validation +| *`name`* __string__ | Name of the guest (pipe \| should be escaped) | | MaxLength: 80 + + +| *`time`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#time-v1-meta[$$Time$$]__ | Time of entry | | | *`comment`* __string__ | Comment by guest. This can be a multi-line comment. + -Just like this one. -| *`rating`* __xref:{anchor_prefix}-github-com-elastic-crd-ref-docs-api-v1-rating[$$Rating$$]__ | Rating provided by the guest +Just like this one. | | Pattern: `[a-z0-9]` + + +| *`rating`* __xref:{anchor_prefix}-github-com-elastic-crd-ref-docs-api-v1-rating[$$Rating$$]__ | Rating provided by the guest | | Maximum: 5 + +Minimum: 1 + + |=== @@ -123,6 +135,8 @@ _Underlying type:_ _string_ GuestbookHeaders are strings to include at the top of a page. + + .Appears In: **** - xref:{anchor_prefix}-github-com-elastic-crd-ref-docs-api-v1-guestbookspec[$$GuestbookSpec$$] @@ -139,14 +153,16 @@ GuestbookList contains a list of Guestbook. -[cols="25a,75a", options="header"] + + +[cols="20a,50a,15a,15a", options="header"] |=== -| Field | Description -| *`apiVersion`* __string__ | `webapp.test.k8s.elastic.co/v1` -| *`kind`* __string__ | `GuestbookList` +| Field | Description | Default | Validation +| *`apiVersion`* __string__ | `webapp.test.k8s.elastic.co/v1` | | +| *`kind`* __string__ | `GuestbookList` | | | *`metadata`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#listmeta-v1-meta[$$ListMeta$$]__ | Refer to Kubernetes API documentation for fields of `metadata`. - -| *`items`* __xref:{anchor_prefix}-github-com-elastic-crd-ref-docs-api-v1-guestbook[$$Guestbook$$] array__ | + | | +| *`items`* __xref:{anchor_prefix}-github-com-elastic-crd-ref-docs-api-v1-guestbook[$$Guestbook$$] array__ | | | |=== @@ -157,24 +173,46 @@ GuestbookList contains a list of Guestbook. GuestbookSpec defines the desired state of Guestbook. + + .Appears In: **** - xref:{anchor_prefix}-github-com-elastic-crd-ref-docs-api-v1-guestbook[$$Guestbook$$] **** -[cols="25a,75a", options="header"] +[cols="20a,50a,15a,15a", options="header"] |=== -| Field | Description -| *`page`* __integer__ | Page indicates the page number -| *`entries`* __xref:{anchor_prefix}-github-com-elastic-crd-ref-docs-api-v1-guestbookentry[$$GuestbookEntry$$] array__ | Entries contain guest book entries for the page -| *`selector`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#labelselector-v1-meta[$$LabelSelector$$]__ | Selector selects something -| *`headers`* __xref:{anchor_prefix}-github-com-elastic-crd-ref-docs-api-v1-guestbookheader[$$GuestbookHeader$$] array__ | Headers contains a list of header items to include in the page -| *`certificateRef`* __link:https://gateway-api.sigs.k8s.io/references/spec/#gateway.networking.k8s.io/v1beta1.SecretObjectReference[$$SecretObjectReference$$]__ | CertificateRef is a reference to a secret containing a certificate +| Field | Description | Default | Validation +| *`page`* __xref:{anchor_prefix}-github-com-elastic-crd-ref-docs-api-v1-positiveint[$$PositiveInt$$]__ | Page indicates the page number | 1 | Minimum: 1 + + +| *`entries`* __xref:{anchor_prefix}-github-com-elastic-crd-ref-docs-api-v1-guestbookentry[$$GuestbookEntry$$] array__ | Entries contain guest book entries for the page | | +| *`selector`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#labelselector-v1-meta[$$LabelSelector$$]__ | Selector selects something | | +| *`headers`* __xref:{anchor_prefix}-github-com-elastic-crd-ref-docs-api-v1-guestbookheader[$$GuestbookHeader$$] array__ | Headers contains a list of header items to include in the page | | MaxItems: 10 + +UniqueItems: true + + +| *`certificateRef`* __link:https://gateway-api.sigs.k8s.io/references/spec/#gateway.networking.k8s.io/v1beta1.SecretObjectReference[$$SecretObjectReference$$]__ | CertificateRef is a reference to a secret containing a certificate | | |=== +[id="{anchor_prefix}-github-com-elastic-crd-ref-docs-api-v1-positiveint"] +==== PositiveInt + +_Underlying type:_ _integer_ + + + +.Validation: +- Minimum: 1 + +.Appears In: +**** +- xref:{anchor_prefix}-github-com-elastic-crd-ref-docs-api-v1-guestbookspec[$$GuestbookSpec$$] +**** + + + [id="{anchor_prefix}-github-com-elastic-crd-ref-docs-api-v1-rating"] ==== Rating @@ -182,6 +220,10 @@ _Underlying type:_ _integer_ Rating is the rating provided by a guest. +.Validation: +- Maximum: 5 +- Minimum: 1 + .Appears In: **** - xref:{anchor_prefix}-github-com-elastic-crd-ref-docs-api-v1-guestbookentry[$$GuestbookEntry$$] @@ -189,6 +231,8 @@ Rating is the rating provided by a guest. + + [id="{anchor_prefix}-github-com-elastic-crd-ref-docs-api-v1-underlying"] ==== Underlying @@ -198,12 +242,17 @@ Underlying tests that Underlying1's underlying type is Underlying2 instead of st -[cols="25a,75a", options="header"] + + +[cols="20a,50a,15a,15a", options="header"] |=== -| Field | Description -| *`apiVersion`* __string__ | `webapp.test.k8s.elastic.co/v1` -| *`kind`* __string__ | `Underlying` -| *`a`* __xref:{anchor_prefix}-github-com-elastic-crd-ref-docs-api-v1-underlying1[$$Underlying1$$]__ | +| Field | Description | Default | Validation +| *`apiVersion`* __string__ | `webapp.test.k8s.elastic.co/v1` | | +| *`kind`* __string__ | `Underlying` | | +| *`metadata`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#objectmeta-v1-meta[$$ObjectMeta$$]__ | Refer to Kubernetes API documentation for fields of `metadata`. + | | +| *`a`* __xref:{anchor_prefix}-github-com-elastic-crd-ref-docs-api-v1-underlying1[$$Underlying1$$]__ | | b | MaxLength: 10 + + |=== @@ -214,6 +263,9 @@ _Underlying type:_ _xref:{anchor_prefix}-github-com-elastic-crd-ref-docs-api-v1- Underlying1 has an underlying type with an underlying type +.Validation: +- MaxLength: 10 + .Appears In: **** - xref:{anchor_prefix}-github-com-elastic-crd-ref-docs-api-v1-underlying[$$Underlying$$] @@ -228,6 +280,9 @@ _Underlying type:_ _string_ Underlying2 is a string alias +.Validation: +- MaxLength: 10 + .Appears In: **** - xref:{anchor_prefix}-github-com-elastic-crd-ref-docs-api-v1-underlying1[$$Underlying1$$] diff --git a/test/expected.md b/test/expected.md index e3a0168..2b077f7 100644 --- a/test/expected.md +++ b/test/expected.md @@ -24,17 +24,19 @@ Package v1 contains API Schema definitions for the webapp v1 API group -| Field | Description | -| --- | --- | -| `apiVersion` _string_ | `webapp.test.k8s.elastic.co/v1` -| `kind` _string_ | `Embedded` -| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | -| `a` _string_ | | -| `b` _string_ | | -| `c` _string_ | | -| `x` _string_ | | -| `d` _string_ | | -| `e` _string_ | | + + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `apiVersion` _string_ | `webapp.test.k8s.elastic.co/v1` | | | +| `kind` _string_ | `Embedded` | | | +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | +| `a` _string_ | | | | +| `b` _string_ | | | | +| `c` _string_ | | | | +| `x` _string_ | | | | +| `d` _string_ | | | | +| `e` _string_ | | | | #### EmbeddedX @@ -43,6 +45,8 @@ Package v1 contains API Schema definitions for the webapp v1 API group + + _Appears in:_ - [Embedded](#embedded) - [Embedded1](#embedded1) @@ -50,9 +54,9 @@ _Appears in:_ - [Embedded3](#embedded3) - [Embedded4](#embedded4) -| Field | Description | -| --- | --- | -| `x` _string_ | | +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `x` _string_ | | | | #### Guestbook @@ -61,15 +65,17 @@ _Appears in:_ Guestbook is the Schema for the guestbooks API. + + _Appears in:_ - [GuestbookList](#guestbooklist) -| Field | Description | -| --- | --- | -| `apiVersion` _string_ | `webapp.test.k8s.elastic.co/v1` -| `kind` _string_ | `Guestbook` -| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | -| `spec` _[GuestbookSpec](#guestbookspec)_ | | +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `apiVersion` _string_ | `webapp.test.k8s.elastic.co/v1` | | | +| `kind` _string_ | `Guestbook` | | | +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | +| `spec` _[GuestbookSpec](#guestbookspec)_ | | \{ page:1 \} | | #### GuestbookEntry @@ -78,15 +84,17 @@ _Appears in:_ GuestbookEntry defines an entry in a guest book. + + _Appears in:_ - [GuestbookSpec](#guestbookspec) -| Field | Description | -| --- | --- | -| `name` _string_ | Name of the guest (pipe \| should be escaped) | -| `time` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#time-v1-meta)_ | Time of entry | -| `comment` _string_ | Comment by guest. This can be a multi-line comment.

Just like this one. | -| `rating` _[Rating](#rating)_ | Rating provided by the guest | +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `name` _string_ | Name of the guest (pipe \| should be escaped) | | MaxLength: 80
| +| `time` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#time-v1-meta)_ | Time of entry | | | +| `comment` _string_ | Comment by guest. This can be a multi-line comment.

Just like this one. | | Pattern: `[a-z0-9]`
| +| `rating` _[Rating](#rating)_ | Rating provided by the guest | | Maximum: 5
Minimum: 1
| #### GuestbookHeader @@ -95,6 +103,8 @@ _Underlying type:_ _string_ GuestbookHeaders are strings to include at the top of a page. + + _Appears in:_ - [GuestbookSpec](#guestbookspec) @@ -108,12 +118,14 @@ GuestbookList contains a list of Guestbook. -| Field | Description | -| --- | --- | -| `apiVersion` _string_ | `webapp.test.k8s.elastic.co/v1` -| `kind` _string_ | `GuestbookList` -| `metadata` _[ListMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#listmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | -| `items` _[Guestbook](#guestbook) array_ | | + + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `apiVersion` _string_ | `webapp.test.k8s.elastic.co/v1` | | | +| `kind` _string_ | `GuestbookList` | | | +| `metadata` _[ListMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#listmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | +| `items` _[Guestbook](#guestbook) array_ | | | | #### GuestbookSpec @@ -122,18 +134,34 @@ GuestbookList contains a list of Guestbook. GuestbookSpec defines the desired state of Guestbook. + + _Appears in:_ - [Guestbook](#guestbook) -| Field | Description | -| --- | --- | -| `page` _integer_ | Page indicates the page number | -| `entries` _[GuestbookEntry](#guestbookentry) array_ | Entries contain guest book entries for the page | -| `selector` _[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#labelselector-v1-meta)_ | Selector selects something | -| `headers` _[GuestbookHeader](#guestbookheader) array_ | Headers contains a list of header items to include in the page | -| `certificateRef` _[SecretObjectReference](https://gateway-api.sigs.k8s.io/references/spec/#gateway.networking.k8s.io/v1beta1.SecretObjectReference)_ | CertificateRef is a reference to a secret containing a certificate | +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `page` _[PositiveInt](#positiveint)_ | Page indicates the page number | 1 | Minimum: 1
| +| `entries` _[GuestbookEntry](#guestbookentry) array_ | Entries contain guest book entries for the page | | | +| `selector` _[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#labelselector-v1-meta)_ | Selector selects something | | | +| `headers` _[GuestbookHeader](#guestbookheader) array_ | Headers contains a list of header items to include in the page | | MaxItems: 10
UniqueItems: true
| +| `certificateRef` _[SecretObjectReference](https://gateway-api.sigs.k8s.io/references/spec/#gateway.networking.k8s.io/v1beta1.SecretObjectReference)_ | CertificateRef is a reference to a secret containing a certificate | | | + + +#### PositiveInt + +_Underlying type:_ _integer_ + + + +_Validation:_ +- Minimum: 1 + +_Appears in:_ +- [GuestbookSpec](#guestbookspec) + #### Rating @@ -142,11 +170,17 @@ _Underlying type:_ _integer_ Rating is the rating provided by a guest. +_Validation:_ +- Maximum: 5 +- Minimum: 1 + _Appears in:_ - [GuestbookEntry](#guestbookentry) + + #### Underlying @@ -155,11 +189,14 @@ Underlying tests that Underlying1's underlying type is Underlying2 instead of st -| Field | Description | -| --- | --- | -| `apiVersion` _string_ | `webapp.test.k8s.elastic.co/v1` -| `kind` _string_ | `Underlying` -| `a` _[Underlying1](#underlying1)_ | | + + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `apiVersion` _string_ | `webapp.test.k8s.elastic.co/v1` | | | +| `kind` _string_ | `Underlying` | | | +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | +| `a` _[Underlying1](#underlying1)_ | | b | MaxLength: 10
| #### Underlying1 @@ -168,6 +205,9 @@ _Underlying type:_ _[Underlying2](#underlying2)_ Underlying1 has an underlying type with an underlying type +_Validation:_ +- MaxLength: 10 + _Appears in:_ - [Underlying](#underlying) @@ -179,6 +219,9 @@ _Underlying type:_ _string_ Underlying2 is a string alias +_Validation:_ +- MaxLength: 10 + _Appears in:_ - [Underlying1](#underlying1) diff --git a/types/types.go b/types/types.go index 668c117..d030604 100644 --- a/types/types.go +++ b/types/types.go @@ -99,6 +99,8 @@ type Type struct { Name string `json:"name"` Package string `json:"package"` Doc string `json:"doc"` + Default string `json:"default"` + Validation []string `json:"validation"` Markers markers.MarkerValues `json:"markers"` GVK *schema.GroupVersionKind `json:"gvk"` Kind Kind `json:"kind"` @@ -205,6 +207,17 @@ func (t *Type) ContainsInlinedTypes() bool { // TypeMap is a map of Type elements type TypeMap map[string]*Type +// PropagateMarkers propagates markers to struct fields and certain types, from +// their underlying types. +func (types TypeMap) PropagateMarkers() { + for _, t := range types { + t.propagateMarkers() + for _, f := range t.Fields { + f.propagateMarkers() + } + } +} + func (types TypeMap) InlineTypes(propagateReference func(original *Type, additional *Type)) { // If C is inlined in B, and B is inlined in A; the fields of C are copied // into B before the fields of B is copied into A. The ideal order of @@ -247,18 +260,53 @@ func (types TypeMap) InlineTypes(propagateReference func(original *Type, additio zap.S().Warnw("Failed to inline all inlined types", "remaining", numTypesToBeInlined) } +func (t *Type) propagateMarkers() { + if t.UnderlyingType == nil { + return + } + + switch t.Kind { + case AliasKind, PointerKind: + t.UnderlyingType.propagateMarkers() + + for name, marker := range t.UnderlyingType.Markers { + if _, ok := t.Markers[name]; !ok { + if t.Markers == nil { + t.Markers = make(markers.MarkerValues) + } + t.Markers[name] = marker + } + } + } +} + // Field describes a field in a struct. type Field struct { - Name string - Embedded bool // Embedded struct in Go typing - Inlined bool // Inlined struct in serialization - Doc string - Markers markers.MarkerValues - Type *Type + Name string + Embedded bool // Embedded struct in Go typing + Inlined bool // Inlined struct in serialization + Doc string + Default string + Validation []string + Markers markers.MarkerValues + Type *Type } type Fields []*Field +func (f *Field) propagateMarkers() { + f.Type.propagateMarkers() + + for name, marker := range f.Type.Markers { + if _, ok := f.Markers[name]; !ok { + if f.Markers == nil { + f.Markers = make(markers.MarkerValues) + } + f.Markers[name] = marker + } + } +} + // inlineType replaces field at index i with the fields of inlined type. func (fields *Fields) inlineType(i int, inlined *Type) { new := make([]*Field, 0, len(*fields)+len(inlined.Fields)-1)