Skip to content
internal/strictclisupport
On this page

First-class support for strictcli projects: reading the schema document the CLI dumps, and rendering its commands, flags, arguments and groups as pages.

#internal/strictclisupport

#internal/strictclisupport

Package strictclisupport is first-class support for strictcli-based projects.

It reads .strictcli/schema.json -- the document <app> --dump-schema writes -- for the CLI's structure (the app, its commands, flags, arguments and groups) and renders that structure as Markdown documentation pages.

#Version 2 only

The reader accepts schema_version 2 and nothing else. v2 is not a superset of v1: it deletes the type, repeatable and arg-level required keys the v1 reader read, and adds constructs (selectors, constraints, update declarations) v1 had no encoding for. A schema of any other version is a hard error naming the regeneration command, because the alternative -- reading a v1 document with v2 rules -- is a page that silently labels every flag str and every positional argument required. That page shipped once already, which is why there is no fallback here.

#KindIndex

Go go
const KindIndex PageKind = "index"

KindIndex is the CLI reference index page.

#KindCommand

Go go
const KindCommand PageKind = "command"

KindCommand is a top-level command's page.

#KindGroup

Go go
const KindGroup PageKind = "group"

KindGroup is a command group's page.

#SupportedSchemaVersion

Go go
const SupportedSchemaVersion = 2

SupportedSchemaVersion is the one dumped-schema format this reader understands. There is no v1 path and no negotiated fallback.

#PageKind

Go go
type PageKind string

PageKind is which CLI page a description belongs to. Every default description and every recognition of one is decided per kind.

#FlagHelp

Go go
type FlagHelp struct

FlagHelp is one declaration a reader sees, as IterFlagHelp reports it.

#SchemaError

Go go
type SchemaError struct

SchemaError is returned when a schema document is present but cannot be read on v2's terms: a wrong or absent schema_version, an absent project_id, or a project_id naming a different project.

It is the counterpart of the Python surface's ValueError, and a distinct type so the command layer renders it as the refusal it is rather than as an unexpected internal failure.

#SchemaDiscoveryError

Go go
type SchemaDiscoveryError struct

SchemaDiscoveryError is returned when .strictcli/schema.json discovery finds nothing or finds more than one candidate.

It is a hard error: a page that asked for a CLI table cannot be rendered from a schema nobody named, and picking one of several silently would document a different app than the author meant.

#Structure

Go go
type Structure struct

Structure is a CLI's structure as the renderers read it: the app's own facts, its behavioral-completeness declarations, and its commands and groups in declaration order.

The per-command and per-group entries stay decoded objects rather than becoming typed records, for two reasons the Python model had as well: every key a schema carries reaches the renderers untouched, whether this version of selfdoc knows it or not, and the staleness measurement hashes a command's whole entry, so anything dropped here would silently change what a hash covers.

#NoSchemaError

Go go
type NoSchemaError struct

NoSchemaError is returned by ExtractCLIStructure when the project has no dumped schema at all -- the one condition ReadSchemaJSON answers in band instead.

#Object

Go go
type Object = extractors.JSONObject

Object is one decoded JSON object of a dumped schema, remembering the order its keys appeared in.

The order is not a nicety: the index page lists commands and groups in the order the schema declares them, so a model that lost the order would reshuffle every generated page from one run to the next.

#ComputeDefaultCLIDescription

Go go
func ComputeDefaultCLIDescription(kind PageKind, name, appName, helpText string) (string, error)

ComputeDefaultCLIDescription returns the machine-default description for a CLI page.

When the page's help text is at least minHelpForFirstSentence characters long the default is the first sentence of that help; otherwise it is a long-form template naming the app and the command. The index default is always the fixed long-form template.

An unrecognized kind is an error: the caller knows which page it is writing, and inventing a description for a page whose kind is unknown would publish one.

#IsDefaultCLIDescription

Go go
func IsDefaultCLIDescription(value string, kind PageKind, name, appName, helpText string) (bool, error)

IsDefaultCLIDescription reports whether value is a machine-generated default CLI description.

Every historical machine form is recognized, so machine residue is reseeded rather than frozen as if a person had written it:

- the current first-sentence form (help at least minHelpForFirstSentence characters), or - the long-form default template (a shorter help, or the index), or - the historical help[:155] truncation, with or without a trailing ellipsis, or - any prefix of the raw help at least 100 characters long (a truncated default from any prior cut point).

An empty value counts as a machine default: it is a blank machine placeholder the caller should reseed. CLI machine text is derivable from the schema, so this is a live recompute -- no static set can cover the truncated prefix family.

name is accepted for symmetry with ComputeDefaultCLIDescription and is not read: which template a value is compared against is decided by the kind and the help text alone.

#ExpectedCLIPageFilenames

Go go
func ExpectedCLIPageFilenames(structure *Structure) []string

ExpectedCLIPageFilenames returns the filenames GenerateCLIPages would write for structure.

The stale-file cleanup pass reads it to know which CLI page names are current, so the pages a prior run generated are not deleted as stale before the new ones have been written.

#GenerateCLIPages

Go go
func GenerateCLIPages(structure *Structure, docsDir string, handle *effects.Handle) ([]string, error)

