From a169c6c74b172002d383f07f94eff5fd8c7248e7 Mon Sep 17 00:00:00 2001 From: Axel Meyer Date: Sat, 16 May 2026 17:51:27 +0200 Subject: [PATCH] fix(parse_readme_api): support namespace-less function names The previous single-pattern approach used a greedy `[^.\x60]*` segment that mis-captured H3 headers without a namespace prefix (e.g. test-lib entrypoints documented as `### \`run_tests(ctx)\``). Replace with a two-pass match: pattern 1 captures `### \`ns.func(...)\`` (namespaced) and pattern 2 captures `### \`func(...)\`` (no namespace). A seen-set prevents the namespace-less pass from re-matching names already collected by the namespaced pass. Enables test-libs to declare a public surface in their READMEs and satisfy --lint's missing-docs check. Co-Authored-By: Claude Opus 4.7 (1M context) --- init.lua | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/init.lua b/init.lua index b6278f4..e72c28d 100644 --- a/init.lua +++ b/init.lua @@ -50,6 +50,8 @@ end -- Returns: { documented = ["bind","unbind",...] } function M.parse_readme_api(markdown_string) local documented = {} + local seen = {} + -- Find "## API" section start (allow trailing whitespace/content) local api_start = string.find(markdown_string, "\n## API[%s\n]") if not api_start then @@ -59,10 +61,24 @@ function M.parse_readme_api(markdown_string) local api_end = string.find(markdown_string, "\n## ", api_start + 5) local section = string.sub(markdown_string, api_start, api_end or #markdown_string) - -- Match H3 headers: "### `[namespace.]name(...)`" — capture name portion - for line in string.gmatch(section, "###%s+`[^.`]*%.?([_%w]+)%s*[%(`]") do - table.insert(documented, line) + -- Two-pass matching to handle both namespace-prefixed and namespace-less + -- function-names in H3 headers. + -- Pattern 1: namespaced — "### `ns.func(...)`" -> capture "func" + for name in string.gmatch(section, "###%s+`[%w_]+%.([_%w]+)") do + if not seen[name] then + seen[name] = true + table.insert(documented, name) + end end + -- Pattern 2: namespace-less — "### `func(...)`" -> capture "func" + -- The seen-set prevents re-matching names already captured by pattern 1. + for name in string.gmatch(section, "###%s+`([_%w]+)%s*[%(`]") do + if not seen[name] then + seen[name] = true + table.insert(documented, name) + end + end + return { documented = documented } end