blob: 40bdcc6ccc2fcca6ce155647a48ab16fb4da249e [file] [log] [blame]
Matthias Andreas Benkard832a54e2019-01-29 09:27:38 +01001/*
2Copyright 2015 The Kubernetes Authors.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17package namer
18
19import (
20 "strings"
21
22 "k8s.io/gengo/types"
23)
24
25var consonants = "bcdfghjklmnpqrsttvwxyz"
26
27type pluralNamer struct {
28 // key is the case-sensitive type name, value is the case-insensitive
29 // intended output.
30 exceptions map[string]string
31 finalize func(string) string
32}
33
34// NewPublicPluralNamer returns a namer that returns the plural form of the input
35// type's name, starting with a uppercase letter.
36func NewPublicPluralNamer(exceptions map[string]string) *pluralNamer {
37 return &pluralNamer{exceptions, IC}
38}
39
40// NewPrivatePluralNamer returns a namer that returns the plural form of the input
41// type's name, starting with a lowercase letter.
42func NewPrivatePluralNamer(exceptions map[string]string) *pluralNamer {
43 return &pluralNamer{exceptions, IL}
44}
45
46// NewAllLowercasePluralNamer returns a namer that returns the plural form of the input
47// type's name, with all letters in lowercase.
48func NewAllLowercasePluralNamer(exceptions map[string]string) *pluralNamer {
49 return &pluralNamer{exceptions, strings.ToLower}
50}
51
52// Name returns the plural form of the type's name. If the type's name is found
53// in the exceptions map, the map value is returned.
54func (r *pluralNamer) Name(t *types.Type) string {
55 singular := t.Name.Name
56 var plural string
57 var ok bool
58 if plural, ok = r.exceptions[singular]; ok {
59 return r.finalize(plural)
60 }
61 if len(singular) < 2 {
62 return r.finalize(plural)
63 }
64
65 switch rune(singular[len(singular)-1]) {
66 case 's', 'x', 'z':
67 plural = esPlural(singular)
68 case 'y':
69 sl := rune(singular[len(singular)-2])
70 if isConsonant(sl) {
71 plural = iesPlural(singular)
72 } else {
73 plural = sPlural(singular)
74 }
75 case 'h':
76 sl := rune(singular[len(singular)-2])
77 if sl == 'c' || sl == 's' {
78 plural = esPlural(singular)
79 } else {
80 plural = sPlural(singular)
81 }
82 case 'e':
83 sl := rune(singular[len(singular)-2])
84 if sl == 'f' {
85 plural = vesPlural(singular[:len(singular)-1])
86 } else {
87 plural = sPlural(singular)
88 }
89 case 'f':
90 plural = vesPlural(singular)
91 default:
92 plural = sPlural(singular)
93 }
94 return r.finalize(plural)
95}
96
97func iesPlural(singular string) string {
98 return singular[:len(singular)-1] + "ies"
99}
100
101func vesPlural(singular string) string {
102 return singular[:len(singular)-1] + "ves"
103}
104
105func esPlural(singular string) string {
106 return singular + "es"
107}
108
109func sPlural(singular string) string {
110 return singular + "s"
111}
112
113func isConsonant(char rune) bool {
114 for _, c := range consonants {
115 if char == c {
116 return true
117 }
118 }
119 return false
120}