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
- Variables
- func BrowserData(values map[string]any, paths []string) ([]byte, error)
- func DecodeJSON(raw []byte, target any) error
- func Explain(path string) (string, error)
- func Markdown() string
- func ValueOffset(raw []byte, keyOffset int) int
- type Assets
- type BookConfig
- type BookISBN
- type Budgets
- type Build
- type BundleConfig
- type Config
- type DeckConfig
- type Deliverables
- type DocumentConfig
- type Field
- type Kind
- type Loaded
- type PrintableConfig
- type Problem
- type Project
- type RuleCheck
- type Seller
- type Social
- type SocialImage
- type SpreadsheetConfig
- type Validation
Constants ¶
const ( Auto = "auto" Inline = "inline" File = "file" )
Packing modes.
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 ¶
var ErrNoProject = errors.New("not an lfm project")
ErrNoProject means a directory holds neither lfm.json nor the template.
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".
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 ¶
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 ¶
DecodeJSON decodes exactly one JSON value, keeping numbers exact.
func Explain ¶ added in v0.1.0
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
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.
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 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 Lookup ¶ added in v0.1.0
Lookup returns the field at a concrete path, matching "*" against map keys.
func (Field) Hint ¶ added in v0.1.0
Hint explains a field in the words of a config finding: what it is for, what it takes, and where to read the rest.
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.
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 (Project) Expect ¶ added in v0.0.2
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 ¶
OptionalDir resolves a contained directory that may be absent; absent yields "".
func (Project) Path ¶
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.
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 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"`
}