layout

package
v0.48.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 10, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package layout is selfdoc's declaration of the per-repository directories it owns, and the single authority for every path it reads or writes inside them.

A repository keeps one hidden directory at its root, Root, holding function-named directories rather than tool-named ones: docs/ is the pages a person writes, .docs-state/ is what selfdoc generates and the repository commits, .docs-cache/ is what selfdoc generates and the repository does not commit, posts/ is the blog, vocabulary/ is the project's word lists. Another tool's state lives beside them under its own function name, never under a tool's name.

Names

A directory a person writes carries its function name as it is; a directory a tool generates carries it behind a leading dot, so the hand-edited directories are the ones a directory listing shows. The dot is derived from the side the declaration states (Directory.DiskName), never typed beside it, and Validate refuses a directory selfdoc owns whose dot disagrees with its side. The dot means that at the top level of Root only: deeper down it means nothing, and selfdoc's committed directories hold no dotted entries.

Ownership

Every directory under Root has exactly one owner tool, declared in the ManifestFileName the directory itself carries. The manifest is the permission to write: EnsureDir refuses a directory whose manifest does not name selfdoc, printing the file and the line to put in it. Manifests are written by the repository's deliberate acts only: adopting selfdoc with `selfdoc init` (GrantInit), and moving off the previous layout with `selfdoc layout migrate`, where the previous manifests naming selfdoc are the grant. A manifest is also what makes a directory with no content yet exist in git. Reading and writing are open to anyone; the owner decides whether what was written is acceptable, which is what Validate answers.

Sides

A directory is entirely handwritten or entirely generated -- never both. The side is a property of the function, so it is declared here once rather than per repository, and Validate holds the tree to it: a generated page in a handwritten directory, or a handwritten page in a generated one, is a defect with a named remedy.

The ignore files

Root holds directories only, with RootFiles as the exceptions, so the ignore rules a directory needs sit inside it: each uncommitted directory selfdoc owns carries its own IgnoreFileName, derived from the commitment its declaration states. Its contents are ignored, and its manifest and the ignore file itself are not, so the permission travels with the repository while the contents do not.

Code generated by strictspec. DO NOT EDIT.

strictspec generator: 0.7.0 schema: selfdoc-directory-manifest (format_version 1) regenerate: strictspec gen --manifest strictspec.toml

Released under the MIT license (unencumbered). This file is machine-generated; edit the schema and regenerate, never this file.

Index

Constants

View Source
const (
	DocsName       = "docs"
	DocsStateName  = "docs-state"
	DocsCacheName  = "docs-cache"
	PostsName      = "posts"
	VocabularyName = "vocabulary"
)

The names of the function directories selfdoc claims, relative to Root.

View Source
const (
	CheckOwnership = "ownership"
	CheckSide      = "side"
	CheckHidden    = "hidden"
	CheckIgnore    = "ignore-file"
)

The names of the rules Validate holds a repository to.

View Source
const CLIOwner = "strictcli"

CLIOwner is the owner the directories a strictcli program's schema and test coverage live in name in their manifests (.cli-schema and .cli-test-coverage). strictcli is a library its programs link rather than a command, so no PATH lookup can answer for it either.

View Source
const DeprecatedRoot = ".selfdoc"

DeprecatedRoot is the directory selfdoc kept a repository's state in three layouts ago. Its presence is what a refusal recognizes: nothing reads it.

View Source
const EarlierRoot = ".stricttools"

EarlierRoot is the hidden directory the layout two before this one kept every function directory in, each under its bare function name, generated ones included. Like PreviousRoot, nothing reads it but the move.

View Source
const GENERATED_BY = "0.7.0"

GENERATED_BY is the strictspec release that produced this file. It is INFORMATIONAL: pairing is on GENERATED_CODE_FORMAT below, so a later release of the runtime reads this file unchanged, and no tool may derive a dependency floor from this string.

View Source
const GENERATED_CODE_FORMAT = 2

