Help us shape the future of Go! Take the 2026 Go Developer Survey

project

package
v0.1.14 Latest Latest
Warning

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

Go to latest
Published: Oct 27, 2026 License: MIT Imports: 15 Imported by: 0

Documentation

Overview

Package project resolves an lfm project on disk: its fixed layout, the boundary that every source read must stay inside, and its configuration.

Index

Constants

View Source
const (
	Auto   = "auto"
	Inline = "inline"
	File   = "file"
)

Packing modes.

View Source
const (
	ConfigFile   = "lfm.json"
	TemplateFile = "index.html.tmpl"
	PartialsDir  = "partials"
	DataDir      = "data"
	PublicDir    = "public"
	OutputDir    = "output"
	// DistributionDir holds the store packages of deliverables: never deployed,
	// because its files are what buyers pay for.
	DistributionDir = "distribution"
	ResearchDir     = "research" // durable research files; never a build input
)

The fixed layout. Everything else inside the root is free-form; assets/ is a convention, not a requirement.

Variables

View Source
var ErrNoProject = errors.New("not an lfm project")

ErrNoProject means a directory holds neither lfm.json nor the template.

View Source
var Moved = map[string]string{
	"deliverables.book.publisher": "seller.name",
	"deliverables.book.imprint":   "seller.imprint",
	"deliverables.printable.shop": "seller.name",
}

Moved maps keys of earlier versions to where they live now, so an old lfm.json is told the new place instead of only "unknown field".

