121 lines
3.6 KiB
Go
121 lines
3.6 KiB
Go
package engine
|
|
|
|
type secretTrigger struct {
|
|
target string
|
|
ordinary bool
|
|
}
|
|
|
|
func closeSecretDependencies(paths map[string]Path, sensitive map[string]bool, dependencies, inherited []secretDependency) map[string]bool {
|
|
return closeSecretDependenciesWithCorrespondence(paths, sensitive, dependencies, inherited, resolutionCorrespondence{})
|
|
}
|
|
|
|
// Matching adds endpoint edges to the same work queue as recorded dependencies.
|
|
// Newly reached coordinates are indexed once, including historical fields that
|
|
// have no physical descendant at the corresponding final position.
|
|
func closeSecretDependenciesWithCorrespondence(paths map[string]Path, sensitive map[string]bool, dependencies, inherited []secretDependency, correspondence resolutionCorrespondence) map[string]bool {
|
|
result := make(map[string]bool, len(sensitive))
|
|
queue := make([]string, 0, len(sensitive))
|
|
for pointer, classified := range sensitive {
|
|
if classified {
|
|
result[pointer] = true
|
|
queue = append(queue, pointer)
|
|
}
|
|
}
|
|
|
|
var triggers pathPrefixIndex
|
|
triggerValues := make([]secretTrigger, 0, len(dependencies)+2*len(inherited))
|
|
fired := make([]bool, 0, cap(triggerValues))
|
|
insert := func(dependency Path, target string, ordinary bool) {
|
|
if ordinary && !dependency.valid() {
|
|
return
|
|
}
|
|
id := len(triggerValues)
|
|
triggerValues = append(triggerValues, secretTrigger{target: target, ordinary: ordinary})
|
|
fired = append(fired, false)
|
|
triggers.insert(dependency.String(), id)
|
|
}
|
|
for _, dependency := range dependencies {
|
|
insert(dependency.dependency, dependency.target.String(), true)
|
|
}
|
|
for _, link := range inherited {
|
|
insert(link.dependency, link.target.String(), false)
|
|
insert(link.target, link.dependency.String(), false)
|
|
}
|
|
|
|
var projected map[string]bool
|
|
if len(correspondence.collections) != 0 {
|
|
projected = make(map[string]bool, len(paths))
|
|
}
|
|
project := func(path Path) {
|
|
if projected == nil || !path.valid() {
|
|
return
|
|
}
|
|
pointer := path.String()
|
|
if projected[pointer] {
|
|
return
|
|
}
|
|
projected[pointer] = true
|
|
add := func(target Path, matched bool) {
|
|
if !matched {
|
|
return
|
|
}
|
|
targetPointer := target.String()
|
|
if targetPointer == pointer {
|
|
return
|
|
}
|
|
if _, exists := paths[targetPointer]; !exists {
|
|
paths[targetPointer] = target
|
|
}
|
|
insert(path, targetPointer, false)
|
|
}
|
|
add(correspondence.finalPath(path))
|
|
add(correspondence.entryPath(path))
|
|
}
|
|
if projected != nil {
|
|
// Projection may add missing target coordinates to paths. Snapshot the
|
|
// original candidates so map insertion cannot affect this traversal.
|
|
candidates := make([]Path, 0, len(paths))
|
|
for _, path := range paths {
|
|
candidates = append(candidates, path)
|
|
}
|
|
for _, path := range candidates {
|
|
project(path)
|
|
}
|
|
}
|
|
activate := func(id int) {
|
|
if fired[id] {
|
|
return
|
|
}
|
|
fired[id] = true
|
|
target := triggerValues[id].target
|
|
if !result[target] {
|
|
result[target] = true
|
|
queue = append(queue, target)
|
|
}
|
|
}
|
|
for head := 0; head < len(queue); head++ {
|
|
pointer := queue[head]
|
|
if classified, ok := paths[pointer]; ok && classified.valid() {
|
|
// Register a synthesized coordinate before visiting triggers, never
|
|
// while a trigger-index traversal is in progress.
|
|
project(classified)
|
|
triggers.visitAncestors(classified.String(), func(id int) {
|
|
if triggerValues[id].ordinary {
|
|
activate(id)
|
|
}
|
|
})
|
|
triggers.visitDescendants(classified.String(), func(id int) {
|
|
if triggerValues[id].ordinary {
|
|
activate(id)
|
|
}
|
|
})
|
|
}
|
|
triggers.visitDescendants(pointer, func(id int) {
|
|
if !triggerValues[id].ordinary {
|
|
activate(id)
|
|
}
|
|
})
|
|
}
|
|
return result
|
|
}
|