Keep import selection evidence with its declaring source

This commit is contained in:
2026-10-25 14:36:39 +00:00
parent e585decdb2
commit 64be8b4df5
5 changed files with 79 additions and 28 deletions

View File

@@ -22,6 +22,7 @@ type admittedImport struct {
identity resourceIdentity
nodeKey importNodeKey
source SourceInfo
sourceIndex int
payload *document.Node
declarations []importDeclarationSpec
sequenceDeclarations []sequenceDeclarationSpec
@@ -156,7 +157,7 @@ func acquireImportedWithAccess(request importAcquisitionRequest, policy *acquisi
scopeOwner: mainNodeKey, payload: body, document: body, processing: processing,
sequenceDeclarations: cloneSequenceDeclarations(sequenceDeclarations),
})
diagnostics = state.walkDeclarations(basePath, declarations, 0, Path{})
diagnostics = state.walkDeclarations(basePath, declarations, 0, Path{}, 0)
} else {
_, placed, err := placeDocument(body, destination, body.Location, maxDocumentDepth, maxDocumentNodes)
placementNodes := destinationWrapperNodeCount(destination)
@@ -172,7 +173,7 @@ func acquireImportedWithAccess(request importAcquisitionRequest, policy *acquisi
destination: destination.clone(), processing: processing,
sequenceDeclarations: cloneSequenceDeclarations(sequenceDeclarations),
})
diagnostics = state.walkDeclarations(basePath, declarations, 0, destination)
diagnostics = state.walkDeclarations(basePath, declarations, 0, destination, 0)
}
}
}
@@ -239,7 +240,7 @@ func (s *importTraversal) checkInitialLimits() *Diagnostic {
return nil
}
func (s *importTraversal) walkDeclarations(basePath string, declarations []importDeclarationSpec, depth int, parentDestination Path) []Diagnostic {
func (s *importTraversal) walkDeclarations(basePath string, declarations []importDeclarationSpec, depth int, parentDestination Path, sourceIndex int) []Diagnostic {
policies := make([]resolvedImportPolicy, len(declarations))
for index, spec := range declarations {
policy, diagnostics := resolveImportPolicy(spec, s.policy.importDefaults)
@@ -280,23 +281,19 @@ func (s *importTraversal) walkDeclarations(basePath string, declarations []impor
}
}
if !policy.required && len(s.sources) == sourcesBefore {
s.recordEmptyImportSelection(spec)
s.recordEmptyImportSelection(sourceIndex, spec)
}
}
return nil
}
func (s *importTraversal) recordEmptyImportSelection(spec importDeclarationSpec) {
for index := range s.sources {
if s.sources[index].ID != spec.location.SourceID {
continue
}
s.sources[index].importSelections = append(s.sources[index].importSelections, importSelectionEvidence{
path: spec.path.clone(), location: spec.location,
selector: spec.selector, outcome: importSelectionNone,
})
return
}
func (s *importTraversal) recordEmptyImportSelection(sourceIndex int, spec importDeclarationSpec) {
// The declaring source's position survives descendant appends and optional
// missing-source rollback, unlike a pointer into the source slice.
s.sources[sourceIndex].importSelections = append(s.sources[sourceIndex].importSelections, importSelectionEvidence{
path: spec.path.clone(), location: spec.location,
selector: spec.selector, outcome: importSelectionNone,
})
}
func (s *importTraversal) admitImportSource(canonical string, identity resourceIdentity, nodeKey importNodeKey, candidate selectedImportCandidate, policy resolvedImportPolicy, destination Path, location Location) (importAdmissionResult, []Diagnostic) {
@@ -321,6 +318,7 @@ func (s *importTraversal) admitImportSource(canonical string, identity resourceI
if kind == SourceKindFilesystem {
info.namespace = s.access.token
}
sourceIndex := len(s.sources)
s.sources = append(s.sources, info)
data, skipped, diagnostic := s.readImport(canonical, sourceID, policy.required)
if diagnostic != nil {
@@ -369,7 +367,7 @@ func (s *importTraversal) admitImportSource(canonical string, identity resourceI
}
return importAdmissionResult{source: admittedImport{
canonical: canonical, identity: identity, nodeKey: nodeKey,
source: cloneSourceInfo(info), payload: processing.payload,
source: cloneSourceInfo(info), sourceIndex: sourceIndex, payload: processing.payload,
declarations: processing.imports,
sequenceDeclarations: cloneSequenceDeclarations(processing.sequences),
processing: &processing,
@@ -477,7 +475,7 @@ func (s *importTraversal) visitPath(candidate selectedImportCandidate, spec impo
s.active[admitted.identity] = len(s.stack)
s.tier.visited[admitted.identity] = route
s.stack = append(s.stack, route)
diagnostics = s.walkDeclarations(s.access.dir(admitted.canonical), admitted.declarations, depth, destination)
diagnostics = s.walkDeclarations(s.access.dir(admitted.canonical), admitted.declarations, depth, destination, admitted.sourceIndex)
delete(s.active, admitted.identity)
s.stack = s.stack[:len(s.stack)-1]
return diagnostics