Answer architecture round 2: each category site carries its source's default modules, set where the walk or the index loads it, and the note is written beside the resolve that finds the read; the decision states why New checks no reads
This commit is contained in:
@@ -11,18 +11,22 @@ import (
|
||||
// the unloaded categories it needs: docs/decisions.md#a-source-whose-manifest-carries-an-index-loads-each-category-on-first-reach-any-other-loads-in-new-with-what-it-reads
|
||||
func loadSources(sources []datafiles.Source) (folder, error) {
|
||||
root := folder{children: map[string]node{}}
|
||||
defaultModules := map[string][]string{}
|
||||
walked := map[string][]string{}
|
||||
for _, src := range sources {
|
||||
if err := addSource(&root, src, defaultModules); err != nil {
|
||||
if err := addSource(&root, src, walked); err != nil {
|
||||
return folder{}, err
|
||||
}
|
||||
}
|
||||
return root, loadReached(&root, categorySites(&root), nil, defaultModules)
|
||||
sites := categorySites(&root)
|
||||
for i := range sites {
|
||||
sites[i].defaultModules = walked[sites[i].path]
|
||||
}
|
||||
return root, loadReached(&root, sites, nil)
|
||||
}
|
||||
|
||||
// addSource places src's categories in root, and sets in defaultModules, for each category
|
||||
// it loads, the modules src reads by default.
|
||||
func addSource(root *folder, src datafiles.Source, defaultModules map[string][]string) error {
|
||||
// addSource places src's categories in root, and sets in walked, for each category it loads
|
||||
// here, the modules src reads by default.
|
||||
func addSource(root *folder, src datafiles.Source, walked map[string][]string) error {
|
||||
m, err := src.Manifest()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -36,7 +40,7 @@ func addSource(root *folder, src datafiles.Source, defaultModules map[string][]s
|
||||
return err
|
||||
}
|
||||
for _, s := range categorySites(g) {
|
||||
defaultModules[s.path] = m.Reads
|
||||
walked[s.path] = m.Reads
|
||||
}
|
||||
mergeFolder(root, g)
|
||||
return nil
|
||||
@@ -83,11 +87,13 @@ func mergeFolder(dst, src *folder) {
|
||||
// single inline node.
|
||||
type nodeSet func(fn func(label string, n node) error) error
|
||||
|
||||
// categorySite is a loaded category, where it sits and its own dot path.
|
||||
// categorySite is a loaded category, where it sits, its own dot path, and the modules its
|
||||
// source reads by default.
|
||||
type categorySite struct {
|
||||
categoryAt
|
||||
n node
|
||||
path string
|
||||
defaultModules []string
|
||||
}
|
||||
|
||||
// categorySites lists every category under root, folders and names in sorted order.
|
||||
|
||||
+3
-2
@@ -583,8 +583,9 @@ when a source carries it.
|
||||
2026-09-24, Lilleman auf Larv; revised 2026-10-10, when the shipped data became Go packages.
|
||||
Serves goal 6.2. `sv_SE.FS` loads alone, and `sv_SE.address` then fails at first reach,
|
||||
naming `github.com/larvit/fejkdata/data/geo/SE`, which `sv_SE`'s manifest reads. `New`
|
||||
checks no `reads`: a stand-in providing the same paths under another name would fail it
|
||||
(goal 9.2).
|
||||
checks no `reads`: a check by module name fails a stand-in providing the same paths (goal
|
||||
9.2), and a check by path needs every reference, which only loading each indexed category
|
||||
gives, against goal 13.
|
||||
`--no-shipped-data -d` takes a locale's folder with its country's, or a set of one's own.
|
||||
|
||||
## The default embed holds every Swedish postort the import can place and give a street-delivery code and a street, and the US places of 25,000 or more
|
||||
|
||||
@@ -60,7 +60,7 @@ func (f *Generator) loadCallerPath(path string) (string, []string, error) {
|
||||
return "", nil, fmt.Errorf("fejkdata: %w", err)
|
||||
}
|
||||
if c, ok := categoryOn(&f.root, segs); ok && c.unloaded() {
|
||||
if err := loadReached(&f.root, nil, []categoryAt{c}, nil); err != nil {
|
||||
if err := loadReached(&f.root, nil, []categoryAt{c}); err != nil {
|
||||
return "", nil, fmt.Errorf("fejkdata: %w", loadError{err})
|
||||
}
|
||||
}
|
||||
@@ -107,9 +107,8 @@ func needs(root *folder, s categorySite) []categoryAt {
|
||||
|
||||
// loadReached loads the unloaded categories among wanted and every unloaded category they
|
||||
// or sites need, then runs sites and all it loaded through a whole load's pipeline. On an
|
||||
// error it puts back what it loaded, so the next call fails the same way. defaultModules
|
||||
// holds, by path, the modules the source of each of sites reads by default.
|
||||
func loadReached(root *folder, sites []categorySite, wanted []categoryAt, defaultModules map[string][]string) error {
|
||||
// error it puts back what it loaded, so the next call fails the same way.
|
||||
func loadReached(root *folder, sites []categorySite, wanted []categoryAt) error {
|
||||
queue := wanted
|
||||
for _, s := range sites {
|
||||
queue = append(queue, needs(root, s)...)
|
||||
@@ -120,14 +119,6 @@ func loadReached(root *folder, sites []categorySite, wanted []categoryAt, defaul
|
||||
err = b.run(root, sites)
|
||||
}
|
||||
if err != nil {
|
||||
err = withDefaultModules(err, func(category string) []string {
|
||||
for _, l := range b {
|
||||
if l.site.path == category {
|
||||
return l.was.defaultModules
|
||||
}
|
||||
}
|
||||
return defaultModules[category]
|
||||
})
|
||||
b.putBack()
|
||||
}
|
||||
return err
|
||||
@@ -158,6 +149,7 @@ func (b *batch) load(root *folder, queue []categoryAt) error {
|
||||
return err
|
||||
}
|
||||
s := siteIn(c.dir, c.in, c.name)
|
||||
s.defaultModules = x.defaultModules
|
||||
*b = append(*b, loaded{site: s, was: x})
|
||||
if parent := parentOf(s.n); parent != x.entry.Parent {
|
||||
return fmt.Errorf("%s: the index entry for %s %s, and its table %s", x.src.ManifestPath(), s.path, namesParent(x.entry.Parent), namesParent(parent))
|
||||
@@ -178,19 +170,6 @@ func (b batch) run(root *folder, sites []categorySite) error {
|
||||
return categoryPipeline(sites, root.children).run()
|
||||
}
|
||||
|
||||
// withDefaultModules adds to err, where a reference of a category names nothing, the modules
|
||||
// the category's source reads by default, or that it names none.
|
||||
func withDefaultModules(err error, of func(category string) []string) error {
|
||||
var u unresolvedRead
|
||||
if !errors.As(err, &u) {
|
||||
return err
|
||||
}
|
||||
if modules := of(u.category); len(modules) > 0 {
|
||||
return fmt.Errorf("%w; the module holding %s reads by default %s", err, u.category, strings.Join(modules, ", "))
|
||||
}
|
||||
return fmt.Errorf("%w, and the module holding %s names no module it reads by default", err, u.category)
|
||||
}
|
||||
|
||||
func (b batch) putBack() {
|
||||
for _, l := range b {
|
||||
l.site.in.putUnloaded(l.site.name, l.was)
|
||||
|
||||
@@ -90,7 +90,7 @@ func loadInline(root *folder, n node, label string, typedByGo bool) error {
|
||||
if err := refuseFolderRefs(nodes); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := loadReached(root, nil, referenced(root, nil, nodes), nil); err != nil {
|
||||
if err := loadReached(root, nil, referenced(root, nil, nodes)); err != nil {
|
||||
return loadError{err}
|
||||
}
|
||||
return pipeline{
|
||||
|
||||
+18
-17
@@ -3,26 +3,18 @@ package fejkdata
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// templateSite is a template to resolve, with its folder and its category's path, both empty for an
|
||||
// templateSite is a template to resolve, with its folder and its category, both empty for an
|
||||
// inline template, and eachNode's label for it.
|
||||
type templateSite struct {
|
||||
t *template
|
||||
folder []string
|
||||
label string
|
||||
category string
|
||||
category *categorySite
|
||||
}
|
||||
|
||||
// unresolvedRead is a reference of a category's template naming nothing.
|
||||
type unresolvedRead struct {
|
||||
category string
|
||||
err error
|
||||
}
|
||||
|
||||
func (u unresolvedRead) Error() string { return u.err.Error() }
|
||||
func (u unresolvedRead) Unwrap() error { return u.err }
|
||||
|
||||
// resolveCategoryTemplates resolves every template of the categories, once all data is merged, so a
|
||||
// reference sees the override-resolved tree.
|
||||
func resolveCategoryTemplates(sites []categorySite, root map[string]node) error {
|
||||
@@ -30,7 +22,7 @@ func resolveCategoryTemplates(sites []categorySite, root map[string]node) error
|
||||
for _, s := range sites {
|
||||
if err := eachNode(s.n, s.path, func(label string, n node) error {
|
||||
if t, isTemplate := n.(*template); isTemplate {
|
||||
ts = append(ts, templateSite{t: t, folder: s.dir, label: label, category: s.path})
|
||||
ts = append(ts, templateSite{t: t, folder: s.dir, label: label, category: &s})
|
||||
}
|
||||
return nil
|
||||
}); err != nil {
|
||||
@@ -66,12 +58,8 @@ type resolvedNames struct {
|
||||
func resolveTemplates(ts []templateSite, root map[string]node) error {
|
||||
for _, s := range ts {
|
||||
refs, err := s.t.resolveRefs(s.folder, s.label, root)
|
||||
var ne noEntry
|
||||
if err != nil && s.category != "" && errors.As(err, &ne) {
|
||||
return unresolvedRead{category: s.category, err: err}
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
return s.withDefaultModules(err)
|
||||
}
|
||||
s.t.refs = refs
|
||||
}
|
||||
@@ -102,3 +90,16 @@ func resolveTemplates(ts []templateSite, root map[string]node) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// withDefaultModules adds to err, where a reference of a category names nothing, the modules
|
||||
// the category's source reads by default, or that it names none.
|
||||
func (s templateSite) withDefaultModules(err error) error {
|
||||
var ne noEntry
|
||||
if s.category == nil || !errors.As(err, &ne) {
|
||||
return err
|
||||
}
|
||||
if modules := s.category.defaultModules; len(modules) > 0 {
|
||||
return fmt.Errorf("%w; the module holding %s reads by default %s", err, s.category.path, strings.Join(modules, ", "))
|
||||
}
|
||||
return fmt.Errorf("%w, and the module holding %s names no module it reads by default", err, s.category.path)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user