content
Content collections for a tcm codebase, as a library: a namespace of pages read as typed entries, each one's
frontmatter checked against a schema. tcm ships it, so tcm lib add tcm content adds the release your tcm has, with
no network (and tcm lib upgrade content the one a newer tcm has). It's a tcm library, not an npm package: it holds
everything its code uses but the yaml, marked and shiki packages.
import * as files from "#codebase/blog/posts";
import { collection, markdown } from "#codebase/app/lib/content";
import { z } from "zod";
export const posts = collection(files, {
schema: z.object({ title: z.string(), date: z.iso.date() }),
sort: (a, b) => b.data.date.localeCompare(a.data.date),
});
export const page = (name: string) => {
const post = posts.get(name);
return post && `<h1>${post.data.title}</h1>${markdown(post.body)}`;
};
What it has
- Collections:
collection(files, { schema, format?, sort? })reads a namespace of files (imported whole) as entries, each with itsname, itsdataas the schema makes it, and itsbody.all(),get(name)andcheck(name, text)read them; an entry that doesn't fit is named when it's read. - Any Standard Schema: Zod, Valibot, ArkType, or anything with a
~standardproperty. - Frontmatter:
frontmatter(text), a Markdown file's YAML at its top, and the text under it. JSON and YAML files are read whole (format). - Markdown:
markdown(text, { link?, highlight? }), as HTML;{@link name}shows the name, linked wherelinksays, and a fenced code block is ashighlightmakes it.await shiki({ langs: ["ts", "sh"] })makes one with Shiki. - Feeds:
rss({ title, link, description, items }), an RSS 2.0 feed with its links made absolute.
Checked when saved
A collection says it is one (by Symbol.for("tcm.collection")), so tcm asks it about each file saved into its
namespace, and refuses one that doesn't fit, saying why (content collections).
Its versions follow semver from its API, as any package's do (releases).
- test/
- 9 definitions
Types
- Collection interface
- A namespace of files, read as entries: see collection.
- ContentOf type
- What a collection's entries hold as `Content`, by what its files are: the pages' component for MDX pages, undefined for other files (or either, in a namespace of both).
- Entry interface
- An entry of a Collection: a file of its namespace, read.
- FeedItem interface
- An item of an rss feed.
- Highlight type
- Highlights a fenced code block: its code, in its language (the info string's first word), as HTML; `undefined` shows it as written.
- Output type
- The data a schema makes: what a collection's entries hold.
- Page type
- An MDX page (`.mdx`), as a namespace of files holds it: its component, with its text as saved.
- StandardPost interface
- A post of a standardSite: what its `site.standard.document` record says.
- StandardRecord interface
- An AT Protocol record of a standardSite: where it goes in its account's repository, and what it says.
- StandardResult type
- What a StandardSchema says of a value: the value it makes of it, or what's wrong with it.
- StandardSchema interface
- A schema in the [Standard Schema](https://standardschema.dev) form, which Zod, Valibot, ArkType and others implement: what a collection checks each entry's data with. Only its `~standard` property is read.
- StandardSite interface
- A site's posts as a [standard.site](https://standard.site) publication: what `tcm publish` writes to its account's repository, and what the site's pages say so readers can tell they're its.
Functions
- collection <S extends StandardSchema, F extends string | Page = string>(files: Readonly<Record<string, F>>, op…
- A namespace of files as a collection of typed entries: each file's data (a Markdown file's frontmatter, or a JSON or YAML file's content, as `format` says) checked against `schema`, any [Standard Schema](https://standardschema.dev) (Zod, Valibot, ArkType). Entries are read when asked for, and in `sort`'s order (by name otherwise).
- frontmatter (text: string) => { data: unknown; body: string; }
- A Markdown file's frontmatter, as YAML between `---` lines at its top, and the text under it. A file without frontmatter has no data (`{}`).
- markdown (text: string, options?: { link?: ((name: string) => string | undefined) | undefined; highlight?: H…
- Markdown as HTML (GitHub's flavour). A definition named as doc comments name one (`@link`, in braces) is shown as its name, in code, linked where `link` says (nowhere, by default). A fenced code block in a language is as `highlight` makes it (`shiki` makes one), if it does.
- rss (feed: { title: string; link: string; description: string; self?: string | undefined; language?: st…
- An RSS 2.0 feed: its items in the order given (newest first, as readers expect).
- shiki (options: { langs: string[]; themes?: { light: string; dark: string; } | undefined; defaultColor?: …
- A Highlight made with Shiki: code in one of `langs` highlighted in a light and a dark theme (`github-light` and `github-dark`, by default). The light theme's colours are written in (`defaultColor`: `"dark"` for the dark one's), and both are CSS variables, `--shiki-light` and `--shiki-dark`; with `defaultColor: false`, only those.
- standardSite (site: { did: string; url: string; name: string; description?: string | undefined; posts: StandardP…
- A blog (any site of posts) as a [standard.site](https://standard.site) publication: a `site.standard.publication` record for it, and a `site.standard.document` for each post, its Markdown in it as [`at.markpub.markdown`](https://markpub.at) and as plain text. Their keys are TIDs, as these records' lexicons ask, made from what doesn't change (the publication's from its address, a post's from its day and its name), so writing them again (`tcm publish`) updates them, and a site's pages can name them before they're written.
Values
- manifest { name: string; npm: boolean; }
- Content collections for a tcm codebase, as a library: a namespace of files (`import * as posts from "#codebase/blog/posts"`) read as typed entries, each one's data checked against a schema. tcm checks a file against the collections of its namespace when it's saved, and refuses one that doesn't fit. No `tcm` host is needed: it runs anywhere.
Files
- README file