Make great documentation goal 1.2, and plan the README's reorganisation and the nested-template gaps #33
@@ -9,40 +9,29 @@ import (
|
||||
// loadSources merges sources in order, the last winning a clash. A source whose manifest
|
||||
// carries an index leaves its categories unloaded; every other source loads here, with
|
||||
// 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{}}
|
||||
walked := map[string][]string{}
|
||||
for _, src := range sources {
|
||||
if err := addSource(&root, src, walked); err != nil {
|
||||
if err := addSource(&root, src); err != nil {
|
||||
return folder{}, err
|
||||
}
|
||||
}
|
||||
sites := categorySites(&root)
|
||||
for i := range sites {
|
||||
sites[i].defaultModules = walked[sites[i].path]
|
||||
}
|
||||
return root, loadReached(&root, sites, nil)
|
||||
return root, loadReached(&root, categorySites(&root), nil)
|
||||
}
|
||||
|
||||
// addSource places src's categories in root. For each category it loads now, it records in
|
||||
// walked the modules src reads by default.
|
||||
func addSource(root *folder, src datafiles.Source, walked map[string][]string) error {
|
||||
func addSource(root *folder, src datafiles.Source) error {
|
||||
m, err := src.Manifest()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if m.Index != nil {
|
||||
placeIndex(root, src, m)
|
||||
placeIndex(root, src, m.Index)
|
||||
return nil
|
||||
}
|
||||
g := &folder{children: map[string]node{}}
|
||||
if err := src.Walk(compileInto(func(dir []string) *folder { return madeFolder(g, dir) })); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, s := range categorySites(g) {
|
||||
walked[s.path] = m.Reads
|
||||
}
|
||||
mergeFolder(root, g)
|
||||
return nil
|
||||
}
|
||||
@@ -88,13 +77,11 @@ 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, its own dot path, and the modules its
|
||||
// source reads by default.
|
||||
// categorySite is a loaded category, where it sits and its own dot path.
|
||||
type categorySite struct {
|
||||
categoryAt
|
||||
n node
|
||||
path string
|
||||
defaultModules []string
|
||||
n node
|
||||
path string
|
||||
}
|
||||
|
||||
// categorySites lists every category under root, folders and names in sorted order.
|
||||
|
||||
@@ -11,20 +11,18 @@ import (
|
||||
"github.com/larvit/fejkdata/internal/grammar"
|
||||
)
|
||||
|
||||
// indexed is a category an index names and no call has reached yet, the source holding it,
|
||||
// and the modules that source reads by default.
|
||||
// indexed is a category an index names and no call has reached yet, and the source holding it.
|
||||
type indexed struct {
|
||||
entry datafiles.IndexEntry
|
||||
src datafiles.Source
|
||||
defaultModules []string
|
||||
entry datafiles.IndexEntry
|
||||
src datafiles.Source
|
||||
}
|
||||
|
||||
// placeIndex sets every category m's index names as unloaded in root, in place of what
|
||||
// placeIndex sets every category the index names as unloaded in root, in place of what
|
||||
// root holds at its path.
|
||||
func placeIndex(root *folder, src datafiles.Source, m datafiles.Manifest) {
|
||||
for _, p := range sortedNames(m.Index) {
|
||||
func placeIndex(root *folder, src datafiles.Source, index map[string]datafiles.IndexEntry) {
|
||||
for _, p := range sortedNames(index) {
|
||||
segs := strings.Split(p, ".")
|
||||
madeFolder(root, segs[:len(segs)-1]).putUnloaded(segs[len(segs)-1], &indexed{entry: m.Index[p], src: src, defaultModules: m.Reads})
|
||||
madeFolder(root, segs[:len(segs)-1]).putUnloaded(segs[len(segs)-1], &indexed{entry: index[p], src: src})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,7 +147,6 @@ 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))
|
||||
|
||||
+1
-1
@@ -206,7 +206,7 @@ func TestNewErrorPathIsCanonical(t *testing.T) {
|
||||
{
|
||||
"bad reference reached through another reference",
|
||||
map[string]string{"a": `"{/b}"`, "b": `"{/nope}"`},
|
||||
`fejkdata: b: reference {/nope}: no entry "nope", and the module holding b names no module it reads by default`,
|
||||
`fejkdata: b: reference {/nope}: no entry "nope", and no loaded module names a module it reads by default`,
|
||||
},
|
||||
}
|
||||
for _, c := range cases {
|
||||
|
||||
+7
-23
@@ -1,18 +1,15 @@
|
||||
package fejkdata
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// templateSite is a template to resolve, with its folder and its category, both empty for an
|
||||
// inline template, and eachNode's label for it.
|
||||
// templateSite is a template to resolve, with its folder and category, both empty for an inline
|
||||
// template, and eachNode's label for it.
|
||||
type templateSite struct {
|
||||
t *template
|
||||
folder []string
|
||||
label string
|
||||
category *categorySite
|
||||
t *template
|
||||
folder []string
|
||||
label string
|
||||
}
|
||||
|
||||
// resolveCategoryTemplates resolves every template of the categories, once all data is merged, so a
|
||||
@@ -22,7 +19,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})
|
||||
ts = append(ts, templateSite{t: t, folder: s.dir, label: label})
|
||||
}
|
||||
return nil
|
||||
}); err != nil {
|
||||
@@ -59,7 +56,7 @@ func resolveTemplates(ts []templateSite, root map[string]node) error {
|
||||
for _, s := range ts {
|
||||
refs, err := s.t.resolveRefs(s.folder, s.label, root)
|
||||
if err != nil {
|
||||
return s.withDefaultModules(err)
|
||||
return err
|
||||
}
|
||||
s.t.refs = refs
|
||||
}
|
||||
@@ -90,16 +87,3 @@ func resolveTemplates(ts []templateSite, root map[string]node) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Where err is a category's reference finding nothing, withDefaultModules adds the modules the
|
||||
// category's source reads by default, or says it reads 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)
|
||||
}
|
||||
|
||||
+5
-5
@@ -215,7 +215,7 @@ func TestAReadNoModuleProvidesNamesTheReadersModules(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("New(WithDataFS(sv_SE.FS)) = %v", err)
|
||||
}
|
||||
if _, err := f.Fake("sv_SE.address"); err == nil || !strings.Contains(err.Error(), "the module holding sv_SE.address reads by default github.com/larvit/fejkdata/data/geo/SE") {
|
||||
if _, err := f.Fake("sv_SE.address"); err == nil || !strings.Contains(err.Error(), "the loaded modules read by default github.com/larvit/fejkdata/data/geo/SE") {
|
||||
t.Errorf(`Fake("sv_SE.address") = %v, want the module it reads named`, err)
|
||||
}
|
||||
for name, opt := range map[string]Option{
|
||||
@@ -226,8 +226,8 @@ func TestAReadNoModuleProvidesNamesTheReadersModules(t *testing.T) {
|
||||
if err == nil {
|
||||
_, err = f.Fake("x")
|
||||
}
|
||||
if err == nil || !strings.Contains(err.Error(), "the module holding x names no module it reads by default") {
|
||||
t.Errorf("%s: x = %v, want it said that x's module names none", name, err)
|
||||
if err == nil || !strings.Contains(err.Error(), "no loaded module names a module it reads by default") {
|
||||
t.Errorf("%s: x = %v, want it said that no loaded module names one", name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -237,7 +237,7 @@ func TestADataPathManifestNamesWhatItReads(t *testing.T) {
|
||||
".fejkdata.json": `{"reads": ["example.com/places"]}`,
|
||||
"x.json": `"{/place}"`,
|
||||
})
|
||||
if _, err := New(WithDataPath(dir)); err == nil || !strings.Contains(err.Error(), "the module holding x reads by default example.com/places") {
|
||||
if _, err := New(WithDataPath(dir)); err == nil || !strings.Contains(err.Error(), "the loaded modules read by default example.com/places") {
|
||||
t.Errorf("New = %v, want the module x reads named", err)
|
||||
}
|
||||
}
|
||||
@@ -250,7 +250,7 @@ func TestAnIndexedModuleNamesWhatItReads(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("New = %v", err)
|
||||
}
|
||||
if _, err := f.Fake("x"); err == nil || !strings.Contains(err.Error(), "the module holding x reads by default example.com/places") {
|
||||
if _, err := f.Fake("x"); err == nil || !strings.Contains(err.Error(), "the loaded modules read by default example.com/places") {
|
||||
t.Errorf(`Fake("x") = %v, want the module x reads named`, err)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user