Integrate policy-aware item scopes

This commit is contained in:
2026-10-23 18:55:03 +00:00
parent d03e56398b
commit dfeaf90320
7 changed files with 353 additions and 30 deletions

View File

@@ -201,10 +201,12 @@ func loadImportedWithAccessTrackedAndProcessingPolicyDeferred(access *filesystem
state.stack = append(state.stack, mainRoute)
var body *document.Node
var declarations []importDeclarationSpec
var sequenceDeclarations []sequenceDeclarationSpec
var diagnostics []Diagnostic
if processing != nil {
body = processing.payload
declarations = processing.imports
sequenceDeclarations = cloneSequenceDeclarations(processing.sequences)
} else {
body, declarations, diagnostics = splitImportDirectives(main.document)
}
@@ -213,6 +215,7 @@ func loadImportedWithAccessTrackedAndProcessingPolicyDeferred(access *filesystem
state.scope.contributions = append(state.scope.contributions, acquiredContribution{
source: cloneSourceInfo(mainInfo), identity: mainNodeKey, role: importRoleMain,
scopeOwner: mainNodeKey, payload: body, document: body, processing: processing,
sequenceDeclarations: cloneSequenceDeclarations(sequenceDeclarations),
})
diagnostics = state.walkDeclarations(basePath, declarations, 0, Path{})
} else {
@@ -255,7 +258,7 @@ func loadImportedWithAccessTrackedAndProcessingPolicyDeferred(access *filesystem
contributions: []acquiredContribution{{
source: cloneSourceInfo(mainInfo), payload: body, identity: mainNodeKey,
role: importRoleMain, scopeOwner: mainNodeKey, destination: destination.clone(),
processing: processing, pendingItem: &localScope,
processing: processing, sequenceDeclarations: cloneSequenceDeclarations(sequenceDeclarations), pendingItem: &localScope,
}},
}
}
@@ -313,14 +316,17 @@ func composeAcquiredInputWithPolicies(input assembledInput, lower collectionPoli
if len(scope.contributions) == 1 && scope.contributions[0].role == importRoleMain && scope.contributions[0].pendingItem != nil {
main := scope.contributions[0]
localScope := cloneAcquisitionScope(*main.pendingItem)
if diagnostics := traversal.composePendingItems(&localScope); len(diagnostics) != 0 {
if diagnostics := traversal.composePendingItems(&localScope, policy); len(diagnostics) != 0 {
return nil, prependCompositionDiagnosticPaths(diagnostics, main.destination.Index(0))
}
documents := make([]*document.Node, 0, len(localScope.contributions))
for _, contribution := range localScope.contributions {
documents = append(documents, contribution.document)
}
completed, diagnostics := composeDocuments(documents...)
completed, diagnostics := composeDocumentsWithCollectionPolicy(
policy, localScope.collectionPolicies,
acquiredSequenceDeclarations(localScope), documents...,
)
if len(diagnostics) != 0 {
return nil, prependCompositionDiagnosticPaths(diagnostics, main.destination.Index(0))
}
@@ -392,19 +398,20 @@ func composeAcquiredScopeWithPolicy(
versionState *sourceVersionState,
accounting *importAccounting,
) (*composedDocument, []Diagnostic) {
_ = lower
traversal := importTraversal{
accounting: accounting, limits: defaultImportLimits(), rule: rule,
versionState: versionState, importGraph: graph.clone(),
}
if diagnostics := traversal.composePendingItems(scope); len(diagnostics) != 0 {
if diagnostics := traversal.composePendingItems(scope, policy); len(diagnostics) != 0 {
return nil, diagnostics
}
documents := make([]*document.Node, 0, len(scope.contributions))
for _, contribution := range scope.contributions {
documents = append(documents, contribution.document)
}
composition, diagnostics := composeDocumentsWithPolicy(policy, documents...)
composition, diagnostics := composeDocumentsWithCollectionPolicy(
policy, lower, acquiredSequenceDeclarations(*scope), documents...,
)
if len(diagnostics) != 0 {
return nil, diagnostics
}
@@ -617,6 +624,7 @@ func (s *importTraversal) visitPath(candidate selectedImportCandidate, spec impo
var body *document.Node
var declarations []importDeclarationSpec
var sequenceDeclarations []sequenceDeclarationSpec
var diagnostics []Diagnostic
var processing *sourceVersionProcessingResult
if s.versionState != nil && s.versionState.mode != sourceVersionModeDefault {
@@ -652,7 +660,7 @@ func (s *importTraversal) visitPath(candidate selectedImportCandidate, spec impo
s.active[identity] = len(s.stack)
s.visited[identity] = route
s.stack = append(s.stack, route)
diagnostics := s.visitItemSource(canonical, nodeKey, destination, relativeDestination, depth, info, body, declarations, processing)
diagnostics := s.visitItemSource(canonical, nodeKey, destination, relativeDestination, depth, info, body, declarations, sequenceDeclarations, processing)
delete(s.active, identity)
s.stack = s.stack[:len(s.stack)-1]
return diagnostics
@@ -671,6 +679,7 @@ func (s *importTraversal) visitPath(candidate selectedImportCandidate, spec impo
source: cloneSourceInfo(info), payload: body, document: placed,
identity: nodeKey, role: role, scopeOwner: s.scope.owner,
destination: placementDestination.clone(), relativeDestination: relativeDestination.clone(), processing: processing,
sequenceDeclarations: cloneSequenceDeclarations(sequenceDeclarations),
})
s.active[identity] = len(s.stack)
s.visited[identity] = route
@@ -701,7 +710,7 @@ func (s *importTraversal) sourceDestination(destination Path) Path {
return s.itemFallback.clone()
}
func (s *importTraversal) visitItemSource(canonical string, identity importNodeKey, destination, relativeDestination Path, depth int, info SourceInfo, body *document.Node, declarations []importDeclarationSpec, processing *sourceVersionProcessingResult) []Diagnostic {
func (s *importTraversal) visitItemSource(canonical string, identity importNodeKey, destination, relativeDestination Path, depth int, info SourceInfo, body *document.Node, declarations []importDeclarationSpec, sequenceDeclarations []sequenceDeclarationSpec, processing *sourceVersionProcessingResult) []Diagnostic {
parentScope := s.scope
parentItemScope, parentPrefix, parentFallback := s.itemScope, s.itemPrefix, s.itemFallback
s.scope = acquisitionScope{owner: identity}
@@ -715,7 +724,7 @@ func (s *importTraversal) visitItemSource(canonical string, identity importNodeK
s.scope.contributions = append(s.scope.contributions, acquiredContribution{
source: cloneSourceInfo(info), payload: body, document: body,
identity: identity, role: importRoleItem, scopeOwner: identity,
processing: processing,
processing: processing, sequenceDeclarations: cloneSequenceDeclarations(sequenceDeclarations),
})
diagnostics := s.walkDeclarations(s.access.dir(canonical), declarations, depth, Path{})
itemScope := s.scope
@@ -742,21 +751,24 @@ func (s *importTraversal) scheduleAcquisitionScopes(scope *acquisitionScope) {
}
}
func (s *importTraversal) composePendingItems(scope *acquisitionScope) []Diagnostic {
func (s *importTraversal) composePendingItems(scope *acquisitionScope, policy sequencePolicy) []Diagnostic {
for index := range scope.contributions {
contribution := &scope.contributions[index]
if contribution.pendingItem == nil {
continue
}
itemScope := contribution.pendingItem
if diagnostics := s.composePendingItems(itemScope); len(diagnostics) != 0 {
if diagnostics := s.composePendingItems(itemScope, policy); len(diagnostics) != 0 {
return projectItemDiagnosticPaths(diagnostics, *scope, contribution.destination, index)
}
documents := make([]*document.Node, 0, len(itemScope.contributions))
for _, nested := range itemScope.contributions {
documents = append(documents, nested.document)
}
completed, diagnostics := composeDocuments(documents...)
completed, diagnostics := composeDocumentsWithCollectionPolicy(
policy, itemScope.collectionPolicies,
acquiredSequenceDeclarations(*itemScope), documents...,
)
if len(diagnostics) != 0 {
return projectItemDiagnosticPaths(diagnostics, *scope, contribution.destination, index)
}
@@ -783,6 +795,18 @@ func (s *importTraversal) composePendingItems(scope *acquisitionScope) []Diagnos
return nil
}
func acquiredSequenceDeclarations(scope acquisitionScope) []sequenceDeclarationSpec {
var declarations []sequenceDeclarationSpec
for _, contribution := range scope.contributions {
for _, declaration := range contribution.sequenceDeclarations {
projected := cloneSequenceDeclarations([]sequenceDeclarationSpec{declaration})[0]
projected.destination = appendDestination(contribution.relativeDestination, declaration.destination)
declarations = append(declarations, projected)
}
}
return declarations
}
func importedVersionClaim(documents []*document.Node, scope acquisitionScope, composed *composedDocument, rule *VersionRule) *Diagnostic {
if composed == nil || rule == nil {
return nil
@@ -915,6 +939,37 @@ func projectNestedEvidence(composed *composedDocument, scope acquisitionScope) {
projectNestedOrigins(composed.origins, contribution.nested.root, contribution.nested.origins, prefix)
}
composed.applications = projectedApplications
projectNestedCollectionPolicies(composed, scope, ranges)
}
func projectNestedCollectionPolicies(composed *composedDocument, scope acquisitionScope, ranges map[sequenceRangeKey]sequenceRange) {
if composed == nil {
return
}
baseOffsets := make(map[string]int)
for sourceIndex, contribution := range scope.contributions {
if contribution.nested == nil || len(contribution.nested.collectionPolicies.collections) == 0 {
continue
}
itemIndex := priorSequenceLength([]acquisitionScope{{contributions: scope.contributions[:sourceIndex]}}, contribution.destination)
if assigned, found := ranges[sequenceRangeKey{sourceIndex: sourceIndex, path: contribution.destination.String()}]; found {
if projected, ok := assigned.outputForInput(0); ok {
itemIndex = projected
}
}
key := contribution.destination.String()
base, initialized := baseOffsets[key]
policy, _ := composed.collectionPolicies.at(contribution.destination)
if !initialized {
base = len(policy.recordOrder)
baseOffsets[key] = base
}
policy.setRecordPolicyAt(base+itemIndex, collectionRecordPolicy{
owner: newCollectionRecordPolicy().owner,
scope: contribution.nested.collectionPolicies,
})
composed.collectionPolicies.set(contribution.destination, policy)
}
}
func projectNestedOrigins(target map[string]Origin, root *document.Node, origins map[string]Origin, prefix Path) {