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  }