Files
sporel-lib-core.api-discovery/README.md
2026-06-16 15:02:11 +00:00

6.6 KiB

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.

  • core verlangt: H1, Badges (ein **Lib-ID:** lib-…-Block), Topology (## Topology), Topology-Block (<!-- topology:start-Marker), API (## API) und References (## References).
  • engine verlangt dieselben Sections, lockert aber den Badges-Check auf eine beliebige fettgedruckte **Key:**-Zeile (die Engine ist keine Lib und trägt kein Lib-ID:, sondern Version/License).
  • module ersetzt ## API durch ## Controls + ## Demonstrates und identifiziert über **Module-ID:** statt **Lib-ID:** (Module haben keine konsumierbare Public-API).
  • community erzwingt 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)