Make great documentation goal 1.2, and plan the README's reorganisation and the nested-template gaps #33

Open
lilleman wants to merge 966 commits from worktree-todo-relative-dates-exact-counts into main
5 changed files with 27 additions and 59 deletions
Showing only changes of commit 6e2555aee6 - Show all commits
+5 -18
View File
@@ -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
}
// categorySites lists every category under root, folders and names in sorted order.
+5 -8
View File
@@ -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
}
// 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
View File
@@ -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 {
+4 -20
View File
@@ -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
}
// 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
View File
@@ -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)
}
}