Parse collection sequence declarations
This commit is contained in:
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user