package field import ( "strings" "git.cw.tr/mukan-network/mukan-ignite/ignite/pkg/errors" "git.cw.tr/mukan-network/mukan-ignite/ignite/pkg/multiformatname" "git.cw.tr/mukan-network/mukan-ignite/ignite/templates/field/datatype" ) // validateField validates the field Name and type, and checks the name is not forbidden by Ignite CLI. func validateField(field string, isForbiddenField func(string) error) (multiformatname.Name, datatype.Name, error) { name, dataTypeName, err := parseField(field) if err != nil { return name, "", err } // Ensure the field Name is not a Go reserved Name, it would generate an incorrect code if err := isForbiddenField(name.LowerCamel); err != nil { return name, "", errors.Errorf("%s can't be used as a field Name: %w", name, err) } return name, dataTypeName, nil } // parseField parses the field string and returns the multiformat name and datatype name. func parseField(field string) (multiformatname.Name, datatype.Name, error) { fieldSplit := strings.Split(field, datatype.Separator) if len(fieldSplit) > 2 { return multiformatname.Name{}, "", errors.Errorf("invalid field format: %s, should be 'Name' or 'Name:type'", field) } name, err := multiformatname.NewName(fieldSplit[0]) if err != nil { return name, "", err } // Check if the object has an explicit type. The default is a string dataTypeName := datatype.String isTypeSpecified := len(fieldSplit) == 2 if isTypeSpecified { dataTypeName = datatype.Name(fieldSplit[1]) } return name, dataTypeName, nil } // MultipleCoins checks if the provided fields contain more than one coin type. func MultipleCoins(fields []string) (bool, error) { coinsCount := 0 for _, field := range fields { _, datatypeName, err := parseField(field) if err != nil { return false, err } if datatypeName == datatype.Coins || datatypeName == datatype.DecCoins || datatypeName == datatype.CoinSliceAlias || datatypeName == datatype.DecCoinSliceAlias { coinsCount++ } } return coinsCount > 1, nil } // ParseFields parses the provided fields, analyses the types // and checks there is no duplicated field. func ParseFields( fields []string, isForbiddenField func(string) error, forbiddenFieldNames ...string, ) (Fields, error) { // Used to check duplicated field existingFields := make(map[string]struct{}) for _, name := range forbiddenFieldNames { if name != "" { existingFields[name] = struct{}{} } } var parsedFields Fields for _, field := range fields { name, datatypeName, err := validateField(field, isForbiddenField) if err != nil { return parsedFields, err } // Ensure the field is not duplicated if _, exists := existingFields[name.LowerCamel]; exists { return parsedFields, errors.Errorf("the field %s is duplicated", name.Original) } existingFields[name.LowerCamel] = struct{}{} // Check if is a static type if _, ok := datatype.IsSupportedType(datatypeName); ok { parsedFields = append(parsedFields, Field{ Name: name, DatatypeName: datatypeName, }) continue } if strings.HasPrefix(string(datatypeName), datatype.ArrayPrefix) { customArrayType := strings.TrimPrefix(string(datatypeName), datatype.ArrayPrefix) if _, ok := datatype.IsSupportedType(datatype.Name(customArrayType)); !ok { parsedFields = append(parsedFields, Field{ Name: name, Datatype: normalizeCustomTypeName(customArrayType), DatatypeName: datatype.CustomSlice, }) continue } } parsedFields = append(parsedFields, Field{ Name: name, Datatype: normalizeCustomTypeName(string(datatypeName)), DatatypeName: datatype.TypeCustom, }) } return parsedFields, nil } func normalizeCustomTypeName(customType string) string { name, err := multiformatname.NewName(customType) if err != nil { return customType } return name.UpperCamel }