@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,53 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
/**
|
|
3
|
+
* How much of an image's digest goes in its filename.
|
|
4
|
+
*
|
|
5
|
+
* Eight hex characters is what the asset pipelines settle on, and it is the
|
|
6
|
+
* length at which a site would need tens of thousands of images before two of
|
|
7
|
+
* them were likely to collide.
|
|
8
|
+
*/
|
|
9
|
+
const hashLength = 8;
|
|
10
|
+
/**
|
|
11
|
+
* The filename one image is written under: `<slug>-<size>.png`, or
|
|
12
|
+
* `<slug>-<size>.<hash>.png` where the placement asks for a hash. The slug
|
|
13
|
+
* carries the post's keywords, and the size name keeps every image of a post
|
|
14
|
+
* distinct (`my-post-og.png`, `my-post-square.png`).
|
|
15
|
+
*
|
|
16
|
+
* A slug carrying directories of its own — what the `route` strategy produces,
|
|
17
|
+
* and what a frontmatter `slug` of `docs/intro` means — puts them in the name,
|
|
18
|
+
* so the image's path mirrors the route wherever it is placed.
|
|
19
|
+
*
|
|
20
|
+
* The digest is the image's rebuild stamp: the props, the config and the size
|
|
21
|
+
* it is drawn from. Hashing the rendered bytes would be a truer name, but they
|
|
22
|
+
* are not known until the image has been rendered, and the point of the stamp
|
|
23
|
+
* is not rendering the ones that have not changed.
|
|
24
|
+
*/
|
|
25
|
+
export function imageName(file, size, hash) {
|
|
26
|
+
const stem = `${file.slug}-${size.name}`;
|
|
27
|
+
return hash === undefined
|
|
28
|
+
? `${stem}.png`
|
|
29
|
+
: `${stem}.${hash.slice(0, hashLength)}.png`;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Where an image goes relative to the content root, in URL form.
|
|
33
|
+
*
|
|
34
|
+
* Slashes rather than the platform's separator, because this is also what a
|
|
35
|
+
* URL is built from: a Windows build must not serve `posts\my-post\a.png`.
|
|
36
|
+
* The disk path is joined back up per platform by whoever places it.
|
|
37
|
+
*
|
|
38
|
+
* A slug with directories of its own is placed from the content root, so its
|
|
39
|
+
* path mirrors the route. Resolving it beside the file would repeat the
|
|
40
|
+
* directories already in the slug, putting `services/iam` under
|
|
41
|
+
* `content/services/iam/`.
|
|
42
|
+
*/
|
|
43
|
+
export function besideContent(file, size, hash) {
|
|
44
|
+
const name = imageName(file, size, hash);
|
|
45
|
+
if (file.slug.includes("/")) {
|
|
46
|
+
return name;
|
|
47
|
+
}
|
|
48
|
+
const directory = path.dirname(file.contentPath);
|
|
49
|
+
return directory === "." || directory === ""
|
|
50
|
+
? name
|
|
51
|
+
: `${directory.split(path.sep).join("/")}/${name}`;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=relative.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relative.js","sourceRoot":"","sources":["../../src/placement/relative.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAI7B;;;;;;GAMG;AACH,MAAM,UAAU,GAAG,CAAC,CAAC;AAErB;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,SAAS,CACvB,IAAiB,EACjB,IAAgB,EAChB,IAAwB;IAExB,MAAM,IAAI,GAAG,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;IAEzC,OAAO,IAAI,KAAK,SAAS;QACvB,CAAC,CAAC,GAAG,IAAI,MAAM;QACf,CAAC,CAAC,GAAG,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,MAAM,CAAC;AACjD,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,aAAa,CAC3B,IAAiB,EACjB,IAAgB,EAChB,IAAwB;IAExB,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IAEzC,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC5B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAEjD,OAAO,SAAS,KAAK,GAAG,IAAI,SAAS,KAAK,EAAE;QAC1C,CAAC,CAAC,IAAI;QACN,CAAC,CAAC,GAAG,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC;AACvD,CAAC"}
|
package/dist/pool.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Map over `items` with at most `limit` calls to `worker` in flight at once,
|
|
3
|
+
* returning the results in input order.
|
|
4
|
+
*
|
|
5
|
+
* `Promise.all` over a mapped array starts everything at once, which for a
|
|
6
|
+
* few hundred images means a few hundred rasterisations queued on the thread
|
|
7
|
+
* pool with every pending bitmap held in memory. This starts `limit` workers
|
|
8
|
+
* instead and lets each pull the next item as it finishes, so the work in
|
|
9
|
+
* flight stays bounded however large the input is.
|
|
10
|
+
*
|
|
11
|
+
* The first rejection propagates, as it would from `Promise.all`. Items
|
|
12
|
+
* already in flight run to completion — there is no cancelling a render — but
|
|
13
|
+
* no further ones are started.
|
|
14
|
+
*
|
|
15
|
+
* Throws if `limit` is not a positive integer.
|
|
16
|
+
*/
|
|
17
|
+
export declare function mapConcurrent<Item, Result>(items: readonly Item[], limit: number, worker: (item: Item, index: number) => Promise<Result>): Promise<Result[]>;
|
|
18
|
+
//# sourceMappingURL=pool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pool.d.ts","sourceRoot":"","sources":["../src/pool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,EAC9C,KAAK,EAAE,SAAS,IAAI,EAAE,EACtB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,GACrD,OAAO,CAAC,MAAM,EAAE,CAAC,CA8CnB"}
|
package/dist/pool.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Map over `items` with at most `limit` calls to `worker` in flight at once,
|
|
3
|
+
* returning the results in input order.
|
|
4
|
+
*
|
|
5
|
+
* `Promise.all` over a mapped array starts everything at once, which for a
|
|
6
|
+
* few hundred images means a few hundred rasterisations queued on the thread
|
|
7
|
+
* pool with every pending bitmap held in memory. This starts `limit` workers
|
|
8
|
+
* instead and lets each pull the next item as it finishes, so the work in
|
|
9
|
+
* flight stays bounded however large the input is.
|
|
10
|
+
*
|
|
11
|
+
* The first rejection propagates, as it would from `Promise.all`. Items
|
|
12
|
+
* already in flight run to completion — there is no cancelling a render — but
|
|
13
|
+
* no further ones are started.
|
|
14
|
+
*
|
|
15
|
+
* Throws if `limit` is not a positive integer.
|
|
16
|
+
*/
|
|
17
|
+
export async function mapConcurrent(items, limit, worker) {
|
|
18
|
+
// A limit below one starts no workers at all, and an empty `Promise.all`
|
|
19
|
+
// resolves happily — so the caller would get an empty result back as though
|
|
20
|
+
// there had been nothing to do. A build reporting success having rendered
|
|
21
|
+
// nothing is the failure worth being loud about.
|
|
22
|
+
if (!Number.isSafeInteger(limit) || limit < 1) {
|
|
23
|
+
throw new Error(`Invalid concurrency limit ${String(limit)}; expected a positive integer.`);
|
|
24
|
+
}
|
|
25
|
+
// Assigned by index rather than pushed, so results come back in input order
|
|
26
|
+
// however the workers interleave.
|
|
27
|
+
const results = [];
|
|
28
|
+
// One shared iterator is the queue: each worker pulls the next entry when it
|
|
29
|
+
// is free, so a slow item holds up only itself rather than a fixed share of
|
|
30
|
+
// the work.
|
|
31
|
+
const queue = items.entries();
|
|
32
|
+
let isStopped = false;
|
|
33
|
+
async function run() {
|
|
34
|
+
for (const [index, item] of queue) {
|
|
35
|
+
if (isStopped) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
// Awaiting in the loop is the whole point: a worker takes one item at a
|
|
39
|
+
// time, and the parallelism comes from there being several of them.
|
|
40
|
+
// eslint-disable-next-line no-await-in-loop
|
|
41
|
+
results[index] = await worker(item, index);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
const workers = Array.from({ length: Math.min(limit, items.length) }, () => run());
|
|
45
|
+
try {
|
|
46
|
+
await Promise.all(workers);
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
// The run is already lost, so stop feeding it: a build that fails on the
|
|
50
|
+
// first file should not render the rest of the tree before it exits.
|
|
51
|
+
isStopped = true;
|
|
52
|
+
throw error;
|
|
53
|
+
}
|
|
54
|
+
return results;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=pool.js.map
|
package/dist/pool.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pool.js","sourceRoot":"","sources":["../src/pool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,KAAsB,EACtB,KAAa,EACb,MAAsD;IAEtD,yEAAyE;IACzE,4EAA4E;IAC5E,0EAA0E;IAC1E,iDAAiD;IACjD,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;QAC9C,MAAM,IAAI,KAAK,CACb,6BAA6B,MAAM,CAAC,KAAK,CAAC,gCAAgC,CAC3E,CAAC;IACJ,CAAC;IAED,4EAA4E;IAC5E,kCAAkC;IAClC,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,6EAA6E;IAC7E,4EAA4E;IAC5E,YAAY;IACZ,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,EAAE,CAAC;IAC9B,IAAI,SAAS,GAAG,KAAK,CAAC;IAEtB,KAAK,UAAU,GAAG;QAChB,KAAK,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,KAAK,EAAE,CAAC;YAClC,IAAI,SAAS,EAAE,CAAC;gBACd,OAAO;YACT,CAAC;YACD,wEAAwE;YACxE,oEAAoE;YACpE,4CAA4C;YAC5C,OAAO,CAAC,KAAK,CAAC,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAC7C,CAAC;IACH,CAAC;IAED,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE,EAAE,GAAG,EAAE,CACzE,GAAG,EAAE,CACN,CAAC;IAEF,IAAI,CAAC;QACH,MAAM,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAC7B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,yEAAyE;QACzE,qEAAqE;QACrE,SAAS,GAAG,IAAI,CAAC;QACjB,MAAM,KAAK,CAAC;IACd,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ColophonConfig, MetaImageProps, RenderedMetaImage } from "../types.js";
|
|
2
|
+
export { buildSvg } from "./svg.js";
|
|
3
|
+
export { renderSvgToPng } from "./png.js";
|
|
4
|
+
/**
|
|
5
|
+
* Render an image for every configured output size from a single set of props.
|
|
6
|
+
* This is the reusable core: it takes props and config and returns rendered
|
|
7
|
+
* bytes, with no filesystem or content-discovery concerns.
|
|
8
|
+
*/
|
|
9
|
+
export declare function renderMetaImages(props: MetaImageProps, config?: ColophonConfig): Promise<RenderedMetaImage[]>;
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/render/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,cAAc,EACd,cAAc,EACd,iBAAiB,EAClB,MAAM,aAAa,CAAC;AAKrB,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACpC,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAE1C;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,cAAc,EACrB,MAAM,CAAC,EAAE,cAAc,GACtB,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAiB9B"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { resolveConfig } from "../config/index.js";
|
|
2
|
+
import { resolveConfigForSize } from "../config/size.js";
|
|
3
|
+
import { renderSvgToPng } from "./png.js";
|
|
4
|
+
import { buildSvg } from "./svg.js";
|
|
5
|
+
import { selectTemplate } from "./template.js";
|
|
6
|
+
export { buildSvg } from "./svg.js";
|
|
7
|
+
export { renderSvgToPng } from "./png.js";
|
|
8
|
+
/**
|
|
9
|
+
* Render an image for every configured output size from a single set of props.
|
|
10
|
+
* This is the reusable core: it takes props and config and returns rendered
|
|
11
|
+
* bytes, with no filesystem or content-discovery concerns.
|
|
12
|
+
*/
|
|
13
|
+
export async function renderMetaImages(props, config) {
|
|
14
|
+
const resolved = resolveConfig(config);
|
|
15
|
+
// Validate the template once up front so a bad name fails fast.
|
|
16
|
+
selectTemplate(resolved, props.template);
|
|
17
|
+
return Promise.all(resolved.sizes.map(async (size) => {
|
|
18
|
+
// Each size renders with its own overrides folded in, so one size wanting
|
|
19
|
+
// a smaller minimum font does not mean a second pass over everything.
|
|
20
|
+
const sizeConfig = resolveConfigForSize(config, size);
|
|
21
|
+
const dimensions = { width: size.width, height: size.height };
|
|
22
|
+
const svg = await buildSvg(props, sizeConfig, dimensions);
|
|
23
|
+
const png = await renderSvgToPng(svg, dimensions, sizeConfig);
|
|
24
|
+
return { name: size.name, dimensions, svg, png };
|
|
25
|
+
}));
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/render/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAMzD,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACpC,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAE/C,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACpC,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAE1C;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,KAAqB,EACrB,MAAuB;IAEvB,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;IAEvC,gEAAgE;IAChE,cAAc,CAAC,QAAQ,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;IAEzC,OAAO,OAAO,CAAC,GAAG,CAChB,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;QAChC,0EAA0E;QAC1E,sEAAsE;QACtE,MAAM,UAAU,GAAG,oBAAoB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QACtD,MAAM,UAAU,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC;QAC9D,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,KAAK,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;QAC1D,MAAM,GAAG,GAAG,MAAM,cAAc,CAAC,GAAG,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;QAC9D,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;IACnD,CAAC,CAAC,CACH,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Dimensions, ResolvedConfig } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Rasterise an SVG string to a PNG buffer, scaled to `dimensions.width`.
|
|
4
|
+
*
|
|
5
|
+
* Text is drawn with the fonts named by `config`, which is what keeps the
|
|
6
|
+
* output the same on a laptop, in CI and in a container. Height follows the
|
|
7
|
+
* SVG's own aspect ratio; `buildSvg` sizes it to match.
|
|
8
|
+
*/
|
|
9
|
+
export declare function renderSvgToPng(svg: string, dimensions: Dimensions, config?: ResolvedConfig): Promise<Buffer>;
|
|
10
|
+
//# sourceMappingURL=png.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"png.d.ts","sourceRoot":"","sources":["../../src/render/png.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAkB9D;;;;;;GAMG;AACH,wBAAsB,cAAc,CAClC,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,UAAU,EACtB,MAAM,GAAE,cAAgC,GACvC,OAAO,CAAC,MAAM,CAAC,CAOjB"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { renderAsync } from "@resvg/resvg-js";
|
|
2
|
+
import { resolveConfig } from "../config/index.js";
|
|
3
|
+
import { fallbackFamily, fontFilePaths } from "../fonts/index.js";
|
|
4
|
+
/**
|
|
5
|
+
* Font options for the rasteriser: the configured font files, and whether to
|
|
6
|
+
* fall back to the machine's own.
|
|
7
|
+
*/
|
|
8
|
+
async function fontOptions(config) {
|
|
9
|
+
const fallback = fallbackFamily(config.fonts);
|
|
10
|
+
return {
|
|
11
|
+
loadSystemFonts: config.systemFonts,
|
|
12
|
+
fontFiles: await fontFilePaths(config.fonts),
|
|
13
|
+
...(fallback !== undefined && { defaultFontFamily: fallback }),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Rasterise an SVG string to a PNG buffer, scaled to `dimensions.width`.
|
|
18
|
+
*
|
|
19
|
+
* Text is drawn with the fonts named by `config`, which is what keeps the
|
|
20
|
+
* output the same on a laptop, in CI and in a container. Height follows the
|
|
21
|
+
* SVG's own aspect ratio; `buildSvg` sizes it to match.
|
|
22
|
+
*/
|
|
23
|
+
export async function renderSvgToPng(svg, dimensions, config = resolveConfig()) {
|
|
24
|
+
const rendered = await renderAsync(svg, {
|
|
25
|
+
fitTo: { mode: "width", value: dimensions.width },
|
|
26
|
+
font: await fontOptions(config),
|
|
27
|
+
});
|
|
28
|
+
return rendered.asPng();
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=png.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"png.js","sourceRoot":"","sources":["../../src/render/png.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAE9C,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAGlE;;;GAGG;AACH,KAAK,UAAU,WAAW,CACxB,MAAsB;IAEtB,MAAM,QAAQ,GAAG,cAAc,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAE9C,OAAO;QACL,eAAe,EAAE,MAAM,CAAC,WAAW;QACnC,SAAS,EAAE,MAAM,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC;QAC5C,GAAG,CAAC,QAAQ,KAAK,SAAS,IAAI,EAAE,iBAAiB,EAAE,QAAQ,EAAE,CAAC;KAC/D,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,GAAW,EACX,UAAsB,EACtB,MAAM,GAAmB,aAAa,EAAE;IAExC,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,GAAG,EAAE;QACtC,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,CAAC,KAAK,EAAE;QACjD,IAAI,EAAE,MAAM,WAAW,CAAC,MAAM,CAAC;KAChC,CAAC,CAAC;IAEH,OAAO,QAAQ,CAAC,KAAK,EAAE,CAAC;AAC1B,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Dimensions, MetaImageProps, ResolvedConfig } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Build the complete SVG document for one image: the enclosing `<svg>` root,
|
|
4
|
+
* the config-driven background, and the template's foreground content.
|
|
5
|
+
*
|
|
6
|
+
* Asynchronous because a template may need to load resources — the `code`
|
|
7
|
+
* template fetches syntax grammars and themes on demand.
|
|
8
|
+
*/
|
|
9
|
+
export declare function buildSvg(props: MetaImageProps, config: ResolvedConfig, dimensions: Dimensions): Promise<string>;
|
|
10
|
+
//# sourceMappingURL=svg.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"svg.d.ts","sourceRoot":"","sources":["../../src/render/svg.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAK9E;;;;;;GAMG;AACH,wBAAsB,QAAQ,CAC5B,KAAK,EAAE,cAAc,EACrB,MAAM,EAAE,cAAc,EACtB,UAAU,EAAE,UAAU,GACrB,OAAO,CAAC,MAAM,CAAC,CAWjB"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { backgroundSvg } from "../background.js";
|
|
2
|
+
import { selectTemplate } from "./template.js";
|
|
3
|
+
const backgroundId = "colophon-bg";
|
|
4
|
+
/**
|
|
5
|
+
* Build the complete SVG document for one image: the enclosing `<svg>` root,
|
|
6
|
+
* the config-driven background, and the template's foreground content.
|
|
7
|
+
*
|
|
8
|
+
* Asynchronous because a template may need to load resources — the `code`
|
|
9
|
+
* template fetches syntax grammars and themes on demand.
|
|
10
|
+
*/
|
|
11
|
+
export async function buildSvg(props, config, dimensions) {
|
|
12
|
+
const template = selectTemplate(config, props.template);
|
|
13
|
+
const background = backgroundSvg(config.background, dimensions, backgroundId);
|
|
14
|
+
const body = await template.render({ props, config, dimensions });
|
|
15
|
+
const { width, height } = dimensions;
|
|
16
|
+
return (`<svg width="${String(width)}" height="${String(height)}"` +
|
|
17
|
+
` viewBox="0 0 ${String(width)} ${String(height)}"` +
|
|
18
|
+
` xmlns="http://www.w3.org/2000/svg">${background}${body}</svg>`);
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=svg.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"svg.js","sourceRoot":"","sources":["../../src/render/svg.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAE/C,MAAM,YAAY,GAAG,aAAa,CAAC;AAEnC;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,KAAqB,EACrB,MAAsB,EACtB,UAAsB;IAEtB,MAAM,QAAQ,GAAG,cAAc,CAAC,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;IACxD,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,UAAU,EAAE,UAAU,EAAE,YAAY,CAAC,CAAC;IAC9E,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC;IAClE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC;IAErC,OAAO,CACL,eAAe,MAAM,CAAC,KAAK,CAAC,aAAa,MAAM,CAAC,MAAM,CAAC,GAAG;QAC1D,iBAAiB,MAAM,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,GAAG;QACnD,uCAAuC,UAAU,GAAG,IAAI,QAAQ,CACjE,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ResolvedConfig, Template } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Look up the template a set of props asks for, failing with the names that
|
|
4
|
+
* are actually available. A template name comes from frontmatter, so getting
|
|
5
|
+
* it wrong is routine, and "unknown template" alone leaves the author guessing
|
|
6
|
+
* at what the project registered.
|
|
7
|
+
*/
|
|
8
|
+
export declare function selectTemplate(config: ResolvedConfig, name: string): Template;
|
|
9
|
+
//# sourceMappingURL=template.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"template.d.ts","sourceRoot":"","sources":["../../src/render/template.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5D;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,GAAG,QAAQ,CAa7E"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Look up the template a set of props asks for, failing with the names that
|
|
3
|
+
* are actually available. A template name comes from frontmatter, so getting
|
|
4
|
+
* it wrong is routine, and "unknown template" alone leaves the author guessing
|
|
5
|
+
* at what the project registered.
|
|
6
|
+
*/
|
|
7
|
+
export function selectTemplate(config, name) {
|
|
8
|
+
const template = config.templates[name];
|
|
9
|
+
if (template === undefined) {
|
|
10
|
+
const available = Object.keys(config.templates)
|
|
11
|
+
.toSorted((a, b) => a.localeCompare(b))
|
|
12
|
+
.join(", ");
|
|
13
|
+
throw new Error(`Unknown template "${name}". Available templates: ${available}.`);
|
|
14
|
+
}
|
|
15
|
+
return template;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=template.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"template.js","sourceRoot":"","sources":["../../src/render/template.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,MAAsB,EAAE,IAAY;IACjE,MAAM,QAAQ,GAAG,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAExC,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC;aAC5C,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;aACtC,IAAI,CAAC,IAAI,CAAC,CAAC;QACd,MAAM,IAAI,KAAK,CACb,qBAAqB,IAAI,2BAA2B,SAAS,GAAG,CACjE,CAAC;IACJ,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
package/dist/render.d.ts
CHANGED
|
@@ -8,9 +8,13 @@ import type { ColophonConfig, Dimensions, MetaImageProps, RenderedMetaImage, Res
|
|
|
8
8
|
*/
|
|
9
9
|
export declare function buildSvg(props: MetaImageProps, config: ResolvedConfig, dimensions: Dimensions): Promise<string>;
|
|
10
10
|
/**
|
|
11
|
-
* Rasterise an SVG string to a PNG buffer
|
|
11
|
+
* Rasterise an SVG string to a PNG buffer, scaled to `dimensions.width`.
|
|
12
|
+
*
|
|
13
|
+
* Text is drawn with the fonts named by `config`, which is what keeps the
|
|
14
|
+
* output the same on a laptop, in CI and in a container. Height follows the
|
|
15
|
+
* SVG's own aspect ratio; {@link buildSvg} sizes it to match.
|
|
12
16
|
*/
|
|
13
|
-
export declare function renderSvgToPng(svg: string, dimensions: Dimensions): Promise<Buffer>;
|
|
17
|
+
export declare function renderSvgToPng(svg: string, dimensions: Dimensions, config?: ResolvedConfig): Promise<Buffer>;
|
|
14
18
|
/**
|
|
15
19
|
* Render an image for every configured output size from a single set of props.
|
|
16
20
|
* This is the reusable core: it takes props and config and returns rendered
|
package/dist/render.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EACV,cAAc,EACd,UAAU,EACV,cAAc,EACd,iBAAiB,EACjB,cAAc,EAEf,MAAM,YAAY,CAAC;AAmBpB;;;;;;GAMG;AACH,wBAAsB,QAAQ,CAC5B,KAAK,EAAE,cAAc,EACrB,MAAM,EAAE,cAAc,EACtB,UAAU,EAAE,UAAU,GACrB,OAAO,CAAC,MAAM,CAAC,CAWjB;AAkBD;;;;;;GAMG;AACH,wBAAsB,cAAc,CAClC,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,UAAU,EACtB,MAAM,GAAE,cAAgC,GACvC,OAAO,CAAC,MAAM,CAAC,CAOjB;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,cAAc,EACrB,MAAM,CAAC,EAAE,cAAc,GACtB,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAiB9B"}
|
package/dist/render.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { renderAsync } from "@resvg/resvg-js";
|
|
2
2
|
import { backgroundSvg } from "./background.js";
|
|
3
|
-
import { resolveConfig } from "./config.js";
|
|
3
|
+
import { resolveConfig, resolveConfigForSize } from "./config.js";
|
|
4
|
+
import { fallbackFamily, fontFilePaths } from "./fonts.js";
|
|
4
5
|
const backgroundId = "colophon-bg";
|
|
5
6
|
function selectTemplate(config, name) {
|
|
6
7
|
const template = config.templates[name];
|
|
@@ -29,13 +30,30 @@ export async function buildSvg(props, config, dimensions) {
|
|
|
29
30
|
` xmlns="http://www.w3.org/2000/svg">${background}${body}</svg>`);
|
|
30
31
|
}
|
|
31
32
|
/**
|
|
32
|
-
*
|
|
33
|
+
* Font options for the rasteriser: the configured font files, and whether to
|
|
34
|
+
* fall back to the machine's own.
|
|
33
35
|
*/
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
.
|
|
38
|
-
.
|
|
36
|
+
async function fontOptions(config) {
|
|
37
|
+
const fallback = fallbackFamily(config.fonts);
|
|
38
|
+
return {
|
|
39
|
+
loadSystemFonts: config.systemFonts,
|
|
40
|
+
fontFiles: await fontFilePaths(config.fonts),
|
|
41
|
+
...(fallback !== undefined && { defaultFontFamily: fallback }),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Rasterise an SVG string to a PNG buffer, scaled to `dimensions.width`.
|
|
46
|
+
*
|
|
47
|
+
* Text is drawn with the fonts named by `config`, which is what keeps the
|
|
48
|
+
* output the same on a laptop, in CI and in a container. Height follows the
|
|
49
|
+
* SVG's own aspect ratio; {@link buildSvg} sizes it to match.
|
|
50
|
+
*/
|
|
51
|
+
export async function renderSvgToPng(svg, dimensions, config = resolveConfig()) {
|
|
52
|
+
const rendered = await renderAsync(svg, {
|
|
53
|
+
fitTo: { mode: "width", value: dimensions.width },
|
|
54
|
+
font: await fontOptions(config),
|
|
55
|
+
});
|
|
56
|
+
return rendered.asPng();
|
|
39
57
|
}
|
|
40
58
|
/**
|
|
41
59
|
* Render an image for every configured output size from a single set of props.
|
|
@@ -47,9 +65,12 @@ export async function renderMetaImages(props, config) {
|
|
|
47
65
|
// Validate the template once up front so a bad name fails fast.
|
|
48
66
|
selectTemplate(resolved, props.template);
|
|
49
67
|
return Promise.all(resolved.sizes.map(async (size) => {
|
|
68
|
+
// Each size renders with its own overrides folded in, so one size wanting
|
|
69
|
+
// a smaller minimum font does not mean a second pass over everything.
|
|
70
|
+
const sizeConfig = resolveConfigForSize(config, size);
|
|
50
71
|
const dimensions = { width: size.width, height: size.height };
|
|
51
|
-
const svg = await buildSvg(props,
|
|
52
|
-
const png = await renderSvgToPng(svg, dimensions);
|
|
72
|
+
const svg = await buildSvg(props, sizeConfig, dimensions);
|
|
73
|
+
const png = await renderSvgToPng(svg, dimensions, sizeConfig);
|
|
53
74
|
return { name: size.name, dimensions, svg, png };
|
|
54
75
|
}));
|
|
55
76
|
}
|
package/dist/render.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render.js","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"render.js","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PNG `tEXt` keyword the stamp is stored under. Keeping it in the image means
|
|
3
|
+
* there is no sidecar file to fall out of sync, and deleting an image deletes
|
|
4
|
+
* its stamp with it.
|
|
5
|
+
*/
|
|
6
|
+
export declare const stampKeyword = "colophon";
|
|
7
|
+
/** The eight bytes every PNG file starts with. */
|
|
8
|
+
export declare const pngSignature: Buffer<ArrayBuffer>;
|
|
9
|
+
/** Signature + the whole `IHDR` chunk: length, type, 13 bytes of data, CRC. */
|
|
10
|
+
export declare const afterHeader: number;
|
|
11
|
+
/**
|
|
12
|
+
* Return `png` with the stamp embedded as a `tEXt` chunk, inserted straight
|
|
13
|
+
* after the header so it can be read back without decoding the image.
|
|
14
|
+
*/
|
|
15
|
+
export declare function stampPng(png: Buffer, stamp: string): Buffer;
|
|
16
|
+
//# sourceMappingURL=chunk.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chunk.d.ts","sourceRoot":"","sources":["../../src/stamp/chunk.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,eAAO,MAAM,YAAY,aAAa,CAAC;AAEvC,kDAAkD;AAClD,eAAO,MAAM,YAAY,qBAEvB,CAAC;AAEH,+EAA+E;AAC/E,eAAO,MAAM,WAAW,QAAuC,CAAC;AAwBhE;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAc3D"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { crc32 } from "node:zlib";
|
|
2
|
+
/**
|
|
3
|
+
* PNG `tEXt` keyword the stamp is stored under. Keeping it in the image means
|
|
4
|
+
* there is no sidecar file to fall out of sync, and deleting an image deletes
|
|
5
|
+
* its stamp with it.
|
|
6
|
+
*/
|
|
7
|
+
export const stampKeyword = "colophon";
|
|
8
|
+
/** The eight bytes every PNG file starts with. */
|
|
9
|
+
export const pngSignature = Buffer.from([
|
|
10
|
+
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
|
|
11
|
+
]);
|
|
12
|
+
/** Signature + the whole `IHDR` chunk: length, type, 13 bytes of data, CRC. */
|
|
13
|
+
export const afterHeader = pngSignature.length + 4 + 4 + 13 + 4;
|
|
14
|
+
/**
|
|
15
|
+
* A PNG `tEXt` chunk: length, type, `keyword\0text`, CRC over type and data.
|
|
16
|
+
*/
|
|
17
|
+
function textChunk(keyword, text) {
|
|
18
|
+
const data = Buffer.concat([
|
|
19
|
+
Buffer.from(keyword, "latin1"),
|
|
20
|
+
Buffer.from([0]),
|
|
21
|
+
Buffer.from(text, "latin1"),
|
|
22
|
+
]);
|
|
23
|
+
const chunk = Buffer.alloc(4 + 4 + data.length + 4);
|
|
24
|
+
chunk.writeUInt32BE(data.length, 0);
|
|
25
|
+
chunk.write("tEXt", 4, "latin1");
|
|
26
|
+
data.copy(chunk, 8);
|
|
27
|
+
chunk.writeUInt32BE(crc32(chunk.subarray(4, 8 + data.length)), 8 + data.length);
|
|
28
|
+
return chunk;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Return `png` with the stamp embedded as a `tEXt` chunk, inserted straight
|
|
32
|
+
* after the header so it can be read back without decoding the image.
|
|
33
|
+
*/
|
|
34
|
+
export function stampPng(png, stamp) {
|
|
35
|
+
if (png.length < afterHeader ||
|
|
36
|
+
!png.subarray(0, pngSignature.length).equals(pngSignature) ||
|
|
37
|
+
png.toString("latin1", 12, 16) !== "IHDR") {
|
|
38
|
+
throw new Error("Cannot stamp: not a PNG image.");
|
|
39
|
+
}
|
|
40
|
+
return Buffer.concat([
|
|
41
|
+
png.subarray(0, afterHeader),
|
|
42
|
+
textChunk(stampKeyword, stamp),
|
|
43
|
+
png.subarray(afterHeader),
|
|
44
|
+
]);
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=chunk.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chunk.js","sourceRoot":"","sources":["../../src/stamp/chunk.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AAElC;;;;GAIG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,UAAU,CAAC;AAEvC,kDAAkD;AAClD,MAAM,CAAC,MAAM,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC;IACtC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;CAC/C,CAAC,CAAC;AAEH,+EAA+E;AAC/E,MAAM,CAAC,MAAM,WAAW,GAAG,YAAY,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;AAEhE;;GAEG;AACH,SAAS,SAAS,CAAC,OAAe,EAAE,IAAY;IAC9C,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC;QACzB,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC;QAC9B,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAChB,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC;KAC5B,CAAC,CAAC;IACH,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAEpD,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IACpC,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,QAAQ,CAAC,CAAC;IACjC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IACpB,KAAK,CAAC,aAAa,CACjB,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,EACzC,CAAC,GAAG,IAAI,CAAC,MAAM,CAChB,CAAC;IAEF,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,QAAQ,CAAC,GAAW,EAAE,KAAa;IACjD,IACE,GAAG,CAAC,MAAM,GAAG,WAAW;QACxB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC;QAC1D,GAAG,CAAC,QAAQ,CAAC,QAAQ,EAAE,EAAE,EAAE,EAAE,CAAC,KAAK,MAAM,EACzC,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IACpD,CAAC;IAED,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,WAAW,CAAC;QAC5B,SAAS,CAAC,YAAY,EAAE,KAAK,CAAC;QAC9B,GAAG,CAAC,QAAQ,CAAC,WAAW,CAAC;KAC1B,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ResolvedConfig } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Digest the config fields that affect what an image looks like.
|
|
4
|
+
*
|
|
5
|
+
* `onWarning` is left out because it cannot change a pixel. So are `sizes` and
|
|
6
|
+
* `templates`: the one size and the one template an image actually uses go into
|
|
7
|
+
* its own stamp, so adding a third size or an unrelated custom template does
|
|
8
|
+
* not invalidate everything already on disk.
|
|
9
|
+
*/
|
|
10
|
+
export declare function configDigest(config: ResolvedConfig): Promise<string>;
|
|
11
|
+
//# sourceMappingURL=config-digest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-digest.d.ts","sourceRoot":"","sources":["../../src/stamp/config-digest.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAc,cAAc,EAAE,MAAM,aAAa,CAAC;AA0B9D;;;;;;;GAOG;AACH,wBAAsB,YAAY,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAkB1E"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { sha256, stableStringify } from "./digest.js";
|
|
3
|
+
/**
|
|
4
|
+
* The installed Colophon version. The built-in templates ship in this package,
|
|
5
|
+
* so an upgrade can change what an image looks like without anything in the
|
|
6
|
+
* project changing; folding the version into the stamp makes that upgrade
|
|
7
|
+
* re-render rather than leave the old images in place.
|
|
8
|
+
*/
|
|
9
|
+
async function packageVersion() {
|
|
10
|
+
const manifest = await readFile(new URL("../../package.json", import.meta.url), "utf8");
|
|
11
|
+
return JSON.parse(manifest).version;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Digest one configured font by its contents, not its path: replacing the file
|
|
15
|
+
* at the same path changes every image drawn with it.
|
|
16
|
+
*/
|
|
17
|
+
async function fontDigest(font) {
|
|
18
|
+
const bytes = "data" in font ? font.data : await readFile(font.path);
|
|
19
|
+
return sha256(stableStringify({ family: font.family, bytes: sha256(bytes) }));
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Digest the config fields that affect what an image looks like.
|
|
23
|
+
*
|
|
24
|
+
* `onWarning` is left out because it cannot change a pixel. So are `sizes` and
|
|
25
|
+
* `templates`: the one size and the one template an image actually uses go into
|
|
26
|
+
* its own stamp, so adding a third size or an unrelated custom template does
|
|
27
|
+
* not invalidate everything already on disk.
|
|
28
|
+
*/
|
|
29
|
+
export async function configDigest(config) {
|
|
30
|
+
const fonts = await Promise.all(config.fonts.map(async (font) => fontDigest(font)));
|
|
31
|
+
return sha256(stableStringify({
|
|
32
|
+
version: await packageVersion(),
|
|
33
|
+
colors: config.colors,
|
|
34
|
+
background: config.background,
|
|
35
|
+
fonts,
|
|
36
|
+
systemFonts: config.systemFonts,
|
|
37
|
+
fontFamily: config.fontFamily,
|
|
38
|
+
footer: config.footer,
|
|
39
|
+
badge: config.badge,
|
|
40
|
+
code: config.code,
|
|
41
|
+
}));
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=config-digest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-digest.js","sourceRoot":"","sources":["../../src/stamp/config-digest.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAG5C,OAAO,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEtD;;;;;GAKG;AACH,KAAK,UAAU,cAAc;IAC3B,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAC7B,IAAI,GAAG,CAAC,oBAAoB,EAAE,OAAO,IAAI,CAAC,GAAG,CAAC,EAC9C,MAAM,CACP,CAAC;IACF,OAAQ,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAyB,CAAC,OAAO,CAAC;AAC/D,CAAC;AAED;;;GAGG;AACH,KAAK,UAAU,UAAU,CAAC,IAAgB;IACxC,MAAM,KAAK,GAAG,MAAM,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACrE,OAAO,MAAM,CAAC,eAAe,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;AAChF,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,MAAsB;IACvD,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,GAAG,CAC7B,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CACnD,CAAC;IAEF,OAAO,MAAM,CACX,eAAe,CAAC;QACd,OAAO,EAAE,MAAM,cAAc,EAAE;QAC/B,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,KAAK;QACL,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,IAAI,EAAE,MAAM,CAAC,IAAI;KAClB,CAAC,CACH,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** SHA-256 of a string or buffer, as hex. */
|
|
2
|
+
export declare function sha256(value: string | Uint8Array): string;
|
|
3
|
+
/**
|
|
4
|
+
* `JSON.stringify` with object keys sorted, so that reordering frontmatter
|
|
5
|
+
* without changing it does not look like a change.
|
|
6
|
+
*/
|
|
7
|
+
export declare function stableStringify(value: unknown): string;
|
|
8
|
+
//# sourceMappingURL=digest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"digest.d.ts","sourceRoot":"","sources":["../../src/stamp/digest.ts"],"names":[],"mappings":"AAEA,6CAA6C;AAC7C,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,GAAG,MAAM,CAEzD;AAMD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAUtD"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
/** SHA-256 of a string or buffer, as hex. */
|
|
3
|
+
export function sha256(value) {
|
|
4
|
+
return createHash("sha256").update(value).digest("hex");
|
|
5
|
+
}
|
|
6
|
+
function isRecord(value) {
|
|
7
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* `JSON.stringify` with object keys sorted, so that reordering frontmatter
|
|
11
|
+
* without changing it does not look like a change.
|
|
12
|
+
*/
|
|
13
|
+
export function stableStringify(value) {
|
|
14
|
+
return JSON.stringify(value, (_key, raw) => isRecord(raw)
|
|
15
|
+
? Object.fromEntries(Object.keys(raw)
|
|
16
|
+
.toSorted((a, b) => a.localeCompare(b))
|
|
17
|
+
.map((key) => [key, raw[key]]))
|
|
18
|
+
: raw);
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=digest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"digest.js","sourceRoot":"","sources":["../../src/stamp/digest.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,6CAA6C;AAC7C,MAAM,UAAU,MAAM,CAAC,KAA0B;IAC/C,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC1D,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,KAAc;IAC5C,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,GAAY,EAAE,EAAE,CAClD,QAAQ,CAAC,GAAG,CAAC;QACX,CAAC,CAAC,MAAM,CAAC,WAAW,CAChB,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;aACb,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;aACtC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CACjC;QACH,CAAC,CAAC,GAAG,CACR,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { MetaImageProps, OutputSize, ResolvedConfig } from "../types.js";
|
|
2
|
+
export { stampPng } from "./chunk.js";
|
|
3
|
+
export { readPngStamp } from "./read.js";
|
|
4
|
+
/**
|
|
5
|
+
* Computes stamps for the images rendered from one resolved config.
|
|
6
|
+
*/
|
|
7
|
+
export interface Stamper {
|
|
8
|
+
/**
|
|
9
|
+
* The stamp for one image: a digest of the props, the config and the size it
|
|
10
|
+
* was rendered from. Equal stamps mean re-rendering would produce the same
|
|
11
|
+
* image.
|
|
12
|
+
*/
|
|
13
|
+
stamp(props: MetaImageProps, size: OutputSize): string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Build a {@link Stamper} for a resolved config. Asynchronous because it reads
|
|
17
|
+
* the configured font files; do it once per run rather than once per image.
|
|
18
|
+
*/
|
|
19
|
+
export declare function createStamper(config: ResolvedConfig): Promise<Stamper>;
|
|
20
|
+
//# sourceMappingURL=index.d.ts.map
|