From 0295cb4fc496faaf2bffca56a15e17b4831fcd88 Mon Sep 17 00:00:00 2001 From: LeadGoEngineer Date: Mon, 9 Nov 2026 20:08:04 -0500 Subject: [PATCH] feat(compat): expose canonical format names --- compat/README.md | 6 ++++-- compat/compat.go | 18 +++++++++++++++--- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/compat/README.md b/compat/README.md index f39a695..9b21cc9 100644 --- a/compat/README.md +++ b/compat/README.md @@ -120,15 +120,17 @@ When `compat.Runner.Subcommands` is set, every row above runs once per declared ### Partial-codec exporters: `Runner.SupportedFormats` -§4 requires markdown and json; csv is recommended but optional. Exporters that do not implement csv can use `compat.Runner.SupportedFormats`: +§4 requires markdown and json; csv is recommended but optional. Exporters that do not implement csv can use `compat.Runner.SupportedFormats`. Prefer the exported format constants to string literals so misspelled constant names fail to compile: ```go formats.RunContract(t, compat.Runner{ Binary: os.Getenv("EXPORT_CLI_BIN"), - SupportedFormats: []string{"markdown", "json"}, // declare what you implement + SupportedFormats: []string{compat.FormatMarkdown, compat.FormatJSON}, // declare what you implement }) ``` +`compat.FormatCSV` names the optional CSV codec, and `compat.CanonicalFormats` contains all three canonical names. String literals remain valid; their spelling is not checked by the compiler. + Semantics: - **Nil (default)** — exporter declares the full §4 surface. Every subtest runs. diff --git a/compat/compat.go b/compat/compat.go index b4af3d9..60a880b 100644 --- a/compat/compat.go +++ b/compat/compat.go @@ -23,6 +23,17 @@ import ( "time" ) +// Canonical §4 output codec names for Runner.SupportedFormats. +const ( + FormatMarkdown = "markdown" + FormatJSON = "json" + FormatCSV = "csv" +) + +// CanonicalFormats is the full set of §4 output codecs. Exporters that +// support a subset can populate Runner.SupportedFormats with the constants. +var CanonicalFormats = []string{FormatMarkdown, FormatJSON, FormatCSV} + // Runner invokes a single *-export-cli binary in a controlled environment. // A zero-value Runner is not usable; Binary must be set to an absolute path. type Runner struct { @@ -65,13 +76,14 @@ type Runner struct { // SupportedFormats declares which §4 output codecs the exporter // implements. Used by compat/formats to gate the codec-specific - // data-path subtests. + // data-path subtests. Use FormatMarkdown, FormatJSON, and FormatCSV + // instead of string literals to catch misspelled identifiers at compile time. // // Default (nil) means the exporter declares the full §4 surface // (markdown, json, csv); compat/formats runs every subtest. // // Non-nil declares an explicit subset — e.g. - // []string{"markdown", "json"} for a CLI that has not yet added a + // []string{FormatMarkdown, FormatJSON} for a CLI that has not yet added a // CSV writer. The bundle's JSONIsArray, CSVHasHeader, and // DefaultIsMarkdown subtests skip via t.Skipf when their codec is // not in the list, naming the missing codec so the gap is visible @@ -253,7 +265,7 @@ func (r Runner) Subcommand() string { return strings.Join(r.subcommandParts, " " // returns true for any name. When SupportedFormats is non-nil // (including empty), only names present in the slice return true. // String comparison is exact: callers pass the canonical CONTRACT.md -// codec names ("markdown", "json", "csv"). +// codec names (FormatMarkdown, FormatJSON, and FormatCSV). // // Section bundles consult this when deciding whether to skip a // codec-specific subtest. Integrators normally do not call it