Parse collection sequence declarations

This commit is contained in:
2026-10-23 14:01:39 +00:00
parent 298e70b552
commit 9d7635d1e4
8 changed files with 444 additions and 21 deletions

View File

@@ -9,29 +9,103 @@ import (
const directiveKey = "configkit"
type rootDirectiveContext uint8
const (
rootDirectiveContextImportsOnly rootDirectiveContext = iota + 1
rootDirectiveContextSource
rootDirectiveContextOverlay
)
type rootDirectiveExtraction struct {
body *document.Node
imports []importDeclarationSpec
sequences []sequenceDeclarationSpec
importsPresent bool
sequencesPresent bool
}
func splitImportDirectives(root *document.Node) (*document.Node, []importDeclarationSpec, []Diagnostic) {
extracted, diagnostics := extractRootDirectives(root, rootDirectiveContextImportsOnly)
if len(diagnostics) != 0 {
return nil, nil, diagnostics
}
return extracted.body, extracted.imports, nil
}
func extractRootDirectives(root *document.Node, context rootDirectiveContext) (rootDirectiveExtraction, []Diagnostic) {
if root == nil {
return rootDirectiveExtraction{}, nil
}
body := document.Clone(root)
var declarations []importDeclarationSpec
directiveIndex := -1
for index, entry := range body.Mapping {
if entry.Key != directiveKey {
continue
}
directiveIndex = index
parsed, diagnostics := parseImportSpecificationDirective(entry.Value, Keys(directiveKey))
extracted, diagnostics := parseRootDirectiveBlock(entry.Value, Keys(directiveKey), context)
if len(diagnostics) != 0 {
return nil, nil, diagnostics
return rootDirectiveExtraction{}, diagnostics
}
declarations = parsed
break
}
if directiveIndex >= 0 {
body.Mapping = append(body.Mapping[:directiveIndex], body.Mapping[directiveIndex+1:]...)
extracted.body = body
if directiveIndex >= 0 {
extracted.body.Mapping = append(extracted.body.Mapping[:directiveIndex], extracted.body.Mapping[directiveIndex+1:]...)
}
if diagnostics := nestedDirectiveDiagnostics(extracted.body, Path{}); len(diagnostics) != 0 {
return rootDirectiveExtraction{}, diagnostics
}
return extracted, nil
}
if diagnostics := nestedDirectiveDiagnostics(body, Path{}); len(diagnostics) != 0 {
return nil, nil, diagnostics
return rootDirectiveExtraction{}, diagnostics
}
return body, declarations, nil
return rootDirectiveExtraction{body: body}, nil
}
func parseRootDirectiveBlock(node *document.Node, directivePath Path, context rootDirectiveContext) (rootDirectiveExtraction, []Diagnostic) {
if node == nil || node.Kind != document.Mapping {
return rootDirectiveExtraction{}, []Diagnostic{nodeImportDiagnostic(CodeImportInvalid, directivePath, "configuration directive must be a mapping", node)}
}
var extracted rootDirectiveExtraction
var diagnostics []Diagnostic
for _, entry := range node.Mapping {
fieldPath := directivePath.Key(entry.Key)
switch entry.Key {
case "imports":
extracted.importsPresent = true
if context == rootDirectiveContextOverlay {
diagnostics = append(diagnostics, nodeImportDiagnostic(CodeOverlayDirective, fieldPath, "overlays cannot contain imports", entry.Value))
continue
}
if context != rootDirectiveContextImportsOnly && context != rootDirectiveContextSource {
diagnostics = append(diagnostics, nodeImportDiagnostic(CodeImportInvalid, fieldPath, "directive extraction context is invalid", entry.Value))
continue
}
parsed, issues := parseImportDeclarations(entry.Value, fieldPath)
extracted.imports = append(extracted.imports, parsed...)
diagnostics = append(diagnostics, issues...)
case "sequences":
extracted.sequencesPresent = true
if context == rootDirectiveContextImportsOnly {
diagnostics = append(diagnostics, sequenceDeclarationDiagnostic(fieldPath, "sequence declarations are not enabled in this extraction context", entry.Value))
continue
}
if context != rootDirectiveContextSource && context != rootDirectiveContextOverlay {
diagnostics = append(diagnostics, sequenceDeclarationDiagnostic(fieldPath, "directive extraction context is invalid", entry.Value))
continue
}
parsed, issues := parseSequenceDeclarationDirective(entry.Value, fieldPath)
extracted.sequences = append(extracted.sequences, parsed...)
diagnostics = append(diagnostics, issues...)
default:
diagnostics = append(diagnostics, nodeImportDiagnostic(CodeImportInvalid, fieldPath, "configuration directive field is not recognized", entry.Value))
}
}
if len(diagnostics) != 0 {
return rootDirectiveExtraction{}, canonicalDiagnostics(diagnostics)
}
return extracted, nil
}
func nestedDirectiveDiagnostics(node *document.Node, current Path) []Diagnostic {