View Source
var Spec = []Field{
	{Path: "schemaVersion", Kind: Int, Required: true, Values: []string{"1"}, Doc: "The format of this file; always 1.", Example: `1`},
	{Path: "url", Kind: String, Required: true, Doc: "The absolute HTTPS URL of the folder the page is deployed to, ending in /: its canonical URL; download paths hang off it.", Example: `"https://example.com/my-page/"`},
	{Path: "language", Kind: String, Required: true, Doc: "The page's language as a BCP 47 tag; deliverables default to it.", Example: `"en"`},
	{Path: "title", Kind: String, Required: true, Doc: "The page title, shown in the browser tab, search results and share previews.", Example: `"Keep your sourdough alive"`},
	{Path: "description", Kind: String, Required: true, Doc: "One sentence for search results and share previews: who it is for and what they get.", Example: `"The jar check and the rescue feeding for a starter that smells wrong."`},
	{Path: "socialImage", Kind: Object, Doc: "The share preview image."},
	{Path: "socialImage.src", Kind: String, Doc: "Project path of a 1200×630 PNG/JPEG, or an HTML card rendered by compile at 1200×630 CSS pixels. Relative card assets are bundled; Chrome is required for the first render.", Example: `"assets/images/share.jpg"`},
	{Path: "socialImage.alt", Kind: String, Doc: "What the image shows, for people who cannot see it.", Example: `"A jar of starter on a kitchen shelf"`},
	{Path: "social", Kind: Object, Doc: "Optional social account attribution."},
	{Path: "social.x", Kind: String, Doc: "The page's X (Twitter) handle: 1–15 ASCII letters, digits or underscores, with or without @; normalized to @handle and available as {{.social.x}}. Leave out or empty when unused. The compiler fills missing twitter:site and twitter:creator tags; authored tags are kept.", Example: `"@example"`},
	{Path: "seller", Kind: Object, Doc: "Who sells: printed on the book's copyright page and in every other deliverable's guide, files and download page."},
	{Path: "seller.name", Kind: String, Doc: "The seller or publisher as buyers see it.", Example: `"Brot & Glas Verlag"`},
	{Path: "seller.imprint", Kind: String, Doc: "The lines of the legal notice (Impressum): address, register, VAT ID; printed on the book's copyright page.", Example: `"Brot & Glas Verlag, Musterstraße 1, 12345 Berlin"`},
	{Path: "urls", Kind: Map, Doc: "Named complete URLs: checkout links, shop listings, contacts. Render them as {{.urls.<name>}}; every rendered link is checked against them.", Example: `{"checkout": "https://buy.stripe.com/…"}`},
	{Path: "urls.*", Kind: String, Doc: "One complete URL.", Example: `"https://www.etsy.com/listing/123456/my-planner"`},
	{Path: "links", Kind: Free, Doc: "Optional free-form labels or key references for links."},
	{Path: "jsonld", Kind: Free, Doc: "A structured data object or array the compiler emits as JSON-LD; strings may reference config, such as \"{{.title}}\"."},
	{Path: "data", Kind: Free, Doc: "Every product value the page uses: offers, prices, copy, FAQ. Each data/<name>.json adds .data.<name>."},
	{Path: "data.commerce", Kind: Object, Reserved: true, Doc: "The commerce facts lfm checks: the offers and their checkout links."},
	{Path: "data.commerce.offers", Kind: Map, Reserved: true, Checked: "commerce.config", Doc: "The offers the page sells, by key; deliverables name theirs in offer."},
	{Path: "data.commerce.offers.*", Kind: Object, Reserved: true, Doc: "One offer.", Example: `{"sku": "planner-2027", "name": "Planner 2027", "checkoutUrlKey": "checkout", "price": {"amountMinor": 990, "currency": "EUR"}}`},
	{Path: "data.commerce.offers.*.sku", Kind: String, Reserved: true, Doc: "A stable product code, unique across offers.", Example: `"planner-2027"`},
	{Path: "data.commerce.offers.*.name", Kind: String, Reserved: true, Doc: "The offer's name as the checkout shows it.", Example: `"Planner 2027"`},
	{Path: "data.commerce.offers.*.checkoutUrlKey", Kind: String, Reserved: true, Doc: "The key in urls of where the buy button goes: a Stripe Payment Link, or a shop listing for a deliverable sold in shops.", Example: `"checkout"`},
	{Path: "data.commerce.offers.*.price", Kind: Object, Reserved: true, Doc: "The price as the checkout charges it.", Example: `{"amountMinor": 990, "currency": "EUR"}`},
	{Path: "data.commerce.offers.*.price.amountMinor", Kind: Int, Reserved: true, Doc: "The amount in minor units: 990 is 9.90.", Example: `990`},
	{Path: "data.commerce.offers.*.price.currency", Kind: String, Reserved: true, Doc: "A three-letter currency code.", Example: `"EUR"`},
	{Path: "data.commerce.offers.*.stripe", Kind: Free, Reserved: true, Checked: "commerce.fields", Doc: "Optional Stripe IDs (productId, priceId, paymentLinkId) and the customFields snapshot of the Payment Link."},
	{Path: "build", Kind: Object, Doc: "How lfm builds the page."},
	{Path: "build.assets", Kind: Object, Doc: "Whether resources are inlined into the page or emitted as files."},
	{Path: "build.assets.default", Kind: String, Values: []string{"auto", "inline", "file"}, Default: "auto: lfm decides per resource", Doc: "The packing policy for every resource.", Example: `"auto"`},
	{Path: "build.assets.overrides", Kind: Map, Doc: "Packing for single source paths; always wins over default.", Example: `{"assets/images/hero.webp": "file"}`},
	{Path: "build.assets.overrides.*", Kind: String, Values: []string{"inline", "file"}, Doc: "How this source path is packed.", Example: `"file"`},
	{Path: "build.browserData", Kind: List, Doc: "Dot paths copied into <script type=\"application/json\" id=\"product-data\"> for scripts, keeping their nesting.", Example: `["data.offer"]`},
	{Path: "build.validation", Kind: Object, Doc: "Rule levels and size budgets."},
	{Path: "build.validation.rules", Kind: Map, Doc: "Per-rule levels; required rules stay errors. `lfm rules` lists them.", Example: `{"design.mono": "off"}`},
	{Path: "build.validation.rules.*", Kind: String, Values: []string{"off", "warn", "error"}, Doc: "The level of this rule.", Example: `"warn"`},
	{Path: "build.validation.budgets", Kind: Object, Doc: "This page's advisory sizes, which perf.budgets warns past; raise one where the page has a reason to be larger instead of turning the rule off.", Checked: "perf.budgets", Example: `{"cssKiB": 80}`},
	{Path: "build.validation.budgets.imageKiB", Kind: Int, Default: "3000", Doc: "Total referenced image, poster, srcset candidate and CSS background image bytes in KiB; unknown sizes are skipped.", Checked: "perf.budgets", Example: `6000`},
	{Path: "build.validation.budgets.videoKiB", Kind: Int, Default: "8000", Doc: "Referenced video source bytes in KiB, counted separately from images.", Checked: "perf.budgets", Example: `16000`},
	{Path: "build.validation.budgets.firstScreenKiB", Kind: Int, Default: "400", Doc: "First content section media bytes in KiB; posters count, lazy images are excluded, and video sources count only with autoplay or preload=auto.", Checked: "perf.budgets", Example: `800`},
	{Path: "build.validation.budgets.cssKiB", Kind: Int, Default: "20", Doc: "Total CSS in KiB, inline and in files.", Checked: "perf.budgets", Example: `80`},
	{Path: "build.validation.budgets.jsKiB", Kind: Int, Default: "50", Doc: "Total JavaScript in KiB, inline and in files.", Checked: "perf.budgets", Example: `120`},
	{Path: "build.validation.budgets.elements", Kind: Int, Default: "1500", Doc: "Elements in the page's DOM.", Checked: "perf.budgets", Example: `3000`},
	{Path: "build.validation.budgets.depth", Kind: Int, Default: "32", Doc: "How deep the DOM nests.", Checked: "perf.budgets", Example: `40`},
	{Path: "deliverables", Kind: Object, Doc: "What buyers receive besides the page: a book, a printable, a spreadsheet, a set of editable documents, slide decks, and two or more of them together as a bundle."},

	{Path: "deliverables.book", Kind: Object, Doc: "A book in deliverables/book, written with `lfm skills book`, or `lfm skills fiction` for fiction."},
	{Path: "deliverables.book.kind", Kind: String, Default: "nonfiction", Checked: "book.config", Doc: "nonfiction (default) or fiction: fiction swaps the concept format and turns off the research minimums and the nonfiction value and readability checks.", Example: `"fiction"`, Values: []string{"nonfiction", "fiction"}},
	{Path: "deliverables.book.author", Kind: String, Required: true, Doc: "The name on the cover.", Example: `"Lena Brot"`},
	{Path: "deliverables.book.sell", Kind: String, Values: []string{"page", "shops", "bundle"}, Default: "page", Doc: sellDoc, Example: `"page"`},
	{Path: "deliverables.book.path", Kind: String, Checked: "book.config", Doc: pathDoc, Example: `"k3x9m2q7w8e4r5t6y1u0"`},
	{Path: "deliverables.book.offer", Kind: String, Checked: "book.config", Doc: offerDoc, Example: `"book"`},
	{Path: "deliverables.book.language", Kind: String, Default: "the page's language", Doc: "The book's language, when it differs from the page's.", Example: `"de"`},
	{Path: "deliverables.book.formats", Kind: List, Values: []string{"epub", "pdf"}, Default: `["epub", "pdf"]`, Doc: "The files the download page offers.", Example: `["epub", "pdf"]`},
	{Path: "deliverables.book.paper", Kind: String, Values: []string{"white", "cream"}, Default: "white", Doc: "The paperback's paper; it sets the spine width.", Example: `"cream"`},
	{Path: "deliverables.book.isbn", Kind: Object, Doc: "ISBNs per edition; each is optional, ebooks need none in most stores."},
	{Path: "deliverables.book.isbn.ebook", Kind: String, Checked: "book.config", Doc: "The ebook's ISBN-13, printed on the copyright page.", Example: `"978-3-16-148410-0"`},
	{Path: "deliverables.book.isbn.paperback", Kind: String, Checked: "book.config", Doc: "The paperback's ISBN-13, printed on the copyright page and as the barcode on the back cover.", Example: `"978-3-16-148411-7"`},

	{Path: "deliverables.printable", Kind: Object, Doc: "A printable in deliverables/printable (planner, game, puzzle pack), built with `lfm skills printable`."},
	{Path: "deliverables.printable.sell", Kind: String, Values: []string{"page", "shops", "bundle"}, Default: "page", Doc: sellDoc, Example: `"shops"`},
	{Path: "deliverables.printable.path", Kind: String, Checked: "printable.config", Doc: pathDoc, Example: `"p7m2x9q4w8e3r6t5y1u0"`},
	{Path: "deliverables.printable.offer", Kind: String, Checked: "printable.config", Doc: offerDoc, Example: `"planner"`},
	{Path: "deliverables.printable.language", Kind: String, Default: "the page's language", Doc: "The printable's language, when it differs from the page's.", Example: `"de"`},
	{Path: "deliverables.printable.version", Kind: String, Doc: "The version printed in the guide, so buyers see they have the latest.", Example: `"2027.1"`},

	{Path: "deliverables.spreadsheet", Kind: Object, Doc: "A spreadsheet template in deliverables/spreadsheet (budget, bookkeeping, tracker), built with `lfm skills spreadsheet`."},
	{Path: "deliverables.spreadsheet.sell", Kind: String, Values: []string{"page", "shops", "bundle"}, Default: "page", Doc: sellDoc, Example: `"shops"`},
	{Path: "deliverables.spreadsheet.path", Kind: String, Checked: "spreadsheet.config", Doc: pathDoc, Example: `"s7m2x9q4w8e3r6t5y1u0"`},
	{Path: "deliverables.spreadsheet.offer", Kind: String, Checked: "spreadsheet.config", Doc: offerDoc, Example: `"budget"`},
	{Path: "deliverables.spreadsheet.language", Kind: String, Default: "the page's language", Doc: "The language of the start guide and download page, when it differs from the page's.", Example: `"de"`},
	{Path: "deliverables.spreadsheet.version", Kind: String, Doc: "The version printed in the start guide.", Example: `"2027.1"`},
	{Path: "deliverables.spreadsheet.sheets", Kind: Map, Checked: "spreadsheet.sheets", Doc: "The Google Sheets master of every edition (and of its example as <key>-example): upload the .xlsx to Google Drive, open it with Google Sheets, share it as anyone with the link can view, paste its address here. Buyers get a copy link to it.", Example: `{"en": "https://docs.google.com/spreadsheets/d/…/edit"}`},
	{Path: "deliverables.spreadsheet.sheets.*", Kind: String, Doc: "The address of one Google Sheets master.", Example: `"https://docs.google.com/spreadsheets/d/1AbC…/edit"`},
	{Path: "deliverables.document", Kind: Object, Doc: "A set of editable documents in deliverables/document (letters, invoices, minutes, programs, binders), built with `lfm skills document`."},
	{Path: "deliverables.document.sell", Kind: String, Values: []string{"page", "shops", "bundle"}, Default: "page", Doc: sellDoc, Example: `"shops"`},
	{Path: "deliverables.document.path", Kind: String, Checked: "document.config", Doc: pathDoc, Example: `"k3n8q2w7x5r9t4m6p1"`},
	{Path: "deliverables.document.offer", Kind: String, Checked: "document.config", Doc: offerDoc, Example: `"kit"`},
	{Path: "deliverables.document.language", Kind: String, Default: "the page's language", Doc: "The language of the download page and the shop facts, when it differs from the page's.", Example: `"de"`},
	{Path: "deliverables.document.version", Kind: String, Doc: "The version printed in the start guide.", Example: `"2027.1"`},
	{Path: "deliverables.document.papers", Kind: List, Values: []string{"a4", "letter"}, Default: "US Letter and A4 for American English, A4 for every other language", Doc: "The paper sizes every language is built in; each size is its own edition and ZIP.", Example: `["a4", "letter"]`},
	{Path: "deliverables.document.docs", Kind: Map, Checked: "document.config", Doc: "Optional Google Docs masters by \"<language>/<document>\": upload the .docx to Google Drive, open it with Google Docs, share it as anyone with the link can view, paste its address. The start guide and download page then carry a copy link.", Example: `{"en/invoice": "https://docs.google.com/document/d/…/edit"}`},
	{Path: "deliverables.document.docs.*", Kind: String, Doc: "The address of one Google Docs master.", Example: `"https://docs.google.com/document/d/1AbC…/edit"`},
	{Path: "deliverables.deck", Kind: Object, Doc: "Slide decks in deliverables/deck (training briefings, workshops, quiz games) with speaker notes, built with `lfm skills deck`."},
	{Path: "deliverables.deck.sell", Kind: String, Values: []string{"page", "shops", "bundle"}, Default: "page", Doc: sellDoc, Example: `"shops"`},
	{Path: "deliverables.deck.path", Kind: String, Checked: "deck.config", Doc: pathDoc, Example: `"k3n8q2w7x5r9t4m6p1"`},
	{Path: "deliverables.deck.offer", Kind: String, Checked: "deck.config", Doc: offerDoc, Example: `"briefing"`},
	{Path: "deliverables.deck.language", Kind: String, Default: "the page's language", Doc: "The language of the download page and the shop facts, when it differs from the page's.", Example: `"de"`},
	{Path: "deliverables.deck.version", Kind: String, Doc: "The version printed in the start guide.", Example: `"2027.1"`},
	{Path: "deliverables.deck.papers", Kind: List, Values: []string{"a4", "letter"}, Default: "US Letter and A4 for American English, A4 for every other language", Doc: "The paper sizes the speaker notes and quiz sheets print on; every language ships one ZIP with each.", Example: `["a4"]`},
	{Path: "deliverables.deck.slides", Kind: Map, Checked: "deck.config", Doc: "Optional Google Slides masters by \"<language>/<deck>\": upload the .pptx to Google Drive, open it with Google Slides, share it as anyone with the link can view, paste its address. The start guide and download page then carry a copy link.", Example: `{"en/briefing": "https://docs.google.com/presentation/d/…/edit"}`},
	{Path: "deliverables.deck.slides.*", Kind: String, Doc: "The address of one Google Slides master.", Example: `"https://docs.google.com/presentation/d/1AbC…/edit"`},
	{Path: "deliverables.bundle", Kind: Object, Doc: "Two or more deliverables sold together, such as a deck with its handout documents or a book with its printable: its own name, listing in deliverables/bundle/listing.md, and download page or shop listing with every file of each."},
	{Path: "deliverables.bundle.units", Kind: List, Values: []string{"book", "printable", "spreadsheet", "document", "deck"}, Default: "every deliverable of the project", Checked: "bundle.config", Doc: "The deliverables the bundle holds, in the order its download page and listing show them. A deliverable whose sell is bundle sells only here.", Example: `["deck", "document"]`},
	{Path: "deliverables.bundle.name", Kind: String, Required: true, Doc: "The bundle's name as buyers see it.", Example: `"Starter Kit: book and workbook"`},
	{Path: "deliverables.bundle.sell", Kind: String, Values: []string{"page", "shops"}, Default: "page", Doc: "How buyers get the bundle: page = your checkout redirects to an unlisted download page with every file; shops = the shops deliver.", Example: `"page"`},
	{Path: "deliverables.bundle.path", Kind: String, Checked: "bundle.config", Doc: pathDoc, Example: `"b7m2x9q4w8e3r6t5y1u0"`},
	{Path: "deliverables.bundle.offer", Kind: String, Checked: "bundle.config", Doc: offerDoc, Example: `"kit"`},
	{Path: "deliverables.bundle.language", Kind: String, Default: "the page's language", Doc: "The bundle's language, when it differs from the page's.", Example: `"de"`},
}