GenerateCLIPages generates the Markdown documentation pages for structure into docsDir: an index page, one page per top-level command and one page per command group.

Every page carries generated: true frontmatter and is written read-only through handle, atomically. A page whose description frontmatter has been hand-edited keeps that description; one still carrying a machine default has it recomputed and is marked seeded: true.

It returns the generated filenames, relative to docsDir.

#IterFlagTokens

Go go
func IterFlagTokens(flags []any) []string

IterFlagTokens returns every --token an invocation can actually type, in declaration order, recursing through selector scopes.

A member-spelled selector's own name is not among them -- it is never typed -- while each of its choices is, and a scoped flag is a token like any other. This is what a completeness check must compare a page against; comparing against flag NAMES would demand that a page document a token no user can write.

#IterFlagHelp

Go go
func IterFlagHelp(flags []any) []FlagHelp

IterFlagHelp returns the label and help of every declaration a reader sees, in declaration order.

It recurses through selector scopes, so a scoped flag's help is measured like any other. A selector's own label is its bare name, and each choice is labelled by the token that elects it.

#UsesStrictcli

Go go
func UsesStrictcli(sourcePaths []string, baseDir string) bool

UsesStrictcli reports whether the project at baseDir has a .strictcli/schema.json file.

sourcePaths is accepted for call-site symmetry and is not read: detection is the presence of the schema document and nothing else.

#DiscoverSchemaDirs

Go go
func DiscoverSchemaDirs(baseDir string) []string

DiscoverSchemaDirs discovers the directories under baseDir that hold a .strictcli/schema.json.

It walks baseDir, pruning vendored and build directories and every hidden directory, and records each visited directory that holds a schema as a path relative to baseDir -- the project root being ".". That relative path is the value a schema-dir attribute takes.

The result is sorted. A walk error is not reported: an unreadable directory holds no schema anyone can name, which is the same answer as a directory that holds none.

#ReadSchemaJSON

Go go
func ReadSchemaJSON(baseDir string) (*Structure, error)

ReadSchemaJSON reads baseDir's .strictcli/schema.json and translates it into the structure the renderers read.

It returns a nil structure and a nil error when the document does not exist -- "this project has no dumped schema" is an answer, not a failure. Every per-entry field the renderers read (value_schema, presence, default, choices, elect_by, nullable, negatable, unique, prefixed, variadic, hidden, deprecated, passthrough, flag_sets, constraints, update_of, write_mode) and every effects-regime per-command field (effect, consequential, grants, dry_run_supported, dry_run_unsupported_reason) is carried through untouched.

strictcli omits the app-level global_flags, infra and deprecated keys when they are empty and some emitters write an explicit null; both normalize to empty containers, so a renderer can truth-test them.

A document declaring a schema_version other than SupportedSchemaVersion, carrying no project_id, or naming a different project than the manifest, is a SchemaError.

#CommandName

Go go
func CommandName(entry *Object) string { return getString(entry, "name") }

CommandName is the name a command or group entry declares.

The entries of a Structure are decoded objects rather than typed records -- see the type's own documentation for why -- so these accessors are how a consumer reads the fields every consumer reads, without each one restating how a missing or wrongly-typed field degrades.

#CommandHelp

Go go
func CommandHelp(entry *Object) string { return getString(entry, "help") }

CommandHelp is the help text a command or group entry declares, "" when it declares none.

#CommandFlags

Go go
func CommandFlags(entry *Object) []any { return getList(entry, "flags") }

CommandFlags are a command's flag declarations, in declaration order. Each element is a decoded object, which is what IterFlagTokens and IterFlagHelp read.

#CommandArgs

Go go
func CommandArgs(entry *Object) []any { return getList(entry, "args") }

CommandArgs are a command's positional-argument declarations, in declaration order.

#GroupCommands

Go go
func GroupCommands(group *Object) []*Object

GroupCommands are a group's subcommands, in declaration order.

#Field

Go go
func Field(entry *Object, key string) string { return getString(entry, key) }

Field is the string value of one declared field of any schema entry -- a flag's env var, an argument's help -- and "" when the entry omits it or declares it as something other than a string.

#ExtractCLIStructure

Go go
func ExtractCLIStructure(sourcePaths []string, baseDir string) (*Structure, error)

ExtractCLIStructure reads the CLI structure from baseDir's dumped schema.

It is ReadSchemaJSON with the absent document turned into a NoSchemaError, for the call sites that have already established the project uses strictcli. sourcePaths is accepted for call-site symmetry and is not read.

#PlainValue

Go go
func PlainValue(v any) any

PlainValue converts a decoded schema value into the plain Go value model -- map[string]any, []any and scalars.

It is what the schema-hash input needs: the hash is canonical JSON with sorted keys, so the ordered model this package reads a schema with carries nothing the hash uses, and a reflect-based encoder cannot walk it.

#SchemaError.Error

Go go
func (e *SchemaError) Error() string { return e.Message }

Error returns the diagnostic.

#SchemaDiscoveryError.Error

Go go
func (e *SchemaDiscoveryError) Error() string { return e.Message }

Error returns the diagnostic.

#NoSchemaError.Error

Go go
func (e *NoSchemaError) Error() string

Error names the directory and the command that writes the missing document.

Search