Family Expansions
This commit is contained in:
@@ -17,10 +17,20 @@ type familyExpansionSource struct {
|
||||
}
|
||||
|
||||
type familyExpansionSpec struct {
|
||||
Family string
|
||||
FamilyKey string
|
||||
Template string
|
||||
ChildSource familyExpansionSource
|
||||
Family string
|
||||
FamilyKey string
|
||||
Template string
|
||||
ChildSource familyExpansionSource
|
||||
NamePrefix string
|
||||
LabelPrefix string
|
||||
ConstantPrefix string
|
||||
TemplateFields []string
|
||||
DefaultFields map[string]any
|
||||
ApplyAfterModules bool
|
||||
ChildRefField string
|
||||
IdentitySource string
|
||||
AllowExistingOnly bool
|
||||
AutoPrereqFields map[string]string
|
||||
}
|
||||
|
||||
func splitFamilyExpansionIdentity(text string) familyIdentity {
|
||||
@@ -78,14 +88,141 @@ func parseFamilyExpansionSpec(path string, obj map[string]any) (familyExpansionS
|
||||
if err != nil {
|
||||
return familyExpansionSpec{}, fmt.Errorf("generated file %s: %w", path, err)
|
||||
}
|
||||
namePrefix, _ := optionalTrimmedString(obj, "name_prefix")
|
||||
labelPrefix, _ := optionalTrimmedString(obj, "label_prefix")
|
||||
constantPrefix, _ := optionalTrimmedString(obj, "constant_prefix")
|
||||
templateFields, err := parseOptionalStringArray(obj["template_fields"], "template_fields")
|
||||
if err != nil {
|
||||
return familyExpansionSpec{}, fmt.Errorf("generated file %s: %w", path, err)
|
||||
}
|
||||
defaultFields, err := parseOptionalObject(obj["default_fields"], "default_fields")
|
||||
if err != nil {
|
||||
return familyExpansionSpec{}, fmt.Errorf("generated file %s: %w", path, err)
|
||||
}
|
||||
applyAfterModules, err := parseOptionalBoolField(obj["apply_after_modules"], "apply_after_modules")
|
||||
if err != nil {
|
||||
return familyExpansionSpec{}, fmt.Errorf("generated file %s: %w", path, err)
|
||||
}
|
||||
childRefField, _ := optionalTrimmedString(obj, "child_ref_field")
|
||||
identitySource, _ := optionalTrimmedString(obj, "identity_source")
|
||||
switch identitySource {
|
||||
case "", "child_source_value":
|
||||
default:
|
||||
return familyExpansionSpec{}, fmt.Errorf("generated file %s: identity_source must be empty or child_source_value", path)
|
||||
}
|
||||
autoPrereqFields, err := parseOptionalStringMap(obj["auto_prereq_fields"], "auto_prereq_fields")
|
||||
if err != nil {
|
||||
return familyExpansionSpec{}, fmt.Errorf("generated file %s: %w", path, err)
|
||||
}
|
||||
allowExistingOnly, err := parseOptionalBoolField(obj["allow_existing_only"], "allow_existing_only")
|
||||
if err != nil {
|
||||
return familyExpansionSpec{}, fmt.Errorf("generated file %s: %w", path, err)
|
||||
}
|
||||
return familyExpansionSpec{
|
||||
Family: strings.TrimSpace(family),
|
||||
FamilyKey: strings.TrimSpace(familyKey),
|
||||
Template: strings.TrimSpace(template),
|
||||
ChildSource: source,
|
||||
Family: strings.TrimSpace(family),
|
||||
FamilyKey: strings.TrimSpace(familyKey),
|
||||
Template: strings.TrimSpace(template),
|
||||
ChildSource: source,
|
||||
NamePrefix: namePrefix,
|
||||
LabelPrefix: labelPrefix,
|
||||
ConstantPrefix: constantPrefix,
|
||||
TemplateFields: templateFields,
|
||||
DefaultFields: defaultFields,
|
||||
ApplyAfterModules: applyAfterModules,
|
||||
ChildRefField: childRefField,
|
||||
IdentitySource: identitySource,
|
||||
AllowExistingOnly: allowExistingOnly,
|
||||
AutoPrereqFields: autoPrereqFields,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func isFamilyExpansionObject(obj map[string]any) bool {
|
||||
_, hasFamilyKey := obj["family_key"]
|
||||
_, hasTemplate := obj["template"]
|
||||
_, hasChildSource := obj["child_source"]
|
||||
_, hasNamePrefix := obj["name_prefix"]
|
||||
_, hasLabelPrefix := obj["label_prefix"]
|
||||
_, hasConstantPrefix := obj["constant_prefix"]
|
||||
_, hasTemplateFields := obj["template_fields"]
|
||||
_, hasDefaultFields := obj["default_fields"]
|
||||
_, hasApplyAfterModules := obj["apply_after_modules"]
|
||||
_, hasChildRefField := obj["child_ref_field"]
|
||||
_, hasIdentitySource := obj["identity_source"]
|
||||
_, hasAllowExistingOnly := obj["allow_existing_only"]
|
||||
_, hasAutoPrereqFields := obj["auto_prereq_fields"]
|
||||
return hasFamilyKey || hasTemplate || hasChildSource || hasNamePrefix || hasLabelPrefix ||
|
||||
hasConstantPrefix || hasTemplateFields || hasDefaultFields || hasApplyAfterModules || hasChildRefField ||
|
||||
hasIdentitySource || hasAllowExistingOnly || hasAutoPrereqFields
|
||||
}
|
||||
|
||||
func optionalTrimmedString(obj map[string]any, field string) (string, bool) {
|
||||
text, ok := obj[field].(string)
|
||||
if !ok || strings.TrimSpace(text) == "" {
|
||||
return "", false
|
||||
}
|
||||
return strings.TrimSpace(text), true
|
||||
}
|
||||
|
||||
func parseOptionalStringArray(raw any, field string) ([]string, error) {
|
||||
if raw == nil {
|
||||
return nil, nil
|
||||
}
|
||||
items, ok := raw.([]any)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("%s must be an array of strings", field)
|
||||
}
|
||||
out := make([]string, 0, len(items))
|
||||
for _, item := range items {
|
||||
text, ok := item.(string)
|
||||
if !ok || strings.TrimSpace(text) == "" {
|
||||
return nil, fmt.Errorf("%s must contain only non-empty strings", field)
|
||||
}
|
||||
out = append(out, strings.TrimSpace(text))
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func parseOptionalObject(raw any, field string) (map[string]any, error) {
|
||||
if raw == nil {
|
||||
return nil, nil
|
||||
}
|
||||
obj, ok := raw.(map[string]any)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("%s must be an object", field)
|
||||
}
|
||||
return obj, nil
|
||||
}
|
||||
|
||||
func parseOptionalStringMap(raw any, field string) (map[string]string, error) {
|
||||
if raw == nil {
|
||||
return nil, nil
|
||||
}
|
||||
obj, ok := raw.(map[string]any)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("%s must be an object of strings", field)
|
||||
}
|
||||
out := make(map[string]string, len(obj))
|
||||
for key, value := range obj {
|
||||
text, ok := value.(string)
|
||||
if !ok || strings.TrimSpace(text) == "" {
|
||||
return nil, fmt.Errorf("%s must contain only non-empty string values", field)
|
||||
}
|
||||
out[key] = strings.TrimSpace(text)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func parseOptionalBoolField(raw any, field string) (bool, error) {
|
||||
if raw == nil {
|
||||
return false, nil
|
||||
}
|
||||
value, ok := raw.(bool)
|
||||
if !ok {
|
||||
return false, fmt.Errorf("%s must be a boolean", field)
|
||||
}
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func familyMetadata(parent, child, source, template string) map[string]any {
|
||||
meta := map[string]any{
|
||||
"parent": strings.TrimSpace(parent),
|
||||
|
||||
Reference in New Issue
Block a user