Spec lists every field of lfm.json, parents before children.

Functions

func BrowserData

func BrowserData(values map[string]any, paths []string) ([]byte, error)

BrowserData selects dot-separated object paths from values and returns them as JSON with their structure intact. encoding/json escapes <, > and &, so the result is safe inside a <script> element.

func DecodeJSON

func DecodeJSON(raw []byte, target any) error

DecodeJSON decodes exactly one JSON value, keeping numbers exact.

func Explain added in v0.1.0

func Explain(path string) (string, error)

Explain renders lfm.json's reference for the terminal: every top-level field for "", the fields of an object or map, or one field in full. Paths may name map entries concretely (urls.checkout) or with "*".

func Markdown added in v0.1.0

func Markdown() string

Markdown renders the whole reference for docs/config.md.

func ValueOffset added in v0.1.0

func ValueOffset(raw []byte, keyOffset int) int

ValueOffset returns where the value of the key at keyOffset starts in raw: past the quoted key, the colon and spaces.

Types

type Assets

type Assets struct {
	Default   string            `json:"default"`
	Overrides map[string]string `json:"overrides"`
}

Assets controls packing. Default "auto" lets the compiler decide per resource; "inline" and "file" force a global policy. Overrides pin single source paths and always win.

func (Assets) Mode

