github.com/blp1526/goa@v1.4.0/goagen/codegen/helpers.go (about) 1 package codegen 2 3 import ( 4 "bytes" 5 "fmt" 6 "os" 7 "path/filepath" 8 "strings" 9 "unicode" 10 11 "github.com/goadesign/goa/design" 12 "github.com/goadesign/goa/version" 13 ) 14 15 // CheckVersion returns an error if the ver is empty, contains an incorrect value or 16 // a version number that is not compatible with the version of this repo. 17 func CheckVersion(ver string) error { 18 compat, err := version.Compatible(ver) 19 if err != nil { 20 return err 21 } 22 if !compat { 23 return fmt.Errorf("version mismatch: using goagen %s to generate code that compiles with goa %s", 24 ver, version.String()) 25 } 26 return nil 27 } 28 29 // CommandLine return the command used to run this process. 30 func CommandLine() string { 31 // We don't use the full path to the tool so that running goagen multiple times doesn't 32 // end up creating different command line comments (because of the temporary directory it 33 // runs in). 34 var param string 35 36 if len(os.Args) > 1 { 37 args := make([]string, len(os.Args)-1) 38 gopaths := filepath.SplitList(os.Getenv("GOPATH")) 39 for i, a := range os.Args[1:] { 40 for _, p := range gopaths { 41 p = "=" + p 42 if strings.Contains(a, p) { 43 args[i] = strings.Replace(a, p, "=$(GOPATH)", 1) 44 break 45 } 46 } 47 if args[i] == "" { 48 args[i] = a 49 } 50 } 51 param = strings.Join(args, " ") 52 } 53 rawcmd := filepath.Base(os.Args[0]) 54 // Remove possible .exe suffix to not create different ouptut just because 55 // you ran goagen on Windows. 56 rawcmd = strings.TrimSuffix(rawcmd, ".exe") 57 58 cmd := fmt.Sprintf("$ %s %s", rawcmd, param) 59 return strings.Replace(cmd, " --", "\n\t--", -1) 60 } 61 62 // Comment produces line comments by concatenating the given strings and producing 80 characters 63 // long lines starting with "//" 64 func Comment(elems ...string) string { 65 var lines []string 66 for _, e := range elems { 67 lines = append(lines, strings.Split(e, "\n")...) 68 } 69 var trimmed = make([]string, len(lines)) 70 for i, l := range lines { 71 trimmed[i] = strings.TrimLeft(l, " \t") 72 } 73 t := strings.Join(trimmed, "\n") 74 75 return Indent(t, "// ") 76 } 77 78 // Indent inserts prefix at the beginning of each non-empty line of s. The 79 // end-of-line marker is NL. 80 func Indent(s, prefix string) string { 81 return string(IndentBytes([]byte(s), []byte(prefix))) 82 } 83 84 // IndentBytes inserts prefix at the beginning of each non-empty line of b. 85 // The end-of-line marker is NL. 86 func IndentBytes(b, prefix []byte) []byte { 87 var res []byte 88 bol := true 89 for _, c := range b { 90 if bol && c != '\n' { 91 res = append(res, prefix...) 92 } 93 res = append(res, c) 94 bol = c == '\n' 95 } 96 return res 97 } 98 99 // Tabs returns a string made of depth tab characters. 100 func Tabs(depth int) string { 101 var tabs string 102 for i := 0; i < depth; i++ { 103 tabs += "\t" 104 } 105 // return fmt.Sprintf("%d%s", depth, tabs) 106 return tabs 107 } 108 109 // Add adds two integers and returns the sum of the two. 110 func Add(a, b int) int { return a + b } 111 112 // CanonicalTemplate returns the resource URI template as a format string suitable for use in the 113 // fmt.Printf function family. 114 func CanonicalTemplate(r *design.ResourceDefinition) string { 115 return design.WildcardRegex.ReplaceAllLiteralString(r.URITemplate(), "/%v") 116 } 117 118 // CanonicalParams returns the list of parameter names needed to build the canonical href to the 119 // resource. It returns nil if the resource does not have a canonical action. 120 func CanonicalParams(r *design.ResourceDefinition) []string { 121 var params []string 122 if ca := r.CanonicalAction(); ca != nil { 123 if len(ca.Routes) > 0 { 124 params = ca.Routes[0].Params() 125 } 126 for i, p := range params { 127 params[i] = Goify(p, false) 128 } 129 } 130 return params 131 } 132 133 // Casing exceptions 134 var toLower = map[string]string{"OAuth": "oauth"} 135 136 // SnakeCase produces the snake_case version of the given CamelCase string. 137 func SnakeCase(name string) string { 138 for u, l := range toLower { 139 name = strings.Replace(name, u, l, -1) 140 } 141 var b bytes.Buffer 142 var lastUnderscore bool 143 ln := len(name) 144 if ln == 0 { 145 return "" 146 } 147 b.WriteRune(unicode.ToLower(rune(name[0]))) 148 for i := 1; i < ln; i++ { 149 r := rune(name[i]) 150 nextIsLower := false 151 if i < ln-1 { 152 n := rune(name[i+1]) 153 nextIsLower = unicode.IsLower(n) && unicode.IsLetter(n) 154 } 155 if unicode.IsUpper(r) { 156 if !lastUnderscore && nextIsLower { 157 b.WriteRune('_') 158 lastUnderscore = true 159 } 160 b.WriteRune(unicode.ToLower(r)) 161 } else { 162 b.WriteRune(r) 163 lastUnderscore = false 164 } 165 } 166 return b.String() 167 } 168 169 // KebabCase produces the kebab-case version of the given CamelCase string. 170 func KebabCase(name string) string { 171 name = SnakeCase(name) 172 return strings.Replace(name, "_", "-", -1) 173 }