package yaml_checker import ( "github.com/pkg/errors" "gopkg.in/yaml.v3" "os" ) const ( schemaNodeTypeObject = "object" schemaNodeTypeField = "field" ) type SchemaDoc struct { rootSchemas []SchemaNode } type SchemaDocYaml struct { RootSchemas []SchemaYaml `yaml:"schema"` } type SchemaYaml struct { Type string `yaml:"type"` Name string `yaml:"name"` Describe string `yaml:"describe"` Required bool `yaml:"required"` AsArray bool `yaml:"as_array"` // object Fields []SchemaYaml `yaml:"fields"` // field FieldType string `yaml:"field_type"` } func NewSchemaDoc(schemaFilePath string) (*SchemaDoc, error) { if isStringEmpty(schemaFilePath) || !pathExists(schemaFilePath) { return nil, errors.New("schema文件不存在") } validatorFileBytes, err := os.ReadFile(schemaFilePath) if err != nil { return nil, errors.New("读取schema文件错误: " + err.Error()) } schemaDocYaml := new(SchemaDocYaml) err = yaml.Unmarshal(validatorFileBytes, schemaDocYaml) if err != nil { return nil, errors.New("schema文件unmarshal错误: " + err.Error()) } if schemaDocYaml.RootSchemas == nil || len(schemaDocYaml.RootSchemas) == 0 { return nil, errors.New("schema文件结构错误: 没有根节点") } doc := new(SchemaDoc) for _, rootSchema := range schemaDocYaml.RootSchemas { rootSchemaNode, err := newSchemaNode(&rootSchema) if err != nil { return nil, err } doc.rootSchemas = append(doc.rootSchemas, rootSchemaNode) } return doc, nil } func newSchemaNode(schemaNodeYaml *SchemaYaml) (SchemaNode, error) { switch schemaNodeYaml.Type { case schemaNodeTypeObject: return newObjectSchemaNode(schemaNodeYaml) case schemaNodeTypeField: return newFieldSchemaNode(schemaNodeYaml) default: return nil, errors.New("不支持的schema节点类型") } } func newObjectSchemaNode(schemaNodeYaml *SchemaYaml) (*ObjectSchemaNode, error) { if schemaNodeYaml.Type != schemaNodeTypeObject { return nil, errors.New("schema节点类型错误: 期望类型" + schemaNodeTypeObject + " 实际类型" + schemaNodeYaml.Type) } if isStringEmpty(schemaNodeYaml.Name) { return nil, errors.New(schemaNodeTypeObject + "schema类型必须有name属性") } if isStringEmpty(schemaNodeYaml.Describe) { return nil, errors.New(schemaNodeTypeObject + "schema类型必须有describe属性") } if schemaNodeYaml.Fields == nil || len(schemaNodeYaml.Fields) == 0 { return nil, errors.New(schemaNodeTypeObject + "schema类型必须有fields属性") } fieldSchemaNodes := make([]SchemaNode, 0) for _, field := range schemaNodeYaml.Fields { fieldSchemaNode, err := newSchemaNode(&field) if err != nil { return nil, err } fieldSchemaNodes = append(fieldSchemaNodes, fieldSchemaNode) } return &ObjectSchemaNode{ BaseNamingSchemaNode: BaseNamingSchemaNode{ Type: schemaNodeYaml.Type, Name: schemaNodeYaml.Name, Describe: schemaNodeYaml.Describe, Required: schemaNodeYaml.Required, }, AsArray: schemaNodeYaml.AsArray, Fields: fieldSchemaNodes, }, nil } func newFieldSchemaNode(schemaNodeYaml *SchemaYaml) (*FieldSchemaNode, error) { if schemaNodeYaml.Type != schemaNodeTypeField { return nil, errors.New("schema节点类型错误: 期望类型" + schemaNodeTypeField + " 实际类型" + schemaNodeYaml.Type) } if isStringEmpty(schemaNodeYaml.Name) { return nil, errors.New(schemaNodeTypeObject + "schema类型必须有name属性") } if isStringEmpty(schemaNodeYaml.Describe) { return nil, errors.New(schemaNodeTypeObject + "schema类型必须有describe属性") } if isStringEmpty(schemaNodeYaml.FieldType) { return nil, errors.New(schemaNodeTypeObject + "schema类型必须有field_type属性") } return &FieldSchemaNode{ BaseNamingSchemaNode: BaseNamingSchemaNode{ Type: schemaNodeYaml.Type, Name: schemaNodeYaml.Name, Describe: schemaNodeYaml.Describe, Required: schemaNodeYaml.Required, }, AsArray: schemaNodeYaml.AsArray, FieldType: schemaNodeYaml.FieldType, }, nil } func (schemaDoc *SchemaDoc) ValidateFile(filePath string) error { if !pathExists(filePath) { return errors.New("文件不存在: " + filePath) } fileBytes, err := os.ReadFile(filePath) if err != nil { return errors.New("读取文件错误: " + err.Error()) } yamlMap := make(map[string]any) err = yaml.Unmarshal(fileBytes, yamlMap) if err != nil { return errors.New("unmarshal文件错误: " + err.Error()) } return schemaDoc.validate(yamlMap) } func (schemaDoc *SchemaDoc) ValidateMap(yamlMap map[string]any) error { if yamlMap == nil || len(yamlMap) == 0 { return errors.New("没有yaml的map") } return schemaDoc.validate(yamlMap) } func (schemaDoc *SchemaDoc) validate(yamlMap map[string]any) error { for _, rootSchemaNode := range schemaDoc.rootSchemas { err := rootSchemaNode.Validate(yamlMap) if err != nil { return err } } return nil }