func (a Assets) Mode(rel string) string

Mode returns the packing mode configured for a project-relative source path.

type BookConfig added in v0.0.3

type BookConfig struct {
	Kind     string   `json:"kind"`
	Author   string   `json:"author"`
	Language string   `json:"language"`
	Path     string   `json:"path"`
	Offer    string   `json:"offer"`
	Formats  []string `json:"formats"`
	Paper    string   `json:"paper"` // white or cream, for print editions
	ISBN     BookISBN `json:"isbn"`
	Sell     string   `json:"sell"` // page (default), shops or bundle
}

BookConfig is deliverables.book: the facts of the book that are not creative decisions, and the unlisted folder its files are served from.

type BookISBN added in v0.0.3

type BookISBN struct {
	Ebook     string `json:"ebook"`
	Paperback string `json:"paperback"`
}

BookISBN holds an ISBN per edition; each is optional.

type Budgets added in v0.1.4

type Budgets struct {
	ImageKiB       int `json:"imageKiB"`
	VideoKiB       int `json:"videoKiB"`
	FirstScreenKiB int `json:"firstScreenKiB"`
	CSSKiB         int `json:"cssKiB"`
	JSKiB          int `json:"jsKiB"`
	Elements       int `json:"elements"`
	Depth          int `json:"depth"`
}

