Answer architecture round 3: the generated header names go generate, one sorted-keys helper everywhere, one site constructor, and an inline folder reference refused before anything loads
This commit is contained in:
@@ -203,13 +203,17 @@ func categorySites(root *folder) []categorySite {
|
||||
walk(append(dir[:len(dir):len(dir)], name), sub)
|
||||
continue
|
||||
}
|
||||
out = append(out, categorySite{dir: dir, path: join(strings.Join(dir, "."), name), in: g, n: g.children[name]})
|
||||
out = append(out, siteIn(dir, g, name))
|
||||
}
|
||||
}
|
||||
walk(nil, root)
|
||||
return out
|
||||
}
|
||||
|
||||
func siteIn(dir []string, in *folder, name string) categorySite {
|
||||
return categorySite{dir: dir, path: join(strings.Join(dir, "."), name), in: in, n: in.children[name]}
|
||||
}
|
||||
|
||||
func sitesScope(sites []categorySite) nodeScope {
|
||||
return func(fn func(path string, n node) error) error {
|
||||
for _, s := range sites {
|
||||
|
||||
+1
-6
@@ -180,12 +180,7 @@ func paths(n node) []string {
|
||||
func tablePaths(t *table) []string {
|
||||
out := append([]string{""}, t.header...)
|
||||
sort.Strings(out[1:])
|
||||
children := make([]string, 0, len(t.children))
|
||||
for name := range t.children {
|
||||
children = append(children, name)
|
||||
}
|
||||
sort.Strings(children)
|
||||
for _, name := range children {
|
||||
for _, name := range sortedNames(t.children) {
|
||||
for _, p := range paths(t.children[name]) {
|
||||
out = append(out, join(name, p))
|
||||
}
|
||||
|
||||
@@ -152,6 +152,9 @@ func inputValue(input string) (any, error) {
|
||||
// binding's.
|
||||
func bindInline(root *folder, n node, label string, typedByGo bool) error {
|
||||
scope := inlineScope(n, label)
|
||||
if err := refuseFolderRefs(scope); err != nil {
|
||||
return err
|
||||
}
|
||||
loadShipped(root, unloadedReads(root, nil, scope))
|
||||
return binding{
|
||||
scope: scope,
|
||||
@@ -166,10 +169,9 @@ func bindInline(root *folder, n node, label string, typedByGo bool) error {
|
||||
}.bind()
|
||||
}
|
||||
|
||||
// linkNodeRefs binds the references in an inline node's templates against the
|
||||
// loaded tree.
|
||||
func linkNodeRefs(scope nodeScope, root map[string]node) error {
|
||||
if err := scope(func(path string, m node) error {
|
||||
// refuseFolderRefs refuses a reference an inline node writes from a folder, which it has none of.
|
||||
func refuseFolderRefs(scope nodeScope) error {
|
||||
return scope(func(path string, m node) error {
|
||||
t, ok := m.(*template)
|
||||
if !ok {
|
||||
return nil
|
||||
@@ -183,7 +185,18 @@ func linkNodeRefs(scope nodeScope, root map[string]node) error {
|
||||
return fmt.Errorf("%s: reference {%s}: an inline template has no folder; write {/%s}", path, name, rest)
|
||||
}
|
||||
}
|
||||
return linkTemplate(nil, path, "", t, root)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// linkNodeRefs binds the references in an inline node's templates against the
|
||||
// loaded tree.
|
||||
func linkNodeRefs(scope nodeScope, root map[string]node) error {
|
||||
if err := scope(func(path string, m node) error {
|
||||
if t, ok := m.(*template); ok {
|
||||
return linkTemplate(nil, path, "", t, root)
|
||||
}
|
||||
return nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
+1
-7
@@ -3,7 +3,6 @@ package fejkdata
|
||||
import (
|
||||
"fmt"
|
||||
"slices"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// checkNameReads refuses each binding of t that checkUses refuses, and a read such as {n} whose
|
||||
@@ -117,12 +116,7 @@ func (b *nameBinding) checkTemplateOnce(read string, t *template, key string) er
|
||||
}
|
||||
}
|
||||
}
|
||||
heads := make([]string, 0, len(fresh))
|
||||
for head := range fresh {
|
||||
heads = append(heads, head)
|
||||
}
|
||||
sort.Strings(heads)
|
||||
for _, head := range heads {
|
||||
for _, head := range sortedNames(fresh) {
|
||||
if by, kept := b.addressed[join(key, head)]; kept && fresh[head] > 1 {
|
||||
return fmt.Errorf("{%s} renders field %q twice, so {%s} cannot say which draw it reads; drop {%s} or {%s}", read, head, by, read, by)
|
||||
}
|
||||
|
||||
+1
-6
@@ -11,12 +11,7 @@ import (
|
||||
// docs/decisions.md#one-name-one-meaning
|
||||
func TestNoFunctionSpellsAMethod(t *testing.T) {
|
||||
funcs, methods := declaredCalls(namespaceFiles(t))
|
||||
names := make([]string, 0, len(funcs))
|
||||
for name := range funcs {
|
||||
names = append(names, name)
|
||||
}
|
||||
sort.Strings(names)
|
||||
for _, name := range names {
|
||||
for _, name := range sortedNames(funcs) {
|
||||
if recv := methods[name]; len(recv) > 0 {
|
||||
sort.Strings(recv)
|
||||
t.Errorf("func %s is spelled by %s too; name them apart", name, strings.Join(recv, " and "))
|
||||
|
||||
@@ -2,7 +2,6 @@ package fejkdata
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -470,11 +469,7 @@ func unreachableInChoice(c *choice, want string) error {
|
||||
if len(c.shared) == 0 {
|
||||
return fmt.Errorf("no variant of this %d-way choice carries %q", len(c.items), want)
|
||||
}
|
||||
offered := make([]string, 0, len(c.shared))
|
||||
for p := range c.shared {
|
||||
offered = append(offered, p)
|
||||
}
|
||||
sort.Strings(offered)
|
||||
offered := sortedNames(c.shared)
|
||||
return fmt.Errorf("not every variant of this %d-way choice carries %q; all carry %v", len(c.items), want, offered)
|
||||
}
|
||||
|
||||
|
||||
+1
-7
@@ -2,7 +2,6 @@ package fejkdata
|
||||
|
||||
import (
|
||||
"os"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -109,12 +108,7 @@ func readsFact(n node) string {
|
||||
if len(set) == 0 {
|
||||
return ""
|
||||
}
|
||||
keys := make([]string, 0, len(set))
|
||||
for k := range set {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
return "\treads " + strings.Join(keys, " ")
|
||||
return "\treads " + strings.Join(sortedNames(set), " ")
|
||||
}
|
||||
|
||||
func TestShippedShapeNamesReads(t *testing.T) {
|
||||
|
||||
+1
-1
@@ -139,7 +139,7 @@ func (u unloadedCategory) load() (categorySite, error) {
|
||||
return categorySite{}, err
|
||||
}
|
||||
delete(u.in.unloaded, u.name)
|
||||
return categorySite{dir: u.dir, path: join(strings.Join(u.dir, "."), u.name), in: u.in, n: u.in.children[u.name]}, nil
|
||||
return siteIn(u.dir, u.in, u.name), nil
|
||||
}
|
||||
|
||||
// linkedTables is the tables beside u that link to it or that it links to: its parent, and
|
||||
|
||||
+2
-2
@@ -66,7 +66,7 @@ func TestShippedIndexIsCurrent(t *testing.T) {
|
||||
|
||||
func shippedIndexSource(whole *Generator) ([]byte, error) {
|
||||
var b bytes.Buffer
|
||||
b.WriteString("// Code generated by TestShippedIndexIsCurrent with REPIN=1. DO NOT EDIT.\n\npackage fejkdata\n\nvar shippedIndex = map[string]shippedEntry{\n")
|
||||
b.WriteString("// Code generated by go generate. DO NOT EDIT.\n\npackage fejkdata\n\nvar shippedIndex = map[string]shippedEntry{\n")
|
||||
for _, s := range categorySites(&whole.root) {
|
||||
fmt.Fprintf(&b, "%q: {", s.path)
|
||||
if t, isTable := s.n.(*table); isTable && t.parentIndex >= 0 {
|
||||
@@ -183,7 +183,7 @@ func TestOnDemandRendersAsTheWholeLoad(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestEveryShippedCategoryLoadsAlone(t *testing.T) {
|
||||
for p := range shippedIndex {
|
||||
for _, p := range sortedNames(shippedIndex) {
|
||||
f, err := New()
|
||||
if err != nil {
|
||||
t.Fatalf("New() = %v", err)
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Code generated by TestShippedIndexIsCurrent with REPIN=1. DO NOT EDIT.
|
||||
// Code generated by go generate. DO NOT EDIT.
|
||||
|
||||
package fejkdata
|
||||
|
||||
|
||||
Reference in New Issue
Block a user