renderer/functions.go (143 lines of code) (raw):

// Licensed to Elasticsearch B.V. under one or more contributor // license agreements. See the NOTICE file distributed with // this work for additional information regarding copyright // ownership. Elasticsearch B.V. licenses this file to you 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 renderer import ( "bytes" "fmt" "regexp" "strings" "text/template" "github.com/elastic/crd-ref-docs/config" "github.com/elastic/crd-ref-docs/types" "go.uber.org/zap" ) const ( kubePackagesRegex = `^k8s\.io/(?:api|apimachinery|apiextensions-apiserver/pkg/apis)/` kubeDocLinkTemplate = `https://kubernetes.io/docs/reference/generated/kubernetes-api/v{{ .kubeVersion }}/#{{ .type }}-{{ .version }}-{{ .group }}` ) type Functions struct { conf *config.Config *kubernetesHelper safeIDRegex *regexp.Regexp } func NewFunctions(conf *config.Config) (*Functions, error) { kubeHelper, err := newKubernetesHelper(conf) if err != nil { return nil, err } safeIDRegex, err := regexp.Compile("[[:punct:]]+") if err != nil { return nil, fmt.Errorf("failed to compile safe ID regex: %w", err) } return &Functions{ conf: conf, kubernetesHelper: kubeHelper, safeIDRegex: safeIDRegex, }, nil } func (f *Functions) TypeID(t *types.Type) string { return f.SafeID(types.Identifier(t)) } func (f *Functions) GroupVersionID(gv types.GroupVersionDetails) string { return f.SafeID(gv.GroupVersionString()) } func (f *Functions) SafeID(id string) string { return strings.ToLower(f.safeIDRegex.ReplaceAllLiteralString(id, "-")) } func (f *Functions) LinkForType(t *types.Type) (link string, local bool) { if f.IsKubeType(t) { return f.LinkForKubeType(t), false } if kt, ok := f.IsKnownType(t); ok { return f.LinkForKnownType(kt), false } if t.IsBasic() || t.Imported { return "", false } return f.TypeID(t), true } func (f *Functions) SimplifiedTypeName(t *types.Type) string { if !t.IsBasic() { return t.Name } switch t.Kind { case types.BasicKind: return f.BasicTypeName(t.Name) case types.PointerKind: return f.BasicTypeName(t.UnderlyingType.Name) case types.SliceKind: return fmt.Sprintf("%s array", f.BasicTypeName(t.UnderlyingType.Name)) case types.MapKind: return "object" default: return t.Name } } func (f *Functions) BasicTypeName(name string) string { switch name { case "int", "int8", "int16", "int32", "int64", "uint", "uint8", "uint16", "uint32", "uint64", "byte", "rune": return "integer" case "float32", "float64": return "float" case "bool": return "boolean" default: return name } } func (f *Functions) IsKnownType(t *types.Type) (*config.KnownType, bool) { for _, kt := range f.conf.Render.KnownTypes { if kt.Package == t.Package && t.Name == kt.Name { return kt, true } } return nil, false } func (f *Functions) LinkForKnownType(kt *config.KnownType) string { return kt.Link } type kubernetesHelper struct { kubeVersion string packagesRegex *regexp.Regexp docLinkTemplate *template.Template } func newKubernetesHelper(conf *config.Config) (*kubernetesHelper, error) { packagesRegex, err := regexp.Compile(kubePackagesRegex) if err != nil { return nil, fmt.Errorf("failed to compile kube package regex: %w", err) } docLinkTemplate, err := template.New("").Parse(kubeDocLinkTemplate) if err != nil { return nil, fmt.Errorf("failed to parse kube doc link template: %w", err) } return &kubernetesHelper{ kubeVersion: conf.Render.KubernetesVersion, packagesRegex: packagesRegex, docLinkTemplate: docLinkTemplate, }, nil } func (k *kubernetesHelper) IsKubeType(t *types.Type) bool { return k.packagesRegex.MatchString(t.Package) } func (k *kubernetesHelper) LinkForKubeType(t *types.Type) string { if !k.IsKubeType(t) { return "" } parts := strings.Split(t.Package, "/") if len(parts) < 2 { zap.S().Fatalw("Unexpected Kubernetes package name", "type", t) } group := strings.ToLower(parts[len(parts)-2]) // this is alias handling if group == "apiextensions" { group = "apiextensions-k8s-io" } args := map[string]string{ "kubeVersion": k.kubeVersion, "group": group, "version": strings.ToLower(parts[len(parts)-1]), "type": strings.ToLower(t.Name), } s := new(bytes.Buffer) if err := k.docLinkTemplate.Execute(s, args); err != nil { zap.S().Fatalw("Failed to render Kube doc link", "type", t, "error", err) } return s.String() }