Prepare post-decode CLI inspection context
This commit is contained in:
151
internal/engine/override_context.go
Normal file
151
internal/engine/override_context.go
Normal file
@@ -0,0 +1,151 @@
|
||||
package engine
|
||||
|
||||
import "gitea.maximumdirect.net/eric/ConfigKit/internal/document"
|
||||
|
||||
// postDecodeOverrideContext keeps the structural, typed pre-CLI, and effective
|
||||
// post-CLI views distinct while preparing the existing inspection machinery.
|
||||
type postDecodeOverrideContext struct {
|
||||
structuralInput *document.Node
|
||||
preCLI *document.Node
|
||||
preCLIOrigins map[string]Origin
|
||||
decoded decodedConfiguration
|
||||
metadata Metadata
|
||||
resolution resolutionInput
|
||||
sources []SourceInfo
|
||||
applications []historyApplication
|
||||
postDecodeApps []historyApplication
|
||||
referenceInput *document.Node
|
||||
}
|
||||
|
||||
func preparePostDecodeOverrideContext(input assembledInput, before decodedConfiguration, assigned decodedOverrideResult) postDecodeOverrideContext {
|
||||
after := before
|
||||
after.value = assigned.value
|
||||
after.presence = cloneInputPresence(assigned.presence)
|
||||
after.origins = cloneOrigins(assigned.origins)
|
||||
after.final = document.Clone(assigned.final)
|
||||
|
||||
metadata := metadataFromDecoded(after)
|
||||
if input.inheritance != nil && input.composition != nil {
|
||||
applyInheritanceMetadata(&metadata, input.composition.root, input.composition.origins, input.composition.overlays, input.inheritance)
|
||||
} else if input.composition != nil {
|
||||
applyOverlayMetadata(&metadata, input.composition.overlays)
|
||||
}
|
||||
|
||||
sources := cloneSourceInfos(input.sources)
|
||||
knownSources := make(map[string]bool, len(sources)+len(assigned.overrides))
|
||||
for _, source := range sources {
|
||||
knownSources[source.ID] = true
|
||||
}
|
||||
for _, override := range assigned.overrides {
|
||||
if !knownSources[override.source.ID] {
|
||||
sources = append(sources, cloneSourceInfo(override.source))
|
||||
knownSources[override.source.ID] = true
|
||||
}
|
||||
}
|
||||
resolution := newResolutionInput(metadata, assigned.final, sources, input.contexts)
|
||||
|
||||
applications := structuralHistoryApplications(input)
|
||||
var postDecodeApps []historyApplication
|
||||
for _, override := range assigned.overrides {
|
||||
postDecodeApps = append(postDecodeApps, historyApplication{
|
||||
layer: LayerCLI,
|
||||
path: override.path.clone(),
|
||||
value: document.Clone(override.value),
|
||||
origin: overlayOrigin(LayerCLI, document.Location{SourceID: override.source.ID}),
|
||||
})
|
||||
}
|
||||
allApplications := append(cloneHistoryApplications(applications), cloneHistoryApplications(postDecodeApps)...)
|
||||
finalizeMetadataPaths(&metadata, assigned.final, allApplications, input.document, before.final)
|
||||
|
||||
return postDecodeOverrideContext{
|
||||
structuralInput: document.Clone(input.document),
|
||||
preCLI: document.Clone(before.final),
|
||||
preCLIOrigins: cloneOrigins(before.origins),
|
||||
decoded: after,
|
||||
metadata: metadata,
|
||||
resolution: resolution,
|
||||
sources: sources,
|
||||
applications: applications,
|
||||
postDecodeApps: postDecodeApps,
|
||||
referenceInput: documentWithMetadataLocations(assigned.final, metadata),
|
||||
}
|
||||
}
|
||||
|
||||
func (context postDecodeOverrideContext) historyApplications() []historyApplication {
|
||||
applications := cloneHistoryApplications(context.applications)
|
||||
return append(applications, cloneHistoryApplications(context.postDecodeApps)...)
|
||||
}
|
||||
|
||||
func structuralHistoryApplications(input assembledInput) []historyApplication {
|
||||
if input.composition != nil {
|
||||
return cloneHistoryApplications(input.composition.applications)
|
||||
}
|
||||
if input.document == nil {
|
||||
return nil
|
||||
}
|
||||
return []historyApplication{{layer: LayerBase, value: document.Clone(input.document)}}
|
||||
}
|
||||
|
||||
// documentWithMetadataLocations attaches effective origin coordinates to a
|
||||
// canonical typed projection for secret and validation diagnostics.
|
||||
func documentWithMetadataLocations(root *document.Node, metadata Metadata) *document.Node {
|
||||
located := document.Clone(root)
|
||||
if located == nil {
|
||||
return nil
|
||||
}
|
||||
var visit func(*document.Node, Path)
|
||||
visit = func(node *document.Node, path Path) {
|
||||
pointer := path.String()
|
||||
if info, exists := metadata.fields[pointer]; exists {
|
||||
if location, ok := metadataFieldLocation(metadata, pointer, info.Origin); ok {
|
||||
node.Location = location
|
||||
}
|
||||
}
|
||||
switch node.Kind {
|
||||
case document.Mapping:
|
||||
for index := range node.Mapping {
|
||||
entry := &node.Mapping[index]
|
||||
childPath := path.Key(entry.Key)
|
||||
if info, exists := metadata.fields[childPath.String()]; exists {
|
||||
if location, ok := metadataFieldLocation(metadata, childPath.String(), info.Origin); ok {
|
||||
entry.KeyLocation = location
|
||||
entry.ValueLocation = location
|
||||
}
|
||||
}
|
||||
visit(entry.Value, childPath)
|
||||
}
|
||||
case document.Sequence:
|
||||
for index, child := range node.Sequence {
|
||||
visit(child, path.Index(index))
|
||||
}
|
||||
}
|
||||
}
|
||||
visit(located, Path{})
|
||||
return located
|
||||
}
|
||||
|
||||
func metadataFieldLocation(metadata Metadata, pointer string, origin Origin) (document.Location, bool) {
|
||||
if location, ok := latestOriginDocumentLocation(origin); ok {
|
||||
return location, true
|
||||
}
|
||||
for index := len(metadata.history[pointer]) - 1; index >= 0; index-- {
|
||||
change := metadata.history[pointer][index]
|
||||
if location, ok := latestOriginDocumentLocation(change.Origin); ok {
|
||||
return location, true
|
||||
}
|
||||
for prior := len(change.Previous) - 1; prior >= 0; prior-- {
|
||||
if location, ok := latestOriginDocumentLocation(change.Previous[prior]); ok {
|
||||
return location, true
|
||||
}
|
||||
}
|
||||
}
|
||||
return document.Location{}, false
|
||||
}
|
||||
|
||||
func latestOriginDocumentLocation(origin Origin) (document.Location, bool) {
|
||||
if len(origin.Locations) == 0 {
|
||||
return document.Location{}, false
|
||||
}
|
||||
location := origin.Locations[len(origin.Locations)-1]
|
||||
return document.Location{SourceID: location.SourceID, Line: location.Line, Column: location.Column}, true
|
||||
}
|
||||
Reference in New Issue
Block a user