github.com/brycereitano/goa@v0.0.0-20170315073847-8ffa6c85e265/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 if strings.Contains(a, p) { 42 args[i] = strings.Replace(a, p, "$(GOPATH)", -1) 43 break 44 } 45 } 46 if args[i] == "" { 47 args[i] = a 48 } 49 } 50 param = strings.Join(args, " ") 51 } 52 rawcmd := filepath.Base(os.Args[0]) 53 // Remove possible .exe suffix to not create different ouptut just because 54 // you ran goagen on Windows. 55 rawcmd = strings.TrimSuffix(rawcmd, ".exe") 56 57 cmd := fmt.Sprintf("$ %s %s", rawcmd, param) 58 return strings.Replace(cmd, " --", "\n\t--", -1) 59 } 60 61 // Comment produces line comments by concatenating the given strings and producing 80 characters 62 // long lines starting with "//" 63 func Comment(elems ...string) string { 64 var lines []string 65 for _, e := range elems { 66 lines = append(lines, strings.Split(e, "\n")...) 67 } 68 var trimmed = make([]string, len(lines)) 69 for i, l := range lines { 70 trimmed[i] = strings.TrimLeft(l, " \t") 71 } 72 t := strings.Join(trimmed, "\n") 73 74 return Indent(t, "// ") 75 } 76 77 // Indent inserts prefix at the beginning of each non-empty line of s. The 78 // end-of-line marker is NL. 79 func Indent(s, prefix string) string { 80 return string(IndentBytes([]byte(s), []byte(prefix))) 81 } 82 83 // IndentBytes inserts prefix at the beginning of each non-empty line of b. 84 // The end-of-line marker is NL. 85 func IndentBytes(b, prefix []byte) []byte { 86 var res []byte 87 bol := true 88 for _, c := range b { 89 if bol && c != '\n' { 90 res = append(res, prefix...) 91 } 92 res = append(res, c) 93 bol = c == '\n' 94 } 95 return res 96 } 97 98 // Tabs returns a string made of depth tab characters. 99 func Tabs(depth int) string { 100 var tabs string 101 for i := 0; i < depth; i++ { 102 tabs += "\t" 103 } 104 // return fmt.Sprintf("%d%s", depth, tabs) 105 return tabs 106 } 107 108 // Add adds two integers and returns the sum of the two. 109 func Add(a, b int) int { return a + b } 110 111 // CanonicalTemplate returns the resource URI template as a format string suitable for use in the 112 // fmt.Printf function family. 113 func CanonicalTemplate(r *design.ResourceDefinition) string { 114 return design.WildcardRegex.ReplaceAllLiteralString(r.URITemplate(), "/%v") 115 } 116 117 // CanonicalParams returns the list of parameter names needed to build the canonical href to the 118 // resource. It returns nil if the resource does not have a canonical action. 119 func CanonicalParams(r *design.ResourceDefinition) []string { 120 var params []string 121 if ca := r.CanonicalAction(); ca != nil { 122 if len(ca.Routes) > 0 { 123 params = ca.Routes[0].Params() 124 } 125 for i, p := range params { 126 params[i] = Goify(p, false) 127 } 128 } 129 return params 130 } 131 132 // Casing exceptions 133 var toLower = map[string]string{"OAuth": "oauth"} 134 135 // SnakeCase produces the snake_case version of the given CamelCase string. 136 func SnakeCase(name string) string { 137 for u, l := range toLower { 138 name = strings.Replace(name, u, l, -1) 139 } 140 var b bytes.Buffer 141 var lastUnderscore bool 142 ln := len(name) 143 if ln == 0 { 144 return "" 145 } 146 b.WriteRune(unicode.ToLower(rune(name[0]))) 147 for i := 1; i < ln; i++ { 148 r := rune(name[i]) 149 nextIsLower := false 150 if i < ln-1 { 151 n := rune(name[i+1]) 152 nextIsLower = unicode.IsLower(n) && unicode.IsLetter(n) 153 } 154 if unicode.IsUpper(r) { 155 if !lastUnderscore && nextIsLower { 156 b.WriteRune('_') 157 lastUnderscore = true 158 } 159 b.WriteRune(unicode.ToLower(r)) 160 } else { 161 b.WriteRune(r) 162 lastUnderscore = false 163 } 164 } 165 return b.String() 166 } 167 168 // KebabCase produces the kebab-case version of the given CamelCase string. 169 func KebabCase(name string) string { 170 name = SnakeCase(name) 171 return strings.Replace(name, "_", "-", -1) 172 }