GENERATED_CODE_FORMAT is the shape of generated code this file was written to. The runtime pairing guard hard-errors unless this format is one the linked runtime reads; the remedy is regeneration.

View Source
const GeneratedMarkerPrefix = "<!-- generated by selfdoc gen"

GeneratedMarkerPrefix opens the HTML comment every page selfdoc generates carries under its frontmatter. It is what tells a generated page from a handwritten one on disk, which is how Validate checks a directory's side.

View Source
const IgnoreFileName = ".gitignore"

IgnoreFileName is the ignore file a directory under Root carries. It starts with a dot because git reads it under no other name, not because it is generated.

View Source
const ManifestFileName = "manifest.toml"

ManifestFileName is the ownership declaration a directory under Root carries, inside the directory it speaks for.

View Source
const MigrateCommand = "selfdoc layout migrate"

MigrateCommand is the command that moves a repository off a previous root.

View Source
const Owner = "selfdoc"

Owner is the name selfdoc is declared under in a directory's manifest.

View Source
const OwnerKey = "owner"

OwnerKey is the one key a manifest declares. The generated validator refuses a manifest carrying any other key.

View Source
const PreFlipRelease = "v0.41.0"

PreFlipRelease is the last selfdoc release that reads the layout this one replaced. Step 3 of MigrationProcedure builds the site with it, because only a release that can still read the repository as it stands today can publish the URL set the move is then held to.

View Source
const PreviousRoot = "stricttools"

PreviousRoot is the visible directory the layout before this one kept every function directory in, each under the name it carries under Root today. Nothing reads it: `selfdoc layout migrate` moves a repository off it, and every other command refuses a repository still on it.

View Source
const Root = ".strictmetadata"

Root is the one directory a repository's tool-owned state lives in, relative to the repository root. It starts with a dot as .git does: the tools that make a project commit these files hide them, so the project's own top level stays tidy.

View Source
const SCHEMA_FORMAT_VERSION = 1

SCHEMA_FORMAT_VERSION is the document format_version this validator accepts.

View Source
const SharedOwner = "strictspec"

SharedOwner is the owner a directory several tools share names in its manifest (the options directory and the upstream directory). strictspec holds the schemas those directories are validated against, and it is a library every reading tool links rather than a command, so no PATH lookup can answer for it.

Variables

View Source
var (
	DocsRel       = declaredRel(DocsName)
	DocsStateRel  = declaredRel(DocsStateName)
	DocsCacheRel  = declaredRel(DocsCacheName)
	PostsRel      = declaredRel(PostsName)
	VocabularyRel = declaredRel(VocabularyName)
)

The function directories, as paths relative to the repository root, in slash form. Each is derived from the declaration, so a directory's on-disk name is written in one place: Directory.DiskName.

View Source
var (
	// GeneratedPagesRel is the second docs root: the pages selfdoc generates,
	// merged into one URL namespace with the handwritten root at build time.
	GeneratedPagesRel = DocsStateRel + "/pages"
	// ManifestRel is the record of what a build published.
	ManifestRel = DocsStateRel + "/manifest.json"
	// PostManifestRel is the posts-only manifest the assembly's post publisher
	// reads.
	PostManifestRel = DocsStateRel + "/post-manifest.json"
	// RevisionsRel is the post revision record.
	RevisionsRel = DocsStateRel + "/revisions.json"
	// HashesDirRel holds the content and description hash baselines.
	HashesDirRel = DocsStateRel + "/hashes"
	// HashesRel is the hash store itself.
	HashesRel = HashesDirRel + "/hashes.json"
	// DataRel is where a sandboxed gen-data script writes its output.
	DataRel = DocsStateRel + "/data"
	// OutputRel is the built site.
	OutputRel = DocsCacheRel + "/build"
	// VersionsRel holds one extracted checkout per archived version.
	VersionsRel = DocsCacheRel + "/versions"
	// TermsRel is the project's accepted and rejected vocabulary.
	TermsRel = VocabularyRel + "/terms.toml"
	// ReviewRel is the vocabulary's review list: words proposed for
	// acceptance that nobody has approved yet.
	ReviewRel = VocabularyRel + "/review.toml"
)

