Make great documentation goal 1.2, and plan the README's reorganisation and the nested-template gaps #33
@@ -875,7 +875,7 @@ the Development section below, and who ships a register the five above then draw
|
|||||||
```
|
```
|
||||||
doc.go the package doc, and the vocabulary the package is written in
|
doc.go the package doc, and the vocabulary the package is written in
|
||||||
fejkdata.go Generator, New, options, the embedded data set, List
|
fejkdata.go Generator, New, options, the embedded data set, List
|
||||||
node.go the node model and JSON -> node compilation
|
node.go the node model and JSON -> node compilation, with its fence on a nested drawGroup
|
||||||
table.go tables: the rows TSV, its options and links, row selection and draws
|
table.go tables: the rows TSV, its options and links, row selection and draws
|
||||||
path.go the dotted-path walks with their selectors, and proving a path resolves
|
path.go the dotted-path walks with their selectors, and proving a path resolves
|
||||||
render.go Fake, the recursive renderer (choices, format strings, expansions) and the reads its tokens make
|
render.go Fake, the recursive renderer (choices, format strings, expansions) and the reads its tokens make
|
||||||
@@ -885,8 +885,8 @@ inline.go inline templates: Template, NewTemplate, FakeTemplate, IsTemplat
|
|||||||
format.go the {token} grammar: scanning, tokens, operands, validation, compiling a format
|
format.go the {token} grammar: scanning, tokens, operands, validation, compiling a format
|
||||||
hold.go the hold: one draw per held name; and the hold set and scope a render reads its reference paths through
|
hold.go the hold: one draw per held name; and the hold set and scope a render reads its reference paths through
|
||||||
holdfence.go the load fences over the hold: the routes and spellings that read one held name two ways
|
holdfence.go the load fences over the hold: the routes and spellings that read one held name two ways
|
||||||
drawfence.go the load fences over reference draws: a drawGroup's, a table's own family, and a render's and a record's columns through the survey
|
drawfence.go the load fences over reference draws: a drawGroup's, and a render's and a record's columns through the survey
|
||||||
readsurvey.go the load-time survey of what a render reads, and what a path reads of a table family, and its verdict on them
|
readsurvey.go the load-time survey of what a render reads, and what a path reads of a table family, and its verdict on them, a table reaching its own family included
|
||||||
pins.go the pin set: the table rows a render fixes, which the draw fences replay
|
pins.go the pin set: the table rows a render fixes, which the draw fences replay
|
||||||
reference.go reference sigils, and binding references across the tree
|
reference.go reference sigils, and binding references across the tree
|
||||||
graph.go the node graph: tree walks, containment and render edges, and the cycle and repeat fences
|
graph.go the node graph: tree walks, containment and render edges, and the cycle and repeat fences
|
||||||
|
|||||||
+1
-68
@@ -2,36 +2,6 @@ package fejkdata
|
|||||||
|
|
||||||
import "fmt"
|
import "fmt"
|
||||||
|
|
||||||
// checkNestedDrawGroup refuses a template beneath one drawing in group that names group again,
|
|
||||||
// short of a repeat or another draw group.
|
|
||||||
func checkNestedDrawGroup(fields map[string]node, group string) error {
|
|
||||||
if group == "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
var walk func(path string, n node) error
|
|
||||||
walk = func(path string, n node) error {
|
|
||||||
t, isTemplate := n.(*template)
|
|
||||||
switch {
|
|
||||||
case isTemplate && t.drawGroup == group:
|
|
||||||
return fmt.Errorf("%q names drawGroup %q, the draw group this template draws in already; drop it", path, group)
|
|
||||||
case isTemplate && (t.drawGroup != "" || t.repeat > 1):
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
for _, c := range contained(n) {
|
|
||||||
if err := walk(join(path, c.name), c.node); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
for _, name := range sortedNames(fields) {
|
|
||||||
if err := walk(name, fields[name]); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// drawFence fences each template of a scope as a render of its own, remembering which nodes read a
|
// drawFence fences each template of a scope as a render of its own, remembering which nodes read a
|
||||||
// reference path.
|
// reference path.
|
||||||
// docs/decisions.md#a-render-shares-one-reference-draw-per-category-per-group
|
// docs/decisions.md#a-render-shares-one-reference-draw-per-category-per-group
|
||||||
@@ -71,41 +41,6 @@ func (f *drawFence) checkDraws(path string, n node) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkOwnFamily refuses a table's format or cell that reads, however many templates
|
|
||||||
// away and through a repeat or a draw group too, a table of its own family: a whole
|
|
||||||
// read draws its row without pinning it, so the family would draw apart from the row
|
|
||||||
// it renders, whichever draws the reaching template holds.
|
|
||||||
// docs/decisions.md#a-table-never-reaches-its-own-family-by-any-route
|
|
||||||
func checkOwnFamily(t *template) error {
|
|
||||||
own := t.site.table
|
|
||||||
if own == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
seen := map[node]bool{}
|
|
||||||
var find func(n node) (renderEdge, *table, bool)
|
|
||||||
find = func(n node) (renderEdge, *table, bool) {
|
|
||||||
if seen[n] {
|
|
||||||
return renderEdge{}, nil, false
|
|
||||||
}
|
|
||||||
seen[n] = true
|
|
||||||
for _, e := range renderEdges(n) {
|
|
||||||
if e.readsRef() {
|
|
||||||
if familyTable, isTable := n.(*template).head(e.read.head).(*table); isTable && familyTable.familyRoot() == own.familyRoot() {
|
|
||||||
return e, familyTable, true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if e, familyTable, found := find(e.to); found {
|
|
||||||
return e, familyTable, true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return renderEdge{}, nil, false
|
|
||||||
}
|
|
||||||
if e, familyTable, found := find(t); found {
|
|
||||||
return fmt.Errorf("%s reads %s, a table of its own family, which a bare read of %s would draw apart from the row it renders; read the family from a template beside it, or add the value as a column", e.reached(), familyTable.segment, own.segment)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// checkRecordDraws fences the columns of a record — a template compiled at the top without a
|
// checkRecordDraws fences the columns of a record — a template compiled at the top without a
|
||||||
// repeat — so a load proves the record view of it as well as the string view.
|
// repeat — so a load proves the record view of it as well as the string view.
|
||||||
// docs/decisions.md#a-category-never-references-itself-and-a-records-fences-run-at-load
|
// docs/decisions.md#a-category-never-references-itself-and-a-records-fences-run-at-load
|
||||||
@@ -123,7 +58,7 @@ func (f *drawFence) checkRecordDraws(path string, n node) error {
|
|||||||
if !reads {
|
if !reads {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if err := checkColumnDraws(t, columns); err != nil {
|
if err := surveyColumns(t, columns).check(); err != nil {
|
||||||
return fmt.Errorf("%s: %w", path, err)
|
return fmt.Errorf("%s: %w", path, err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@@ -186,5 +121,3 @@ func readsTable(n node, a arm) bool {
|
|||||||
_, isTable := t.head(a.head).(*table)
|
_, isTable := t.head(a.head).(*table)
|
||||||
return isTable
|
return isTable
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkColumnDraws(t *template, columns []string) error { return surveyColumns(t, columns).check() }
|
|
||||||
|
|||||||
@@ -427,6 +427,36 @@ func repeatOf(m map[string]any) (int, error) {
|
|||||||
return int(r), nil
|
return int(r), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// checkNestedDrawGroup refuses a template beneath one drawing in group that names group again,
|
||||||
|
// short of a repeat or another draw group.
|
||||||
|
func checkNestedDrawGroup(fields map[string]node, group string) error {
|
||||||
|
if group == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
var walk func(path string, n node) error
|
||||||
|
walk = func(path string, n node) error {
|
||||||
|
t, isTemplate := n.(*template)
|
||||||
|
switch {
|
||||||
|
case isTemplate && t.drawGroup == group:
|
||||||
|
return fmt.Errorf("%q names drawGroup %q, the draw group this template draws in already; drop it", path, group)
|
||||||
|
case isTemplate && (t.drawGroup != "" || t.repeat > 1):
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
for _, c := range contained(n) {
|
||||||
|
if err := walk(join(path, c.name), c.node); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
for _, name := range sortedNames(fields) {
|
||||||
|
if err := walk(name, fields[name]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// drawGroupOf reads a template's "drawGroup" (default ""), which a repeat cannot carry: each
|
// drawGroupOf reads a template's "drawGroup" (default ""), which a repeat cannot carry: each
|
||||||
// iteration renders in no draw group.
|
// iteration renders in no draw group.
|
||||||
func drawGroupOf(m map[string]any, repeat int) (string, error) {
|
func drawGroupOf(m map[string]any, repeat int) (string, error) {
|
||||||
|
|||||||
@@ -248,6 +248,41 @@ func checkFamilies(reads []pathRead) error {
|
|||||||
return replayPairs(reads)
|
return replayPairs(reads)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// checkOwnFamily refuses a table's format or cell that reads, however many templates
|
||||||
|
// away and through a repeat or a draw group too, a table of its own family: a whole
|
||||||
|
// read draws its row without pinning it, so the family would draw apart from the row
|
||||||
|
// it renders, whichever draws the reaching template holds.
|
||||||
|
// docs/decisions.md#a-table-never-reaches-its-own-family-by-any-route
|
||||||
|
func checkOwnFamily(t *template) error {
|
||||||
|
own := t.site.table
|
||||||
|
if own == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
seen := map[node]bool{}
|
||||||
|
var find func(n node) (renderEdge, *table, bool)
|
||||||
|
find = func(n node) (renderEdge, *table, bool) {
|
||||||
|
if seen[n] {
|
||||||
|
return renderEdge{}, nil, false
|
||||||
|
}
|
||||||
|
seen[n] = true
|
||||||
|
for _, e := range renderEdges(n) {
|
||||||
|
if e.readsRef() {
|
||||||
|
if familyTable, isTable := n.(*template).head(e.read.head).(*table); isTable && familyTable.familyRoot() == own.familyRoot() {
|
||||||
|
return e, familyTable, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if e, familyTable, found := find(e.to); found {
|
||||||
|
return e, familyTable, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return renderEdge{}, nil, false
|
||||||
|
}
|
||||||
|
if e, familyTable, found := find(t); found {
|
||||||
|
return fmt.Errorf("%s reads %s, a table of its own family, which a bare read of %s would draw apart from the row it renders; read the family from a template beside it, or add the value as a column", e.reached(), familyTable.segment, own.segment)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// checkFamilyPair refuses a table read whole beside a path into its family, and a
|
// checkFamilyPair refuses a table read whole beside a path into its family, and a
|
||||||
// table one read draws that the other pins, since which token renders first would
|
// table one read draws that the other pins, since which token renders first would
|
||||||
// then decide the row.
|
// then decide the row.
|
||||||
|
|||||||
@@ -31,11 +31,6 @@ on 2026-09-29 a third time (Navigation 7.0, Locality 5.6, Shape 6.3, Self-suffic
|
|||||||
|
|
||||||
This round, in order:
|
This round, in order:
|
||||||
|
|
||||||
- Move `checkOwnFamily` into `readsurvey.go` beside `checkFamilies`, and
|
|
||||||
`checkNestedDrawGroup` into `node.go` beside `drawGroupOf`, the compile step calling
|
|
||||||
it; delete `checkColumnDraws` for `surveyColumns(…).check()` at its caller. Both
|
|
||||||
architects found the family fence in two files, and draw-group checks of two
|
|
||||||
lifecycles in one.
|
|
||||||
- Replace `formatOps`' `held`, `holder` and `pathHeads` with one map from a held name
|
- Replace `formatOps`' `held`, `holder` and `pathHeads` with one map from a held name
|
||||||
to its first reader and the path it starts, if any: four seats traced
|
to its first reader and the path it starts, if any: four seats traced
|
||||||
`formatOps.holdName` writing four fields at once.
|
`formatOps.holdName` writing four fields at once.
|
||||||
@@ -332,7 +327,7 @@ because pairing a street with its exact postnummer rewrites shipped rows.
|
|||||||
records `Navigation`, `Locality`, `Shape` and `Self-sufficiency`.
|
records `Navigation`, `Locality`, `Shape` and `Self-sufficiency`.
|
||||||
- Delete `doc.go`'s "The draw fences are …" sentence: it names a function, a type and
|
- Delete `doc.go`'s "The draw fences are …" sentence: it names a function, a type and
|
||||||
a helper reached only through `readSurvey.check`, and misses `checkDrawGroup`,
|
a helper reached only through `readSurvey.check`, and misses `checkDrawGroup`,
|
||||||
`checkOwnFamily` and `checkColumnDraws`; the README's Layout indexes the fences by file.
|
`checkOwnFamily` and `checkNestedDrawGroup`; the README's Layout indexes the fences by file.
|
||||||
Say "fences" in the `pin` entry then, which names the draw fences too.
|
Say "fences" in the `pin` entry then, which names the draw fences too.
|
||||||
- Cut the README's Layout block to the lines that say what a file name cannot:
|
- Cut the README's Layout block to the lines that say what a file name cannot:
|
||||||
`calc.go`, `doc.go` and `cmd/fejkdata/` restate their names.
|
`calc.go`, `doc.go` and `cmd/fejkdata/` restate their names.
|
||||||
|
|||||||
Reference in New Issue
Block a user