Budgets are a page's advisory sizes, which perf.budgets warns past; a field left out keeps lfm's default.

type Build

type Build struct {
	Assets      Assets     `json:"assets"`
	BrowserData []string   `json:"browserData"`
	Validation  Validation `json:"validation"`
}

type BundleConfig added in v0.1.0

type BundleConfig struct {
	Name     string   `json:"name"`
	Units    []string `json:"units"` // the deliverables it holds; every one when empty
	Path     string   `json:"path"`
	Offer    string   `json:"offer"`
	Sell     string   `json:"sell"` // page (default) or shops
	Language string   `json:"language"`
}

BundleConfig is deliverables.bundle: two or more deliverables sold together, with its own name, listing and download path.

type Config

type Config struct {
	SchemaVersion int               `json:"schemaVersion"`
	URL           string            `json:"url"`
	Language      string            `json:"language"`
	Title         string            `json:"title"`
	Description   string            `json:"description"`
	SocialImage   SocialImage       `json:"socialImage"`
	Social        Social            `json:"social"`
	Seller        Seller            `json:"seller"`
	Links         map[string]any    `json:"links"`
	URLs          map[string]string `json:"urls"`
	JSONLD        any               `json:"jsonld,omitempty"`
	Build         Build             `json:"build"`
	Deliverables  Deliverables      `json:"deliverables"`
	Data          map[string]any    `json:"data"`
}