The files and subdirectories selfdoc keeps inside its function directories, as paths relative to the repository root, in slash form.

View Source
var (
	DocsDefault   = DocsRel + "/"
	OutputDefault = OutputRel + "/"
	PostsDefault  = PostsRel + "/"
)

The declared values of the config keys that name a layout directory. A project that declares nothing gets these, and a project that declares something else has to keep it under Root.

InitDirectories are the directories `selfdoc init` grants selfdoc: the pages, the generated state and the cache every project writes from its first build on, and the vocabulary its spell check reads.

View Source
var LibraryOwners = []string{SharedOwner, CLIOwner}

LibraryOwners are the owners a manifest may name that are libraries rather than commands.

MoveScript is the script that moves a repository off the layout selfdoc used before this one, as it is spelled inside selfdoc's own checkout. A refusal prints the fetch-and-run commands instead, because the repository being refused does not have this path.

View Source
var PreviousLayouts = []PreviousLayout{
	{Root: PreviousRoot, DottedGenerated: true},
	{Root: EarlierRoot, DottedGenerated: false},
}

PreviousLayouts are the roots `selfdoc layout migrate` moves a repository off, newest first.

View Source
var RootFiles = []string{"go.mod"}

RootFiles are the files Root may hold beside its directories: go.mod, the stub module that keeps the tree out of a Go module's zip.

View Source
var RootIgnoreRel = Root + "/" + IgnoreFileName

RootIgnoreRel is the ignore file an earlier selfdoc derived at the top of Root, which `selfdoc layout migrate` converts into one per directory.

Functions

func CurrentSelfdocEntries added in v0.45.0

func CurrentSelfdocEntries(baseDir string) ([]string, error)

CurrentSelfdocEntries returns the entries under Root that are one of the directories selfdoc claims, by the name each carries on disk, sorted. An entry whose dot disagrees with its side still counts: it is the claimed directory, misnamed.

func DirectoryIgnoreContent added in v0.47.0

func DirectoryIgnoreContent() string

DirectoryIgnoreContent returns what an uncommitted directory's ignore file holds.

func DirectoryIgnoreRel added in v0.47.0

func DirectoryIgnoreRel(name string) string

DirectoryIgnoreRel returns where the ignore file of the directory with the given function name sits, relative to the repository root, in slash form.

func DirectoryManifestContent

func DirectoryManifestContent(owner string) string

DirectoryManifestContent renders the manifest that declares one tool the owner of a directory. Every refusal that asks for a manifest prints from here, so the text a person is told to write is generated from the declaration rather than typed beside it.

func DirectoryManifestPath

func DirectoryManifestPath(baseDir, name string) string

DirectoryManifestPath is where a directory's ownership manifest sits, in the operating system's own spelling.

func DirectoryManifestRel

func DirectoryManifestRel(name string) string

DirectoryManifestRel is a directory's ownership manifest, as a path relative to the repository root, in slash form. name is a function name: a directory selfdoc claims resolves to the name it carries on disk.

func DiskNameOf added in v0.45.0

func DiskNameOf(name string) string

DiskNameOf is the name a directory carries under Root: the derived name for a directory selfdoc claims, and the name as given for any other.

func EnsureDir

func EnsureDir(h *effects.Handle, baseDir, rel string) error

EnsureDir creates a directory inside one of selfdoc's function directories, after checking the manifest that permits it, and brings that function directory's ignore file up to date when it is uncommitted.

rel is one of this package's slash-form relative paths. Creating anything under Root goes through here, so no path can reach the filesystem without its owning manifest having been read.

func EnsureOwned

func EnsureOwned(baseDir, name string) error

EnsureOwned answers whether selfdoc may write into one of the directories under Root in this repository.

