@kensio/colophon 2.1.0 → 2.3.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 +608 -34
- package/dist/cli/args.d.ts +14 -0
- package/dist/cli/args.d.ts.map +1 -0
- package/dist/cli/args.js +67 -0
- package/dist/cli/args.js.map +1 -0
- package/dist/cli/config.d.ts +12 -0
- package/dist/cli/config.d.ts.map +1 -0
- package/dist/cli/config.js +43 -0
- package/dist/cli/config.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +35 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli.js +34 -6
- package/dist/cli.js.map +1 -1
- package/dist/config/defaults.d.ts +64 -0
- package/dist/config/defaults.d.ts.map +1 -0
- package/dist/config/defaults.js +64 -0
- package/dist/config/defaults.js.map +1 -0
- package/dist/config/index.d.ts +22 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +52 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/resolve.d.ts +24 -0
- package/dist/config/resolve.d.ts.map +1 -0
- package/dist/config/resolve.js +66 -0
- package/dist/config/resolve.js.map +1 -0
- package/dist/config/size.d.ts +20 -0
- package/dist/config/size.d.ts.map +1 -0
- package/dist/config/size.js +46 -0
- package/dist/config/size.js.map +1 -0
- package/dist/config.d.ts +33 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +94 -4
- package/dist/config.js.map +1 -1
- package/dist/content/index.d.ts +5 -51
- package/dist/content/index.d.ts.map +1 -1
- package/dist/content/index.js +3 -115
- package/dist/content/index.js.map +1 -1
- package/dist/content/props.d.ts +15 -0
- package/dist/content/props.d.ts.map +1 -0
- package/dist/content/props.js +71 -0
- package/dist/content/props.js.map +1 -0
- package/dist/content/slug.d.ts +23 -0
- package/dist/content/slug.d.ts.map +1 -0
- package/dist/content/slug.js +52 -0
- package/dist/content/slug.js.map +1 -0
- package/dist/content/walk.d.ts +17 -0
- package/dist/content/walk.d.ts.map +1 -0
- package/dist/content/walk.js +57 -0
- package/dist/content/walk.js.map +1 -0
- package/dist/fonts/index.d.ts +10 -0
- package/dist/fonts/index.d.ts.map +1 -0
- package/dist/fonts/index.js +11 -0
- package/dist/fonts/index.js.map +1 -0
- package/dist/fonts/materialise.d.ts +7 -0
- package/dist/fonts/materialise.d.ts.map +1 -0
- package/dist/fonts/materialise.js +47 -0
- package/dist/fonts/materialise.js.map +1 -0
- package/dist/fonts/resolve.d.ts +7 -0
- package/dist/fonts/resolve.d.ts.map +1 -0
- package/dist/fonts/resolve.js +50 -0
- package/dist/fonts/resolve.js.map +1 -0
- package/dist/fonts.d.ts +18 -0
- package/dist/fonts.d.ts.map +1 -0
- package/dist/fonts.js +102 -0
- package/dist/fonts.js.map +1 -0
- package/dist/generate/extra.d.ts +16 -0
- package/dist/generate/extra.d.ts.map +1 -0
- package/dist/generate/extra.js +60 -0
- package/dist/generate/extra.js.map +1 -0
- package/dist/generate/index.d.ts +19 -0
- package/dist/generate/index.d.ts.map +1 -0
- package/dist/generate/index.js +46 -0
- package/dist/generate/index.js.map +1 -0
- package/dist/generate/job.d.ts +35 -0
- package/dist/generate/job.d.ts.map +1 -0
- package/dist/generate/job.js +2 -0
- package/dist/generate/job.js.map +1 -0
- package/dist/generate/options.d.ts +56 -0
- package/dist/generate/options.d.ts.map +1 -0
- package/dist/generate/options.js +17 -0
- package/dist/generate/options.js.map +1 -0
- package/dist/generate/output-path.d.ts +12 -0
- package/dist/generate/output-path.d.ts.map +1 -0
- package/dist/generate/output-path.js +18 -0
- package/dist/generate/output-path.js.map +1 -0
- package/dist/generate/outputs.d.ts +28 -0
- package/dist/generate/outputs.d.ts.map +1 -0
- package/dist/generate/outputs.js +71 -0
- package/dist/generate/outputs.js.map +1 -0
- package/dist/generate/plan.d.ts +21 -0
- package/dist/generate/plan.d.ts.map +1 -0
- package/dist/generate/plan.js +72 -0
- package/dist/generate/plan.js.map +1 -0
- package/dist/generate/render-image.d.ts +11 -0
- package/dist/generate/render-image.d.ts.map +1 -0
- package/dist/generate/render-image.js +27 -0
- package/dist/generate/render-image.js.map +1 -0
- package/dist/generate.d.ts +27 -6
- package/dist/generate.d.ts.map +1 -1
- package/dist/generate.js +77 -15
- package/dist/generate.js.map +1 -1
- package/dist/highlight/color.d.ts +9 -0
- package/dist/highlight/color.d.ts.map +1 -0
- package/dist/highlight/color.js +15 -0
- package/dist/highlight/color.js.map +1 -0
- package/dist/highlight/grid.d.ts +14 -0
- package/dist/highlight/grid.d.ts.map +1 -0
- package/dist/highlight/grid.js +36 -0
- package/dist/highlight/grid.js.map +1 -0
- package/dist/highlight/index.d.ts +12 -0
- package/dist/highlight/index.d.ts.map +1 -0
- package/dist/highlight/index.js +31 -0
- package/dist/highlight/index.js.map +1 -0
- package/dist/highlight/language.d.ts +14 -0
- package/dist/highlight/language.d.ts.map +1 -0
- package/dist/highlight/language.js +42 -0
- package/dist/highlight/language.js.map +1 -0
- package/dist/highlight/normalise.d.ts +17 -0
- package/dist/highlight/normalise.d.ts.map +1 -0
- package/dist/highlight/normalise.js +37 -0
- package/dist/highlight/normalise.js.map +1 -0
- package/dist/highlight/types.d.ts +40 -0
- package/dist/highlight/types.d.ts.map +1 -0
- package/dist/highlight/types.js +2 -0
- package/dist/highlight/types.js.map +1 -0
- package/dist/highlight.d.ts +10 -0
- package/dist/highlight.d.ts.map +1 -1
- package/dist/highlight.js +25 -2
- package/dist/highlight.js.map +1 -1
- package/dist/index.d.ts +15 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -5
- package/dist/index.js.map +1 -1
- package/dist/manifest/build.d.ts +14 -0
- package/dist/manifest/build.d.ts.map +1 -0
- package/dist/manifest/build.js +43 -0
- package/dist/manifest/build.js.map +1 -0
- package/dist/manifest/index.d.ts +27 -0
- package/dist/manifest/index.d.ts.map +1 -0
- package/dist/manifest/index.js +31 -0
- package/dist/manifest/index.js.map +1 -0
- package/dist/manifest/order.d.ts +12 -0
- package/dist/manifest/order.d.ts.map +1 -0
- package/dist/manifest/order.js +17 -0
- package/dist/manifest/order.js.map +1 -0
- package/dist/manifest/page.d.ts +24 -0
- package/dist/manifest/page.d.ts.map +1 -0
- package/dist/manifest/page.js +55 -0
- package/dist/manifest/page.js.map +1 -0
- package/dist/meta/html.d.ts +14 -0
- package/dist/meta/html.d.ts.map +1 -0
- package/dist/meta/html.js +24 -0
- package/dist/meta/html.js.map +1 -0
- package/dist/meta/index.d.ts +11 -0
- package/dist/meta/index.d.ts.map +1 -0
- package/dist/meta/index.js +11 -0
- package/dist/meta/index.js.map +1 -0
- package/dist/meta/tags.d.ts +21 -0
- package/dist/meta/tags.d.ts.map +1 -0
- package/dist/meta/tags.js +72 -0
- package/dist/meta/tags.js.map +1 -0
- package/dist/meta/url.d.ts +15 -0
- package/dist/meta/url.d.ts.map +1 -0
- package/dist/meta/url.js +34 -0
- package/dist/meta/url.js.map +1 -0
- package/dist/placement/check.d.ts +16 -0
- package/dist/placement/check.d.ts.map +1 -0
- package/dist/placement/check.js +40 -0
- package/dist/placement/check.js.map +1 -0
- package/dist/placement/index.d.ts +29 -0
- package/dist/placement/index.d.ts.map +1 -0
- package/dist/placement/index.js +61 -0
- package/dist/placement/index.js.map +1 -0
- package/dist/placement/relative.d.ts +31 -0
- package/dist/placement/relative.d.ts.map +1 -0
- package/dist/placement/relative.js +53 -0
- package/dist/placement/relative.js.map +1 -0
- package/dist/pool.d.ts +18 -0
- package/dist/pool.d.ts.map +1 -0
- package/dist/pool.js +56 -0
- package/dist/pool.js.map +1 -0
- package/dist/render/index.d.ts +10 -0
- package/dist/render/index.d.ts.map +1 -0
- package/dist/render/index.js +27 -0
- package/dist/render/index.js.map +1 -0
- package/dist/render/png.d.ts +10 -0
- package/dist/render/png.d.ts.map +1 -0
- package/dist/render/png.js +30 -0
- package/dist/render/png.js.map +1 -0
- package/dist/render/svg.d.ts +10 -0
- package/dist/render/svg.d.ts.map +1 -0
- package/dist/render/svg.js +20 -0
- package/dist/render/svg.js.map +1 -0
- package/dist/render/template.d.ts +9 -0
- package/dist/render/template.d.ts.map +1 -0
- package/dist/render/template.js +17 -0
- package/dist/render/template.js.map +1 -0
- package/dist/render.d.ts +6 -2
- package/dist/render.d.ts.map +1 -1
- package/dist/render.js +31 -10
- package/dist/render.js.map +1 -1
- package/dist/stamp/chunk.d.ts +16 -0
- package/dist/stamp/chunk.d.ts.map +1 -0
- package/dist/stamp/chunk.js +46 -0
- package/dist/stamp/chunk.js.map +1 -0
- package/dist/stamp/config-digest.d.ts +11 -0
- package/dist/stamp/config-digest.d.ts.map +1 -0
- package/dist/stamp/config-digest.js +43 -0
- package/dist/stamp/config-digest.js.map +1 -0
- package/dist/stamp/digest.d.ts +8 -0
- package/dist/stamp/digest.d.ts.map +1 -0
- package/dist/stamp/digest.js +20 -0
- package/dist/stamp/digest.js.map +1 -0
- package/dist/stamp/index.d.ts +20 -0
- package/dist/stamp/index.d.ts.map +1 -0
- package/dist/stamp/index.js +40 -0
- package/dist/stamp/index.js.map +1 -0
- package/dist/stamp/read.d.ts +7 -0
- package/dist/stamp/read.d.ts.map +1 -0
- package/dist/stamp/read.js +62 -0
- package/dist/stamp/read.js.map +1 -0
- package/dist/stamp.d.ts +29 -0
- package/dist/stamp.d.ts.map +1 -0
- package/dist/stamp.js +198 -0
- package/dist/stamp.js.map +1 -0
- package/dist/templates/banner/badge.d.ts +7 -0
- package/dist/templates/banner/badge.d.ts.map +1 -0
- package/dist/templates/banner/badge.js +24 -0
- package/dist/templates/banner/badge.js.map +1 -0
- package/dist/templates/banner/index.d.ts +9 -0
- package/dist/templates/banner/index.d.ts.map +1 -0
- package/dist/templates/banner/index.js +66 -0
- package/dist/templates/banner/index.js.map +1 -0
- package/dist/templates/banner/lines.d.ts +27 -0
- package/dist/templates/banner/lines.d.ts.map +1 -0
- package/dist/templates/banner/lines.js +46 -0
- package/dist/templates/banner/lines.js.map +1 -0
- package/dist/templates/card/index.d.ts +7 -0
- package/dist/templates/card/index.d.ts.map +1 -0
- package/dist/templates/card/index.js +43 -0
- package/dist/templates/card/index.js.map +1 -0
- package/dist/templates/card/lines.d.ts +17 -0
- package/dist/templates/card/lines.d.ts.map +1 -0
- package/dist/templates/card/lines.js +32 -0
- package/dist/templates/card/lines.js.map +1 -0
- package/dist/templates/code/chrome.d.ts +9 -0
- package/dist/templates/code/chrome.d.ts.map +1 -0
- package/dist/templates/code/chrome.js +32 -0
- package/dist/templates/code/chrome.js.map +1 -0
- package/dist/templates/code/clip.d.ts +18 -0
- package/dist/templates/code/clip.d.ts.map +1 -0
- package/dist/templates/code/clip.js +44 -0
- package/dist/templates/code/clip.js.map +1 -0
- package/dist/templates/code/ellipsis.d.ts +3 -0
- package/dist/templates/code/ellipsis.d.ts.map +1 -0
- package/dist/templates/code/ellipsis.js +3 -0
- package/dist/templates/code/ellipsis.js.map +1 -0
- package/dist/templates/code/fit.d.ts +27 -0
- package/dist/templates/code/fit.d.ts.map +1 -0
- package/dist/templates/code/fit.js +59 -0
- package/dist/templates/code/fit.js.map +1 -0
- package/dist/templates/code/index.d.ts +12 -0
- package/dist/templates/code/index.d.ts.map +1 -0
- package/dist/templates/code/index.js +64 -0
- package/dist/templates/code/index.js.map +1 -0
- package/dist/templates/code/layout.d.ts +21 -0
- package/dist/templates/code/layout.d.ts.map +1 -0
- package/dist/templates/code/layout.js +21 -0
- package/dist/templates/code/layout.js.map +1 -0
- package/dist/templates/code/panel.d.ts +17 -0
- package/dist/templates/code/panel.d.ts.map +1 -0
- package/dist/templates/code/panel.js +20 -0
- package/dist/templates/code/panel.js.map +1 -0
- package/dist/templates/code/plate.d.ts +15 -0
- package/dist/templates/code/plate.d.ts.map +1 -0
- package/dist/templates/code/plate.js +32 -0
- package/dist/templates/code/plate.js.map +1 -0
- package/dist/templates/code/spans.d.ts +19 -0
- package/dist/templates/code/spans.d.ts.map +1 -0
- package/dist/templates/code/spans.js +36 -0
- package/dist/templates/code/spans.js.map +1 -0
- package/dist/templates/code/warn.d.ts +11 -0
- package/dist/templates/code/warn.d.ts.map +1 -0
- package/dist/templates/code/warn.js +24 -0
- package/dist/templates/code/warn.js.map +1 -0
- package/dist/templates/code.d.ts.map +1 -1
- package/dist/templates/code.js +101 -29
- package/dist/templates/code.js.map +1 -1
- package/dist/templates/footer.d.ts +21 -0
- package/dist/templates/footer.d.ts.map +1 -0
- package/dist/templates/footer.js +25 -0
- package/dist/templates/footer.js.map +1 -0
- package/dist/templates/index.d.ts +3 -3
- package/dist/templates/index.d.ts.map +1 -1
- package/dist/templates/index.js +6 -6
- package/dist/templates/index.js.map +1 -1
- package/dist/text/element.d.ts +18 -0
- package/dist/text/element.d.ts.map +1 -0
- package/dist/text/element.js +19 -0
- package/dist/text/element.js.map +1 -0
- package/dist/text/escape.d.ts +5 -0
- package/dist/text/escape.d.ts.map +1 -0
- package/dist/text/escape.js +12 -0
- package/dist/text/escape.js.map +1 -0
- package/dist/text/index.d.ts +7 -0
- package/dist/text/index.d.ts.map +1 -0
- package/dist/text/index.js +5 -0
- package/dist/text/index.js.map +1 -0
- package/dist/text/stack.d.ts +24 -0
- package/dist/text/stack.d.ts.map +1 -0
- package/dist/text/stack.js +18 -0
- package/dist/text/stack.js.map +1 -0
- package/dist/text/wrap.d.ts +12 -0
- package/dist/text/wrap.d.ts.map +1 -0
- package/dist/text/wrap.js +33 -0
- package/dist/text/wrap.js.map +1 -0
- package/dist/types.d.ts +345 -6
- package/dist/types.d.ts.map +1 -1
- package/dist/validate/check.d.ts +13 -0
- package/dist/validate/check.d.ts.map +1 -0
- package/dist/validate/check.js +34 -0
- package/dist/validate/check.js.map +1 -0
- package/dist/validate/index.d.ts +15 -0
- package/dist/validate/index.d.ts.map +1 -0
- package/dist/validate/index.js +41 -0
- package/dist/validate/index.js.map +1 -0
- package/dist/validate/keys.d.ts +58 -0
- package/dist/validate/keys.d.ts.map +1 -0
- package/dist/validate/keys.js +166 -0
- package/dist/validate/keys.js.map +1 -0
- package/dist/validate/overrides.d.ts +5 -0
- package/dist/validate/overrides.d.ts.map +1 -0
- package/dist/validate/overrides.js +43 -0
- package/dist/validate/overrides.js.map +1 -0
- package/dist/validate/placement.d.ts +10 -0
- package/dist/validate/placement.d.ts.map +1 -0
- package/dist/validate/placement.js +38 -0
- package/dist/validate/placement.js.map +1 -0
- package/dist/validate/sizes.d.ts +9 -0
- package/dist/validate/sizes.d.ts.map +1 -0
- package/dist/validate/sizes.js +27 -0
- package/dist/validate/sizes.js.map +1 -0
- package/dist/validate/suggest.d.ts +10 -0
- package/dist/validate/suggest.d.ts.map +1 -0
- package/dist/validate/suggest.js +55 -0
- package/dist/validate/suggest.js.map +1 -0
- package/dist/validate/values.d.ts +21 -0
- package/dist/validate/values.d.ts.map +1 -0
- package/dist/validate/values.js +57 -0
- package/dist/validate/values.js.map +1 -0
- package/dist/validate.d.ts +15 -0
- package/dist/validate.d.ts.map +1 -0
- package/dist/validate.js +300 -0
- package/dist/validate.js.map +1 -0
- package/package.json +14 -7
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
/**
|
|
3
|
+
* Derive a slug from a content file's path, relative to the root of the walk.
|
|
4
|
+
*
|
|
5
|
+
* `basename` gives the filename without extension, or the parent directory for
|
|
6
|
+
* `index.*` — the page-bundle convention, where an image sits beside its post.
|
|
7
|
+
* `route` keeps the directories, so a site addressed by route gets a slug that
|
|
8
|
+
* matches the address rather than just its last segment.
|
|
9
|
+
*
|
|
10
|
+
* The path must be relative to the content root for `route` to mean anything;
|
|
11
|
+
* `basename` reads the same either way.
|
|
12
|
+
*/
|
|
13
|
+
export function slugFromPath(contentPath, strategy = "basename") {
|
|
14
|
+
const extension = path.extname(contentPath);
|
|
15
|
+
const base = path.basename(contentPath, extension);
|
|
16
|
+
const directory = path.dirname(contentPath);
|
|
17
|
+
if (strategy === "basename") {
|
|
18
|
+
if (base !== "index") {
|
|
19
|
+
return base;
|
|
20
|
+
}
|
|
21
|
+
// A root-level `index.*` has no parent inside the tree to be named after,
|
|
22
|
+
// so it keeps its own name rather than borrowing the content directory's.
|
|
23
|
+
const parent = path.basename(directory);
|
|
24
|
+
return parent === "" || parent === "." ? base : parent;
|
|
25
|
+
}
|
|
26
|
+
const route = base === "index" ? directory : path.join(directory, base);
|
|
27
|
+
// `path.dirname` of a root-level file is ".", which as a route is the site
|
|
28
|
+
// root — and the one place there is no directory name to fall back on.
|
|
29
|
+
const normalised = route === "." ? "index" : route.split(path.sep).join("/");
|
|
30
|
+
return normalised;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Reject a slug that would name a file outside the tree it came from.
|
|
34
|
+
*
|
|
35
|
+
* A slug is a filename, and may carry directories under the `route` strategy —
|
|
36
|
+
* but a declared one is written by hand, and `slug: ../../../tmp/x` would have
|
|
37
|
+
* `generate` create directories and write an image there. Nothing derived from
|
|
38
|
+
* a path can look like this, so the check only ever fires on frontmatter.
|
|
39
|
+
*/
|
|
40
|
+
export function assertSlugStaysInside(slug, contentPath) {
|
|
41
|
+
// An empty segment catches a leading or doubled separator, so an absolute
|
|
42
|
+
// slug is rejected by the same pass as a traversing one.
|
|
43
|
+
const outside = new Set(["", ".", ".."]);
|
|
44
|
+
const isEscaping = slug.split(/[/\\]/).some((segment) => outside.has(segment)) ||
|
|
45
|
+
/^[A-Za-z]:/.test(slug);
|
|
46
|
+
if (isEscaping) {
|
|
47
|
+
throw new Error(`Invalid slug "${slug}" in ${contentPath}: a slug names an image inside` +
|
|
48
|
+
` the output tree, so it cannot be absolute or contain "." or ".."` +
|
|
49
|
+
` segments.`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=slug.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slug.js","sourceRoot":"","sources":["../../src/content/slug.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAI7B;;;;;;;;;;GAUG;AACH,MAAM,UAAU,YAAY,CAC1B,WAAmB,EACnB,QAAQ,GAAiB,UAAU;IAEnC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IAC5C,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;IACnD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IAE5C,IAAI,QAAQ,KAAK,UAAU,EAAE,CAAC;QAC5B,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;YACrB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,0EAA0E;QAC1E,0EAA0E;QAC1E,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;QACxC,OAAO,MAAM,KAAK,EAAE,IAAI,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;IACzD,CAAC;IAED,MAAM,KAAK,GAAG,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IACxE,2EAA2E;IAC3E,uEAAuE;IACvE,MAAM,UAAU,GAAG,KAAK,KAAK,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC7E,OAAO,UAAU,CAAC;AACpB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAAY,EAAE,WAAmB;IACrE,0EAA0E;IAC1E,yDAAyD;IACzD,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,CAAC,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC;IACzC,MAAM,UAAU,GACd,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC3D,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAE1B,IAAI,UAAU,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CACb,iBAAiB,IAAI,QAAQ,WAAW,gCAAgC;YACtE,mEAAmE;YACnE,YAAY,CACf,CAAC;IACJ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ContentFile, ContentOptions } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Options for {@link walkContent}: everything a project can say about reading
|
|
4
|
+
* its own content, plus the directory to read it from. Only `dir` is required.
|
|
5
|
+
*/
|
|
6
|
+
export interface WalkOptions extends ContentOptions {
|
|
7
|
+
/** Root directory to search recursively for content files. */
|
|
8
|
+
readonly dir: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Walk a content tree, read each file's frontmatter with `gray-matter`, and
|
|
12
|
+
* return the files that image props can be built for. This is the host-project
|
|
13
|
+
* concern — finding content and reading frontmatter — kept separate from
|
|
14
|
+
* rendering.
|
|
15
|
+
*/
|
|
16
|
+
export declare function walkContent(options: WalkOptions): Promise<ContentFile[]>;
|
|
17
|
+
//# sourceMappingURL=walk.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"walk.d.ts","sourceRoot":"","sources":["../../src/content/walk.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAQ/D;;;GAGG;AACH,MAAM,WAAW,WAAY,SAAQ,cAAc;IACjD,8DAA8D;IAC9D,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AA8BD;;;;;GAKG;AACH,wBAAsB,WAAW,CAC/B,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,WAAW,EAAE,CAAC,CAoCxB"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { readdir, readFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import matter from "gray-matter";
|
|
4
|
+
import { coerceString, extractProps } from "./props.js";
|
|
5
|
+
import { assertSlugStaysInside, slugFromPath } from "./slug.js";
|
|
6
|
+
const defaultSlugField = "slug";
|
|
7
|
+
const defaultSlugStrategy = "basename";
|
|
8
|
+
const defaultExtensions = [".md", ".markdown"];
|
|
9
|
+
async function collectContentFiles(dir, extensions) {
|
|
10
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
11
|
+
const nested = await Promise.all(entries.map(async (entry) => {
|
|
12
|
+
const entryPath = path.join(dir, entry.name);
|
|
13
|
+
if (entry.isDirectory()) {
|
|
14
|
+
return collectContentFiles(entryPath, extensions);
|
|
15
|
+
}
|
|
16
|
+
if (entry.isFile() &&
|
|
17
|
+
extensions.some((extension) => entry.name.endsWith(extension))) {
|
|
18
|
+
return [entryPath];
|
|
19
|
+
}
|
|
20
|
+
return [];
|
|
21
|
+
}));
|
|
22
|
+
return nested.flat();
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Walk a content tree, read each file's frontmatter with `gray-matter`, and
|
|
26
|
+
* return the files that image props can be built for. This is the host-project
|
|
27
|
+
* concern — finding content and reading frontmatter — kept separate from
|
|
28
|
+
* rendering.
|
|
29
|
+
*/
|
|
30
|
+
export async function walkContent(options) {
|
|
31
|
+
const extensions = options.extensions ?? defaultExtensions;
|
|
32
|
+
const filePaths = await collectContentFiles(options.dir, extensions);
|
|
33
|
+
const slugField = options.slugField ?? defaultSlugField;
|
|
34
|
+
const slugStrategy = options.slugStrategy ?? defaultSlugStrategy;
|
|
35
|
+
const files = await Promise.all(filePaths.map(async (filePath) => {
|
|
36
|
+
const raw = await readFile(filePath, "utf8");
|
|
37
|
+
const frontmatter = matter(raw).data;
|
|
38
|
+
const props = extractProps(frontmatter, options);
|
|
39
|
+
if (props === undefined) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const contentPath = path.relative(options.dir, filePath);
|
|
43
|
+
const declaredSlug = coerceString(frontmatter[slugField])?.trim();
|
|
44
|
+
const slug = declaredSlug !== undefined && declaredSlug !== ""
|
|
45
|
+
? declaredSlug
|
|
46
|
+
: slugFromPath(contentPath, slugStrategy);
|
|
47
|
+
assertSlugStaysInside(slug, contentPath);
|
|
48
|
+
return {
|
|
49
|
+
contentPath,
|
|
50
|
+
absolutePath: filePath,
|
|
51
|
+
slug,
|
|
52
|
+
props,
|
|
53
|
+
};
|
|
54
|
+
}));
|
|
55
|
+
return files.filter((file) => file !== undefined);
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=walk.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"walk.js","sourceRoot":"","sources":["../../src/content/walk.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { FontSource } from "../types.js";
|
|
2
|
+
export { fontFilePaths } from "./materialise.js";
|
|
3
|
+
export { resolveFonts } from "./resolve.js";
|
|
4
|
+
/**
|
|
5
|
+
* The family the rasteriser should fall back to when a `font-family` names
|
|
6
|
+
* something it has not loaded — the first declared family, so the fallback is
|
|
7
|
+
* the same wherever the build runs rather than whichever font loaded first.
|
|
8
|
+
*/
|
|
9
|
+
export declare function fallbackFamily(fonts: readonly FontSource[]): string | undefined;
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/fonts/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,SAAS,UAAU,EAAE,GAC3B,MAAM,GAAG,SAAS,CAEpB"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { fontFilePaths } from "./materialise.js";
|
|
2
|
+
export { resolveFonts } from "./resolve.js";
|
|
3
|
+
/**
|
|
4
|
+
* The family the rasteriser should fall back to when a `font-family` names
|
|
5
|
+
* something it has not loaded — the first declared family, so the fallback is
|
|
6
|
+
* the same wherever the build runs rather than whichever font loaded first.
|
|
7
|
+
*/
|
|
8
|
+
export function fallbackFamily(fonts) {
|
|
9
|
+
return fonts.find((font) => font.family !== undefined)?.family;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/fonts/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAC5B,KAA4B;IAE5B,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC,EAAE,MAAM,CAAC;AACjE,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { FontSource } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* File paths for the configured fonts, in order, writing any supplied as
|
|
4
|
+
* bytes to a temp file first.
|
|
5
|
+
*/
|
|
6
|
+
export declare function fontFilePaths(fonts: readonly FontSource[]): Promise<string[]>;
|
|
7
|
+
//# sourceMappingURL=materialise.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"materialise.d.ts","sourceRoot":"","sources":["../../src/fonts/materialise.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AA4C9C;;;GAGG;AACH,wBAAsB,aAAa,CACjC,KAAK,EAAE,SAAS,UAAU,EAAE,GAC3B,OAAO,CAAC,MAAM,EAAE,CAAC,CAMnB"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
4
|
+
import os from "node:os";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
/**
|
|
7
|
+
* Directory in-memory fonts are written to. The rasteriser takes file paths
|
|
8
|
+
* only, so a font supplied as bytes has to land on disk somewhere; the temp
|
|
9
|
+
* directory keeps it out of the user's project.
|
|
10
|
+
*/
|
|
11
|
+
const materialisedDir = path.join(os.tmpdir(), "colophon-fonts");
|
|
12
|
+
/**
|
|
13
|
+
* In-flight and completed writes of in-memory fonts, keyed by content hash.
|
|
14
|
+
* A build renders many images from one config, so the same bytes would
|
|
15
|
+
* otherwise be written once per image.
|
|
16
|
+
*/
|
|
17
|
+
const materialised = new Map();
|
|
18
|
+
/**
|
|
19
|
+
* Write font bytes to a temp file and return its path, reusing the file for
|
|
20
|
+
* identical bytes. The name is the content hash, so a rebuild reuses whatever
|
|
21
|
+
* an earlier run left behind and nothing has to be cleaned up.
|
|
22
|
+
*/
|
|
23
|
+
async function materialise(data) {
|
|
24
|
+
const hash = createHash("sha256").update(data).digest("hex").slice(0, 32);
|
|
25
|
+
const pending = materialised.get(hash);
|
|
26
|
+
if (pending !== undefined) {
|
|
27
|
+
return pending;
|
|
28
|
+
}
|
|
29
|
+
const write = (async () => {
|
|
30
|
+
const file = path.join(materialisedDir, `${hash}.font`);
|
|
31
|
+
if (!existsSync(file)) {
|
|
32
|
+
await mkdir(materialisedDir, { recursive: true });
|
|
33
|
+
await writeFile(file, data);
|
|
34
|
+
}
|
|
35
|
+
return file;
|
|
36
|
+
})();
|
|
37
|
+
materialised.set(hash, write);
|
|
38
|
+
return write;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* File paths for the configured fonts, in order, writing any supplied as
|
|
42
|
+
* bytes to a temp file first.
|
|
43
|
+
*/
|
|
44
|
+
export async function fontFilePaths(fonts) {
|
|
45
|
+
return Promise.all(fonts.map(async (font) => "data" in font ? materialise(font.data) : font.path));
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=materialise.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"materialise.js","sourceRoot":"","sources":["../../src/fonts/materialise.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAI7B;;;;GAIG;AACH,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,gBAAgB,CAAC,CAAC;AAEjE;;;;GAIG;AACH,MAAM,YAAY,GAAG,IAAI,GAAG,EAA2B,CAAC;AAExD;;;;GAIG;AACH,KAAK,UAAU,WAAW,CAAC,IAAgB;IACzC,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC1E,MAAM,OAAO,GAAG,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAEvC,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,MAAM,KAAK,GAAG,CAAC,KAAK,IAAqB,EAAE;QACzC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,GAAG,IAAI,OAAO,CAAC,CAAC;QAExD,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YACtB,MAAM,KAAK,CAAC,eAAe,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAClD,MAAM,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAC9B,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC,CAAC,EAAE,CAAC;IAEL,YAAY,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAC9B,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,KAA4B;IAE5B,OAAO,OAAO,CAAC,GAAG,CAChB,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CACvB,MAAM,IAAI,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CACpD,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { FontSource } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Validate the configured fonts and make their paths absolute. Safe to call
|
|
4
|
+
* with no fonts, which is the default.
|
|
5
|
+
*/
|
|
6
|
+
export declare function resolveFonts(fonts: readonly FontSource[] | undefined): readonly FontSource[];
|
|
7
|
+
//# sourceMappingURL=resolve.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/fonts/resolve.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AA0D9C;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,SAAS,UAAU,EAAE,GAAG,SAAS,GACvC,SAAS,UAAU,EAAE,CAMvB"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { existsSync, statSync } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
function label(index) {
|
|
4
|
+
return `fonts[${String(index)}]`;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Validate one font source and make its path absolute.
|
|
8
|
+
*
|
|
9
|
+
* The rasteriser ignores a font file it cannot read and renders the text in
|
|
10
|
+
* whatever else it has loaded — or, with system fonts off, renders no text at
|
|
11
|
+
* all. A typo in a path would therefore show up as a blank image rather than
|
|
12
|
+
* an error, so the path is checked here instead.
|
|
13
|
+
*/
|
|
14
|
+
function resolveFont(font, index) {
|
|
15
|
+
const source = font;
|
|
16
|
+
const hasPath = source.path !== undefined;
|
|
17
|
+
const hasData = source.data !== undefined;
|
|
18
|
+
if (hasPath && hasData) {
|
|
19
|
+
throw new Error(`${label(index)} has both "path" and "data"; give one or the other.`);
|
|
20
|
+
}
|
|
21
|
+
if (source.data !== undefined) {
|
|
22
|
+
if (source.data.byteLength === 0) {
|
|
23
|
+
throw new Error(`${label(index)} has empty font data.`);
|
|
24
|
+
}
|
|
25
|
+
return font;
|
|
26
|
+
}
|
|
27
|
+
if (source.path === undefined || source.path === "") {
|
|
28
|
+
throw new Error(`${label(index)} needs a "path" to a font file, or its bytes as "data".`);
|
|
29
|
+
}
|
|
30
|
+
const absolute = path.resolve(source.path);
|
|
31
|
+
if (!existsSync(absolute) || !statSync(absolute).isFile()) {
|
|
32
|
+
throw new Error(`${label(index)}: font file not found at ${absolute}` +
|
|
33
|
+
` (from "${source.path}"). Relative paths resolve from the working directory.`);
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
...(source.family !== undefined && { family: source.family }),
|
|
37
|
+
path: absolute,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Validate the configured fonts and make their paths absolute. Safe to call
|
|
42
|
+
* with no fonts, which is the default.
|
|
43
|
+
*/
|
|
44
|
+
export function resolveFonts(fonts) {
|
|
45
|
+
if (fonts === undefined || fonts.length === 0) {
|
|
46
|
+
return [];
|
|
47
|
+
}
|
|
48
|
+
return fonts.map((font, index) => resolveFont(font, index));
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=resolve.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../src/fonts/resolve.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,IAAI,MAAM,WAAW,CAAC;AAI7B,SAAS,KAAK,CAAC,KAAa;IAC1B,OAAO,SAAS,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC;AACnC,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,WAAW,CAAC,IAAgB,EAAE,KAAa;IAClD,MAAM,MAAM,GAAG,IAId,CAAC;IACF,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,KAAK,SAAS,CAAC;IAC1C,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,KAAK,SAAS,CAAC;IAE1C,IAAI,OAAO,IAAI,OAAO,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CACb,GAAG,KAAK,CAAC,KAAK,CAAC,qDAAqD,CACrE,CAAC;IACJ,CAAC;IAED,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC9B,IAAI,MAAM,CAAC,IAAI,CAAC,UAAU,KAAK,CAAC,EAAE,CAAC;YACjC,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC;QAC1D,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,IAAI,MAAM,CAAC,IAAI,KAAK,EAAE,EAAE,CAAC;QACpD,MAAM,IAAI,KAAK,CACb,GAAG,KAAK,CAAC,KAAK,CAAC,yDAAyD,CACzE,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAE3C,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC;QAC1D,MAAM,IAAI,KAAK,CACb,GAAG,KAAK,CAAC,KAAK,CAAC,4BAA4B,QAAQ,EAAE;YACnD,WAAW,MAAM,CAAC,IAAI,wDAAwD,CACjF,CAAC;IACJ,CAAC;IAED,OAAO;QACL,GAAG,CAAC,MAAM,CAAC,MAAM,KAAK,SAAS,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;QAC7D,IAAI,EAAE,QAAQ;KACf,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAC1B,KAAwC;IAExC,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9C,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;AAC9D,CAAC"}
|
package/dist/fonts.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { FontSource } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Validate the configured fonts and make their paths absolute. Safe to call
|
|
4
|
+
* with no fonts, which is the default.
|
|
5
|
+
*/
|
|
6
|
+
export declare function resolveFonts(fonts: readonly FontSource[] | undefined): readonly FontSource[];
|
|
7
|
+
/**
|
|
8
|
+
* File paths for the configured fonts, in order, writing any supplied as
|
|
9
|
+
* bytes to a temp file first.
|
|
10
|
+
*/
|
|
11
|
+
export declare function fontFilePaths(fonts: readonly FontSource[]): Promise<string[]>;
|
|
12
|
+
/**
|
|
13
|
+
* The family the rasteriser should fall back to when a `font-family` names
|
|
14
|
+
* something it has not loaded — the first declared family, so the fallback is
|
|
15
|
+
* the same wherever the build runs rather than whichever font loaded first.
|
|
16
|
+
*/
|
|
17
|
+
export declare function fallbackFamily(fonts: readonly FontSource[]): string | undefined;
|
|
18
|
+
//# sourceMappingURL=fonts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fonts.d.ts","sourceRoot":"","sources":["../src/fonts.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAwE7C;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,SAAS,UAAU,EAAE,GAAG,SAAS,GACvC,SAAS,UAAU,EAAE,CAMvB;AA8BD;;;GAGG;AACH,wBAAsB,aAAa,CACjC,KAAK,EAAE,SAAS,UAAU,EAAE,GAC3B,OAAO,CAAC,MAAM,EAAE,CAAC,CAMnB;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,SAAS,UAAU,EAAE,GAC3B,MAAM,GAAG,SAAS,CAEpB"}
|
package/dist/fonts.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { existsSync, statSync } from "node:fs";
|
|
3
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
4
|
+
import os from "node:os";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
/**
|
|
7
|
+
* Directory in-memory fonts are written to. The rasteriser takes file paths
|
|
8
|
+
* only, so a font supplied as bytes has to land on disk somewhere; the temp
|
|
9
|
+
* directory keeps it out of the user's project.
|
|
10
|
+
*/
|
|
11
|
+
const materialisedDir = path.join(os.tmpdir(), "colophon-fonts");
|
|
12
|
+
/**
|
|
13
|
+
* In-flight and completed writes of in-memory fonts, keyed by content hash.
|
|
14
|
+
* A build renders many images from one config, so the same bytes would
|
|
15
|
+
* otherwise be written once per image.
|
|
16
|
+
*/
|
|
17
|
+
const materialised = new Map();
|
|
18
|
+
function label(index) {
|
|
19
|
+
return `fonts[${String(index)}]`;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Validate one font source and make its path absolute.
|
|
23
|
+
*
|
|
24
|
+
* The rasteriser ignores a font file it cannot read and renders the text in
|
|
25
|
+
* whatever else it has loaded — or, with system fonts off, renders no text at
|
|
26
|
+
* all. A typo in a path would therefore show up as a blank image rather than
|
|
27
|
+
* an error, so the path is checked here instead.
|
|
28
|
+
*/
|
|
29
|
+
function resolveFont(font, index) {
|
|
30
|
+
const source = font;
|
|
31
|
+
const hasPath = source.path !== undefined;
|
|
32
|
+
const hasData = source.data !== undefined;
|
|
33
|
+
if (hasPath && hasData) {
|
|
34
|
+
throw new Error(`${label(index)} has both "path" and "data"; give one or the other.`);
|
|
35
|
+
}
|
|
36
|
+
if (source.data !== undefined) {
|
|
37
|
+
if (source.data.byteLength === 0) {
|
|
38
|
+
throw new Error(`${label(index)} has empty font data.`);
|
|
39
|
+
}
|
|
40
|
+
return font;
|
|
41
|
+
}
|
|
42
|
+
if (source.path === undefined || source.path === "") {
|
|
43
|
+
throw new Error(`${label(index)} needs a "path" to a font file, or its bytes as "data".`);
|
|
44
|
+
}
|
|
45
|
+
const absolute = path.resolve(source.path);
|
|
46
|
+
if (!existsSync(absolute) || !statSync(absolute).isFile()) {
|
|
47
|
+
throw new Error(`${label(index)}: font file not found at ${absolute}` +
|
|
48
|
+
` (from "${source.path}"). Relative paths resolve from the working directory.`);
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
...(source.family !== undefined && { family: source.family }),
|
|
52
|
+
path: absolute,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Validate the configured fonts and make their paths absolute. Safe to call
|
|
57
|
+
* with no fonts, which is the default.
|
|
58
|
+
*/
|
|
59
|
+
export function resolveFonts(fonts) {
|
|
60
|
+
if (fonts === undefined || fonts.length === 0) {
|
|
61
|
+
return [];
|
|
62
|
+
}
|
|
63
|
+
return fonts.map((font, index) => resolveFont(font, index));
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Write font bytes to a temp file and return its path, reusing the file for
|
|
67
|
+
* identical bytes. The name is the content hash, so a rebuild reuses whatever
|
|
68
|
+
* an earlier run left behind and nothing has to be cleaned up.
|
|
69
|
+
*/
|
|
70
|
+
async function materialise(data) {
|
|
71
|
+
const hash = createHash("sha256").update(data).digest("hex").slice(0, 32);
|
|
72
|
+
const pending = materialised.get(hash);
|
|
73
|
+
if (pending !== undefined) {
|
|
74
|
+
return pending;
|
|
75
|
+
}
|
|
76
|
+
const write = (async () => {
|
|
77
|
+
const file = path.join(materialisedDir, `${hash}.font`);
|
|
78
|
+
if (!existsSync(file)) {
|
|
79
|
+
await mkdir(materialisedDir, { recursive: true });
|
|
80
|
+
await writeFile(file, data);
|
|
81
|
+
}
|
|
82
|
+
return file;
|
|
83
|
+
})();
|
|
84
|
+
materialised.set(hash, write);
|
|
85
|
+
return write;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* File paths for the configured fonts, in order, writing any supplied as
|
|
89
|
+
* bytes to a temp file first.
|
|
90
|
+
*/
|
|
91
|
+
export async function fontFilePaths(fonts) {
|
|
92
|
+
return Promise.all(fonts.map(async (font) => "data" in font ? materialise(font.data) : font.path));
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* The family the rasteriser should fall back to when a `font-family` names
|
|
96
|
+
* something it has not loaded — the first declared family, so the fallback is
|
|
97
|
+
* the same wherever the build runs rather than whichever font loaded first.
|
|
98
|
+
*/
|
|
99
|
+
export function fallbackFamily(fonts) {
|
|
100
|
+
return fonts.find((font) => font.family !== undefined)?.family;
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=fonts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fonts.js","sourceRoot":"","sources":["../src/fonts.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Stamper } from "../stamp/index.js";
|
|
2
|
+
import type { ColophonConfig, ResolvedConfig } from "../types.js";
|
|
3
|
+
import type { RenderJob } from "./job.js";
|
|
4
|
+
/**
|
|
5
|
+
* The jobs for the images a config declares outright, rather than finding in
|
|
6
|
+
* the content tree.
|
|
7
|
+
*
|
|
8
|
+
* An extra image is a size like any other as far as the renderer is concerned,
|
|
9
|
+
* so it goes through `resolveConfigForSize` too and gets the same override
|
|
10
|
+
* rules rather than a second set that would have to agree with the first.
|
|
11
|
+
* Each resolves its own: there are a handful of these at most, and one
|
|
12
|
+
* carrying overrides is the normal case rather than the exception, so caching
|
|
13
|
+
* them by name the way the content jobs do would save nothing.
|
|
14
|
+
*/
|
|
15
|
+
export declare function extraJobs(config: ColophonConfig | undefined, resolved: ResolvedConfig, stamper: Stamper): RenderJob[];
|
|
16
|
+
//# sourceMappingURL=extra.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extra.d.ts","sourceRoot":"","sources":["../../src/generate/extra.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,KAAK,EAAE,cAAc,EAAc,cAAc,EAAE,MAAM,aAAa,CAAC;AAE9E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AA4B1C;;;;;;;;;;GAUG;AACH,wBAAgB,SAAS,CACvB,MAAM,EAAE,cAAc,GAAG,SAAS,EAClC,QAAQ,EAAE,cAAc,EACxB,OAAO,EAAE,OAAO,GACf,SAAS,EAAE,CA0Bb"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { SIZE_PRESETS } from "../config/defaults.js";
|
|
2
|
+
import { resolveConfigForSize } from "../config/size.js";
|
|
3
|
+
import { isRecord } from "../validate/check.js";
|
|
4
|
+
/**
|
|
5
|
+
* Reject an extra image that says too little to be rendered or written.
|
|
6
|
+
*
|
|
7
|
+
* The type requires both fields, but a CLI user's config module is plain
|
|
8
|
+
* JavaScript with nothing checking it, and neither omission fails anywhere
|
|
9
|
+
* near the config: a missing `output` surfaces as a complaint about an
|
|
10
|
+
* argument to `path`, and missing props as a property read on `undefined`.
|
|
11
|
+
* Key validation is no help either — it is the option that is not there.
|
|
12
|
+
*/
|
|
13
|
+
function checkImage(image, index) {
|
|
14
|
+
// The types say what should be here; this exists for when it is not.
|
|
15
|
+
const declared = image;
|
|
16
|
+
const label = `extra[${String(index)}]`;
|
|
17
|
+
if (typeof declared.output !== "string" || declared.output === "") {
|
|
18
|
+
throw new Error(`${label} needs an "output" path to write the image to.`);
|
|
19
|
+
}
|
|
20
|
+
if (!isRecord(declared.props)) {
|
|
21
|
+
throw new Error(`${label} needs a "props" object describing the image.`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* The jobs for the images a config declares outright, rather than finding in
|
|
26
|
+
* the content tree.
|
|
27
|
+
*
|
|
28
|
+
* An extra image is a size like any other as far as the renderer is concerned,
|
|
29
|
+
* so it goes through `resolveConfigForSize` too and gets the same override
|
|
30
|
+
* rules rather than a second set that would have to agree with the first.
|
|
31
|
+
* Each resolves its own: there are a handful of these at most, and one
|
|
32
|
+
* carrying overrides is the normal case rather than the exception, so caching
|
|
33
|
+
* them by name the way the content jobs do would save nothing.
|
|
34
|
+
*/
|
|
35
|
+
export function extraJobs(config, resolved, stamper) {
|
|
36
|
+
// `resolveSizes` never returns an empty list; the default is for the type.
|
|
37
|
+
const [firstSize = SIZE_PRESETS.og] = resolved.sizes;
|
|
38
|
+
return (config?.extra ?? []).map((image, index) => {
|
|
39
|
+
checkImage(image, index);
|
|
40
|
+
const size = image.size ?? firstSize;
|
|
41
|
+
return {
|
|
42
|
+
contentPath: undefined,
|
|
43
|
+
// Not a page, so not something the manifest can key by.
|
|
44
|
+
slug: undefined,
|
|
45
|
+
props: image.props,
|
|
46
|
+
size,
|
|
47
|
+
// Left as written rather than made absolute: the file system resolves a
|
|
48
|
+
// relative path against the working directory anyway, and the build log
|
|
49
|
+
// reads better saying what the config said.
|
|
50
|
+
outputPath: image.output,
|
|
51
|
+
// An extra names its own path, so the placement — which maps posts to
|
|
52
|
+
// paths — has nothing to say about where this one is served, nor about
|
|
53
|
+
// hashing a filename it did not choose.
|
|
54
|
+
url: undefined,
|
|
55
|
+
stamp: stamper.stamp(image.props, size),
|
|
56
|
+
config: resolveConfigForSize(config, size),
|
|
57
|
+
};
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=extra.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extra.js","sourceRoot":"","sources":["../../src/generate/extra.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAGzD,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAGhD;;;;;;;;GAQG;AACH,SAAS,UAAU,CAAC,KAAiB,EAAE,KAAa;IAClD,qEAAqE;IACrE,MAAM,QAAQ,GAAG,KAGhB,CAAC;IACF,MAAM,KAAK,GAAG,SAAS,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC;IAExC,IAAI,OAAO,QAAQ,CAAC,MAAM,KAAK,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,EAAE,EAAE,CAAC;QAClE,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,gDAAgD,CAAC,CAAC;IAC5E,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,+CAA+C,CAAC,CAAC;IAC3E,CAAC;AACH,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,SAAS,CACvB,MAAkC,EAClC,QAAwB,EACxB,OAAgB;IAEhB,2EAA2E;IAC3E,MAAM,CAAC,SAAS,GAAG,YAAY,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC;IAErD,OAAO,CAAC,MAAM,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;QAChD,UAAU,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QACzB,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,IAAI,SAAS,CAAC;QAErC,OAAO;YACL,WAAW,EAAE,SAAS;YACtB,wDAAwD;YACxD,IAAI,EAAE,SAAS;YACf,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,IAAI;YACJ,wEAAwE;YACxE,wEAAwE;YACxE,4CAA4C;YAC5C,UAAU,EAAE,KAAK,CAAC,MAAM;YACxB,sEAAsE;YACtE,uEAAuE;YACvE,wCAAwC;YACxC,GAAG,EAAE,SAAS;YACd,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC;YACvC,MAAM,EAAE,oBAAoB,CAAC,MAAM,EAAE,IAAI,CAAC;SAC3C,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { GeneratedImage, GenerateOptions } from "./options.js";
|
|
2
|
+
export { defaultOutputPath } from "./output-path.js";
|
|
3
|
+
export type { GeneratedImage, GenerateOptions } from "./options.js";
|
|
4
|
+
/**
|
|
5
|
+
* Walk a content tree and render meta images for every file that declares
|
|
6
|
+
* props, writing PNGs to disk. Images the config declares outright under
|
|
7
|
+
* `extra` are rendered by the same pass, on the same terms.
|
|
8
|
+
*
|
|
9
|
+
* Each image is stamped with a digest of the props, config and size it came
|
|
10
|
+
* from, so a rebuild renders only what has actually changed: an image whose
|
|
11
|
+
* stamp still matches is left alone, and one whose title, colours or template
|
|
12
|
+
* has moved on is rendered again. `overwrite` ignores the stamps and renders
|
|
13
|
+
* everything. Sizes with no image to render are never rasterised.
|
|
14
|
+
*
|
|
15
|
+
* Rendering runs `concurrency` images at a time rather than all of them, so a
|
|
16
|
+
* large tree does not start hundreds of rasterisations at once.
|
|
17
|
+
*/
|
|
18
|
+
export declare function generate(options: GenerateOptions): Promise<GeneratedImage[]>;
|
|
19
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/generate/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAKpE,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEpE;;;;;;;;;;;;;GAaG;AACH,wBAAsB,QAAQ,CAC5B,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,cAAc,EAAE,CAAC,CA6B3B"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { writeManifest } from "../manifest/index.js";
|
|
2
|
+
import { mapConcurrent } from "../pool.js";
|
|
3
|
+
import { readPngStamp } from "../stamp/index.js";
|
|
4
|
+
import { resolveConcurrency } from "./options.js";
|
|
5
|
+
import { planBuild } from "./plan.js";
|
|
6
|
+
import { renderImage } from "./render-image.js";
|
|
7
|
+
export { defaultOutputPath } from "./output-path.js";
|
|
8
|
+
/**
|
|
9
|
+
* Walk a content tree and render meta images for every file that declares
|
|
10
|
+
* props, writing PNGs to disk. Images the config declares outright under
|
|
11
|
+
* `extra` are rendered by the same pass, on the same terms.
|
|
12
|
+
*
|
|
13
|
+
* Each image is stamped with a digest of the props, config and size it came
|
|
14
|
+
* from, so a rebuild renders only what has actually changed: an image whose
|
|
15
|
+
* stamp still matches is left alone, and one whose title, colours or template
|
|
16
|
+
* has moved on is rendered again. `overwrite` ignores the stamps and renders
|
|
17
|
+
* everything. Sizes with no image to render are never rasterised.
|
|
18
|
+
*
|
|
19
|
+
* Rendering runs `concurrency` images at a time rather than all of them, so a
|
|
20
|
+
* large tree does not start hundreds of rasterisations at once.
|
|
21
|
+
*/
|
|
22
|
+
export async function generate(options) {
|
|
23
|
+
const concurrency = resolveConcurrency(options.concurrency);
|
|
24
|
+
const plan = await planBuild(options);
|
|
25
|
+
const results = await mapConcurrent(plan.jobs, concurrency, async (job) => {
|
|
26
|
+
const isSkipped = options.overwrite !== true &&
|
|
27
|
+
(await readPngStamp(job.outputPath)) === job.stamp;
|
|
28
|
+
if (!isSkipped) {
|
|
29
|
+
await renderImage(job, job.stamp);
|
|
30
|
+
}
|
|
31
|
+
const result = {
|
|
32
|
+
contentPath: job.contentPath,
|
|
33
|
+
size: job.size,
|
|
34
|
+
outputPath: job.outputPath,
|
|
35
|
+
url: job.url,
|
|
36
|
+
skipped: isSkipped,
|
|
37
|
+
};
|
|
38
|
+
options.onResult?.(result);
|
|
39
|
+
return result;
|
|
40
|
+
});
|
|
41
|
+
// Written last, and only once every image is on disk: a manifest naming a
|
|
42
|
+
// file that failed to render would outlive the build that failed.
|
|
43
|
+
await writeManifest(plan.manifest);
|
|
44
|
+
return results;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/generate/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAGrD;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,OAAwB;IAExB,MAAM,WAAW,GAAG,kBAAkB,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IAC5D,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,CAAC;IAEtC,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;QACxE,MAAM,SAAS,GACb,OAAO,CAAC,SAAS,KAAK,IAAI;YAC1B,CAAC,MAAM,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,KAAK,GAAG,CAAC,KAAK,CAAC;QAErD,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,MAAM,WAAW,CAAC,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC;QACpC,CAAC;QAED,MAAM,MAAM,GAAmB;YAC7B,WAAW,EAAE,GAAG,CAAC,WAAW;YAC5B,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,UAAU,EAAE,GAAG,CAAC,UAAU;YAC1B,GAAG,EAAE,GAAG,CAAC,GAAG;YACZ,OAAO,EAAE,SAAS;SACnB,CAAC;QACF,OAAO,CAAC,QAAQ,EAAE,CAAC,MAAM,CAAC,CAAC;QAC3B,OAAO,MAAM,CAAC;IAChB,CAAC,CAAC,CAAC;IAEH,0EAA0E;IAC1E,kEAAkE;IAClE,MAAM,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAEnC,OAAO,OAAO,CAAC;AACjB,CAAC"}
|