Config is lfm.json. Reserved fields use exact casing; product values live under data, which data/*.json files extend.

type DeckConfig added in v0.1.0

type DeckConfig struct {
	Path     string            `json:"path"`
	Offer    string            `json:"offer"`
	Language string            `json:"language"`
	Sell     string            `json:"sell"`
	Version  string            `json:"version"`
	Papers   []string          `json:"papers"`
	Slides   map[string]string `json:"slides"` // "language/deck" -> Google Slides address
}

DeckConfig is deliverables.deck: how the decks sell, the papers their notes print on and the Google Slides masters behind their copy links.

type Deliverables added in v0.0.3

type Deliverables struct {
	Book        *BookConfig        `json:"book"`
	Printable   *PrintableConfig   `json:"printable"`
	Bundle      *BundleConfig      `json:"bundle"`
	Spreadsheet *SpreadsheetConfig `json:"spreadsheet"`
	Document    *DocumentConfig    `json:"document"`
	Deck        *DeckConfig        `json:"deck"`
}

Deliverables configures what buyers receive besides the page: a book in deliverables/book and a printable in deliverables/printable each need their entry, and a bundle sells both together.

type DocumentConfig added in v0.1.0

type DocumentConfig struct {
	Path     string            `json:"path"`
	Offer    string            `json:"offer"`
	Language string            `json:"language"`
	Sell     string            `json:"sell"`
	Version  string            `json:"version"`
	Papers   []string          `json:"papers"`
	Docs     map[string]string `json:"docs"` // "language/document" -> Google Docs address
}

DocumentConfig is deliverables.document: how the editable document set sells, its paper sizes and the Google Docs masters behind its copy links.

type Field added in v0.1.0

type Field struct {
	Path     string   // dotted JSON path; "*" stands for a key of a map
	Kind     Kind     // for a list, the kind of its items is String
	Values   []string // the allowed values of a string or of a list's items
	Default  string   // what lfm uses when the field is absent, as prose
	Required bool     // must be present whenever its parent object is
	Doc      string   // one line: what it is for
	Example  string   // a JSON value to copy
	Checked  string   // the rule that checks it beyond its shape, if any
	Reserved bool     // a documented subtree inside free data, checked by its rule
}

Field is one key of lfm.json: its shape, its meaning and how it is checked. Spec is the single source of the file's format: loading checks against it, config errors quote it, `lfm help config` prints it and docs/config.md is generated from it.

func Children added in v0.1.0

func Children(path string) []Field

Children returns the fields directly under path, in Spec order.

func Lookup added in v0.1.0

func Lookup(path string) (Field, bool)

Lookup returns the field at a concrete path, matching "*" against map keys.

func (Field) Hint added in v0.1.0

func (f Field) Hint() string

Hint explains a field in the words of a config finding: what it is for, what it takes, and where to read the rest.

func (Field) Name added in v0.1.0

func (f Field) Name() string

Name is the last segment of the field's path.

func (Field) Shape added in v0.1.0

func (f Field) Shape() string

Shape describes the field's type and values in a few words.

type Kind added in v0.1.0

type Kind string

Kind is the JSON shape a field holds.

const (
	Object Kind = "object"
	String Kind = "string"
	Int    Kind = "integer"
	List   Kind = "list"
	Map    Kind = "map"
	Free   Kind = "any"
)

Field kinds. A map holds keys of the author's choosing whose values the field's "*" child describes; free holds anything, unchecked.

type Loaded

type Loaded struct {
	Config   Config
	Values   map[string]any
	Sources  map[string][]byte
	Problems []Problem
}

Loaded is the result of reading lfm.json and data/. Values mirrors Config as generic JSON so template paths equal JSON field names. Sources holds the raw bytes of every file read, for locating diagnostics.

func Load

func Load(p Project, rules RuleCheck) Loaded

Load reads and validates the configuration. It never stops at the first problem: every defect is collected so one compile reports all of them.

type PrintableConfig added in v0.1.0

type PrintableConfig struct {
	Path     string `json:"path"`
	Offer    string `json:"offer"`
	Language string `json:"language"`
	Version  string `json:"version"` // printed in the guide, e.g. 2027.1
	Sell     string `json:"sell"`    // page (default), shops or bundle
}

PrintableConfig is deliverables.printable: the unlisted folder its files are served from and the facts printed on its guide page.

type Problem

type Problem struct {
	File, Path string
	Err        error
	Offset     int
	Hint       string // what the field is for and what it takes, from Spec
	AtValue    bool   // the value is wrong, not the key: locate the value
}

Problem is a config or data defect located by file and JSON path.

type Project

type Project struct {
	Root string // absolute, symlinks resolved
	// contains filtered or unexported fields
}

Project is a resolved project root. The zero value is not usable.

func Open

func Open(dir string) (Project, error)

Open resolves dir to a real directory.

func (Project) Expect added in v0.0.2

func (p Project) Expect(dir string) error

Expect reports ErrNoProject, with what to do, when the root holds neither lfm.json nor index.html.tmpl. A project missing only one of them is still a project: the compile reports the missing file as a finding.

func (Project) OptionalDir

func (p Project) OptionalDir(name string) (string, error)

OptionalDir resolves a contained directory that may be absent; absent yields "".

func (Project) Output

func (p Project) Output() string

Output is the directory a successful compile replaces.

func (Project) Path

func (p Project) Path(name string) (string, error)

Path resolves name (relative to the root, or absolute) to a real source file path. Sources must stay inside the root and outside output/ (and the output.next-* folders of a publish in progress), also after following symlinks, so generated files can never feed back into a build.

func (Project) Read

func (p Project) Read(name string) ([]byte, error)

Read reads a contained source file.

func (Project) Rel

func (p Project) Rel(path string) string

Rel returns a slash-separated path relative to the root.

type RuleCheck

type RuleCheck func(id string, level diagnostic.Severity) error

RuleCheck validates one build.validation.rules entry.

type Seller added in v0.1.0

type Seller struct {
	Name    string `json:"name"`
	Imprint string `json:"imprint"` // the legal notice lines: address, register, VAT ID
}

Seller is who sells: printed on the book's copyright page and the printable's guide and licence.

type Social added in v0.1.7

type Social struct {
	X string `json:"x"`
}

Social holds optional social account attribution.

type SocialImage

type SocialImage struct {
	Src string `json:"src"`
	Alt string `json:"alt"`
}

type SpreadsheetConfig added in v0.1.0

type SpreadsheetConfig struct {
	Path     string            `json:"path"`
	Offer    string            `json:"offer"`
	Language string            `json:"language"`
	Sell     string            `json:"sell"`
	Version  string            `json:"version"`
	Sheets   map[string]string `json:"sheets"` // edition key, or key-example -> Google Sheets address
}

SpreadsheetConfig is deliverables.spreadsheet: how the spreadsheet sells and the Google Sheets masters buyers copy.

type Validation

type Validation struct {
	Rules   map[string]diagnostic.Severity `json:"rules"`
	Budgets Budgets                        `json:"budgets"`
}

Jump to

Keyboard shortcuts

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