Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
lib-core.api-discovery
Pure-Lua-Library für Surface-Discovery (extrahiert M.* aus Lua-Quelltext)
und README-Parsing (extrahiert die dokumentierte API aus Markdown). Außerdem
ein README-Struktur-Linter, der die API-Doc-Convention (ADR-0038) gegen die
MUST-Sections eines Tiers prüft. Sandbox-safe — kein FS-Zugriff, keine
Seiteneffekte. Verwendet vom Sporel---lint-CLI-Modus.
Version: 0.1.0 Lib-ID: lib-core.api-discovery Requires: (none) Tags: api-discovery, lint, readme, surface, topology, tooling
Topology
graph LR
this["lib-core.api-discovery"]
Reine Lua-Lib ohne Dependencies und ohne engine.*-Aufrufe — daher kein
engine-Knoten im Topology-Graphen (sandbox-safe per Design, damit der
Linter im --lint-CLI-Modus ohne Engine-Kontext laufen kann).
API
api-discovery.parse_lua_surface(source_string)
Syntax: parse_lua_surface(source_string: string) -> {public: string[], private: string[]}
Example:
local ad = require("lib-core.api-discovery")
local src = io.read_file("init.lua")
local s = ad.parse_lua_surface(src)
-- s.public == { "load", "create", ... }
-- s.private == { "_normalize", ... }
Description: Extrahiert die öffentliche und private Surface aus
Lua-Quelltext. Konvention: M.<name> ist öffentlich, M._<name> privat.
Erkennt beide Schreibweisen — explizite Zuweisung (M.foo = function) und
Syntax-Sugar (function M.foo). Lua-Zeilenkommentare (-- bis Zeilenende)
werden vor dem Pattern-Matching entfernt, damit auskommentierte
Forward-Compat-Stubs (z. B. DEPRECATED-MVP-Platzhalter) keine
False-Positives erzeugen. Block-Kommentare (--[[ ... ]]) werden nicht
behandelt (in Sporel-Lib-Code nicht verwendet). Dedupliziert über alle
Namen. Liefert { public = [...], private = [...] }.
api-discovery.parse_readme_api(markdown_string)
Syntax: parse_readme_api(markdown_string: string) -> {documented: string[]}
Example:
local r = ad.parse_readme_api(readme_text)
-- r.documented == { "bind", "unbind", ... }
Description: Extrahiert die dokumentierten Funktionsnamen aus dem
## API-Abschnitt eines READMEs. Sucht den Abschnitt zwischen ## API und
der nächsten H2-Überschrift und parst die H3-Header darin. Konvention: ein
H3-Header öffnet mit einem Backtick, der Funktionsname folgt nach einem
optionalen Namespace-Punkt — sowohl die namespaced-Form ns.func(...)
(Capture func) als auch die namespace-lose Form func(...) werden
erkannt. Dedupliziert; Pattern 2 matcht
keine Namen, die Pattern 1 bereits erfasst hat. Fehlt der ## API-Abschnitt,
ist documented leer.
api-discovery.diff_surface(surface, readme)
Syntax: diff_surface(surface: {public: string[]}, readme: {documented: string[]}) -> {missing_docs: string[], stale_docs: string[]}
Example:
local s = ad.parse_lua_surface(src)
local r = ad.parse_readme_api(readme_text)
local diff = ad.diff_surface(s, r)
-- diff.missing_docs == öffentliche Funktionen ohne README-Eintrag
-- diff.stale_docs == README-Einträge ohne öffentliche Funktion
Description: Vergleicht die Code-Surface (surface.public) gegen die
README-Dokumentation (readme.documented). missing_docs sind öffentliche
Funktionen ohne dokumentierten Eintrag; stale_docs sind dokumentierte
Einträge ohne korrespondierende öffentliche Funktion. Beide Listen sind
alphabetisch sortiert.
api-discovery.grep_engine_calls(source_string)
Syntax: grep_engine_calls(source_string: string) -> string[]
Example:
local calls = ad.grep_engine_calls(src)
-- calls == { "engine.render.draw_rect", "engine.window.size", ... }
Description: Extrahiert alle eindeutigen engine.<namespace>.<func>-Aufrufe
aus Lua-Quelltext. Liefert ein dedupliziertes, alphabetisch sortiertes Array.
Wird von generate_topology_block genutzt, um zu entscheiden, ob ein
engine.*-Knoten in den Topology-Graphen aufgenommen wird.
api-discovery.generate_topology_block(manifest, engine_calls)
Syntax: generate_topology_block(manifest: {id: string, deps?: {id: string}[]}, engine_calls: string[]) -> string
Example:
local manifest = { id = "lib-core.maps", deps = {} }
local calls = ad.grep_engine_calls(src)
local mermaid = ad.generate_topology_block(manifest, calls)
-- mermaid == "graph LR\n this[\"lib-core.maps\"]\n engine[\"engine.*\"]\n this --> engine"
Description: Generiert den Mermaid-Topology-Block aus Manifest +
engine_calls. Der this-Knoten trägt die manifest.id. Für jede
Dependency in manifest.deps wird ein Knoten plus this --> dep-Kante
ausgegeben (die Dep-ID wird für den Mermaid-Variablennamen entschärft: -
und . → _). Enthält engine_calls mindestens einen Eintrag, kommt ein
engine["engine.*"]-Knoten mit this --> engine-Kante hinzu. Liefert den
reinen Mermaid-Quelltext ohne Marker — der Aufrufer wrappt ihn in die
<!-- topology:start --> / <!-- topology:end -->-Marker.
api-discovery.validate_readme_structure(markdown_string, tier)
Syntax: validate_readme_structure(markdown_string: string, tier: "core"|"engine"|"module"|"community") -> {missing_sections: string[], section_order_ok: boolean}
Example:
local res = ad.validate_readme_structure(readme_text, "core")
if #res.missing_sections > 0 or not res.section_order_ok then
-- README verletzt die API-Doc-Convention
end
Description: Prüft die README-Struktur gegen die MUST-Sections des angegebenen Tiers.
coreverlangt:H1,Badges(ein**Lib-ID:** lib-…-Block),Topology(## Topology),Topology-Block(<!-- topology:start-Marker),API(## API) undReferences(## References).engineverlangt dieselben Sections, lockert aber den Badges-Check auf eine beliebige fettgedruckte**Key:**-Zeile (die Engine ist keine Lib und trägt keinLib-ID:, sondernVersion/License).moduleersetzt## APIdurch## Controls+## Demonstratesund identifiziert über**Module-ID:**statt**Lib-ID:**(Module haben keine konsumierbare Public-API).communityerzwingt nichts (liefert ein leeres Ergebnis).
section_order_ok ist true, wenn ## API vor ## References steht
(bzw. ## Demonstrates vor ## References im Module-Tier) — oder wenn
keine der beiden Sections vorhanden ist. Liefert
{ missing_sections = [...], section_order_ok = bool }.
References
- API-Doc-Convention Spec:
meta/docs/superpowers/specs/2026-05-16-api-doc-convention-design.md - ADR-0038 (API-Doc-Convention)
- ADR-0001 (engine knows verbs, libs bring nouns)