8.1 Site Configuration Language
| #lang camp/site | package: camp-lib |
A Camp site is a single website, organized as a Racket package.
A site has one or more collections, which are named groups of pages with a sort order, a mapping between source and output paths, and optional taxonomies for further organization.
A page is a single source document.
A feed is an RSS or Atom feed which includes all pages from a set of one or more collections. A site may specify zero feeds, one feed, or multiple feeds.
The #lang camp/site language provides a TOML-based configuration format for defining Camp sites. Files written in this language are parsed and validated against the site schema.
#lang camp/site # Required values ------ title = "Site Title" url = "https://example.com" founded = 1912-07-04 # Note no quotes authors = ["Me (me@example.com)"] # List of strings, must be in this format # Optional values ------ sources = ".mypage" # .md.rkt and .page.rkt are always recognized static-folder = "res" # default is "static" output-folder = "public" # default is "publish" deploy-script = "deploy.sh" default-render = "(camp-demo/render render-page)" # → string datum: list of module and a function identifier # function signature: Document, Context -> Xexpr # Collections ---------- [[collections]] name = "blog" source = "blog/*" output-paths = "blog/[yyyy]/[MM]/*/" render-with = "(camp-demo/render render-post)" # same as default-render order = "descending" sort-key = "date" taxonomies = ["tags", "series"] [[collections]] name = "pages" source = "pages/*" output-paths = "*/" render-with = "(camp-demo/render render-page)" sort-key = "title" order = "ascending" [[feeds]] filename = "feed.atom" # Extension .atom or .rss sets format collections = ["blog"] # List of collection names render-with = "(camp-demo/feeds feed-content)" # same as default-render
8.1.1 Required Fields
Field | Type | Description |
title | Site title | |
url | Base URL (must be valid) | |
founded | Founding date for tag URI generation | |
authors | Authors in "Name (email)" format |
procedure
(author-string? v) → boolean?
v : any/c
> (author-string? "Me (me@example.com)") #t
> (author-string? "Me (me@1.com)") #f
> (author-string? " (me@example.com)") #f
8.1.2 Optional Fields
Field | Type | Default | Description |
sources | ".md.rkt" | Source file extension | |
static-folder | "static" | Static assets directory | |
output-folder | "publish" | Build output directory | |
deploy-script | #f | Deployment script path | |
default-render | #f | Default render function |
8.1.3 Collections
Each [[collections]] entry defines a group of source documents:
Field | Type | Default | Description |
name | Collection identifier | ||
source | Location of sources | ||
output-paths | Defines output paths/URLs | ||
render-with | Render function specification | ||
taxonomies | (Optional) metadata keys | ||
sort-key | "date" | Metadata sort key | |
order | (or/c "ascending" "descending") | "descending" | Sort order |
procedure
(render-spec? v) → (or/c #f (listof module-path? symbol?))
v : any/c
In order to be valid, at site build time the identifier must be that of a function provided by the module, and the function must have the signature (-> document? context? xexpr?). This information is not checked by render-spec?, however.
> (render-spec? "(my-module render-func)") '(my-module render-func)
> (render-spec? "(\"mod.rkt\" func)") '("mod.rkt" func)
> (render-spec? "(100)") #f
8.1.4 Feeds
Each [[feeds]] entry defines an RSS or Atom feed:
Field | Type | Description |
filename | Output filename (.atom or .rss) | |
collections | Collection names to include | |
render-with | Feed content render function |
Each feed’s render-with value should identify a function with the same signature as page render functions:
(define (feed-content doc ctxt) ;; doc: the Punct document ;; ctxt: same context as page render functions (slug, url, collection, etc.) ;; Returns x-expression for the feed entry body `(article ,@(document-body doc) (p (a ((href ,(context-url ctxt))) "Read more..."))))
The ctxt argument is a context whch provides access to the page’s canonical URL, enabling feed content to include links back to the original page on your site.
procedure
(feed-filename? v) → boolean?
v : any/c
> (feed-filename? "posts.atom") #t
> (feed-filename? "blog.rss") #t
> (feed-filename? "comments") #f
8.1.5 Source/Output Path Mapping
Camp uses path patterns to map source files to output locations.
A source path pattern specifies where to find source documents within a collection (e.g., "blog/*"). An output path pattern specifies the URL structure for rendered pages, with support for slug substitution and date-based paths (e.g., "blog/[yyyy]/[MM]/*/").
An output path pattern specifies the folder/file structure (and thus the URL) for rendered pages, with support for slug substitution, date-based paths, and meta value interpolation. In output path patterns:
Any folder name consisting only of * will be replaced by the source’s slug.
Any name inside a pair of brackets [] will first be looked up as a key in the source’s metadata. If a matching meta key is found, the bracket is replaced by that value. Otherwise, the name is interpreted as a CLDR date format code and formatted using the source’s date meta.
If the pattern ends in a trailing slash /, the output file will be named "index.html". Otherwise the output is the name of the pattern’s final element with an added ".html" extension.
A pattern must contain at least one * or [] element.
procedure
(source-path-pattern? v) → boolean?
v : any/c
> (source-path-pattern? "writing/*") #t
> (source-path-pattern? "/writing/*") #f
> (source-path-pattern? "writing/") #f
> (source-path-pattern? "../writing/*") #f
procedure
(output-path-pattern? v) → boolean?
v : any/c
> (output-path-pattern? "posts/*/") #t
> (output-path-pattern? "posts/[YYYY]/*/") #t
> (output-path-pattern? "../posts/*/") #f
> (output-path-pattern? "posts/") #f
procedure
(format-output-path pattern slug date metas) → path?
pattern : output-path-pattern? slug : string? date : (or/c date-provider? #f) metas : (or/c hash? #f)
> (format-output-path "posts/*/" "hello-world" #f #f) #<path:posts/hello-world/index.html>
> (format-output-path "blog/[yyyy]/[MM]/*/" "my-post" (date 2025 1 15) #f) #<path:blog/2025/01/my-post/index.html>
> (format-output-path "newsletter/[issue]/*/" "my-post" #f (hasheq 'issue 42)) #<path:newsletter/42/my-post/index.html>
procedure
(file-extension? v) → boolean?
v : any/c
procedure
v : any/c
> (non-rkt-file-extension? ".myformat.rkt") #t
> (non-rkt-file-extension? ".rkt") #f
8.1.6 Site Configuration API
The following data types from camp underlie the site configuration language. They are represented as hash-views: hash tables with struct-like accessor functions. For more information on hash-views, see hash-view: Struct-like Views of Hashes.
hash-view
(hash-view site ( title url founded authors [sources #:default ....] [static-folder #:default ....] [output-folder #:default ....] collections [racket-collection #:default ....] [deploy-script #:default ....] [default-render #:default ....] [feeds #:default ....]))
title : string?
url : valid-url-string?
founded : date-provider?
authors : (listof string?)
sources : string? = ".md.rkt"
static-folder : string? = "static"
output-folder : string? = "publish"
collections : (listof collection?)
racket-collection : (or/c string? #f)
deploy-script : (or/c string? #f)
default-render : (or/c list? #f)
feeds : (listof feed-config?) = '()
Required fields are title, url, founded, authors, and collections.
The racket-collection field is set automatically by load-site from the package’s "info.rkt". It contains the Racket collection name (e.g., "myblog") and is #f if the site is not installed as a package.
hash-view
(hash-view collection ( name source output-paths render-with [order #:default ....] [sort-key #:default ....] taxonomies))
name : string?
source : source-path-pattern?
output-paths : output-path-pattern?
render-with : (or/c list? #f)
order : string? = "descending"
sort-key : string? = "date"
taxonomies : (listof string?)
Required fields are name, source, and output-paths.
hash-view
(hash-view feed-config ( filename collections render-with))
filename : string?
collections : (listof string?)
render-with : list?
procedure
mod-path :
(or/c path-string? module-path? (and/c hash? (λ (h) (hash-has-key? h 'path))))
A filesystem path to a "site.rkt" file
A module path like 'my-site/site
A hash containing a 'path key (such as a book configuration returned by load-book)—
the site is discovered from the package’s "info.rkt"
When searching by collection name, finds packages with a 'camp-site field in their "info.rkt" whose 'collection name matches.
(resolve-site-spec "site.rkt") ; path if file exists (resolve-site-spec "myblog") ; finds myblog package (resolve-site-spec 'myblog) ; same, with symbol
procedure
(file-path->site-path file-path) → path?
file-path : path-string?
Raises an error if the file is not in a package, no "info.rkt" exists, or the 'camp-site field is not defined.
procedure
file-path : path-string?
To load the associated site for a book:
(define mybook (load-book "path/to/my.book.rkt")) (define mysite (load-site book)) ; discovers site from package info.rkt