Extract import declaration parsing helpers

This commit is contained in:
2026-10-25 13:23:09 +00:00
parent 6bc625b68f
commit 2c3eb3308b
2 changed files with 95 additions and 53 deletions

View File

@@ -251,40 +251,17 @@ func parseImportDeclarationSpec(node *document.Node, declarationPath Path) (impo
}
switch entry.Key {
case "required", "recursive", "follow", "hidden":
if entry.Value.Kind != document.Boolean {
return importDeclarationSpec{}, []Diagnostic{nodeImportDiagnostic(CodeImportInvalid, fieldPath, entry.Key+" must be a boolean", entry.Value)}
}
value := entry.Value.Text == "true"
switch entry.Key {
case "required":
spec.required = &value
case "recursive":
spec.recursive = &value
case "follow":
spec.follow = &value
case "hidden":
spec.hidden = &value
if diagnostic := parseImportBooleanAssignment(&spec, entry.Key, entry.Value, fieldPath); diagnostic != nil {
return importDeclarationSpec{}, []Diagnostic{*diagnostic}
}
case "pattern":
values, origins, ok, badIndex := parseStringSet(entry.Value)
if !ok {
return importDeclarationSpec{}, []Diagnostic{stringSetDiagnostic(entry.Value, fieldPath, "pattern", badIndex)}
if diagnostic := parseImportWildcardAssignment(&spec, entry.Key, entry.Value, fieldPath); diagnostic != nil {
return importDeclarationSpec{}, []Diagnostic{*diagnostic}
}
if badIndex, ok := invalidWildcard(values); ok {
badPath, badNode := listMemberSite(entry.Value, fieldPath, origins[badIndex])
return importDeclarationSpec{}, []Diagnostic{nodeImportDiagnostic(CodeImportInvalid, badPath, "pattern contains an invalid wildcard expression", badNode)}
}
spec.pattern, spec.patternSet = values, true
case "exclude":
values, origins, ok, badIndex := parseStringSet(entry.Value)
if !ok {
return importDeclarationSpec{}, []Diagnostic{stringSetDiagnostic(entry.Value, fieldPath, "exclude", badIndex)}
if diagnostic := parseImportWildcardAssignment(&spec, entry.Key, entry.Value, fieldPath); diagnostic != nil {
return importDeclarationSpec{}, []Diagnostic{*diagnostic}
}
if badIndex, ok := invalidWildcard(values); ok {
badPath, badNode := listMemberSite(entry.Value, fieldPath, origins[badIndex])
return importDeclarationSpec{}, []Diagnostic{nodeImportDiagnostic(CodeImportInvalid, badPath, "exclude contains an invalid wildcard expression", badNode)}
}
spec.exclude, spec.excludeSet = values, true
case "depth":
depth, ok := parseImportDepth(entry.Value)
if !ok {
@@ -298,17 +275,11 @@ func parseImportDeclarationSpec(node *document.Node, declarationPath Path) (impo
}
spec.destination = destination
case "placement":
if entry.Value.Kind != document.String {
return importDeclarationSpec{}, []Diagnostic{nodeImportDiagnostic(CodeImportInvalid, fieldPath, "placement must be mapping or sequence-item", entry.Value)}
}
switch entry.Value.Text {
case "mapping":
spec.placement = placementModeMapping
case "sequence-item":
spec.placement = placementModeSequenceItem
default:
return importDeclarationSpec{}, []Diagnostic{nodeImportDiagnostic(CodeImportInvalid, fieldPath, "placement must be mapping or sequence-item", entry.Value)}
placement, diagnostic := parseImportPlacement(entry.Value, fieldPath)
if diagnostic != nil {
return importDeclarationSpec{}, []Diagnostic{*diagnostic}
}
spec.placement = placement
default:
return importDeclarationSpec{}, []Diagnostic{nodeImportDiagnostic(CodeImportInvalid, fieldPath, "import declaration field is not recognized", entry.Value)}
}
@@ -316,33 +287,98 @@ func parseImportDeclarationSpec(node *document.Node, declarationPath Path) (impo
selectorPath := declarationPath.Key(selectorEntry.Key)
spec.fieldSites[selectorEntry.Key] = importFieldSite{path: selectorPath.clone(), location: publicLocation(selectorEntry.Value.Location)}
if diagnostic := parseImportSelectorValue(&spec, selectorEntry.Key, selectorEntry.Value, selectorPath); diagnostic != nil {
return importDeclarationSpec{}, []Diagnostic{*diagnostic}
}
return spec, nil
}
func parseImportBooleanAssignment(spec *importDeclarationSpec, field string, node *document.Node, fieldPath Path) *Diagnostic {
if node.Kind != document.Boolean {
diagnostic := nodeImportDiagnostic(CodeImportInvalid, fieldPath, field+" must be a boolean", node)
return &diagnostic
}
value := node.Text == "true"
switch field {
case "required":
spec.required = &value
case "recursive":
spec.recursive = &value
case "follow":
spec.follow = &value
case "hidden":
spec.hidden = &value
}
return nil
}
func parseImportWildcardAssignment(spec *importDeclarationSpec, field string, node *document.Node, fieldPath Path) *Diagnostic {
values, origins, ok, badIndex := parseStringSet(node)
if !ok {
diagnostic := stringSetDiagnostic(node, fieldPath, field, badIndex)
return &diagnostic
}
if badIndex, ok := invalidWildcard(values); ok {
badPath, badNode := listMemberSite(node, fieldPath, origins[badIndex])
diagnostic := nodeImportDiagnostic(CodeImportInvalid, badPath, field+" contains an invalid wildcard expression", badNode)
return &diagnostic
}
switch field {
case "pattern":
spec.pattern, spec.patternSet = values, true
case "exclude":
spec.exclude, spec.excludeSet = values, true
}
return nil
}
func parseImportPlacement(node *document.Node, fieldPath Path) (placementMode, *Diagnostic) {
if node.Kind != document.String {
diagnostic := nodeImportDiagnostic(CodeImportInvalid, fieldPath, "placement must be mapping or sequence-item", node)
return placementModeMapping, &diagnostic
}
switch node.Text {
case "mapping":
return placementModeMapping, nil
case "sequence-item":
return placementModeSequenceItem, nil
default:
diagnostic := nodeImportDiagnostic(CodeImportInvalid, fieldPath, "placement must be mapping or sequence-item", node)
return placementModeMapping, &diagnostic
}
}
func parseImportSelectorValue(spec *importDeclarationSpec, field string, node *document.Node, selectorPath Path) *Diagnostic {
switch spec.selector {
case importSelectorPath, importSelectorDirectory:
values, origins, ok, badIndex := parseStringSet(selectorEntry.Value)
values, origins, ok, badIndex := parseStringSet(node)
if !ok {
name := selectorEntry.Key
return importDeclarationSpec{}, []Diagnostic{stringSetDiagnostic(selectorEntry.Value, selectorPath, name, badIndex)}
diagnostic := stringSetDiagnostic(node, selectorPath, field, badIndex)
return &diagnostic
}
for index, value := range values {
if !validImportPath(value) {
badPath, badNode := listMemberSite(selectorEntry.Value, selectorPath, origins[index])
return importDeclarationSpec{}, []Diagnostic{nodeImportDiagnostic(CodeImportInvalid, badPath, selectorEntry.Key+" contains an invalid source path", badNode)}
badPath, badNode := listMemberSite(node, selectorPath, origins[index])
diagnostic := nodeImportDiagnostic(CodeImportInvalid, badPath, field+" contains an invalid source path", badNode)
return &diagnostic
}
badPath, badNode := listMemberSite(selectorEntry.Value, selectorPath, origins[index])
badPath, badNode := listMemberSite(node, selectorPath, origins[index])
spec.selectorSites = append(spec.selectorSites, importFieldSite{path: badPath.clone(), location: publicLocation(badNode.Location)})
}
spec.paths = values
case importSelectorGlob:
if selectorEntry.Value.Kind != document.String || !validImportPath(selectorEntry.Value.Text) {
return importDeclarationSpec{}, []Diagnostic{nodeImportDiagnostic(CodeImportInvalid, selectorPath, "glob must be a valid nonempty path pattern string", selectorEntry.Value)}
if node.Kind != document.String || !validImportPath(node.Text) {
diagnostic := nodeImportDiagnostic(CodeImportInvalid, selectorPath, "glob must be a valid nonempty path pattern string", node)
return &diagnostic
}
segments, ok := validGlobPattern(selectorEntry.Value.Text)
segments, ok := validGlobPattern(node.Text)
if !ok {
return importDeclarationSpec{}, []Diagnostic{nodeImportDiagnostic(CodeImportInvalid, selectorPath, "glob pattern is invalid", selectorEntry.Value)}
diagnostic := nodeImportDiagnostic(CodeImportInvalid, selectorPath, "glob pattern is invalid", node)
return &diagnostic
}
spec.glob, spec.globSegments = selectorEntry.Value.Text, segments
spec.glob, spec.globSegments = node.Text, segments
}
return spec, nil
return nil
}
func selectorForField(field string) importSelector {