package internal
import (
"fmt"
"regexp"
"strings"
"github.com/client9/misspell"
"github.com/knq/snaker"
)
const (
// Base64EncodedParamName is the base64encoded variable name in command
// return values when they are optionally base64 encoded.
Base64EncodedParamName = "base64Encoded"
// Base64EncodedDescriptionPrefix is the prefix for command return
// description prefix when base64 encoded.
Base64EncodedDescriptionPrefix = "Base64-encoded"
)
// misspellReplacer is the misspelling replacer
var misspellReplacer *misspell.Replacer
func init() {
misspellReplacer = misspell.New()
misspellReplacer.Compile()
}
var descReplacer = strings.NewReplacer(
"<", "<",
">", ">",
">", ">",
"`", "",
"\n", " ",
)
// codeRE is a regexp to match and
tags.
var codeRE = regexp.MustCompile(`<\/?code>`)
// CleanDesc cleans comments / descriptions of "" and "
" strings
// and "`" characters, and fixes common misspellings.
func CleanDesc(s string) string {
s, _ = misspellReplacer.Replace(codeRE.ReplaceAllString(s, ""))
return descReplacer.Replace(s)
}
// ForceCamel forces camel case specific to go.
func ForceCamel(s string) string {
if s == "" {
return ""
}
return snaker.SnakeToCamelIdentifier(snaker.CamelToSnake(s))
}
// ForceCamelWithFirstLower forces the first portion to be lower case.
func ForceCamelWithFirstLower(s string) string {
if s == "" {
return ""
}
s = snaker.CamelToSnake(s)
first := strings.SplitN(s, "_", -1)[0]
s = snaker.SnakeToCamelIdentifier(s)
return strings.ToLower(first) + s[len(first):]
}
// resolve finds the ref in the provided domains, relative to domain d when ref
// is not namespaced.
func resolve(ref string, d *Domain, domains []*Domain) (DomainType, *Type, string) {
n := strings.SplitN(ref, ".", 2)
// determine domain
dtyp := d.Domain
typ := n[0]
if len(n) == 2 {
err := (&dtyp).UnmarshalJSON([]byte(`"` + n[0] + `"`))
if err != nil {
panic(err)
}
typ = n[1]
}
// determine if ref points to an object
var other *Type
for _, z := range domains {
if dtyp == z.Domain {
for _, j := range z.Types {
if j.ID == typ {
other = j
break
}
}
break
}
}
if other == nil {
panic(fmt.Sprintf("could not resolve type %s in domain %s", ref, d))
}
var s string
// add prefix if not an internal type and not defined in the domain
if IsCDPType(dtyp, typ) {
if d.Domain != DomainType("cdp") {
s += "cdp."
}
} else if dtyp != d.Domain {
s += strings.ToLower(dtyp.String()) + "."
}
return dtyp, other, s + ForceCamel(typ)
}
// structDef returns a struct definition for a list of types.
func structDef(types []*Type, d *Domain, domains []*Domain, noExposeOverride, omitOnlyWhenOptional bool) string {
s := "struct"
if len(types) > 0 {
s += " "
}
s += "{"
for _, v := range types {
s += "\n\t" + v.GoName(noExposeOverride) + " " + v.GoType(d, domains)
omit := ",omitempty"
if omitOnlyWhenOptional && !v.Optional.Bool() {
omit = ""
}
// add json tag
if v.NoExpose {
s += " `json:\"-\"`"
} else {
s += " `json:\"" + v.Name + omit + "\"`"
}
// add comment
if v.Type != TypeObject && v.Description != "" {
s += " // " + CleanDesc(v.Description)
}
}
if len(types) > 0 {
s += "\n"
}
s += "}"
return s
}
// cdpTypes is the list of internal types.
var cdpTypes map[string]bool
// SetCDPTypes sets the internal types.
func SetCDPTypes(types map[string]bool) {
cdpTypes = types
}
// IsCDPType determines if the specified domain and typ constitute an
// internal type.
func IsCDPType(dtyp DomainType, typ string) bool {
if _, ok := cdpTypes[dtyp.String()+"."+typ]; ok {
return true
}
return false
}
// CDPTypeList returns the list of internal types.
func CDPTypeList() []string {
var types []string
for k := range cdpTypes {
n := strings.SplitN(k, ".", 2)
types = append(types, ForceCamel(n[1]))
}
return types
}
// goReservedNames is the list of reserved names in Go.
var goReservedNames = map[string]bool{
// language words
"break": true,
"case": true,
"chan": true,
"const": true,
"continue": true,
"default": true,
"defer": true,
"else": true,
"fallthrough": true,
"for": true,
"func": true,
"go": true,
"goto": true,
"if": true,
"import": true,
"interface": true,
"map": true,
"package": true,
"range": true,
"return": true,
"select": true,
"struct": true,
"switch": true,
"type": true,
"var": true,
// go types
"error": true,
"bool": true,
"string": true,
"byte": true,
"rune": true,
"uintptr": true,
"int": true,
"int8": true,
"int16": true,
"int32": true,
"int64": true,
"uint": true,
"uint8": true,
"uint16": true,
"uint32": true,
"uint64": true,
"float32": true,
"float64": true,
"complex64": true,
"complex128": true,
}