mirror of
https://github.com/mainflux/mainflux.git
synced 2025-04-29 13:49:28 +08:00

* authz service init Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * authz service init Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * add proto Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * add proto Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * authorize method Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * add casbib Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * add casbib Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * add casbib Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * add policy grpc Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * add policy grpc Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * fix db connection, add environment variables, docker-compose Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * add model.conf policy Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * add model.conf policy Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * fix test Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * adding tests, and token for auth Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * revert changes Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * fix auth service Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * small changes, add model conf env var Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * remove users grpc for now Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * fix error Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * some cosmetics Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * resolvin minor comments Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * change endpoint, add file to fix test Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * fix docker env Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * fix alignment and path for model.conf Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>
340 lines
6.4 KiB
Go
340 lines
6.4 KiB
Go
// Package kace provides common case conversion functions which take into
|
|
// consideration common initialisms.
|
|
package kace
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"unicode"
|
|
|
|
"github.com/codemodus/kace/ktrie"
|
|
)
|
|
|
|
const (
|
|
kebabDelim = '-'
|
|
snakeDelim = '_'
|
|
none = rune(-1)
|
|
)
|
|
|
|
var (
|
|
ciTrie *ktrie.KTrie
|
|
)
|
|
|
|
func init() {
|
|
var err error
|
|
if ciTrie, err = ktrie.NewKTrie(ciMap); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
// Camel returns a camelCased string.
|
|
func Camel(s string) string {
|
|
return camelCase(ciTrie, s, false)
|
|
}
|
|
|
|
// Pascal returns a PascalCased string.
|
|
func Pascal(s string) string {
|
|
return camelCase(ciTrie, s, true)
|
|
}
|
|
|
|
// Kebab returns a kebab-cased string with all lowercase letters.
|
|
func Kebab(s string) string {
|
|
return delimitedCase(s, kebabDelim, false)
|
|
}
|
|
|
|
// KebabUpper returns a KEBAB-CASED string with all upper case letters.
|
|
func KebabUpper(s string) string {
|
|
return delimitedCase(s, kebabDelim, true)
|
|
}
|
|
|
|
// Snake returns a snake_cased string with all lowercase letters.
|
|
func Snake(s string) string {
|
|
return delimitedCase(s, snakeDelim, false)
|
|
}
|
|
|
|
// SnakeUpper returns a SNAKE_CASED string with all upper case letters.
|
|
func SnakeUpper(s string) string {
|
|
return delimitedCase(s, snakeDelim, true)
|
|
}
|
|
|
|
// Kace provides common case conversion methods which take into
|
|
// consideration common initialisms set by the user.
|
|
type Kace struct {
|
|
t *ktrie.KTrie
|
|
}
|
|
|
|
// New returns a pointer to an instance of kace loaded with a common
|
|
// initialsms trie based on the provided map. Before conversion to a
|
|
// trie, the provided map keys are all upper cased.
|
|
func New(initialisms map[string]bool) (*Kace, error) {
|
|
ci := initialisms
|
|
if ci == nil {
|
|
ci = map[string]bool{}
|
|
}
|
|
|
|
ci = sanitizeCI(ci)
|
|
|
|
t, err := ktrie.NewKTrie(ci)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("kace: cannot create trie: %s", err)
|
|
}
|
|
|
|
k := &Kace{
|
|
t: t,
|
|
}
|
|
|
|
return k, nil
|
|
}
|
|
|
|
// Camel returns a camelCased string.
|
|
func (k *Kace) Camel(s string) string {
|
|
return camelCase(k.t, s, false)
|
|
}
|
|
|
|
// Pascal returns a PascalCased string.
|
|
func (k *Kace) Pascal(s string) string {
|
|
return camelCase(k.t, s, true)
|
|
}
|
|
|
|
// Snake returns a snake_cased string with all lowercase letters.
|
|
func (k *Kace) Snake(s string) string {
|
|
return delimitedCase(s, snakeDelim, false)
|
|
}
|
|
|
|
// SnakeUpper returns a SNAKE_CASED string with all upper case letters.
|
|
func (k *Kace) SnakeUpper(s string) string {
|
|
return delimitedCase(s, snakeDelim, true)
|
|
}
|
|
|
|
// Kebab returns a kebab-cased string with all lowercase letters.
|
|
func (k *Kace) Kebab(s string) string {
|
|
return delimitedCase(s, kebabDelim, false)
|
|
}
|
|
|
|
// KebabUpper returns a KEBAB-CASED string with all upper case letters.
|
|
func (k *Kace) KebabUpper(s string) string {
|
|
return delimitedCase(s, kebabDelim, true)
|
|
}
|
|
|
|
func camelCase(t *ktrie.KTrie, s string, ucFirst bool) string {
|
|
rs := []rune(s)
|
|
offset := 0
|
|
prev := none
|
|
|
|
for i := 0; i < len(rs); i++ {
|
|
r := rs[i]
|
|
|
|
switch {
|
|
case unicode.IsLetter(r):
|
|
ucCurr := isToBeUpper(r, prev, ucFirst)
|
|
|
|
if ucCurr || isSegmentStart(r, prev) {
|
|
prv, skip := updateRunes(rs, i, offset, t, ucCurr)
|
|
if skip > 0 {
|
|
i += skip - 1
|
|
prev = prv
|
|
continue
|
|
}
|
|
}
|
|
|
|
prev = updateRune(rs, i, offset, ucCurr)
|
|
continue
|
|
|
|
case unicode.IsNumber(r):
|
|
prev = updateRune(rs, i, offset, false)
|
|
continue
|
|
|
|
default:
|
|
prev = r
|
|
offset--
|
|
}
|
|
}
|
|
|
|
return string(rs[:len(rs)+offset])
|
|
}
|
|
|
|
func isToBeUpper(curr, prev rune, ucFirst bool) bool {
|
|
if prev == none {
|
|
return ucFirst
|
|
}
|
|
|
|
return isSegmentStart(curr, prev)
|
|
}
|
|
|
|
func isSegmentStart(curr, prev rune) bool {
|
|
if !unicode.IsLetter(prev) || unicode.IsUpper(curr) && unicode.IsLower(prev) {
|
|
return true
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func updateRune(rs []rune, i, offset int, upper bool) rune {
|
|
r := rs[i]
|
|
|
|
dest := i + offset
|
|
if dest < 0 || i > len(rs)-1 {
|
|
panic("this function has been used or designed incorrectly")
|
|
}
|
|
|
|
fn := unicode.ToLower
|
|
if upper {
|
|
fn = unicode.ToUpper
|
|
}
|
|
|
|
rs[dest] = fn(r)
|
|
|
|
return r
|
|
}
|
|
|
|
func updateRunes(rs []rune, i, offset int, t *ktrie.KTrie, upper bool) (rune, int) {
|
|
r := rs[i]
|
|
ns := nextSegment(rs, i)
|
|
ct := len(ns)
|
|
|
|
if ct < t.MinDepth() || ct > t.MaxDepth() || !t.FindAsUpper(ns) {
|
|
return r, 0
|
|
}
|
|
|
|
for j := i; j < i+ct; j++ {
|
|
r = updateRune(rs, j, offset, upper)
|
|
}
|
|
|
|
return r, ct
|
|
}
|
|
|
|
func nextSegment(rs []rune, i int) []rune {
|
|
for j := i; j < len(rs); j++ {
|
|
if !unicode.IsLetter(rs[j]) && !unicode.IsNumber(rs[j]) {
|
|
return rs[i:j]
|
|
}
|
|
|
|
if j == len(rs)-1 {
|
|
return rs[i : j+1]
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func delimitedCase(s string, delim rune, upper bool) string {
|
|
buf := make([]rune, 0, len(s)*2)
|
|
|
|
for i := len(s); i > 0; i-- {
|
|
switch {
|
|
case unicode.IsLetter(rune(s[i-1])):
|
|
if i < len(s) && unicode.IsUpper(rune(s[i])) {
|
|
if i > 1 && unicode.IsLower(rune(s[i-1])) || i < len(s)-2 && unicode.IsLower(rune(s[i+1])) {
|
|
buf = append(buf, delim)
|
|
}
|
|
}
|
|
|
|
buf = appendCased(buf, upper, rune(s[i-1]))
|
|
|
|
case unicode.IsNumber(rune(s[i-1])):
|
|
if i == len(s) || i == 1 || unicode.IsNumber(rune(s[i])) {
|
|
buf = append(buf, rune(s[i-1]))
|
|
continue
|
|
}
|
|
|
|
buf = append(buf, delim, rune(s[i-1]))
|
|
|
|
default:
|
|
if i == len(s) {
|
|
continue
|
|
}
|
|
|
|
buf = append(buf, delim)
|
|
}
|
|
}
|
|
|
|
reverse(buf)
|
|
|
|
return string(buf)
|
|
}
|
|
|
|
func appendCased(rs []rune, upper bool, r rune) []rune {
|
|
if upper {
|
|
rs = append(rs, unicode.ToUpper(r))
|
|
return rs
|
|
}
|
|
|
|
rs = append(rs, unicode.ToLower(r))
|
|
|
|
return rs
|
|
}
|
|
|
|
func reverse(s []rune) {
|
|
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
|
|
s[i], s[j] = s[j], s[i]
|
|
}
|
|
}
|
|
|
|
var (
|
|
// github.com/golang/lint/blob/master/lint.go
|
|
ciMap = map[string]bool{
|
|
"ACL": true,
|
|
"API": true,
|
|
"ASCII": true,
|
|
"CPU": true,
|
|
"CSS": true,
|
|
"DNS": true,
|
|
"EOF": true,
|
|
"GUID": true,
|
|
"HTML": true,
|
|
"HTTP": true,
|
|
"HTTPS": true,
|
|
"ID": true,
|
|
"IP": true,
|
|
"JSON": true,
|
|
"LHS": true,
|
|
"QPS": true,
|
|
"RAM": true,
|
|
"RHS": true,
|
|
"RPC": true,
|
|
"SLA": true,
|
|
"SMTP": true,
|
|
"SQL": true,
|
|
"SSH": true,
|
|
"TCP": true,
|
|
"TLS": true,
|
|
"TTL": true,
|
|
"UDP": true,
|
|
"UI": true,
|
|
"UID": true,
|
|
"UUID": true,
|
|
"URI": true,
|
|
"URL": true,
|
|
"UTF8": true,
|
|
"VM": true,
|
|
"XML": true,
|
|
"XMPP": true,
|
|
"XSRF": true,
|
|
"XSS": true,
|
|
}
|
|
)
|
|
|
|
func sanitizeCI(m map[string]bool) map[string]bool {
|
|
r := map[string]bool{}
|
|
|
|
for k := range m {
|
|
fn := func(r rune) rune {
|
|
if !unicode.IsLetter(r) && !unicode.IsNumber(r) {
|
|
return -1
|
|
}
|
|
return r
|
|
}
|
|
|
|
k = strings.Map(fn, k)
|
|
k = strings.ToUpper(k)
|
|
|
|
if k == "" {
|
|
continue
|
|
}
|
|
|
|
r[k] = true
|
|
}
|
|
|
|
return r
|
|
}
|