@zeropress/build-core 0.6.12 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +136 -42
- package/package.json +7 -7
- package/src/api/build-site.js +891 -305
- package/src/index.d.ts +43 -11
- package/src/render/control-flow-renderer.js +5 -2
- package/src/render/variable-resolver.js +6 -1
- package/src/render/zeropress-engine.js +3 -1
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|

|
|
5
5
|

|
|
6
6
|
|
|
7
|
-
Shared deterministic rendering core for
|
|
7
|
+
Shared deterministic rendering core for Preview Data v0.7 and Theme Runtime v0.7.
|
|
8
8
|
|
|
9
9
|
This package is the canonical rendering core for preview-data and theme packages consumed directly by:
|
|
10
10
|
|
|
@@ -13,10 +13,10 @@ This package is the canonical rendering core for preview-data and theme packages
|
|
|
13
13
|
|
|
14
14
|
Public contract references:
|
|
15
15
|
|
|
16
|
-
- [Preview Data v0.
|
|
17
|
-
- [Preview Data v0.
|
|
18
|
-
- [Theme Runtime v0.
|
|
19
|
-
- [Theme Runtime v0.
|
|
16
|
+
- [Preview Data v0.7 Spec](https://zeropress.dev/reference/preview-data/specs/v0.7/)
|
|
17
|
+
- [Preview Data v0.7 Schema](https://schemas.zeropress.dev/preview-data/v0.7/schema.json)
|
|
18
|
+
- [Theme Runtime v0.7 Spec](https://zeropress.dev/reference/theme-runtime/specs/v0.7/)
|
|
19
|
+
- [Theme Runtime v0.7 Schema](https://schemas.zeropress.dev/theme-runtime/v0.7/schema.json)
|
|
20
20
|
|
|
21
21
|
It accepts canonical preview-data plus a validated theme package and produces static HTML artifacts through a writer interface.
|
|
22
22
|
|
|
@@ -83,9 +83,6 @@ const result = await buildSite({
|
|
|
83
83
|
previewData,
|
|
84
84
|
themePackage,
|
|
85
85
|
writer,
|
|
86
|
-
options: {
|
|
87
|
-
writeManifest: true,
|
|
88
|
-
},
|
|
89
86
|
});
|
|
90
87
|
```
|
|
91
88
|
|
|
@@ -100,18 +97,7 @@ Returns:
|
|
|
100
97
|
size: 1234,
|
|
101
98
|
sha256: '...'
|
|
102
99
|
}
|
|
103
|
-
]
|
|
104
|
-
manifest: {
|
|
105
|
-
generatedAt: '2026-04-02T00:00:00Z',
|
|
106
|
-
files: [
|
|
107
|
-
{
|
|
108
|
-
path: 'index.html',
|
|
109
|
-
contentType: 'text/html',
|
|
110
|
-
size: 1234,
|
|
111
|
-
sha256: '...'
|
|
112
|
-
}
|
|
113
|
-
]
|
|
114
|
-
}
|
|
100
|
+
]
|
|
115
101
|
}
|
|
116
102
|
```
|
|
117
103
|
|
|
@@ -121,11 +107,13 @@ Notes:
|
|
|
121
107
|
- `previewData` must already satisfy the canonical preview-data contract
|
|
122
108
|
- `themePackage` must already be a validated in-memory theme package
|
|
123
109
|
- `sitemap.xml` is emitted only when `site.url` is a non-empty canonical URL
|
|
124
|
-
- `feed.xml` is emitted only when `site.url` is a non-empty canonical URL and `generateFeed` is not `false`
|
|
110
|
+
- `feed.xml` is emitted only when `site.feed.enabled` is not `false`, `site.url` is a non-empty canonical URL, and `generateFeed` is not `false`
|
|
125
111
|
- callers may pass `sitemapStylesheetHref` to add an XML stylesheet processing instruction to generated `sitemap.xml`
|
|
126
|
-
- fallback `robots.txt` is emitted when `
|
|
127
|
-
- fallback `robots.txt` uses `site.
|
|
112
|
+
- fallback `robots.txt` is emitted when `generateRobotsTxt` is not `false`
|
|
113
|
+
- fallback `robots.txt` uses the effective `site.robots.allow_indexing` policy; omitted Preview Data defaults to `true`, `false` emits `Disallow: /`, and `true` emits `Allow: /`
|
|
128
114
|
- callers that disable fallback robots because a public `robots.txt` exists should copy that file as-is; sitemap directives in custom robots files are caller/user responsibility
|
|
115
|
+
- dotted slug segments such as `v0.6` remain literal in route URLs, canonical URLs, and output filenames
|
|
116
|
+
- output planning rejects duplicate public URLs, including clean-host aliases (`page.html` → `/page` and `page/index.html` → `/page/`), content routes shadowed by generated special files, and file/directory path hierarchy conflicts before writing
|
|
129
117
|
|
|
130
118
|
### `buildSiteFromThemeDir(input)`
|
|
131
119
|
|
|
@@ -179,7 +167,7 @@ Theme validation is enforced through:
|
|
|
179
167
|
|
|
180
168
|
JavaScript theme assets are emitted as provided. Build-core may hash output filenames, but it does not rewrite or minify JavaScript content.
|
|
181
169
|
|
|
182
|
-
|
|
170
|
+
User-defined scalar metadata under `site.meta`, `post.meta`, `page.meta`, and item `meta` is always HTML-escaped during template interpolation. Names ending in `_html` or `_url` do not opt metadata into raw rendering; use the explicit content and custom HTML contracts for trusted raw markup.
|
|
183
171
|
|
|
184
172
|
Build-core derives:
|
|
185
173
|
|
|
@@ -187,31 +175,138 @@ Build-core derives:
|
|
|
187
175
|
- post list HTML blocks
|
|
188
176
|
- pagination HTML
|
|
189
177
|
- taxonomy link HTML
|
|
190
|
-
-
|
|
178
|
+
- localized fallback `published_at` / `updated_at` values plus unconditional `published_at_iso` / `updated_at_iso` values
|
|
191
179
|
- datetime formatting from `site.locale`, `site.timezone`, `site.date_style`, and `site.time_style`
|
|
192
180
|
- `reading_time`
|
|
193
|
-
- `
|
|
181
|
+
- a route-root `comments` discriminated context
|
|
182
|
+
|
|
183
|
+
Every ordinary rendered route receives effective feature state on `site`, regardless of whether the corresponding Preview Data preference was omitted:
|
|
184
|
+
|
|
185
|
+
```js
|
|
186
|
+
{
|
|
187
|
+
search: { enabled: true },
|
|
188
|
+
feed: { enabled: true, url: '/feed.xml' },
|
|
189
|
+
archive: { enabled: true, url: '/archive/' },
|
|
190
|
+
comments: {
|
|
191
|
+
enabled: true,
|
|
192
|
+
provider: 'zeropress',
|
|
193
|
+
api_base_url: 'https://comments.example.com',
|
|
194
|
+
per_page: 50,
|
|
195
|
+
order: 'desc',
|
|
196
|
+
threading: { enabled: true, max_depth: 2 }
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Disabled states are exactly `{ enabled: false }`. Search combines the Preview Data request with `theme.json.features.search`. Feed additionally requires a canonical `site.url` and is hard-disabled by `generateFeed: false`. Archive additionally requires `archive.html`; its URL is `/archive/` for directory output and `/archive` for html-extension output. Comments additionally require `theme.json.features.comments`. `site.post_index.enabled` and `site.post_index.paginate` are also effective values after applying `theme.json.features.post_index` and route generation.
|
|
202
|
+
|
|
203
|
+
Build Core always emits localized fallback datetime strings together with canonical ISO timestamps. Themes may progressively enhance explicitly marked `<time datetime="...">` elements for the visitor's browser locale and timezone, but must preserve the fallback when JavaScript, `Intl`, or ISO parsing is unavailable. Themes that want canonical site-local display should use the fallback without client enhancement.
|
|
204
|
+
|
|
205
|
+
When `site.comments` is present, Build Core materializes the following defaults before rendering:
|
|
206
|
+
|
|
207
|
+
- `provider: "zeropress"`
|
|
208
|
+
- `per_page: 50`
|
|
209
|
+
- `order: "desc"`
|
|
210
|
+
- `threading.enabled: true`
|
|
211
|
+
- `threading.max_depth: 2`
|
|
212
|
+
|
|
213
|
+
Trailing slashes are removed from `site.comments.api_base_url`, except when the value is the same-origin root `/`. The normalized configuration remains available as `site.comments`.
|
|
194
214
|
|
|
195
|
-
|
|
215
|
+
Every rendered route receives a top-level `comments` object. Inactive and non-detail routes receive exactly:
|
|
196
216
|
|
|
197
|
-
|
|
198
|
-
|
|
217
|
+
```js
|
|
218
|
+
{
|
|
219
|
+
comments: {
|
|
220
|
+
enabled: false
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
An active post or page detail route receives:
|
|
226
|
+
|
|
227
|
+
```js
|
|
228
|
+
{
|
|
229
|
+
comments: {
|
|
230
|
+
enabled: true,
|
|
231
|
+
target_type: 'post', // or 'page'
|
|
232
|
+
target_public_id: 101,
|
|
233
|
+
provider: 'zeropress', // or 'wordpress'
|
|
234
|
+
api_base_url: 'https://comments.example.com',
|
|
235
|
+
per_page: 50,
|
|
236
|
+
order: 'desc',
|
|
237
|
+
threading: {
|
|
238
|
+
enabled: true,
|
|
239
|
+
max_depth: 2
|
|
240
|
+
},
|
|
241
|
+
request_token: '...'
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
```
|
|
199
245
|
|
|
200
|
-
The
|
|
246
|
+
The active state requires all of the following:
|
|
201
247
|
|
|
202
|
-
- `
|
|
248
|
+
- the theme declares `features.comments: true`
|
|
249
|
+
- `site.comments` is configured with `enabled: true`
|
|
250
|
+
- the post or page has `allow_comments: true` and a positive `public_id`
|
|
251
|
+
- the ZeroPress provider has a non-empty item `comments.request_token`
|
|
252
|
+
|
|
253
|
+
The theme-facing `request_token` key exists only for the `zeropress` provider. Preview-data items may retain ignored token metadata for `wordpress` or inactive comment states, but Build Core drops it. An active `wordpress` context omits that key entirely. Post/page objects, structured list items, collection items and cursors, adjacent-item summaries, search data, feeds, and non-detail route roots do not receive a copy of the item token. Themes must use the route-root `comments.enabled` discriminator.
|
|
254
|
+
|
|
255
|
+
The canonical `preview-data v0.7` site contract uses:
|
|
256
|
+
|
|
257
|
+
- `site.media_origin`
|
|
203
258
|
- `site.media_delivery_mode`
|
|
204
259
|
- `site.locale`
|
|
205
260
|
- `site.timezone`
|
|
206
|
-
- `site.datetime_display`
|
|
207
261
|
- `site.date_style`
|
|
208
262
|
- `site.time_style`
|
|
209
|
-
- `site.
|
|
210
|
-
- `site.
|
|
263
|
+
- `site.feed`
|
|
264
|
+
- `site.archive`
|
|
265
|
+
- `site.comments`
|
|
266
|
+
- `site.robots`
|
|
211
267
|
- `site.expose_generator`
|
|
212
268
|
- `site.search`
|
|
213
269
|
|
|
214
|
-
|
|
270
|
+
Post objects use `public_id` as their public numeric identity. The removed internal `content.posts[].id` field is neither required nor exposed to the theme runtime.
|
|
271
|
+
|
|
272
|
+
`site.url` is either an empty string or a credential-free HTTP(S) origin. A trailing root slash is accepted and normalized to `URL.origin`; credentials, paths, queries, and fragments are invalid. Menu and newsletter navigation URLs must be safe single-slash root-relative paths or credential-free HTTP(S) URLs. Query and fragment are allowed, while bare/dot-relative paths, protocol-relative URLs, path dot segments, backslashes, whitespace/control characters, and malformed percent escapes are invalid.
|
|
273
|
+
|
|
274
|
+
`site.media_origin` is either an empty string or an absolute HTTP(S) origin. Media fields accept only safe single-slash root-relative paths with a real path or credential-free HTTP(S) URLs with a path; `/`, bare paths, and dot-relative paths are invalid. Build Core resolves root-relative site favicon/logo, profile-widget avatar, author avatar, Post/Page featured-image, and `content.media[].src` values against that origin, while preserving already-absolute external URLs. SEO image metadata receives the normalized featured image. Responsive `srcset` variants require `media_delivery_mode: "media_domain"`, a non-empty origin, and an exact origin match; paths, credentials, query strings, and fragments are not part of the media-origin contract.
|
|
275
|
+
|
|
276
|
+
Locale and time zone are canonicalized once at build start. Locale uses canonical BCP 47. Time zone accepts `UTC`, canonical IANA identifiers, or canonical fixed offsets within `±14:00`; zero offset becomes `UTC`. The same values drive fallback date strings, archives, date-based permalinks, feeds, and rendered metadata.
|
|
277
|
+
|
|
278
|
+
When routing fields are omitted, Build Core uses directory output, `/posts/:slug/`, `/:slug/`, `/categories/:slug/`, and `/tags/:slug/`; `front_page` defaults to `theme_index`; and `post_index` defaults to `{ enabled: true, path: "/", paginate: true }`. Page objects retain a leaf `slug`, but external identity uses the NFC-normalized effective route path. Page front-page references use `page_path`, Page collection references use `path`, and different Page paths may share the same leaf slug.
|
|
279
|
+
|
|
280
|
+
`site.favicon.icon`, `svg`, and `png` form the default favicon set. `icon_dark` is the optional dark color-scheme icon. When both sets exist, Build Core emits the dark icon first with `media="(prefers-color-scheme: dark)"` and marks every default icon link with the light media query. A single available set is emitted without a media condition, and `apple_touch_icon` is always unconditional. An explicit preview-data `site.favicon` object replaces the complete auto-discovered build option instead of merging field by field.
|
|
281
|
+
|
|
282
|
+
### Custom HTML
|
|
283
|
+
|
|
284
|
+
Preview Data v0.7 carries optional trusted site-level HTML as flat raw strings:
|
|
285
|
+
|
|
286
|
+
```json
|
|
287
|
+
{
|
|
288
|
+
"custom_html": {
|
|
289
|
+
"head_end": "<meta name=\"example\" content=\"value\">",
|
|
290
|
+
"body_end": "<script src=\"/assets/example.js\"></script>"
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
Each configured slot must be nonblank and is limited to 65,536 Unicode code points. Build Core preserves the string without trimming, escaping, sanitizing, or interpreting it.
|
|
296
|
+
|
|
297
|
+
For ordinary theme-rendered HTML routes, site customization order is deterministic:
|
|
298
|
+
|
|
299
|
+
1. favicon links
|
|
300
|
+
2. ZeroPress generator metadata, unless disabled
|
|
301
|
+
3. the generated custom CSS link
|
|
302
|
+
4. `custom_html.head_end`
|
|
303
|
+
5. `custom_html.body_end`
|
|
304
|
+
|
|
305
|
+
Closing `</head>` and `</body>` tags are matched case-insensitively. If a configured custom HTML slot has no matching closing tag, the build fails with the route, output path, missing tag, and remediation guidance instead of silently dropping the configured content. Themes that consume these slots must render the corresponding closing tag. A `site.front_page.type: "standalone_html"` document remains byte-for-byte independent and does not receive favicon, generator, custom CSS, or custom HTML injection.
|
|
306
|
+
|
|
307
|
+
Native search artifacts are emitted only when preview-data does not set `site.search.enabled: false` and the active theme declares `features.search: true`. When that effective search state is disabled, search widgets are omitted from resolved widget items while their widget areas and non-search siblings remain available. `search_pagefind.js` is a Pagefind adapter that can replace `search.js` after a post-build Pagefind step.
|
|
308
|
+
|
|
309
|
+
When archive is disabled or `archive.html` is missing, archive routes and archive widget items are omitted while authored menu items, widget areas, and non-archive siblings remain unchanged. No archive output path is claimed in that state, so content may use `/archive`. Feed behaves the same way for `feed.xml`: a disabled feed neither emits nor claims the file. Enabled feeds add one RSS autodiscovery link to `meta.head_tags` on ordinary theme-rendered routes; `404.html` and standalone front-page HTML do not receive it.
|
|
215
310
|
|
|
216
311
|
Optional route templates behave as rendering capabilities, not guaranteed outputs:
|
|
217
312
|
|
|
@@ -220,7 +315,9 @@ Optional route templates behave as rendering capabilities, not guaranteed output
|
|
|
220
315
|
- `tag.html`
|
|
221
316
|
- `404.html`
|
|
222
317
|
|
|
223
|
-
If preview-data includes content that could produce archive/category/tag pages but the theme omits the matching optional template, build-core skips those outputs. Special files are derived from emitted outputs rather than raw preview-data alone.
|
|
318
|
+
If preview-data includes content that could produce archive/category/tag pages but the theme omits the matching optional template, build-core skips those outputs. `404.html` is emitted only when the theme provides its matching template. Special files are derived from emitted outputs rather than raw preview-data alone.
|
|
319
|
+
|
|
320
|
+
Generated `404.html` uses the document title `Page Not Found - <site title>` and always includes `robots: noindex`. It omits description, canonical, Open Graph, and article metadata because a static error document is not a canonical or shareable content route. Build-core writes the artifact only; the development server or deployment host remains responsible for serving it with HTTP status `404` for missing URLs.
|
|
224
321
|
|
|
225
322
|
## Build Options
|
|
226
323
|
|
|
@@ -229,20 +326,17 @@ Supported options:
|
|
|
229
326
|
- `assetHashing`
|
|
230
327
|
- `favicon`
|
|
231
328
|
- `sitemapStylesheetHref`
|
|
232
|
-
- `generateSpecialFiles`
|
|
233
329
|
- `generateFeed`
|
|
234
330
|
- `generateRobotsTxt`
|
|
235
|
-
- `
|
|
236
|
-
|
|
237
|
-
These options apply to both full builds and partial renders where relevant.
|
|
331
|
+
- `reservedOutputPaths`
|
|
238
332
|
|
|
239
333
|
Defaults:
|
|
240
334
|
|
|
241
335
|
- `assetHashing: true`
|
|
242
|
-
- `generateSpecialFiles: true`
|
|
243
336
|
- `generateFeed: true`
|
|
244
337
|
- `generateRobotsTxt: true`
|
|
245
|
-
|
|
338
|
+
|
|
339
|
+
`reservedOutputPaths` is an internal orchestration boundary for callers that already own files in the final output tree, such as a copied public directory. Reserved files are safety-validated and participate in clean-URL alias, exact-path, and file/directory hierarchy collision checks, but Build Core does not write them or include them in the returned file summaries.
|
|
246
340
|
|
|
247
341
|
## License
|
|
248
342
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zeropress/build-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Shared ZeroPress build core",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -30,14 +30,14 @@
|
|
|
30
30
|
"test": "node --test"
|
|
31
31
|
},
|
|
32
32
|
"engines": {
|
|
33
|
-
"node": ">=
|
|
33
|
+
"node": ">=22.12.0"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@zeropress/slug-policy": "0.1
|
|
37
|
-
"@zeropress/preview-data-validator": "0.
|
|
38
|
-
"@zeropress/theme-validator": "0.
|
|
36
|
+
"@zeropress/slug-policy": "0.2.1",
|
|
37
|
+
"@zeropress/preview-data-validator": "0.7.0",
|
|
38
|
+
"@zeropress/theme-validator": "0.7.0",
|
|
39
39
|
"highlight.js": "11.11.1",
|
|
40
|
-
"markdown-it": "14.
|
|
41
|
-
"markdown-it-anchor": "9.2.
|
|
40
|
+
"markdown-it": "14.3.0",
|
|
41
|
+
"markdown-it-anchor": "9.2.1"
|
|
42
42
|
}
|
|
43
43
|
}
|