Skip to content

Commit

Permalink
feat: add extended-rules option (#27)
Browse files Browse the repository at this point in the history
  • Loading branch information
ldez authored Dec 8, 2024
1 parent 4e6384a commit 29393e1
Show file tree
Hide file tree
Showing 8 changed files with 322 additions and 103 deletions.
116 changes: 116 additions & 0 deletions converter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package tagliatelle

import (
"fmt"
"strings"

"github.com/ettle/strcase"
)

// https://github.com/dominikh/go-tools/blob/v0.5.1/config/config.go#L167-L175
//
//nolint:gochecknoglobals // For now I'll accept this, but I think will refactor to use a structure.
var staticcheckInitialisms = map[string]bool{
"AMQP": true,
"DB": true,
"GID": true,
"LHS": false,
"RHS": false,
"RTP": true,
"SIP": true,
"TS": true,
}

// Converter is the signature of a case converter.
type Converter func(s string) string

// ConverterCallback allows to abstract `getSimpleConverter` and `ruleToConverter`.
type ConverterCallback func() (Converter, error)

func getSimpleConverter(c string) (Converter, error) {
switch c {
case "camel":
return strcase.ToCamel, nil
case "pascal":
return strcase.ToPascal, nil
case "kebab":
return strcase.ToKebab, nil
case "snake":
return strcase.ToSnake, nil
case "goCamel":
return strcase.ToGoCamel, nil
case "goPascal":
return strcase.ToGoPascal, nil
case "goKebab":
return strcase.ToGoKebab, nil
case "goSnake":
return strcase.ToGoSnake, nil
case "upperSnake":
return strcase.ToSNAKE, nil
case "header":
return toHeader, nil
case "upper":
return strings.ToUpper, nil
case "lower":
return strings.ToLower, nil
default:
return nil, fmt.Errorf("unsupported case: %s", c)
}
}

func toHeader(s string) string {
return strcase.ToCase(s, strcase.TitleCase, '-')
}

func ruleToConverter(rule ExtendedRule) (Converter, error) {
if rule.ExtraInitialisms {
for k, v := range staticcheckInitialisms {
if _, found := rule.InitialismOverrides[k]; found {
continue
}

rule.InitialismOverrides[k] = v
}
}

caser := strcase.NewCaser(strings.HasPrefix(rule.Case, "go"), rule.InitialismOverrides, nil)

switch strings.ToLower(strings.TrimPrefix(rule.Case, "go")) {
case "camel":
return caser.ToCamel, nil

case "pascal":
return caser.ToPascal, nil

case "kebab":
return caser.ToKebab, nil

case "snake":
return caser.ToSnake, nil

case "uppersnake":
return caser.ToSNAKE, nil

case "header":
return toHeaderCase(caser), nil

case "upper":
return func(s string) string {
return caser.ToCase(s, strcase.UpperCase, 0)
}, nil

case "lower":
return func(s string) string {
return caser.ToCase(s, strcase.LowerCase, 0)
}, nil

default:
return nil, fmt.Errorf("unsupported case: %s", rule.Case)
}
}

func toHeaderCase(caser *strcase.Caser) Converter {
return func(s string) string {
return caser.ToCase(s, strcase.TitleCase, '-')
}
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module github.com/ldez/tagliatelle
go 1.22.0

require (
github.com/ettle/strcase v0.2.0
github.com/ettle/strcase v0.2.1-0.20230114185658-e5db6a6becf3
github.com/hashicorp/go-immutable-radix/v2 v2.1.0
golang.org/x/tools v0.27.0
)
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
github.com/ettle/strcase v0.2.0 h1:fGNiVF21fHXpX1niBgk0aROov1LagYsOwV/xqKDKR/Q=
github.com/ettle/strcase v0.2.0/go.mod h1:DajmHElDSaX76ITe3/VHVyMin4LWSJN5Z909Wp+ED1A=
github.com/ettle/strcase v0.2.1-0.20230114185658-e5db6a6becf3 h1:UveVPOxnOkBoelw2vLZTm+L0Z7fe/nz5d6JlY+A3QdE=
github.com/ettle/strcase v0.2.1-0.20230114185658-e5db6a6becf3/go.mod h1:DajmHElDSaX76ITe3/VHVyMin4LWSJN5Z909Wp+ED1A=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/hashicorp/go-immutable-radix/v2 v2.1.0 h1:CUW5RYIcysz+D3B+l1mDeXrQ7fUvGGCwJfdASSzbrfo=
Expand Down
56 changes: 45 additions & 11 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,15 +97,14 @@ type Foo struct {
}
```

## What this tool is about
## What this linter is about

This tool is about validating tags according to rules you define.
The tool also allows to fix tags according to the rules you defined.
This linter is about validating tags according to rules you define.
The linter also allows to fix tags according to the rules you defined.

This tool is not intended to validate the fact a tag in valid or not.
To do that, you can use `go vet`, or use [golangci-lint](https://golangci-lint.run) ["go vet"](https://golangci-lint.run/usage/linters/#govet) linter.
This linter is not intended to validate the fact a tag in valid or not.

## How to use the tool
## How to use the linter

### As a golangci-lint linter

Expand All @@ -114,9 +113,9 @@ Define the rules, you want via your [golangci-lint](https://golangci-lint.run) c
```yaml
linters-settings:
tagliatelle:
# Check the struct tag name case.
# Checks the struct tag name case.
case:
# Define the association between tag name and case.
# Defines the association between tag name and case.
# Any struct tag name can be used.
# Supported string cases:
# - `camel`
Expand All @@ -142,7 +141,38 @@ linters-settings:
env: upperSnake
envconfig: upperSnake
whatever: snake
# Use the struct field name to check the name of the struct tag.
# Defines the association between tag name and case.
# Important: the `extended-rules` overrides `rules`.
# Default: empty
extended-rules:
json:
# Supported string cases:
# - `camel`
# - `pascal`
# - `kebab`
# - `snake`
# - `upperSnake`
# - `goCamel`
# - `goPascal`
# - `goKebab`
# - `goSnake`
# - `header`
# - `lower`
# - `header`
#
# Required
case: camel
# Adds 'AMQP', 'DB', 'GID', 'RTP', 'SIP', 'TS' to initialisms,
# and removes 'LHS', 'RHS' from initialisms.
# Default: true
extra-initialisms: false
# Defines initialism additions and overrides.
# Default: empty
initialism-overrides:
DB: true # add a new initialism
LHS: false # disable a default initialism.
# ...
# Uses the struct field name to check the name of the struct tag.
# Default: false
use-field-name: true
# The field names to ignore.
Expand All @@ -161,6 +191,9 @@ linters-settings:
rules:
json: snake
xml: pascal
# Default: empty or the same as the default/root configuration.
extended-rules:
# same options as the base `extended-rules`.
# Default: false (WARNING: it doesn't follow the default/root configuration)
use-field-name: true
# The field names to ignore.
Expand All @@ -171,6 +204,7 @@ linters-settings:
# Ignore the package (takes precedence over all other configurations).
# Default: false
ignore: true

```

#### Examples
Expand Down Expand Up @@ -251,9 +285,9 @@ Here are the default rules for the well known and used tags, when using tagliate

### Custom Rules

The tool is not limited to the tags used in example, you can use it to validate any tag.
The linter is not limited to the tags used in example, **you can use it to validate any tag**.

You can add your own tag, for example `whatever` and tells the tool you want to use `kebab`.
You can add your own tag, for example `whatever` and tells the linter you want to use `kebab`.

This option is only available via [golangci-lint](https://golangci-lint.run).

Expand Down
Loading

0 comments on commit 29393e1

Please sign in to comment.