package suite import ( "slices" "git.vakhrushev.me/av/convy/internal/doc" ) // Component is what a copy is assembled for: one language, one set of tools, // one kind of application. Both axes may stay empty — a flat suite has no axes // at all, and a component of it selects the base layer and nothing else. // // Each axis is a list because a component may take two stack layers at once: // sqlite and postgres in the schema topic hold together, being different tables // of one service. Two languages never hold together, and that the axis allows // the list anyway is a matter of one shape for both rather than a licence. type Component struct { Lang []string Stack []string } // Assemble picks the layers of a topic a component takes, in the order they go // into a copy: base, then language, then stack. // // A layer is chosen by the axis keys of its front matter rather than by where // its file lies (META-38). A layer with no keys is the base one and travels // always; a key the layer does not declare puts no demand on the component, so // a language layer with no stack key fits any stack. // // This is the read-only half of assembly. The project commands write files out // of the same selection, so the two must never come to differ — which is why // the selection lives here rather than inside whichever command needs it. func (s *Suite) Assemble(topic string, c Component) (taken, left []*doc.Document) { for _, d := range s.Layers(topic) { if fits(d, c) { taken = append(taken, d) continue } left = append(left, d) } return taken, left } // fits reports whether a component takes a layer. func fits(d *doc.Document, c Component) bool { if d.Front.Lang != "" && !slices.Contains(c.Lang, d.Front.Lang) { return false } if d.Front.Stack != "" && !slices.Contains(c.Stack, d.Front.Stack) { return false } return true } // rank orders the layers of a topic the way a copy carries them. A layer on // both axes comes last: it narrows the most. func rank(d *doc.Document) int { switch { case d.Front.Lang == "" && d.Front.Stack == "": return 0 case d.Front.Stack == "": return 1 case d.Front.Lang == "": return 2 } return 3 } // Axis describes a layer in one word, for a report. func Axis(d *doc.Document) string { switch { case d.Front.Lang != "" && d.Front.Stack != "": return "lang=" + d.Front.Lang + " stack=" + d.Front.Stack case d.Front.Lang != "": return "lang=" + d.Front.Lang case d.Front.Stack != "": return "stack=" + d.Front.Stack } return "base" }