The manifest is the permission. A directory carrying none, or one naming another tool, is refused -- the first with the file and the line to write, which no command but `selfdoc init` writes.

func EntryOf added in v0.45.0

func EntryOf(rel string) (string, bool)

EntryOf returns the entry directly under Root a relative path sits in, as it is spelled on disk.

func FunctionOf

func FunctionOf(rel string) (string, bool)

FunctionOf returns the function of the claimed directory a relative path sits in. A path under Root in a directory selfdoc does not claim, or in one whose dot disagrees with the claimed side, sits in none.

func GrantInit added in v0.44.0

func GrantInit(h *effects.Handle, baseDir string) ([]string, error)

GrantInit writes the ownership manifests of InitDirectories that are missing, naming selfdoc, and the ignore file of each uncommitted one. It returns the slash-form relative paths of the manifests it wrote and of every uncommitted directory's ignore file.

It is the adopting act a repository performs by running `selfdoc init`. A manifest already naming selfdoc is kept as it stands, and one naming another tool refuses the whole grant before anything is written: that directory is the other tool's.

func KnownOwner

func KnownOwner(owner string) bool

KnownOwner reports whether a manifest names an owner this machine has: selfdoc itself, one of LibraryOwners, or any name PATH answers with an executable.

func MigratedPath added in v0.45.0

func MigratedPath(previous string) string

MigratedPath maps a path under one of the PreviousLayouts roots onto this layout: a directory selfdoc claims moves under Root with the name its side calls for, and the rest of the path is kept, trailing slash included. A path that is not inside one of selfdoc's directories under a previous root is returned unchanged.

func MigrationProcedure

func MigrationProcedure() string

MigrationProcedure is the whole ordered move onto this layout, as a refusal prints it.

The move has a chain of prerequisites, and each one used to be discovered only by running into the next refusal: the move needs the URL set the site publishes today, that set comes from a build made with the last pre-flip release, that build refuses a selfdoc.json with no "versions" or "locales" array, and it refuses every document still carrying the retired "---" frontmatter block -- including the generated pages the converter leaves alone unless it is told to take them too. The chain is printed in full, in order, by the first refusal a repository meets.

func Path

func Path(baseDir, rel string) string

Path joins a repository root with one of this package's slash-form relative paths, in the operating system's own spelling.

func PreviousSelfdocEntries added in v0.45.0

func PreviousSelfdocEntries(baseDir, previousRoot string) ([]string, error)

PreviousSelfdocEntries returns the directories under a previous root whose manifest names selfdoc, by the name each carries there, sorted. A directory with no manifest, or one naming another tool, is not selfdoc's to move and is not returned.

func RefuseOldLayout

func RefuseOldLayout(baseDir, docsDeclared, outputDeclared, postsDeclared string) error

RefuseOldLayout returns an OldLayoutError when a repository has not been moved to this layout yet.

It is called from the config loader, so every command that reads project state refuses before it reads anything. The three declared paths are the config keys that name a layout directory; an empty one is taken as undeclared and therefore already the default, which is inside Root.

func RefuseUnmigrated added in v0.45.0

func RefuseUnmigrated(baseDir string) error

RefuseUnmigrated returns an UnmigratedError when a repository still keeps selfdoc's directories under a previous root and none under Root: the repository `selfdoc layout migrate` is for.

A repository holding selfdoc's directories under Root and a previous root is part-way through a move, which only the migrate command judges; every other command reads the current layout alone.

func UnderRoot

func UnderRoot(declaredPath string) bool

UnderRoot reports whether a declared path names something inside Root. A project may spell its docs and output paths as it likes as long as they live in the layout.

func WithoutIgnoreBlock added in v0.45.0

func WithoutIgnoreBlock(existing string) string

WithoutIgnoreBlock returns an ignore file's content with selfdoc's block removed and every other line kept, for the ignore file a move leaves behind.

func WriteDirectoryIgnore added in v0.47.0

