Match bDS2 canonical file serialization
This commit is contained in:
@@ -364,7 +364,10 @@ invariant MediaSidecarFormat {
|
||||
-- Sidecar files use YAML-like key-value format (hand-built, not gray-matter)
|
||||
-- Path: {binary_path}.meta
|
||||
-- Only truthy fields are written (except required fields)
|
||||
-- Fields: title, alt, caption, author, tags, language, linkedPostIds
|
||||
-- linkedPostIds is always written (including []), immediately before tags.
|
||||
-- Always-quoted values and inline-list strings escape backslash, quote, and
|
||||
-- newline; the reader reverses those escapes.
|
||||
-- Fields include: title, alt, caption, author, language, linkedPostIds, tags.
|
||||
-- Note: 'filename' is NOT written to sidecar (it is the binary filename itself)
|
||||
}
|
||||
|
||||
|
||||
@@ -81,6 +81,10 @@ invariant MenuPersistedAsOpml {
|
||||
-- OPML outline attributes: text (label), type (kind),
|
||||
-- pageSlug (slug for page/home), categoryName (slug for category_archive).
|
||||
-- Nested <outline> elements represent submenu children.
|
||||
-- The head title is the project name. dateCreated and dateModified both use
|
||||
-- the project's updated timestamp, falling back to created timestamp.
|
||||
-- Empty outlines have one space before '/>' and the document ends in one
|
||||
-- newline, matching bDS2's canonical serializer.
|
||||
parse_opml(read_file("meta/menu.opml")) = menu.items
|
||||
}
|
||||
|
||||
|
||||
@@ -70,6 +70,17 @@ invariant MetadataPersistedAsFiles {
|
||||
-- meta/category-meta.json — per-category render settings
|
||||
-- meta/publishing.json — SSH connection details (non-secret)
|
||||
-- All writes are atomic (temp file + rename)
|
||||
-- JSON is pretty-printed without a trailing newline and uses bDS2/Jason
|
||||
-- byte-order key ordering. Project keys are blogLanguages,
|
||||
-- blogmarkCategory, defaultAuthor, description, imageImportConcurrency,
|
||||
-- mainLanguage, maxPostsPerPage, name, picoTheme, publicUrl,
|
||||
-- semanticSimilarityEnabled (nil keys absent). Publishing keys are sshHost,
|
||||
-- sshMode, sshRemotePath, sshUser (nil keys absent; sshMode defaults to scp).
|
||||
-- Category names and per-category keys are byte-order sorted; per-category
|
||||
-- keys are listTemplateSlug, postTemplateSlug, renderInLists, showTitle,
|
||||
-- title. categories.json uses case-sensitive byte-order sorting. tags.json
|
||||
-- remains case-insensitively name-sorted; entry keys are color, name,
|
||||
-- postTemplateSlug and blank optional values are absent.
|
||||
}
|
||||
|
||||
config {
|
||||
|
||||
@@ -297,6 +297,20 @@ invariant FrontmatterRoundtrip {
|
||||
parse_frontmatter(read_file(post.file_path)) = frontmatter_fields(post)
|
||||
}
|
||||
|
||||
invariant CanonicalFrontmatterSerialization {
|
||||
-- Post field order is id, title, slug, excerpt, status, author, language,
|
||||
-- doNotTranslate, templateSlug, createdAt, updatedAt, publishedAt, tags,
|
||||
-- categories; nil/empty optional fields and false doNotTranslate are absent.
|
||||
-- Translation field order is id, translationFor, language, title, excerpt,
|
||||
-- status, createdAt, updatedAt, publishedAt.
|
||||
-- Strings containing only Unicode letters/numbers, space, dot, underscore,
|
||||
-- slash, or hyphen are bare. Other strings are double quoted with backslash,
|
||||
-- quote, and newline escaping. Timestamp values are single-quoted ISO values.
|
||||
-- Empty lists use a bare key line. Written bodies have all trailing newlines
|
||||
-- removed and the complete file ends in exactly one newline; reads remove
|
||||
-- that terminal body newline before comparing or storing content.
|
||||
}
|
||||
|
||||
invariant DateBasedFileLayout {
|
||||
for post in Posts where file_path != "":
|
||||
post.file_path = format("posts/{yyyy}/{mm}/{slug}.md",
|
||||
|
||||
@@ -199,7 +199,10 @@ invariant ScriptFileLayout {
|
||||
for s in Scripts where file_path != "":
|
||||
s.file_path = format("scripts/{slug}.lua", slug: s.slug)
|
||||
}
|
||||
-- Script files use standard --- YAML frontmatter
|
||||
-- Script files use standard --- YAML frontmatter in field order id, projectId,
|
||||
-- slug, title, kind, entrypoint, enabled, version, createdAt, updatedAt. Scalars
|
||||
-- use the canonical post quoting rules, timestamps are single-quoted ISO values,
|
||||
-- and the complete file ends in one newline.
|
||||
|
||||
rule CreateScript {
|
||||
when: CreateScriptRequested(project, title, kind, content, entrypoint)
|
||||
|
||||
@@ -56,6 +56,9 @@ invariant UniqueTemplateSlug {
|
||||
invariant TemplateFrontmatter {
|
||||
-- .liquid files use standard --- YAML frontmatter
|
||||
-- Fields: id, slug, title, kind, enabled, version, createdAt, updatedAt
|
||||
-- Field order also includes projectId after id when present. Scalars use
|
||||
-- the canonical post frontmatter quoting rules, timestamps are single-quoted
|
||||
-- ISO values, and the complete file ends in one newline.
|
||||
for t in Templates where status = published:
|
||||
parse_frontmatter(read_file(t.file_path)).slug = t.slug
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user