Documentation
¶
Overview ¶
Package corpus is the pure-domain model of a scanned markdown repository: the documents, their front matter and section trees, and the in-memory Corpus that holds them along with the indices (HeadingInventory, AliasTable) that downstream resolution and analysis read from.
This package depends only on the standard library and the sibling identity and reference packages (it imports nothing from application, infrastructure, cobra, or goldmark). See ADR 0004.
Index ¶
- Variables
- type Corpus
- func (c *Corpus) Add(doc *Document) error
- func (c *Corpus) DocumentIDs() []DocumentID
- func (c *Corpus) Documents() []*Document
- func (c *Corpus) Freeze()
- func (c *Corpus) Frozen() bool
- func (c *Corpus) Get(id DocumentID) (*Document, bool)
- func (c *Corpus) HasDocument(id DocumentID) bool
- func (c *Corpus) HasHeading(id DocumentID, slug string) bool
- func (c *Corpus) HeadingCount() int
- func (c *Corpus) Len() int
- func (c *Corpus) LookupAlias(alias string) []DocumentID
- type Document
- type DocumentID
- type FrontMatter
- type Section
Constants ¶
This section is empty.
Variables ¶
var ErrFrozen = errors.New("corpus: frozen (no mutations allowed after Freeze)")
ErrFrozen is returned by mutators called after Freeze. It signals a programming error (a write attempted past the corpus lifecycle boundary), surfaced as an error (not a panic) so the pipeline can degrade gracefully.
Functions ¶
This section is empty.
Types ¶
type Corpus ¶
type Corpus struct {
// contains filtered or unexported fields
}
Corpus is the in-memory collection of parsed documents plus the indices that resolution and analysis read from. It is built up during the pipeline and then treated as read-only. It is not safe for concurrent mutation.
Lifecycle / concurrency contract: the Corpus is mutated only during the single-threaded parse-and-merge stage (Add). At the phase boundary it is FROZEN — no further Add calls — after which the read-only accessors (Get, Documents, HasDocument, HasHeading, LookupAlias, …) are safe for concurrent readers. Resolution in P2 runs single-threaded over the frozen Corpus by design; any future fan-out must read, never mutate, a frozen Corpus.
The indices (headingInventory, aliasTable) are unexported and never handed out by reference: callers populate them through Add* methods and query them through read-only accessors. This preserves the "built once, read-only thereafter" invariant and avoids baking in a data-race shape for later phases.
func NewCorpus ¶
func NewCorpus() *Corpus
NewCorpus returns an empty Corpus with initialized indices.
func (*Corpus) Add ¶
Add inserts a document. It returns an error if a document with the same DocumentID is already present (identities are unique, ADR 0001) or if doc is nil or has an empty ID.
func (*Corpus) DocumentIDs ¶
func (c *Corpus) DocumentIDs() []DocumentID
DocumentIDs returns all known document identities, sorted for determinism.
func (*Corpus) Documents ¶
Documents returns all documents sorted by DocumentID. Sorting makes downstream iteration deterministic regardless of map insertion order.
func (*Corpus) Freeze ¶
func (c *Corpus) Freeze()
Freeze marks the corpus read-only: subsequent Add/AddHeading/AddAlias calls return ErrFrozen. The pipeline calls Freeze once parsing and the single-threaded merge complete, before resolution/analysis, so the read-only accessors are then safe for concurrent readers (ADR 0004). Freeze is idempotent.
func (*Corpus) Get ¶
func (c *Corpus) Get(id DocumentID) (*Document, bool)
Get returns the document with the given ID and whether it was found.
func (*Corpus) HasDocument ¶
func (c *Corpus) HasDocument(id DocumentID) bool
HasDocument reports whether id is a known markdown document in the corpus. It (together with DocumentIDs, HasHeading and LookupAlias) lets *Corpus satisfy the reference.Catalog read-only interface used by the link resolver.
func (*Corpus) HasHeading ¶
func (c *Corpus) HasHeading(id DocumentID, slug string) bool
HasHeading reports whether document id contains a heading with the given slug. It is the read-only query used by anchor resolution.
func (*Corpus) HeadingCount ¶
HeadingCount returns the total number of heading slugs indexed across all documents.
func (*Corpus) LookupAlias ¶
func (c *Corpus) LookupAlias(alias string) []DocumentID
LookupAlias returns the candidate documents for an alias, sorted by DocumentID for deterministic iteration. The result is a freshly allocated slice (mutating it does not affect the corpus) and is empty if the alias is unknown.
type Document ¶
type Document struct {
// ID is the canonical identity (ADR 0001).
ID identity.DocumentID
// FrontMatter holds the document's parsed front matter.
FrontMatter FrontMatter
// Root is the synthetic root of the section tree (Level 0). May be nil for
// a document with no headings.
Root *Section
// RawReferences are the outbound link edges extracted from the document,
// before resolution.
RawReferences []reference.RawReference
// ModTime is the file's last-modified time.
ModTime time.Time
// FrontMatterPresent reports whether the source began with a frontmatter fence
// block (`---`/`+++`) at all — independent of whether it parsed. It is pure
// data set by the parser, used by the OKF conformance mode (ADR 0023) to tell
// an ABSENT frontmatter block from a present-but-unparseable one. A document
// whose oversized frontmatter was stripped by the size guard (ADR 0003) is
// FrontMatterPresent=true, FrontMatterParsed=false.
FrontMatterPresent bool
// FrontMatterParsed reports whether a present frontmatter block decoded
// successfully into FrontMatter. It is false when there was no block at all
// (FrontMatterPresent=false), when the YAML/TOML failed to decode, or when the
// oversized-frontmatter guard stripped the block before decoding. Pure data
// set by the parser (ADR 0023).
FrontMatterParsed bool
}
Document is one parsed markdown file as a pure-domain value: its identity, front matter, section tree, the raw reference edges extracted from it, and the file's modification time. Built once by the parser and treated as immutable thereafter.
func (*Document) FirstHeadingText ¶
FirstHeadingText returns the text of the first (document-order) heading with non-empty text, or "" if the document has no headings.
func (*Document) HeadingTextBySlug ¶ added in v0.0.3
HeadingTextBySlug returns the heading text of the section whose canonical anchor slug (ADR 0006) equals slug, walking the section tree in document order. Slugs are unique per document (duplicates are suffixed per ADR 0006), so the first match wins. The information-scent analysis (ADR 0016) uses it to score an anchored link against the heading it actually points at.
func (*Document) HeadingTexts ¶
HeadingTexts returns every non-empty heading text in the document, in document order (ADR 0016): the information-scent analysis scores a document-targeted anchor against each of these (plus the title) and takes the best match.
func (*Document) Title ¶
Title returns the document's display title with the documented fallbacks (ADR 0016): front-matter title → first heading text → the DocumentID string. This is the single source of truth for a document's title; the emit-layer presentation helper and the information-scent analysis both go through it so they cannot drift.
type DocumentID ¶
type DocumentID = identity.DocumentID
DocumentID is the canonical document identity (ADR 0001). It is re-exported from the identity package as a convenience alias so existing corpus call sites keep working; the validating constructor lives in identity.
type FrontMatter ¶
type FrontMatter struct {
Title string
Description string
Tags []string
Aliases []string
// Name is an alternate single-name alias for the document (common in note
// systems). It is indexed into the AliasTable alongside Aliases so a wikilink
// `[[name]]` resolves to this document (ADR 0001).
Name string
Parent string
Related []string
Status string
// Date is kept as a string in the skeleton; typed-date parsing is deferred.
Date string
// Extra holds front-matter keys not modeled above, preserved verbatim.
Extra map[string]any
}
FrontMatter holds the typed YAML/TOML front-matter fields matlatl understands, plus any unrecognized keys in Extra. A zero FrontMatter is a valid "no front matter" value.
type Section ¶
type Section struct {
// Level is the heading level (1-6); the synthetic root uses 0.
Level int
// Text is the rendered heading text.
Text string
// Slug is the canonical anchor slug for the heading (ADR 0006).
Slug string
// Parent is the enclosing section, or nil for the root. It is a back-pointer
// set once during single-goroutine construction (see the type note above).
Parent *Section
// Children are the directly nested sections, in document order.
Children []*Section
// Start and End are the byte offsets of the section's span in the source.
Start int
End int
// StartLine and EndLine are the 1-based source line span of the section
// (heading line through the last line it encloses). Used to attribute a
// reference (which carries a line number) to its containing section when
// building the graph (ADR 0007). 0 means unset.
StartLine int
EndLine int
}
Section is a heading-scoped node of a document. Sections form a tree rooted at the synthetic document root (Level 0). It is a graph vertex in later phases (ADR 0004). This is a pure data type; slug computation lives in the infrastructure parser (ADR 0006).
Concurrency: the section tree (including the Parent back-pointers) is built by a single goroutine in the parser and is never mutated after the Document is handed to the corpus. It is therefore safe to hand off and read concurrently; callers must not mutate it post-construction.