func WriteDirectoryIgnore(h *effects.Handle, baseDir, name string) error

WriteDirectoryIgnore brings the ignore file of the directory with the given function name up to date, writing nothing when the directory is committed or the file already holds what it should.

Types

type Commitment

type Commitment string

Commitment is whether a directory's contents belong in the repository.

const (
	Committed   Commitment = "committed"
	Uncommitted Commitment = "uncommitted"
)

The two commitments. An uncommitted directory carries its own ignore file.

type Directory

type Directory struct {
	// Name is the directory's function name. The name it carries on disk is
	// [Directory.DiskName].
	Name string
	// Side is whether people or selfdoc write its contents.
	Side Side
	// Commitment is whether the repository carries its contents.
	Commitment Commitment
	// Description says what the directory holds.
	Description string
	// DeprecatedNames are the paths this directory replaced, as they were
	// spelled relative to the repository root. A repository that still has
	// one of them is refused.
	DeprecatedNames []string
}

Directory is one function directory selfdoc claims: what it is for, which side of the authorship line it sits on, whether the repository commits it, and the paths it replaced.

func Declared

func Declared() []Directory

Declared returns the directories selfdoc claims, in declaration order.

func IgnoredDirectories added in v0.47.0

func IgnoredDirectories() []Directory

IgnoredDirectories are the directories selfdoc claims whose contents the repository does not commit, each of which carries its own ignore file.

func Lookup

func Lookup(name string) (Directory, bool)

Lookup returns the declaration of one claimed directory.

func LookupDiskName added in v0.45.0

func LookupDiskName(entry string) (Directory, bool)

LookupDiskName returns the claimed directory an entry under Root is, by the name it carries on disk. An entry whose dot disagrees with the claimed directory's side is not that directory.

func LookupFunction added in v0.45.0

func LookupFunction(entry string) (Directory, bool)

LookupFunction returns the claimed directory an entry under Root names by its function, whatever its dot says: the entry with its one leading dot removed, when that is a function selfdoc claims.

func (Directory) DiskName added in v0.45.0

func (d Directory) DiskName() string

DiskName is the name the directory carries under Root: its function name, behind a leading dot when selfdoc generates its contents.

func (Directory) Rel added in v0.45.0

func (d Directory) Rel() string

Rel is the directory as a path relative to the repository root, in slash form.

type DirectoryManifest

type DirectoryManifest struct {
	FormatVersion int64
	Owner         string
}

DirectoryManifest is the frozen typed binding of the "DirectoryManifest" record. Fields are immutable by convention (shallow-plus-generated-immutability); use With* for copy-on-write.

func ReadDirectoryManifest

func ReadDirectoryManifest(baseDir, name string) (*DirectoryManifest, error)

ReadDirectoryManifest reads and validates one directory's ownership manifest.

strictspec is the boundary validator: the file is checked against .strictspec/directory-manifest.schema.toml by the generated validator in this package, so a manifest that reaches a caller declares an owner and nothing else. A missing manifest is returned as the underlying os.ErrNotExist, which callers answer with the file to create.

The schema's format-version gate is supplied here rather than written into the file, the way a frontmatter block's is: a manifest on disk is the one OwnerKey line, and a file that declares the gate itself is refused, so the key has exactly one author.

func ValidateBytes

func ValidateBytes(input []byte, syntax string) (*DirectoryManifest, []strictspec.Diagnostic)

ValidateBytes is the raw-bytes entry point: lossless parse of input in the given syntax ("json" | "toml" | "jsonl"), then validate. It returns the typed root value (nil when any diagnostic fired) and the ordered diagnostics.

func ValidateBytesWithEvidence

func ValidateBytesWithEvidence(input []byte, syntax string, evidence map[string][]map[string]any) (*DirectoryManifest, []strictspec.Diagnostic)

ValidateBytesWithEvidence is ValidateBytes plus cross-document resolver evidence for the constraint vocabulary.

func ValidateValue

