layout

package
v0.43.0 Latest Latest
Warning

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

Go to latest
Published: Sep 19, 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.

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, and selfdoc never writes one itself. 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 derived ignore file

git needs one file inside Root to keep the uncommitted directories out of the repository. It is derived, at Root/IgnoreFileName, from the commitment each tool declares: an uncommitted directory's contents are ignored and its manifest is not, so the permission travels with the repository while the contents do not. selfdoc owns only the block between its two marker comments and leaves every other line of that file alone, so several tools can write their own blocks into one file.

Code generated by strictspec. DO NOT EDIT.

strictspec generator: 0.2.5 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 (
	DocsRel       = Root + "/" + DocsName
	DocsStateRel  = Root + "/" + DocsStateName
	DocsCacheRel  = Root + "/" + DocsCacheName
	PostsRel      = Root + "/" + PostsName
	VocabularyRel = Root + "/" + VocabularyName
)

The function directories, as paths relative to the repository root, in slash form.

View Source
const (
	// 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 sidecar.
	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"
)

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

View Source
const (
	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.

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 DeprecatedRoot = ".selfdoc"

DeprecatedRoot is the directory selfdoc kept a repository's state in before this layout. Its presence is what a refusal recognizes: nothing reads it.

View Source
const GeneratedBy = "0.2.5"

GeneratedBy is the strictspec release that produced this file. The runtime pairing guard hard-errors unless it matches the linked runtime exactly.

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 derived ignore file inside Root, and the one entry there allowed to start with a dot.

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 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 Root = ".stricttools"

Root is the one hidden directory a repository's tool-owned state lives in, relative to the repository root.

View Source
const SchemaFormatVersion = 1

SchemaFormatVersion is the document format_version this validator accepts.

Variables

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.

Functions

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.

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 refreshes the derived ignore file.

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 selfdoc never writes itself.

func FunctionOf

func FunctionOf(rel string) (string, bool)

FunctionOf returns the function directory a relative path sits in.

func IgnoreBlock

func IgnoreBlock() []string

IgnoreBlock is selfdoc's block of the derived ignore file: the marker comments around the lines that keep each uncommitted directory it owns out of the repository.

An uncommitted directory contributes two lines rather than one. Its contents are ignored, and its ManifestFileName is not: the manifest is the permission to write into the directory, and a permission that git did not carry would have to be written again in every fresh checkout -- including the ones a multi-version build extracts out of git tags.

func IgnoreIsCurrent

func IgnoreIsCurrent(baseDir string) (bool, string)

IgnoreIsCurrent reports whether the derived ignore file holds selfdoc's block as declared, and returns the content it should hold.

func IgnorePath

func IgnorePath(baseDir string) string

IgnorePath is where the derived ignore file sits.

func KnownOwner

func KnownOwner(owner string) bool

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

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 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 RenderIgnore

func RenderIgnore(existing string) string

RenderIgnore returns what the derived ignore file should hold, given what it holds now: selfdoc's block replaced in place, or appended when the file carries none, with every other line untouched.

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 WriteIgnore

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

WriteIgnore brings the derived ignore file up to date, writing nothing when it 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 contributes one line to the derived ignore file.

type Directory

type Directory struct {
	// Name is the directory's name under [Root].
	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 Lookup

func Lookup(name string) (Directory, bool)

Lookup returns the declaration of one claimed directory.

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 phase-2 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 Problem

type Problem struct {
	// Check names the rule that failed: "ownership", "side", "hidden" or
	// "ignore-file".
	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, and every directory selfdoc claims that exists names selfdoc; every directory selfdoc owns holds only what its side allows; nothing under Root starts with a dot except the derived ignore file; and that file's selfdoc block is what the declaration says it should be.

A missing Root is returned as an error rather than a problem: the rest of the rules are unanswerable without it.

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.

Jump to

Keyboard shortcuts

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