One declaration does three jobs: renders the panel, carries the defaults, names
the values that come back. A module writes no DOM and reads no DOM.
Validation refuses rather than repairs -- unknown type, a renderer its type does
not have, a label that is not text, a default outside its own bounds, a when
naming a key the module never declared. A module that is wrong does not get a
best-effort panel; it does not load, and says why once.
Ordering is by declared relation and stage, never priority numbers, and a cycle
drops only the modules in it. Compatibility is by trait, never model name.
The shell hands a module { composer, values, on, shell } and nothing else: no
node, no document, no kit internals. It cannot style anything because it is
never given anything that could.
catalogue/hide.html puts one good module and five broken ones through the real
shell and shows the result: one panel, five absent, no placeholders. The lint
fixtures make the scanner prove it catches each rule, so a clean scan means
something.
First slice: modules/system/appearance. Two settings, an optional ui.js, and
clicking Light actually turns the app light.
25 lines
970 B
Python
25 lines
970 B
Python
"""Compatibility by trait, never by model name.
|
|
|
|
A module listing model names has to be edited every time a model ships, and the
|
|
one nobody remembers to edit is the one that silently stops appearing. A model
|
|
says what it IS; a module says what it NEEDS.
|
|
"""
|
|
|
|
from typing import Iterable, List, Sequence, Set, Tuple
|
|
|
|
from .contract import ModuleSpec
|
|
|
|
|
|
def split(specs: Iterable[ModuleSpec], available: Sequence[str]) -> Tuple[List[ModuleSpec], List[ModuleSpec]]:
|
|
"""(compatible, incompatible) for the traits currently on offer."""
|
|
have: Set[str] = set(available or ())
|
|
compatible, incompatible = [], []
|
|
for spec in specs:
|
|
(compatible if set(spec.requires) <= have else incompatible).append(spec)
|
|
return compatible, incompatible
|
|
|
|
|
|
def missing_for(spec: ModuleSpec, available: Sequence[str]) -> List[str]:
|
|
"""Which traits a module wanted and did not get. For the modules dump."""
|
|
return sorted(set(spec.requires) - set(available or ()))
|