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 + "}"
}