update definition

This commit is contained in:
2025-11-21 14:30:34 +03:00
parent 516f22bd6c
commit 5c10b432f7
19 changed files with 124 additions and 536 deletions

View File

@@ -1,7 +1,7 @@
package definition
import (
"fmt"
"gitoa.ru/go-4devs/config"
)
func New() Definition {
@@ -11,21 +11,9 @@ func New() Definition {
}
type Definition struct {
options Options
options []config.Option
}
func (d *Definition) Add(opts ...Option) *Definition {
func (d *Definition) Add(opts ...config.Option) {
d.options = append(d.options, opts...)
return d
}
func (d *Definition) View(handle func(Option) error) error {
for idx, opt := range d.options {
if err := handle(opt); err != nil {
return fmt.Errorf("%s[%d]:%w", opt.Kind(), idx, err)
}
}
return nil
}

View File

@@ -1,71 +0,0 @@
package generate
import (
"fmt"
"io"
"gitoa.ru/go-4devs/config/definition"
)
type Generator struct {
ViewOption
pkg string
Imp Imports
errs []error
defaultErrors []string
}
func (g *Generator) Pkg() string {
return g.pkg
}
func (g *Generator) Imports() []Import {
return g.Imp.Imports()
}
func (g *Generator) Handle(w io.Writer, data Handler, opt definition.Option) error {
handle := get(opt.Kind())
return handle(w, data, opt)
}
func (g *Generator) StructName() string {
return FuncName(g.Prefix + "_" + g.Struct + "_" + g.Suffix)
}
func (g *Generator) Options() ViewOption {
return g.ViewOption
}
func (g *Generator) Keys() []string {
return nil
}
func (g *Generator) DefaultErrors() []string {
if len(g.defaultErrors) > 0 {
return g.defaultErrors
}
if len(g.Errors.Default) > 0 {
g.Imp.Adds("errors")
}
g.defaultErrors = make([]string, len(g.Errors.Default))
for idx, name := range g.Errors.Default {
short, err := g.AddType(name)
if err != nil {
g.errs = append(g.errs, fmt.Errorf("add default error[%d]:%w", idx, err))
return nil
}
g.defaultErrors[idx] = short
}
return g.defaultErrors
}
func (g *Generator) AddType(pkg string) (string, error) {
return g.Imp.AddType(pkg)
}

View File

@@ -1,18 +0,0 @@
package generate
import (
"errors"
"github.com/iancoleman/strcase"
)
var (
ErrNotFound = errors.New("not found")
ErrAlreadyExist = errors.New("already exist")
ErrWrongType = errors.New("wrong type")
ErrWrongFormat = errors.New("wrong format")
)
func FuncName(in string) string {
return strcase.ToCamel(in)
}

View File

@@ -1,89 +0,0 @@
package generate
import (
"fmt"
"strconv"
"strings"
)
func NewImports() Imports {
return Imports{
data: make(map[string]string),
}
}
type Imports struct {
data map[string]string
}
func (i *Imports) Imports() []Import {
imports := make([]Import, 0, len(i.data))
for name, alias := range i.data {
imports = append(imports, Import{
Package: name,
Alias: alias,
})
}
return imports
}
func (i *Imports) Short(fullType string) (string, error) {
idx := strings.LastIndexByte(fullType, '.')
if idx == -1 {
return "", fmt.Errorf("%w: expect package.Type", ErrWrongFormat)
}
if alias, ok := i.data[fullType[:idx]]; ok {
return alias + fullType[idx:], nil
}
return "", fmt.Errorf("%w alias for pkg %v", ErrNotFound, fullType[:idx])
}
func (i *Imports) AddType(fullType string) (string, error) {
idx := strings.LastIndexByte(fullType, '.')
if idx == -1 {
return "", fmt.Errorf("%w: expect pckage.Type", ErrWrongFormat)
}
imp := i.Add(fullType[:idx])
return imp.Alias + fullType[idx:], nil
}
func (i *Imports) Adds(pkgs ...string) {
for _, pkg := range pkgs {
i.Add(pkg)
}
}
func (i *Imports) Add(pkg string) Import {
alias := pkg
if idx := strings.LastIndexByte(pkg, '/'); idx != -1 {
alias = pkg[idx+1:]
}
if al, ok := i.data[pkg]; ok {
return Import{Package: pkg, Alias: al}
}
for _, al := range i.data {
if al == alias {
alias += strconv.Itoa(len(i.data))
}
}
i.data[pkg] = alias
return Import{
Alias: alias,
Package: pkg,
}
}
type Import struct {
Alias string
Package string
}

View File

@@ -1,41 +0,0 @@
package generate
import (
"bytes"
"fmt"
"io"
"gitoa.ru/go-4devs/config/definition"
)
func Run(w io.Writer, pkgName string, defs definition.Definition, viewOpt ViewOption) error {
gen := Generator{
errs: nil,
defaultErrors: nil,
pkg: pkgName,
ViewOption: viewOpt,
Imp: NewImports(),
}
gen.Imp.Adds("gitoa.ru/go-4devs/config", "fmt", "context")
var view bytes.Buffer
err := defs.View(func(o definition.Option) error {
return gen.Handle(&view, &gen, o)
})
if err != nil {
return fmt.Errorf("render options:%w", err)
}
if err := tpl.Execute(w, gen); err != nil {
return fmt.Errorf("render base:%w", err)
}
_, cerr := io.Copy(w, &view)
if cerr != nil {
return fmt.Errorf("copy error:%w", cerr)
}
return nil
}

View File

@@ -1,42 +0,0 @@
package generate
import "text/template"
var (
tpl = template.Must(template.New("tpls").Parse(baseTemplate))
baseTemplate = `// Code generated gitoa.ru/go-4devs/config DO NOT EDIT.
package {{.Pkg}}
import (
{{range .Imports}}
{{- .Alias }}"{{ .Package }}"
{{end}}
)
func With{{.StructName}}Log(log func(context.Context, string, ...any)) func(*{{.StructName}}) {
return func(ci *{{.StructName}}) {
ci.log = log
}
}
func New{{.StructName}}(prov config.Provider, opts ...func(*{{.StructName}})) {{.StructName}} {
i := {{.StructName}}{
Provider: prov,
log: func(_ context.Context, format string, args ...any) {
fmt.Printf(format, args...)
},
}
for _, opt := range opts {
opt(&i)
}
return i
}
type {{.StructName}} struct {
config.Provider
log func(context.Context, string, ...any)
}
`
)

View File

@@ -1,62 +0,0 @@
package generate
import (
"fmt"
"io"
"sync"
"gitoa.ru/go-4devs/config/definition"
)
var handlers = sync.Map{}
func Add(kind string, h Handle) error {
_, ok := handlers.Load(kind)
if ok {
return fmt.Errorf("kind %v: %w", kind, ErrAlreadyExist)
}
handlers.Store(kind, h)
return nil
}
//nolint:forcetypeassert
func get(kind string) Handle {
handler, ok := handlers.Load(kind)
if !ok {
return func(_ io.Writer, _ Handler, _ definition.Option) error {
return fmt.Errorf("handler by %v:%w", kind, ErrNotFound)
}
}
return handler.(Handle)
}
func MustAdd(kind string, h Handle) {
if err := Add(kind, h); err != nil {
panic(err)
}
}
type Handle func(io.Writer, Handler, definition.Option) error
type Handler interface {
StructName() string
Handle(w io.Writer, handler Handler, opt definition.Option) error
Options() ViewOption
Keys() []string
AddType(fullName string) (string, error)
DefaultErrors() []string
}
type ViewOption struct {
Prefix, Suffix string
Context bool
Struct string
Errors ViewErrors
}
type ViewErrors struct {
Default []string
}

View File

@@ -1,25 +1,36 @@
package group
import (
"gitoa.ru/go-4devs/config/definition"
"gitoa.ru/go-4devs/config"
"gitoa.ru/go-4devs/config/definition/option"
"gitoa.ru/go-4devs/config/param"
)
const Kind = "group"
var (
_ config.Group = New("", "")
)
func New(name, desc string, opts ...definition.Option) Group {
return Group{
Name: name,
Description: desc,
Options: opts,
func New(name, desc string, opts ...config.Option) Group {
group := Group{
name: name,
opts: opts,
Params: param.New(option.Description(desc)),
}
return group
}
type Group struct {
Options definition.Options
Name string
Description string
param.Params
name string
opts []config.Option
}
func (o Group) Kind() string {
return Kind
func (g Group) Name() string {
return g.name
}
func (g Group) Options() []config.Option {
return g.opts
}

View File

@@ -1,89 +0,0 @@
package group
import (
"fmt"
"io"
"text/template"
"gitoa.ru/go-4devs/config/definition"
"gitoa.ru/go-4devs/config/definition/generate"
)
//nolint:gochecknoinits
func init() {
generate.MustAdd(Kind, handle)
}
func handle(w io.Writer, data generate.Handler, option definition.Option) error {
group, ok := option.(Group)
if !ok {
return fmt.Errorf("%w:%T", generate.ErrWrongType, option)
}
viewData := View{
Group: group,
ParentName: data.StructName(),
ViewOption: data.Options(),
}
err := tpl.Execute(w, viewData)
if err != nil {
return fmt.Errorf("render group:%w", err)
}
childData := ChildData{
Handler: data,
structName: viewData.StructName(),
keys: append(data.Keys(), group.Name),
}
for idx, child := range group.Options {
if cerr := data.Handle(w, childData, child); cerr != nil {
return fmt.Errorf("render group child[%d]:%w", idx, cerr)
}
}
return nil
}
type ChildData struct {
generate.Handler
structName string
keys []string
}
func (c ChildData) StructName() string {
return c.structName
}
func (c ChildData) Keys() []string {
return c.keys
}
type View struct {
Group
generate.ViewOption
ParentName string
}
func (v View) FuncName() string {
return generate.FuncName(v.Name)
}
func (v View) StructName() string {
return generate.FuncName(v.Prefix + v.Name + v.Suffix)
}
var (
tpl = template.Must(template.New("tpls").Parse(gpoupTemplate))
gpoupTemplate = `type {{.StructName}} struct {
{{.ParentName}}
}
// {{.FuncName}} {{.Description}}.
func (i {{.ParentName}}) {{.FuncName}}() {{.StructName}} {
return {{.StructName}}{i}
}
`
)

View File

@@ -1,27 +0,0 @@
package definition
type Option interface {
Kind() string
}
type Options []Option
func (s Options) Len() int { return len(s) }
func (s Options) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
type Params []Param
func (p Params) Get(name string) (any, bool) {
for _, param := range p {
if param.Name == name {
return param.Value, true
}
}
return nil, false
}
type Param struct {
Name string
Value any
}

View File

@@ -3,21 +3,24 @@ package option
import (
"time"
"gitoa.ru/go-4devs/config"
"gitoa.ru/go-4devs/config/param"
)
var _ config.Option = New("", "", nil)
func New(name, desc string, vtype any, opts ...param.Option) Option {
opts = append(opts, Description(desc), WithType(vtype))
res := Option{
name: name,
Param: param.New(opts...),
name: name,
Params: param.New(opts...),
}
return res
}
type Option struct {
param.Param
param.Params
name string
}

View File

@@ -19,25 +19,25 @@ const (
)
func Short(in rune) param.Option {
return func(v param.Param) param.Param {
return func(v param.Params) param.Params {
return param.With(v, paramShort, string(in))
}
}
func ParamShort(fn param.Param) (string, bool) {
func ParamShort(fn param.Params) (string, bool) {
data, ok := param.String(paramShort, fn)
return data, ok
}
func HasShort(short string, fn param.Param) bool {
func HasShort(short string, fn param.Params) bool {
data, ok := param.String(paramShort, fn)
return ok && data == short
}
func WithType(in any) param.Option {
return func(v param.Param) param.Param {
return func(v param.Params) param.Params {
out := param.With(v, paramType, in)
if _, ok := in.(bool); ok {
return param.With(out, paramBool, ok)
@@ -48,82 +48,82 @@ func WithType(in any) param.Option {
}
func Position(pos uint64) param.Option {
return func(p param.Param) param.Param {
return func(p param.Params) param.Params {
return param.With(p, paramPos, pos)
}
}
func Hidden(v param.Param) param.Param {
func Hidden(v param.Params) param.Params {
return param.With(v, paramHidden, true)
}
func Required(v param.Param) param.Param {
func Required(v param.Params) param.Params {
return param.With(v, paramRequired, true)
}
func Slice(v param.Param) param.Param {
func Slice(v param.Params) param.Params {
return param.With(v, paramSlice, true)
}
func Default(in any) param.Option {
return func(v param.Param) param.Param {
return func(v param.Params) param.Params {
return param.With(v, paramDefault, in)
}
}
func Description(in string) param.Option {
return func(v param.Param) param.Param {
return func(v param.Params) param.Params {
return param.With(v, paramDesc, in)
}
}
func HasDefaut(fn param.Param) bool {
_, ok := fn.Value(paramDefault)
func HasDefaut(fn param.Params) bool {
_, ok := fn.Param(paramDefault)
return ok
}
func DataPosition(fn param.Param) (uint64, bool) {
func DataPosition(fn param.Params) (uint64, bool) {
return param.Uint64(paramPos, fn)
}
func DataDefaut(fn param.Param) (any, bool) {
data, ok := fn.Value(paramDefault)
func DataDefaut(fn param.Params) (any, bool) {
data, ok := fn.Param(paramDefault)
return data, ok
}
func IsSlice(fn param.Param) bool {
func IsSlice(fn param.Params) bool {
data, ok := param.Bool(paramSlice, fn)
return ok && data
}
func IsBool(fn param.Param) bool {
func IsBool(fn param.Params) bool {
data, ok := param.Bool(paramBool, fn)
return ok && data
}
func IsHidden(fn param.Param) bool {
func IsHidden(fn param.Params) bool {
data, ok := param.Bool(paramHidden, fn)
return ok && data
}
func IsRequired(fn param.Param) bool {
func IsRequired(fn param.Params) bool {
data, ok := param.Bool(paramRequired, fn)
return ok && data
}
func DataType(fn param.Param) any {
param, _ := fn.Value(paramType)
func DataType(fn param.Params) any {
param, _ := fn.Param(paramType)
return param
}
func DataDescription(fn param.Param) string {
func DataDescription(fn param.Params) string {
data, _ := param.String(paramDesc, fn)
return data

View File

@@ -1,27 +1,34 @@
package proto
import (
"gitoa.ru/go-4devs/config/definition"
"gitoa.ru/go-4devs/config"
"gitoa.ru/go-4devs/config/definition/option"
"gitoa.ru/go-4devs/config/param"
)
const Kind = "proto"
var (
_ config.Group = New("", "")
)
func New(name, desc string, opt definition.Option) Proto {
pr := Proto{
Name: name,
Description: desc,
Option: opt,
func New(name string, desc string, opts ...config.Option) Proto {
return Proto{
name: name,
opts: opts,
Params: param.New(option.Description(desc)),
}
return pr
}
type Proto struct {
Name string
Description string
Option definition.Option
param.Params
opts []config.Option
name string
}
func (p Proto) Kind() string {
return Kind
func (p Proto) Options() []config.Option {
return p.opts
}
func (p Proto) Name() string {
return "{" + p.name + "}"
}

2
go.mod
View File

@@ -1,5 +1,3 @@
module gitoa.ru/go-4devs/config
go 1.23
require github.com/iancoleman/strcase v0.3.0

2
go.sum
View File

@@ -1,2 +0,0 @@
github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI=
github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=

View File

@@ -2,8 +2,8 @@ package param
import "gitoa.ru/go-4devs/config"
func String(key any, fn Param) (string, bool) {
val, ok := fn.Value(key)
func String(key any, fn Params) (string, bool) {
val, ok := fn.Param(key)
if !ok {
return "", false
}
@@ -13,8 +13,8 @@ func String(key any, fn Param) (string, bool) {
return data, ok
}
func Bool(key any, fn Param) (bool, bool) {
val, ok := fn.Value(key)
func Bool(key any, fn Params) (bool, bool) {
val, ok := fn.Param(key)
if !ok {
return false, false
}
@@ -24,8 +24,8 @@ func Bool(key any, fn Param) (bool, bool) {
return data, ok
}
func Value(key any, fn Param) (config.Value, bool) {
data, ok := fn.Value(key)
func Value(key any, fn Params) (config.Value, bool) {
data, ok := fn.Param(key)
if !ok {
return nil, false
}
@@ -35,8 +35,8 @@ func Value(key any, fn Param) (config.Value, bool) {
return res, ok
}
func Uint64(key any, fn Param) (uint64, bool) {
data, ok := fn.Value(key)
func Uint64(key any, fn Params) (uint64, bool) {
data, ok := fn.Param(key)
if !ok {
return 0, false
}

View File

@@ -7,11 +7,11 @@ const (
)
func WithTimeFormat(format string) Option {
return func(p Param) Param {
return func(p Params) Params {
return With(p, paramTimeFormat, format)
}
}
func TimeFormat(fn Param) (string, bool) {
func TimeFormat(fn Params) (string, bool) {
return String(paramTimeFormat, fn)
}

View File

@@ -8,28 +8,28 @@ var (
emptyParam = empty{}
)
type Option func(p Param) Param
type Option func(p Params) Params
type Param interface {
Value(key any) (any, bool)
type Params interface {
Param(key any) (any, bool)
}
func Chain(vals ...Param) Param {
func Chain(vals ...Params) Params {
slices.Reverse(vals)
return chain(vals)
}
func With(parent Param, key, val any) Param {
func With(parent Params, key, val any) Params {
return value{
Param: parent,
key: key,
val: val,
Params: parent,
key: key,
val: val,
}
}
func New(opts ...Option) Param {
var parms Param
func New(opts ...Option) Params {
var parms Params
parms = emptyParam
@@ -42,29 +42,29 @@ func New(opts ...Option) Param {
type empty struct{}
func (v empty) Value(_ any) (any, bool) {
func (v empty) Param(_ any) (any, bool) {
return nil, false
}
type value struct {
Param
Params
key, val any
}
func (v value) Value(key any) (any, bool) {
func (v value) Param(key any) (any, bool) {
if v.key == key {
return v.val, true
}
return v.Param.Value(key)
return v.Params.Param(key)
}
type chain []Param
type chain []Params
func (c chain) Value(key any) (any, bool) {
func (c chain) Param(key any) (any, bool) {
for _, p := range c {
val, ok := p.Value(key)
val, ok := p.Param(key)
if ok {
return val, ok
}

View File

@@ -18,3 +18,25 @@ type WatchProvider interface {
}
type Factory func(ctx context.Context, cfg Provider) (Provider, error)
type Option interface {
Name() string
Param(key any) (any, bool)
}
type Group interface {
Option
Options
}
type Options interface {
Options() []Option
}
type Definition interface {
Add(opts ...Option)
}
type BindProvider interface {
Bind(ctx context.Context, def Definition)
}