desc_visitor.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. /*
  2. Copyright 2019 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package crd
  14. import (
  15. "strings"
  16. "unicode"
  17. apiext "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
  18. )
  19. // TruncateDescription truncates the description of fields in given schema if it
  20. // exceeds maxLen.
  21. // It tries to chop off the description at the closest sentence boundary.
  22. func TruncateDescription(schema *apiext.JSONSchemaProps, maxLen int) {
  23. EditSchema(schema, descVisitor{maxLen: maxLen})
  24. }
  25. // descVisitor recursively visits all fields in the schema and truncates the
  26. // description of the fields to specified maxLen.
  27. type descVisitor struct {
  28. // maxLen is the maximum allowed length for decription of a field
  29. maxLen int
  30. }
  31. func (v descVisitor) Visit(schema *apiext.JSONSchemaProps) SchemaVisitor {
  32. if schema == nil {
  33. return v
  34. }
  35. if v.maxLen < 0 {
  36. return nil /* no further work to be done for this schema */
  37. }
  38. if v.maxLen == 0 {
  39. schema.Description = ""
  40. return v
  41. }
  42. if len(schema.Description) > v.maxLen {
  43. schema.Description = truncateString(schema.Description, v.maxLen)
  44. return v
  45. }
  46. return v
  47. }
  48. // truncateString truncates given desc string if it exceeds maxLen. It may
  49. // return string with length less than maxLen even in cases where original desc
  50. // exceeds maxLen because it tries to chop off the desc at the closest sentence
  51. // boundary to avoid incomplete sentences.
  52. func truncateString(desc string, maxLen int) string {
  53. desc = desc[0:maxLen]
  54. // Trying to chop off at closest sentence boundary.
  55. if n := strings.LastIndexFunc(desc, isSentenceTerminal); n > 0 {
  56. return desc[0 : n+1]
  57. }
  58. // TODO(droot): Improve the logic to chop off at closest word boundary
  59. // or add elipses (...) to indicate that it's chopped incase no closest
  60. // sentence found within maxLen.
  61. return desc
  62. }
  63. // helper function to determine if given rune is a sentence terminal or not.
  64. func isSentenceTerminal(r rune) bool {
  65. return unicode.Is(unicode.STerm, r)
  66. }