@zeropress/build-pages 0.5.2 → 0.5.5
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 +82 -36
- package/action.yml +8 -4
- package/dist/action.js +47 -5
- package/dist/prebuild.js +4635 -0
- package/package.json +1 -1
- package/src/action.js +6 -1
- package/src/index.js +69 -17
- package/src/prebuild.js +10 -4
package/README.md
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
# @zeropress/build-pages
|
|
2
2
|
|
|
3
|
+

|
|
4
|
+

|
|
5
|
+
|
|
3
6
|
Build ZeroPress static output for modern hosting platforms.
|
|
4
7
|
|
|
5
|
-
`@zeropress/build-pages` turns a directory of Markdown files and public assets into a static ZeroPress site. It discovers Markdown pages, prepares the site data, stages public files, and runs `@zeropress/build
|
|
8
|
+
`@zeropress/build-pages` turns a directory of Markdown files and public assets into a static ZeroPress site. It discovers Markdown pages, prepares the site data, stages public files, and runs [`@zeropress/build`](https://github.com/zeropress-app/zeropress-build).
|
|
6
9
|
|
|
7
10
|
The generated output is plain static files that can be deployed to GitHub Pages, Cloudflare Pages, Netlify, Vercel, or any static hosting provider.
|
|
8
11
|
|
|
@@ -97,10 +100,52 @@ jobs:
|
|
|
97
100
|
|
|
98
101
|
The action `zeropress-build-pages` builds the static files only. Uploading and deploying are handled by your hosting provider's deployment action or CLI.
|
|
99
102
|
|
|
103
|
+
Minimal action usage:
|
|
104
|
+
|
|
105
|
+
```yaml
|
|
106
|
+
- name: Build ZeroPress Pages
|
|
107
|
+
uses: zeropress-app/zeropress-build-pages@v0
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
That is equivalent to:
|
|
111
|
+
|
|
112
|
+
```yaml
|
|
113
|
+
- name: Build ZeroPress Pages
|
|
114
|
+
uses: zeropress-app/zeropress-build-pages@v0
|
|
115
|
+
with:
|
|
116
|
+
source: ./docs
|
|
117
|
+
destination: ./_site
|
|
118
|
+
theme: docs
|
|
119
|
+
skip-untitled-markdown: false
|
|
120
|
+
skip-link-check: false
|
|
121
|
+
copy-markdown-source: true
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Custom input example:
|
|
125
|
+
|
|
126
|
+
```yaml
|
|
127
|
+
- name: Build ZeroPress Pages
|
|
128
|
+
uses: zeropress-app/zeropress-build-pages@v0
|
|
129
|
+
with:
|
|
130
|
+
source: ./documents
|
|
131
|
+
destination: ./_site
|
|
132
|
+
theme-path: ./theme-docs
|
|
133
|
+
config: ./documents/.zeropress/config.json
|
|
134
|
+
site-url: https://example.com/docs
|
|
135
|
+
copy-markdown-source: false
|
|
136
|
+
```
|
|
137
|
+
|
|
100
138
|
In the action inputs:
|
|
101
139
|
|
|
102
140
|
- `source` is the directory that contains your Markdown pages, public files, and optional `.zeropress/config.json`. The default is `./docs`.
|
|
103
141
|
- `destination` is the directory where the generated static site is written. The default is `./_site`.
|
|
142
|
+
- `theme` is the bundled theme name. The default is `docs`.
|
|
143
|
+
- `theme-path` is a custom local ZeroPress theme directory. It takes precedence over `theme`.
|
|
144
|
+
- `config` is the config file path. The default is `<source>/.zeropress/config.json`.
|
|
145
|
+
- `site-url` overrides the canonical site URL from config.
|
|
146
|
+
- `skip-untitled-markdown` skips Markdown files without a page title instead of failing. The default is `false`.
|
|
147
|
+
- `skip-link-check` skips internal link checking after build. The default is `false`.
|
|
148
|
+
- `copy-markdown-source` copies original Markdown files to the generated output and enables `View this page as Markdown` links in the bundled docs theme. The default is `true`.
|
|
104
149
|
|
|
105
150
|
For GitHub Pages, the generated `destination` directory can be passed to `actions/upload-pages-artifact`. For Cloudflare Pages, Netlify, Vercel, or another static host, pass the same `destination` directory to that provider's deploy step.
|
|
106
151
|
|
|
@@ -138,42 +183,37 @@ The CLI requires explicit input and output paths. The GitHub Action keeps safe d
|
|
|
138
183
|
|
|
139
184
|
| Option | Default | Purpose |
|
|
140
185
|
| --- | --- | --- |
|
|
141
|
-
| `--source <dir>` | required |
|
|
186
|
+
| `--source <dir>` | required | Dedicated source directory containing Markdown and public files |
|
|
142
187
|
| `--destination <dir>` | required | Output directory |
|
|
143
188
|
| `--theme docs` | `docs` | Bundled docs theme |
|
|
144
189
|
| `--theme-path <dir>` | none | Custom ZeroPress theme directory |
|
|
145
190
|
| `--config <path>` | `<source>/.zeropress/config.json` | Build Pages config |
|
|
146
191
|
| `--site-url <url>` | config `site.url` | Canonical URL override |
|
|
147
192
|
| `--skip-untitled-markdown` | `false` | Skip Markdown without a page title |
|
|
148
|
-
| `--
|
|
149
|
-
|
|
150
|
-
Equivalent environment variables:
|
|
151
|
-
|
|
152
|
-
| Env | Maps to |
|
|
153
|
-
| --- | --- |
|
|
154
|
-
| `ZEROPRESS_PUBLIC_DIR` | `--source` |
|
|
155
|
-
| `ZEROPRESS_OUT_DIR` | `--destination` |
|
|
156
|
-
| `ZEROPRESS_THEME_DIR` | `--theme-path` |
|
|
157
|
-
| `ZEROPRESS_BUILD_PAGES_CONFIG` | `--config` |
|
|
158
|
-
| `ZEROPRESS_SITE_URL` | `--site-url` |
|
|
159
|
-
| `ZEROPRESS_SKIP_UNTITLED_MARKDOWN=true` | `--skip-untitled-markdown` |
|
|
160
|
-
|
|
161
|
-
CLI options take precedence over environment variables.
|
|
193
|
+
| `--skip-link-check` | `false` | Skip link checking |
|
|
194
|
+
| `--no-copy-markdown-source` | `false` | Do not copy original Markdown files to output |
|
|
162
195
|
|
|
163
196
|
## Source Tree
|
|
164
197
|
|
|
165
|
-
The source directory is both the Markdown source root and the public passthrough root. GitHub Action usage defaults to `./docs`; CLI usage requires `--source
|
|
198
|
+
The source directory is the folder that Build Pages reads. It is both the Markdown source root and the public passthrough root. GitHub Action usage defaults to `./docs`; CLI usage requires `--source`.
|
|
199
|
+
|
|
200
|
+
Use a dedicated content directory such as `docs/` or `documents/`. Repository root source (`--source ./`) is not supported.
|
|
166
201
|
|
|
167
202
|
```txt
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
203
|
+
my-site/
|
|
204
|
+
docs/ # source
|
|
205
|
+
index.md
|
|
206
|
+
guide.md
|
|
207
|
+
assets/
|
|
208
|
+
logo.png
|
|
209
|
+
.zeropress/
|
|
210
|
+
config.json
|
|
211
|
+
_site/ # destination, generated
|
|
174
212
|
```
|
|
175
213
|
|
|
176
|
-
Build Pages stages the source tree before calling `@zeropress/build
|
|
214
|
+
Build Pages stages the source tree before calling [`@zeropress/build`](https://github.com/zeropress-app/zeropress-build). Generated ZeroPress output wins over staged public files.
|
|
215
|
+
|
|
216
|
+
The source directory must not overlap the destination directory, the selected theme directory, or the internal `.zeropress/` working directory.
|
|
177
217
|
|
|
178
218
|
Ignored while staging and Markdown discovery:
|
|
179
219
|
|
|
@@ -201,7 +241,8 @@ Additional Markdown discovery ignores:
|
|
|
201
241
|
- Nested `index.md` maps to a directory route, such as `cli/index.md` -> `/cli/`.
|
|
202
242
|
- Other Markdown files map to extensionless routes, such as `cli/tool.md` -> `/cli/tool`.
|
|
203
243
|
- Markdown links to other discovered `.md` files are rewritten to generated public URLs.
|
|
204
|
-
- Original Markdown files remain available as public passthrough files.
|
|
244
|
+
- Original Markdown files remain available as public passthrough files by default.
|
|
245
|
+
- Use `--no-copy-markdown-source` or Action input `copy-markdown-source: false` to keep source Markdown out of the generated output. This also hides bundled theme `View this page as Markdown` links.
|
|
205
246
|
|
|
206
247
|
Optional YAML front matter is supported at the top of Markdown files:
|
|
207
248
|
|
|
@@ -236,6 +277,8 @@ Unknown front matter fields are ignored to make migration from existing Markdown
|
|
|
236
277
|
|
|
237
278
|
Build Pages reads `<source>/.zeropress/config.json` when present. Missing config falls back to defaults.
|
|
238
279
|
|
|
280
|
+
See the public config reference at [zeropress.dev/build-pages-config](https://zeropress.dev/build-pages-config/).
|
|
281
|
+
|
|
239
282
|
```json
|
|
240
283
|
{
|
|
241
284
|
"$schema": "https://zeropress.dev/schemas/zeropress-build-pages.config.v0.1.schema.json",
|
|
@@ -285,12 +328,11 @@ The bundled docs theme shows `Published with ZeroPress.` by default. Set `site.f
|
|
|
285
328
|
|
|
286
329
|
Schemas:
|
|
287
330
|
|
|
288
|
-
-
|
|
289
|
-
- `schemas/zeropress-build-pages.config.schema.json`
|
|
331
|
+
- [ZeroPress Build Pages Config v0.1](https://zeropress.dev/schemas/zeropress-build-pages.config.v0.1.schema.json)
|
|
290
332
|
|
|
291
|
-
##
|
|
333
|
+
## Internal `.zeropress/` Files
|
|
292
334
|
|
|
293
|
-
Build Pages writes
|
|
335
|
+
Build Pages writes internal working files to `.zeropress/` in the current working directory. These files are not the final deploy output. The final static site is written to the `destination` directory.
|
|
294
336
|
|
|
295
337
|
```txt
|
|
296
338
|
.zeropress/
|
|
@@ -300,14 +342,18 @@ Build Pages writes:
|
|
|
300
342
|
public-assets/
|
|
301
343
|
```
|
|
302
344
|
|
|
303
|
-
`build-pages-config.json` is the resolved user-facing Build Pages config used for the current run. It combines
|
|
345
|
+
`build-pages-config.json` is the resolved user-facing Build Pages config used for the current run. It combines source config, defaults, and CLI or Action input overrides where applicable.
|
|
304
346
|
|
|
305
347
|
`preview-data.json` is an internal generated build input for the ZeroPress renderer. Most users do not need to edit or understand this file.
|
|
306
348
|
|
|
307
|
-
|
|
349
|
+
`build-report.json` records discovered Markdown counts, skipped Markdown files, front page resolution, source Markdown copy policy, and custom HTML slots.
|
|
308
350
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
351
|
+
`public-assets/` is a temporary staged public root used before the final ZeroPress render.
|
|
352
|
+
|
|
353
|
+
## Destination Output
|
|
354
|
+
|
|
355
|
+
The `destination` directory contains the deployable static site. It includes generated ZeroPress HTML, copied public files, and original Markdown files unless Markdown source copy is disabled or files are excluded by the public passthrough rules.
|
|
356
|
+
|
|
357
|
+
## Demo
|
|
358
|
+
|
|
359
|
+
- [zeropress.dev](https://github.com/zeropress-app/zeropress.dev) is built with `@zeropress/build-pages`.
|
package/action.yml
CHANGED
|
@@ -6,7 +6,7 @@ branding:
|
|
|
6
6
|
color: blue
|
|
7
7
|
inputs:
|
|
8
8
|
source:
|
|
9
|
-
description:
|
|
9
|
+
description: Dedicated source directory containing Markdown files and optional .zeropress/config.json. Repository root source is not supported.
|
|
10
10
|
required: false
|
|
11
11
|
default: ./docs
|
|
12
12
|
destination:
|
|
@@ -27,11 +27,15 @@ inputs:
|
|
|
27
27
|
description: Canonical site URL override.
|
|
28
28
|
required: false
|
|
29
29
|
skip-untitled-markdown:
|
|
30
|
-
description: Skip Markdown files without
|
|
30
|
+
description: Skip Markdown files without a page title instead of failing.
|
|
31
31
|
required: false
|
|
32
32
|
default: "false"
|
|
33
|
-
check
|
|
34
|
-
description:
|
|
33
|
+
skip-link-check:
|
|
34
|
+
description: Skip internal link checking after the site is built.
|
|
35
|
+
required: false
|
|
36
|
+
default: "false"
|
|
37
|
+
copy-markdown-source:
|
|
38
|
+
description: Copy original Markdown files to output and expose View this page as Markdown links.
|
|
35
39
|
required: false
|
|
36
40
|
default: "true"
|
|
37
41
|
runs:
|
package/dist/action.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { createRequire as __zeropressCreateRequire } from "node:module";
|
|
3
|
+
const require = __zeropressCreateRequire(import.meta.url);
|
|
2
4
|
var __create = Object.create;
|
|
3
5
|
var __defProp = Object.defineProperty;
|
|
4
6
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -62137,18 +62139,26 @@ async function linkExists(siteDir, link2) {
|
|
|
62137
62139
|
// src/index.js
|
|
62138
62140
|
var __dirname = path3.dirname(fileURLToPath(import.meta.url));
|
|
62139
62141
|
var packageDir = path3.resolve(__dirname, "..");
|
|
62140
|
-
var prebuildScript = path3.join(packageDir, "src", "prebuild.js");
|
|
62142
|
+
var prebuildScript = __dirname === path3.join(packageDir, "dist") ? path3.join(__dirname, "prebuild.js") : path3.join(packageDir, "src", "prebuild.js");
|
|
62141
62143
|
var PREVIEW_DATA_PATH = ".zeropress/preview-data.json";
|
|
62142
62144
|
var STAGING_DIR = ".zeropress/public-assets";
|
|
62143
62145
|
var DEFAULT_THEME = "docs";
|
|
62144
62146
|
async function runBuildPages(options2) {
|
|
62145
62147
|
const cwd = path3.resolve(options2.cwd || process.cwd());
|
|
62148
|
+
const copyMarkdownSource = options2.copyMarkdownSource !== false;
|
|
62146
62149
|
const sourceDir = path3.resolve(cwd, options2.source);
|
|
62147
62150
|
const destinationDir = path3.resolve(cwd, options2.destination);
|
|
62148
62151
|
const generatedDir = path3.join(cwd, ".zeropress");
|
|
62149
62152
|
const stagingDir = path3.join(cwd, STAGING_DIR);
|
|
62150
62153
|
const previewDataPath = path3.join(cwd, PREVIEW_DATA_PATH);
|
|
62151
62154
|
const themeDir = resolveThemeDir(cwd, options2);
|
|
62155
|
+
assertBuildPagesPathLayout({
|
|
62156
|
+
cwd,
|
|
62157
|
+
sourceDir,
|
|
62158
|
+
destinationDir,
|
|
62159
|
+
themeDir,
|
|
62160
|
+
generatedDir
|
|
62161
|
+
});
|
|
62152
62162
|
await assertDirectory(sourceDir, "Source directory");
|
|
62153
62163
|
await fs3.rm(generatedDir, { recursive: true, force: true });
|
|
62154
62164
|
await fs3.mkdir(generatedDir, { recursive: true });
|
|
@@ -62156,7 +62166,8 @@ async function runBuildPages(options2) {
|
|
|
62156
62166
|
...process.env,
|
|
62157
62167
|
ZEROPRESS_BUILD_PAGES_SOURCE: sourceDir,
|
|
62158
62168
|
ZEROPRESS_PUBLIC_DIR: sourceDir,
|
|
62159
|
-
ZEROPRESS_SKIP_UNTITLED_MARKDOWN: String(Boolean(options2.skipUntitledMarkdown))
|
|
62169
|
+
ZEROPRESS_SKIP_UNTITLED_MARKDOWN: String(Boolean(options2.skipUntitledMarkdown)),
|
|
62170
|
+
ZEROPRESS_COPY_MARKDOWN_SOURCE: String(copyMarkdownSource)
|
|
62160
62171
|
};
|
|
62161
62172
|
if (options2.config) {
|
|
62162
62173
|
env.ZEROPRESS_BUILD_PAGES_CONFIG = path3.resolve(cwd, options2.config);
|
|
@@ -62179,7 +62190,8 @@ async function runBuildPages(options2) {
|
|
|
62179
62190
|
await fs3.rm(stagingDir, { recursive: true, force: true });
|
|
62180
62191
|
await fs3.mkdir(stagingDir, { recursive: true });
|
|
62181
62192
|
await copyPublicStaging(sourceDir, stagingDir, {
|
|
62182
|
-
excludePaths: [destinationDir, themeDir, generatedDir]
|
|
62193
|
+
excludePaths: [destinationDir, themeDir, generatedDir],
|
|
62194
|
+
copyMarkdownSource
|
|
62183
62195
|
});
|
|
62184
62196
|
const previousPublicDir = process.env.ZEROPRESS_PUBLIC_DIR;
|
|
62185
62197
|
process.env.ZEROPRESS_PUBLIC_DIR = stagingDir;
|
|
@@ -62195,7 +62207,7 @@ async function runBuildPages(options2) {
|
|
|
62195
62207
|
process.env.ZEROPRESS_PUBLIC_DIR = previousPublicDir;
|
|
62196
62208
|
}
|
|
62197
62209
|
}
|
|
62198
|
-
if (options2.
|
|
62210
|
+
if (!options2.skipLinkCheck) {
|
|
62199
62211
|
const result = await checkInternalLinks(destinationDir);
|
|
62200
62212
|
if (result.brokenLinks.length) {
|
|
62201
62213
|
console.warn("Warning: broken internal links found:");
|
|
@@ -62229,6 +62241,26 @@ async function assertDirectory(dir, label) {
|
|
|
62229
62241
|
throw new Error(`${label} is not a directory: ${dir}`);
|
|
62230
62242
|
}
|
|
62231
62243
|
}
|
|
62244
|
+
function assertBuildPagesPathLayout({ cwd, sourceDir, destinationDir, themeDir, generatedDir }) {
|
|
62245
|
+
if (samePath(sourceDir, cwd)) {
|
|
62246
|
+
throw new Error(
|
|
62247
|
+
`Source directory must be a dedicated content directory, not the current working directory. Received: ${formatPath(cwd, sourceDir)}`
|
|
62248
|
+
);
|
|
62249
|
+
}
|
|
62250
|
+
assertNoPathOverlap(cwd, "Source directory", sourceDir, "internal .zeropress working directory", generatedDir);
|
|
62251
|
+
assertNoPathOverlap(cwd, "Destination directory", destinationDir, "internal .zeropress working directory", generatedDir);
|
|
62252
|
+
assertNoPathOverlap(cwd, "Theme directory", themeDir, "internal .zeropress working directory", generatedDir);
|
|
62253
|
+
assertNoPathOverlap(cwd, "Source directory", sourceDir, "destination directory", destinationDir);
|
|
62254
|
+
assertNoPathOverlap(cwd, "Source directory", sourceDir, "theme directory", themeDir);
|
|
62255
|
+
}
|
|
62256
|
+
function assertNoPathOverlap(cwd, firstLabel, firstPath, secondLabel, secondPath) {
|
|
62257
|
+
if (!pathsOverlap2(firstPath, secondPath)) {
|
|
62258
|
+
return;
|
|
62259
|
+
}
|
|
62260
|
+
throw new Error(
|
|
62261
|
+
`${firstLabel} must not overlap the ${secondLabel}. ${firstLabel}: ${formatPath(cwd, firstPath)}; ${secondLabel}: ${formatPath(cwd, secondPath)}`
|
|
62262
|
+
);
|
|
62263
|
+
}
|
|
62232
62264
|
async function copyPublicStaging(sourceDir, targetDir, options2) {
|
|
62233
62265
|
const entries = await fs3.readdir(sourceDir, { withFileTypes: true });
|
|
62234
62266
|
for (const entry of entries) {
|
|
@@ -62248,6 +62280,9 @@ async function copyPublicStaging(sourceDir, targetDir, options2) {
|
|
|
62248
62280
|
if (!entry.isFile()) {
|
|
62249
62281
|
continue;
|
|
62250
62282
|
}
|
|
62283
|
+
if (options2.copyMarkdownSource === false && entry.name.toLowerCase().endsWith(".md")) {
|
|
62284
|
+
continue;
|
|
62285
|
+
}
|
|
62251
62286
|
await fs3.mkdir(path3.dirname(targetPath), { recursive: true });
|
|
62252
62287
|
await fs3.copyFile(sourcePath, targetPath);
|
|
62253
62288
|
}
|
|
@@ -62265,6 +62300,9 @@ function pathsOverlap2(firstPath, secondPath) {
|
|
|
62265
62300
|
const second = path3.resolve(secondPath);
|
|
62266
62301
|
return first === second || isPathInside2(first, second) || isPathInside2(second, first);
|
|
62267
62302
|
}
|
|
62303
|
+
function samePath(firstPath, secondPath) {
|
|
62304
|
+
return path3.resolve(firstPath) === path3.resolve(secondPath);
|
|
62305
|
+
}
|
|
62268
62306
|
function isPathInside2(parentPath, childPath) {
|
|
62269
62307
|
const relativePath = path3.relative(parentPath, childPath);
|
|
62270
62308
|
return Boolean(relativePath) && !relativePath.startsWith("..") && !path3.isAbsolute(relativePath);
|
|
@@ -62283,7 +62321,8 @@ var options = {
|
|
|
62283
62321
|
config: input("config"),
|
|
62284
62322
|
siteUrl: input("site-url"),
|
|
62285
62323
|
skipUntitledMarkdown: booleanInput("skip-untitled-markdown", false),
|
|
62286
|
-
|
|
62324
|
+
skipLinkCheck: booleanInput("skip-link-check", false),
|
|
62325
|
+
copyMarkdownSource: falseOnlyInput("copy-markdown-source")
|
|
62287
62326
|
};
|
|
62288
62327
|
try {
|
|
62289
62328
|
await runBuildPages(options);
|
|
@@ -62302,3 +62341,6 @@ function booleanInput(name, fallback) {
|
|
|
62302
62341
|
}
|
|
62303
62342
|
return value.toLowerCase() === "true";
|
|
62304
62343
|
}
|
|
62344
|
+
function falseOnlyInput(name) {
|
|
62345
|
+
return input(name).toLowerCase() !== "false";
|
|
62346
|
+
}
|