1
0
Fork 0
golang-forgejo-f3-gof3/tree/generic/references.go

93 lines
3.2 KiB
Go
Raw Permalink Normal View History

// Copyright Earl Warren <contact@earl-warren.org>
// Copyright Loïc Dachary <loic@dachary.org>
// SPDX-License-Identifier: MIT
package generic
import (
"context"
"strings"
"code.forgejo.org/f3/gof3/v3/f3"
"code.forgejo.org/f3/gof3/v3/path"
"code.forgejo.org/f3/gof3/v3/util"
)
type ErrorRemapReferencesRelative error
func RemapReferences(ctx context.Context, node NodeInterface, f f3.Interface) {
for _, reference := range f.GetReferences() {
toPath := path.NewPath()
collectTo := func(ctx context.Context, parent, p path.Path, node NodeInterface) {
element := NewNode()
mappedID := node.GetMappedID()
if mappedID.String() == "" {
node.Trace("mapped ID for %s is not defined", p.ReadableString())
}
element.SetID(mappedID)
toPath = toPath.Append(element.(path.PathElement))
}
from := reference.Get()
isRelative := !strings.HasPrefix(from, "/")
if isRelative && !strings.HasPrefix(from, "..") {
panic(NewError[ErrorRemapReferencesRelative]("relative references that do not start with .. are not supported '%s'", from))
}
current := node.GetCurrentPath().String()
fromPath := path.PathAbsolute(NewElementNode, current, from)
node.GetTree().Apply(ctx, fromPath, NewApplyOptions(collectTo).SetWhere(ApplyEachNode))
to := toPath.String()
node.Trace("from '%s' to '%s'", fromPath.ReadableString(), toPath.ReadableString())
if isRelative {
currentMapped := node.GetParent().GetCurrentPath().PathMappedString().Join()
// because the mapped ID of the current node has not been allocated yet
// and it does not matter as long as it is replaced with ..
// it will not work at all if a relative reference does not start with ..
currentMapped += "/PLACEHODLER"
to = path.PathRelativeString(currentMapped, to)
}
node.Trace("convert reference %s => %s", reference.Get(), to)
reference.Set(to)
}
}
func NodeCollectReferences(ctx context.Context, node NodeInterface) []path.Path {
pathToReferences := make(map[string]path.Path, 5)
tree := node.GetTree()
collect := func(ctx context.Context, parent path.Path, node NodeInterface) {
util.MaybeTerminate(ctx)
f := node.GetSelf().ToFormat()
for _, reference := range f.GetReferences() {
absoluteReference := path.PathAbsoluteString(node.GetCurrentPath().String(), reference.Get())
if _, ok := pathToReferences[absoluteReference]; ok {
continue
}
tree.ApplyAndGet(ctx, path.NewPathFromString(NewElementNode, absoluteReference), NewApplyOptions(func(ctx context.Context, parent, path path.Path, node NodeInterface) {
pathToReferences[absoluteReference] = node.GetCurrentPath()
}))
}
}
node.Walk(ctx, path.NewPath(node.(path.PathElement)), NewWalkOptions(collect))
references := make([]path.Path, 0, len(pathToReferences))
for _, reference := range pathToReferences {
tree.Debug("collect %s", reference)
references = append(references, reference)
}
return references
}
func TreeCollectReferences(ctx context.Context, tree TreeInterface, p path.Path) []path.Path {
var references []path.Path
tree.Apply(ctx, p, NewApplyOptions(func(ctx context.Context, parent, path path.Path, node NodeInterface) {
references = NodeCollectReferences(ctx, node)
}))
return references
}