整理代码结构, 增加普通结构体单元测试
This commit is contained in:
		
							
								
								
									
										44
									
								
								abstract.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								abstract.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,44 @@ | ||||
| // Package dynamicstruct ... | ||||
| // | ||||
| // Description : dynamicstruct ... | ||||
| // | ||||
| // Author : go_developer@163.com<白茶清欢> | ||||
| // | ||||
| // Date : 2025-03-23 13:34 | ||||
| package dynamicstruct | ||||
|  | ||||
| // IBuilder 运行时动态生成结构体的接口约束 | ||||
| type IBuilder interface { | ||||
| 	// AddField 添加结构体字段 | ||||
| 	AddField(name string, pkg string, typ any, tag string, anonymous bool) IBuilder | ||||
| 	// RemoveField 移除指定名称的结构体字段 | ||||
| 	RemoveField(name string) IBuilder | ||||
| 	// HasField 检测指定名称的结构体字段是否存在 | ||||
| 	HasField(name string) bool | ||||
| 	// GetField 根据名称获取结构体字段定义 | ||||
| 	GetField(name string) IFieldConfig | ||||
| 	// Build 返回动态定义的结构体. | ||||
| 	Build() IDynamicStruct | ||||
| } | ||||
|  | ||||
| // IFieldConfig 结构体字段的定义. | ||||
| type IFieldConfig interface { | ||||
| 	// SetType 设置字段类型. | ||||
| 	SetType(typ any) IFieldConfig | ||||
| 	// SetTag 设置字段 tag. | ||||
| 	SetTag(tag string) IFieldConfig | ||||
| } | ||||
|  | ||||
| // IDynamicStruct contains defined dynamic struct. | ||||
| // This definition can't be changed anymore, once is built. | ||||
| // It provides a method for creating new instances of same defintion. | ||||
| type IDynamicStruct interface { | ||||
| 	// New 获取结构体实例, 所有字段值均为对应类型的初始零值 | ||||
| 	New() any | ||||
|  | ||||
| 	// NewSliceOfStructs slice实例化 | ||||
| 	NewSliceOfStructs() any | ||||
|  | ||||
| 	// NewMapOfStructs map 或者 struct实例化 | ||||
| 	NewMapOfStructs(key any) any | ||||
| } | ||||
							
								
								
									
										119
									
								
								builder.go
									
									
									
									
									
								
							
							
						
						
									
										119
									
								
								builder.go
									
									
									
									
									
								
							| @ -7,73 +7,22 @@ import ( | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| type ( | ||||
| 	// Builder 运行时动态生成结构体的接口约束 | ||||
| 	Builder interface { | ||||
| 		// AddField 添加结构体字段 | ||||
| 		AddField(name string, pkg string, typ any, tag string, anonymous bool) Builder | ||||
| 		// RemoveField 移除指定名称的结构体字段 | ||||
| 		RemoveField(name string) Builder | ||||
| 		// HasField 检测指定名称的结构体字段是否存在 | ||||
| 		HasField(name string) bool | ||||
| 		// GetField 根据名称获取结构体字段定义 | ||||
| 		GetField(name string) FieldConfig | ||||
| 		// Build 返回动态定义的结构体. | ||||
| 		Build() DynamicStruct | ||||
| 	} | ||||
| type nestedStruct struct { | ||||
| 	Field   string | ||||
| 	Builder IBuilder | ||||
| 	Tag     string | ||||
| } | ||||
|  | ||||
| 	// FieldConfig 结构体字段的定义. | ||||
| 	FieldConfig interface { | ||||
| 		// SetType 设置字段类型. | ||||
| 		SetType(typ any) FieldConfig | ||||
| 		// SetTag 设置字段 tag. | ||||
| 		SetTag(tag string) FieldConfig | ||||
| 	} | ||||
|  | ||||
| 	// DynamicStruct contains defined dynamic struct. | ||||
| 	// This definition can't be changed anymore, once is built. | ||||
| 	// It provides a method for creating new instances of same defintion. | ||||
| 	DynamicStruct interface { | ||||
| 		// New 获取结构体实例, 所有字段值均为对应类型的初始零值 | ||||
| 		New() any | ||||
|  | ||||
| 		// NewSliceOfStructs slice实例化 | ||||
| 		NewSliceOfStructs() any | ||||
|  | ||||
| 		// NewMapOfStructs map 或者 struct实例化 | ||||
| 		NewMapOfStructs(key any) any | ||||
| 	} | ||||
|  | ||||
| 	nestedStruct struct { | ||||
| 		Field   string | ||||
| 		Builder Builder | ||||
| 		Tag     string | ||||
| 	} | ||||
|  | ||||
| 	builderImpl struct { | ||||
| 		fields            []*fieldConfigImpl | ||||
| 		nestedStructTable map[string]nestedStruct // 嵌套结构体的定义, 父级路径 => 父级路径下挂接的子路径 | ||||
| 		maxFieldDeep      int                     // 字段嵌套最大深度 | ||||
| 		structTagTable    map[string]string       // 字段路径 => json tag,最高优先级, 没传的时候会使用AddField的tag, 也为空使用手搓json tag | ||||
| 	} | ||||
|  | ||||
| 	fieldConfigImpl struct { | ||||
| 		name      string | ||||
| 		pkg       string | ||||
| 		typ       any | ||||
| 		tag       string | ||||
| 		anonymous bool | ||||
| 	} | ||||
|  | ||||
| 	dynamicStructImpl struct { | ||||
| 		structFields []reflect.StructField | ||||
| 		definition   reflect.Type | ||||
| 	} | ||||
| ) | ||||
| type builderImpl struct { | ||||
| 	fields            []*fieldConfigImpl | ||||
| 	nestedStructTable map[string]nestedStruct // 嵌套结构体的定义, 父级路径 => 父级路径下挂接的子路径 | ||||
| 	maxFieldDeep      int                     // 字段嵌套最大深度 | ||||
| 	structTagTable    map[string]string       // 字段路径 => json tag,最高优先级, 没传的时候会使用AddField的tag, 也为空使用手搓json tag | ||||
| } | ||||
|  | ||||
| // NewStruct 获取builder实例 | ||||
| // 传入的tag映射表: 字段路径 => json tag,最高优先级, 没传的时候会使用AddField的tag, 也为空使用手搓json tag | ||||
| func NewStruct(structTagTable map[string]string) Builder { | ||||
| func NewStruct(structTagTable map[string]string) IBuilder { | ||||
| 	return &builderImpl{ | ||||
| 		fields:            []*fieldConfigImpl{}, | ||||
| 		nestedStructTable: make(map[string]nestedStruct), | ||||
| @ -82,12 +31,12 @@ func NewStruct(structTagTable map[string]string) Builder { | ||||
| } | ||||
|  | ||||
| // ExtendStruct 基于已有结构体, 生成动态结构体(相当于继承指定的结构体属性) | ||||
| func ExtendStruct(value ...any) Builder { | ||||
| func ExtendStruct(value ...any) IBuilder { | ||||
| 	return MergeStructs(value...) | ||||
| } | ||||
|  | ||||
| // MergeStructs 多个结构体合并成一个动态结构体 | ||||
| func MergeStructs(values ...any) Builder { | ||||
| func MergeStructs(values ...any) IBuilder { | ||||
| 	builder := NewStruct(map[string]string{}) | ||||
|  | ||||
| 	for _, value := range values { | ||||
| @ -111,8 +60,8 @@ func (b *builderImpl) parseNestedField(fieldName string) ([]string, bool) { | ||||
| } | ||||
|  | ||||
| // AddField 添加结构体字段 | ||||
| func (b *builderImpl) AddField(name string, pkg string, typ any, tag string, anonymous bool) Builder { | ||||
| 	// 瞎话线转驼峰, 传入的name实际对应序列化时的json tag | ||||
| func (b *builderImpl) AddField(name string, pkg string, typ any, tag string, anonymous bool) IBuilder { | ||||
| 	// 下划线转驼峰, 传入的name实际对应序列化时的json tag | ||||
| 	// name = wrapper.String(name).SnakeCaseToCamel() | ||||
| 	if cfgTag, exist := b.structTagTable[name]; exist && len(cfgTag) > 0 { | ||||
| 		tag = cfgTag | ||||
| @ -191,7 +140,7 @@ func (b *builderImpl) addNestedField(nameArr []string, pkg string, typ any, tag | ||||
| } | ||||
|  | ||||
| // RemoveField 根据名称移除结构体字段 | ||||
| func (b *builderImpl) RemoveField(name string) Builder { | ||||
| func (b *builderImpl) RemoveField(name string) IBuilder { | ||||
| 	newFieldList := make([]*fieldConfigImpl, 0) | ||||
| 	for i := range b.fields { | ||||
| 		if b.fields[i].name == name { | ||||
| @ -214,7 +163,7 @@ func (b *builderImpl) HasField(name string) bool { | ||||
| } | ||||
|  | ||||
| // GetField 根据名称获取字段配置, 不存在, 返回nil | ||||
| func (b *builderImpl) GetField(name string) FieldConfig { | ||||
| func (b *builderImpl) GetField(name string) IFieldConfig { | ||||
| 	for i := range b.fields { | ||||
| 		if b.fields[i].name == name { | ||||
| 			return b.fields[i] | ||||
| @ -224,7 +173,7 @@ func (b *builderImpl) GetField(name string) FieldConfig { | ||||
| } | ||||
|  | ||||
| // Build 构建动态结构体 | ||||
| func (b *builderImpl) Build() DynamicStruct { | ||||
| func (b *builderImpl) Build() IDynamicStruct { | ||||
| 	// 按照嵌套深度, 进行一次回溯处理 | ||||
| 	for deep := b.maxFieldDeep - 1; deep > 0; deep-- { | ||||
| 		// 嵌套数据结构 | ||||
| @ -281,7 +230,7 @@ func (b *builderImpl) Build() DynamicStruct { | ||||
| 	var structFields []reflect.StructField | ||||
| 	for _, field := range b.fields { | ||||
| 		if strings.Contains(field.name, ArraySplit) { | ||||
| 			// TODO : 临时过滤, 后续需要在正确逻辑处正确移除 | ||||
| 			// 去除数组路径 | ||||
| 			continue | ||||
| 		} | ||||
| 		structFields = append(structFields, reflect.StructField{ | ||||
| @ -297,31 +246,3 @@ func (b *builderImpl) Build() DynamicStruct { | ||||
| 		definition:   reflect.StructOf(structFields), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // SetType 设置字段类型 | ||||
| func (f *fieldConfigImpl) SetType(typ any) FieldConfig { | ||||
| 	f.typ = typ | ||||
| 	return f | ||||
| } | ||||
|  | ||||
| // SetTag 设置字段标签 | ||||
| func (f *fieldConfigImpl) SetTag(tag string) FieldConfig { | ||||
| 	f.tag = tag | ||||
| 	return f | ||||
| } | ||||
|  | ||||
| // New 创建动态结构体实例 | ||||
| func (ds *dynamicStructImpl) New() any { | ||||
| 	// 不要指针,全部解引用 | ||||
| 	return reflect.New(ds.definition).Interface() | ||||
| } | ||||
|  | ||||
| // NewSliceOfStructs 创建动态结构体切片实例 | ||||
| func (ds *dynamicStructImpl) NewSliceOfStructs() any { | ||||
| 	return reflect.New(reflect.SliceOf(ds.definition)).Interface() | ||||
| } | ||||
|  | ||||
| // NewMapOfStructs 创建动态结构体map实例 | ||||
| func (ds *dynamicStructImpl) NewMapOfStructs(key any) any { | ||||
| 	return reflect.New(reflect.MapOf(reflect.Indirect(reflect.ValueOf(key)).Type(), ds.definition)).Interface() | ||||
| } | ||||
|  | ||||
| @ -9,19 +9,14 @@ package dynamicstruct | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"reflect" | ||||
| 	"testing" | ||||
|  | ||||
| 	. "github.com/smartystreets/goconvey/convey" | ||||
| ) | ||||
|  | ||||
| func Test_dynamicStructImpl_New(t *testing.T) { | ||||
| /*func Test_dynamicStructImpl_New(t *testing.T) { | ||||
| 	instance := NewStruct(map[string]string{}). | ||||
| 		/*AddField("Integer", "", 0, `json:"int"`, false). | ||||
| 		AddField("Text", "", "", `json:"someText"`, false). | ||||
| 		AddField("Float", "", 0.0, `json:"double"`, false). | ||||
| 		AddField("Boolean", "", false, "", false). | ||||
| 		AddField("Slice", "", []int{}, "", false). | ||||
| 		AddField("Anonymous", "", "", `json:"-"`, false).*/ | ||||
| 		AddField("user.base.age", "", 20, `json:"age"`, false). | ||||
| 		AddField("user.base.name", "", "", `json:"name"`, false). | ||||
| 		AddField("user.job.address", "", "", `json:"address"`, false). | ||||
| @ -52,3 +47,50 @@ func Test_dynamicStructImpl_New(t *testing.T) { | ||||
| 	fmt.Println(string(valByte)) | ||||
| 	// fmt.Println(reflect.ValueOf(val).Elem().FieldByName("Integer").Interface()) | ||||
| } | ||||
| */ | ||||
| // TestStruct : 测试结构体 | ||||
| func TestStruct(t *testing.T) { | ||||
| 	Convey("普通结构体,无嵌套", t, func() { | ||||
| 		data := []byte(` | ||||
| 		{ | ||||
| 			"age": 123, | ||||
| 			"name": "example", | ||||
| 			"double": 123.45, | ||||
| 			"tag_map": "ttt", | ||||
| 			"bool": true, | ||||
| 			"slice": [1, 2, 3] | ||||
| 		} | ||||
| 		`) | ||||
| 		instance := NewStruct(map[string]string{ | ||||
| 			"test_tag_map": `json:"tag_map"`, | ||||
| 		}). | ||||
| 			AddField("age", "", 0, `json:"age"`, false). | ||||
| 			AddField("name", "", "", `json:"name"`, false). | ||||
| 			AddField("test_tag_map", "", "", "", false). | ||||
| 			AddField("double", "", 0.0, `json:"double"`, false). | ||||
| 			AddField("bool", "", false, "", false). | ||||
| 			AddField("slice", "", []int{}, `json:"slice"`, false).Build() | ||||
| 		val := instance.New() | ||||
| 		err := json.Unmarshal(data, &val) | ||||
| 		So(err, ShouldBeNil) | ||||
| 		reflectType := reflect.TypeOf(val) | ||||
| 		// 需要是结构体类型 | ||||
| 		So(reflectType.Elem().Kind(), ShouldEqual, reflect.Struct) | ||||
| 		// 验证数据 | ||||
| 		// 数据序列化成功 | ||||
| 		targetByte, targetErr := json.Marshal(val) | ||||
| 		So(targetErr, ShouldBeNil) | ||||
| 		// 数据转map成功 | ||||
| 		var res map[string]any | ||||
| 		targetUnmarshalErr := json.Unmarshal(targetByte, &res) | ||||
| 		So(targetUnmarshalErr, ShouldBeNil) | ||||
| 		// 验证数据 | ||||
| 		So(len(res), ShouldEqual, 6) | ||||
| 		So(res["age"], ShouldEqual, float64(123)) | ||||
| 		So(res["name"], ShouldEqual, "example") | ||||
| 		So(res["tag_map"], ShouldEqual, "ttt") | ||||
| 		So(res["double"], ShouldEqual, 123.45) | ||||
| 		So(res["bool"], ShouldEqual, true) | ||||
| 		So(res["slice"], ShouldEqual, []any{float64(1), float64(2), float64(3)}) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
							
								
								
									
										31
									
								
								dynamic_struct.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								dynamic_struct.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,31 @@ | ||||
| // Package dynamicstruct ... | ||||
| // | ||||
| // Description : dynamicstruct ... | ||||
| // | ||||
| // Author : go_developer@163.com<白茶清欢> | ||||
| // | ||||
| // Date : 2025-03-23 14:14 | ||||
| package dynamicstruct | ||||
|  | ||||
| import "reflect" | ||||
|  | ||||
| type dynamicStructImpl struct { | ||||
| 	structFields []reflect.StructField | ||||
| 	definition   reflect.Type | ||||
| } | ||||
|  | ||||
| // New 创建动态结构体实例 | ||||
| func (ds *dynamicStructImpl) New() any { | ||||
| 	// 不要指针,全部解引用 | ||||
| 	return reflect.New(ds.definition).Interface() | ||||
| } | ||||
|  | ||||
| // NewSliceOfStructs 创建动态结构体切片实例 | ||||
| func (ds *dynamicStructImpl) NewSliceOfStructs() any { | ||||
| 	return reflect.New(reflect.SliceOf(ds.definition)).Interface() | ||||
| } | ||||
|  | ||||
| // NewMapOfStructs 创建动态结构体map实例 | ||||
| func (ds *dynamicStructImpl) NewMapOfStructs(key any) any { | ||||
| 	return reflect.New(reflect.MapOf(reflect.Indirect(reflect.ValueOf(key)).Type(), ds.definition)).Interface() | ||||
| } | ||||
							
								
								
									
										28
									
								
								field_config.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								field_config.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,28 @@ | ||||
| // Package dynamicstruct ... | ||||
| // | ||||
| // Description : dynamicstruct ... | ||||
| // | ||||
| // Author : go_developer@163.com<白茶清欢> | ||||
| // | ||||
| // Date : 2025-03-23 14:07 | ||||
| package dynamicstruct | ||||
|  | ||||
| type fieldConfigImpl struct { | ||||
| 	name      string | ||||
| 	pkg       string | ||||
| 	typ       any | ||||
| 	tag       string | ||||
| 	anonymous bool | ||||
| } | ||||
|  | ||||
| // SetType 设置字段类型 | ||||
| func (f *fieldConfigImpl) SetType(typ any) IFieldConfig { | ||||
| 	f.typ = typ | ||||
| 	return f | ||||
| } | ||||
|  | ||||
| // SetTag 设置字段标签 | ||||
| func (f *fieldConfigImpl) SetTag(tag string) IFieldConfig { | ||||
| 	f.tag = tag | ||||
| 	return f | ||||
| } | ||||
							
								
								
									
										13
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								go.mod
									
									
									
									
									
								
							| @ -2,18 +2,29 @@ module git.zhangdeman.cn/zhangdeman/dynamic-struct | ||||
|  | ||||
| go 1.24.1 | ||||
|  | ||||
| require ( | ||||
| 	git.zhangdeman.cn/zhangdeman/wrapper v0.0.0-20250302133417-c1588abcb436 | ||||
| 	github.com/smartystreets/goconvey v1.8.1 | ||||
| ) | ||||
|  | ||||
| require ( | ||||
| 	git.zhangdeman.cn/zhangdeman/consts v0.0.0-20250227040546-863c03f34bb8 // indirect | ||||
| 	git.zhangdeman.cn/zhangdeman/op_type v0.0.0-20240122104027-4928421213c0 // indirect | ||||
| 	git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20241223084948-de2e49144fcd // indirect | ||||
| 	git.zhangdeman.cn/zhangdeman/util v0.0.0-20240618042405-6ee2c904644e // indirect | ||||
| 	git.zhangdeman.cn/zhangdeman/wrapper v0.0.0-20250302133417-c1588abcb436 // indirect | ||||
| 	github.com/BurntSushi/toml v1.5.0 // indirect | ||||
| 	github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394 // indirect | ||||
| 	github.com/go-ini/ini v1.67.0 // indirect | ||||
| 	github.com/gopherjs/gopherjs v1.17.2 // indirect | ||||
| 	github.com/jtolds/gls v4.20.0+incompatible // indirect | ||||
| 	github.com/smarty/assertions v1.15.0 // indirect | ||||
| 	github.com/spaolacci/murmur3 v1.1.0 // indirect | ||||
| 	github.com/tidwall/gjson v1.18.0 // indirect | ||||
| 	github.com/tidwall/match v1.1.1 // indirect | ||||
| 	github.com/tidwall/pretty v1.2.1 // indirect | ||||
| 	golang.org/x/mod v0.24.0 // indirect | ||||
| 	golang.org/x/sync v0.12.0 // indirect | ||||
| 	golang.org/x/sys v0.31.0 // indirect | ||||
| 	golang.org/x/tools v0.31.0 // indirect | ||||
| 	gopkg.in/yaml.v3 v3.0.1 // indirect | ||||
| ) | ||||
|  | ||||
							
								
								
									
										25
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								go.sum
									
									
									
									
									
								
							| @ -12,10 +12,26 @@ github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg | ||||
| github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= | ||||
| github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394 h1:OYA+5W64v3OgClL+IrOD63t4i/RW7RqrAVl9LTZ9UqQ= | ||||
| github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394/go.mod h1:Q8n74mJTIgjX4RBBcHnJ05h//6/k6foqmgE45jTQtxg= | ||||
| github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||||
| github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||||
| github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A= | ||||
| github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= | ||||
| github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g= | ||||
| github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k= | ||||
| github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= | ||||
| github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= | ||||
| github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= | ||||
| github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= | ||||
| github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||||
| github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||||
| github.com/smarty/assertions v1.15.0 h1:cR//PqUBUiQRakZWqBiFFQ9wb8emQGDb0HeGdqGByCY= | ||||
| github.com/smarty/assertions v1.15.0/go.mod h1:yABtdzeQs6l1brC900WlRNwj6ZR55d7B+E8C6HtKdec= | ||||
| github.com/smartystreets/goconvey v1.8.1 h1:qGjIddxOk4grTu9JPOU31tVfq3cNdBlNa5sSznIX1xY= | ||||
| github.com/smartystreets/goconvey v1.8.1/go.mod h1:+/u4qLyY6x1jReYOp7GOM2FSt8aP9CzCZL03bI28W60= | ||||
| github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= | ||||
| github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= | ||||
| github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= | ||||
| github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= | ||||
| github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= | ||||
| github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= | ||||
| github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= | ||||
| @ -23,6 +39,15 @@ github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JT | ||||
| github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= | ||||
| github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= | ||||
| github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= | ||||
| golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU= | ||||
| golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= | ||||
| golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= | ||||
| golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= | ||||
| golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= | ||||
| golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= | ||||
| golang.org/x/tools v0.31.0 h1:0EedkvKDbh+qistFTd0Bcwe/YLh4vHwWEkiI0toFIBU= | ||||
| golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ= | ||||
| gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= | ||||
| gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||||
| gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | ||||
| gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||||
|  | ||||
		Reference in New Issue
	
	Block a user