ValidateValue is the tagged-value entry point: validate an already-parsed tagged document value (from strictspec.LoadValue or a typed constructor).

func (*DirectoryManifest) WithFormatVersion

func (x *DirectoryManifest) WithFormatVersion(v int64) *DirectoryManifest

WithFormatVersion returns a copy of DirectoryManifest with FormatVersion set to the given value.

func (*DirectoryManifest) WithOwner

func (x *DirectoryManifest) WithOwner(v string) *DirectoryManifest

WithOwner returns a copy of DirectoryManifest with Owner set to the given value.

type OldLayoutError

type OldLayoutError struct {
	// Found is what was found, as the repository spells it.
	Found string
	// Replacement is where that thing lives now.
	Replacement string
	// Detail says what was found and why it is refused.
	Detail string
}

OldLayoutError is a repository refused for still being laid out the way selfdoc used to lay one out.

There is no migrator and no dual reading: a repository is moved once, by hand, with the script MoveScript names, and until it is, every command that reads project state refuses it.

func (*OldLayoutError) Error

func (e *OldLayoutError) Error() string

type PreviousLayout added in v0.46.0

type PreviousLayout struct {
	// Root is the directory, relative to the repository root.
	Root string
	// DottedGenerated reports whether a generated directory's name started
	// with a dot under this root, as it does under [Root].
	DottedGenerated bool
}

PreviousLayout is one root a repository may still keep selfdoc's directories in, and how the directories were named there.

func (PreviousLayout) EntryName added in v0.46.0

func (p PreviousLayout) EntryName(dir Directory) string

EntryName is the name a claimed directory carried under this root.

func (PreviousLayout) Lookup added in v0.46.0

func (p PreviousLayout) Lookup(entry string) (Directory, bool)

Lookup returns the claimed directory an entry under this root is. Under a root that dotted generated directories, an entry whose dot disagrees with its side is still that directory, misnamed; the move names it correctly.

type Problem

type Problem struct {
	// Check names the rule that failed: "ownership", "side", "hidden" or
	// "ignore-file". "hidden" covers both halves of the dot rule: a directory
	// selfdoc owns whose leading dot disagrees with its side, and a dotted
	// entry inside one of its committed directories.
	Check string
	// Message states the defect and names the remedy.
	Message string
}

Problem is one thing wrong with a repository's layout: what is wrong, and what to do about it.

func Validate

func Validate(baseDir string) ([]Problem, error)

Validate checks one repository's layout and returns every problem it finds, in check order.

The rules: every directory under Root carries a ManifestFileName naming a tool this machine has (KnownOwner), and every directory selfdoc claims that exists names selfdoc; every directory selfdoc owns carries the leading dot its side calls for; every directory selfdoc owns holds only what its side allows; nothing inside selfdoc's committed directories starts with a dot; every uncommitted directory selfdoc owns carries the ignore file its declaration derives; and Root holds directories and RootFiles only, the ignore file an earlier selfdoc derived at its top included. A directory another tool owns is held to the manifest rule only: its name and its contents are its owner's to judge.

A missing Root is returned as an error rather than a problem: the rest of the rules are unanswerable without it. So is a repository still on the layout before this one, which RefuseUnmigrated names.

func (Problem) Error

func (p Problem) Error() string

Error renders a problem the way the command prints it.

type Side

type Side string

Side is whether a directory's contents are written by a person or by a tool.

const (
	Handwritten Side = "handwritten"
	Generated   Side = "generated"
)

The two sides. A directory is entirely one or entirely the other.

type UnmigratedError added in v0.45.0

type UnmigratedError struct {
	// Root is the previous root the directories are under.
	Root string
	// Found are the directories under Root whose manifest names selfdoc, as
	// paths relative to the repository root.
	Found []string
}

UnmigratedError is a repository refused for still keeping selfdoc's directories under a previous root.

func (*UnmigratedError) Error added in v0.45.0

func (e *UnmigratedError) Error() string

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL