From 93268869c5351dbcdd855af4d93b956e2971f0dd Mon Sep 17 00:00:00 2001 From: Rodin Date: Fri, 15 May 2026 04:46:38 +0000 Subject: [PATCH] feat(#141): export FileCoveredByDocMap helper in review/docmap.go MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds FileCoveredByDocMap(cfg *DocMapConfig, file string) bool — a thin wrapper over the existing unexported mappingMatches that lets cmd/ check per-file docmap coverage without duplicating glob logic. Also adds unit tests covering matched globs, non-matching paths, empty file, and empty config. --- review/docmap.go | 12 +++++++++++ review/docmap_test.go | 49 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/review/docmap.go b/review/docmap.go index 8916b6f..7317936 100644 --- a/review/docmap.go +++ b/review/docmap.go @@ -66,6 +66,18 @@ func ParseDocMapConfig(localPath string) (*DocMapConfig, error) { return &cfg, nil } +// FileCoveredByDocMap reports whether at least one paths: glob in any mapping +// of cfg matches the given file path. It is used by static validation tooling +// (e.g. the validate-docmap subcommand) to check per-file docmap coverage. +func FileCoveredByDocMap(cfg *DocMapConfig, file string) bool { + for _, mapping := range cfg.Mappings { + if mappingMatches(mapping.Paths, []string{file}) { + return true + } + } + return false +} + // MatchDocs returns deduplicated doc paths for the given changed file paths. // A mapping matches if any of its path globs matches any of the changed files. func MatchDocs(cfg *DocMapConfig, changedFiles []string) []string { diff --git a/review/docmap_test.go b/review/docmap_test.go index 7ad51c0..5e42be7 100644 --- a/review/docmap_test.go +++ b/review/docmap_test.go @@ -436,3 +436,52 @@ func writeTempYAML(t *testing.T, content string) string { } return filepath.Clean(f.Name()) } + +// ============================================================ +// FileCoveredByDocMap +// ============================================================ + +func TestFileCoveredByDocMap(t *testing.T) { + cfg := &DocMapConfig{ + Mappings: []DocMapping{ + { + Paths: []string{"lib/foo/**", "lib/bar/*.go"}, + Docs: []string{"docs/foo.md"}, + }, + { + Paths: []string{"cmd/**"}, + Docs: []string{"docs/cmd.md"}, + }, + }, + } + + cases := []struct { + file string + covered bool + }{ + {"lib/foo/baz.ex", true}, + {"lib/foo/sub/deep.ex", true}, + {"lib/bar/util.go", true}, + {"lib/bar/sub/util.go", false}, // *.go only matches one level + {"cmd/main.go", true}, + {"cmd/sub/main.go", true}, + {"internal/secret.go", false}, + {"", false}, + } + + for _, tc := range cases { + t.Run(tc.file, func(t *testing.T) { + got := FileCoveredByDocMap(cfg, tc.file) + if got != tc.covered { + t.Errorf("FileCoveredByDocMap(%q) = %v, want %v", tc.file, got, tc.covered) + } + }) + } +} + +func TestFileCoveredByDocMap_EmptyConfig(t *testing.T) { + cfg := &DocMapConfig{} + if FileCoveredByDocMap(cfg, "lib/foo/bar.go") { + t.Error("expected false for empty config, got true") + } +}