Skip to content

Commit c749868

Browse files
KianNHsdnts
authored andcommitted
[Docs Site] Add remark plugin to validate images exist (cloudflare#22820)
* [Docs Site] Add remark plugin to validate images exist * Remove relative path support
1 parent d0840ce commit c749868

File tree

2 files changed

+55
-0
lines changed

2 files changed

+55
-0
lines changed

astro.config.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import react from "@astrojs/react";
1111
import { readdir } from "fs/promises";
1212
import { fileURLToPath } from "url";
1313

14+
import remarkValidateImages from "./src/plugins/remark/validate-images";
15+
1416
import rehypeTitleFigure from "rehype-title-figure";
1517
import rehypeMermaid from "./src/plugins/rehype/mermaid.ts";
1618
import rehypeAutolinkHeadings from "./src/plugins/rehype/autolink-headings.ts";
@@ -61,6 +63,7 @@ export default defineConfig({
6163
site: "https://developers.cloudflare.com",
6264
markdown: {
6365
smartypants: false,
66+
remarkPlugins: [remarkValidateImages],
6467
rehypePlugins: [
6568
rehypeMermaid,
6669
rehypeExternalLinks,
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { existsSync } from "node:fs";
2+
import { join } from "node:path";
3+
import { visit } from "unist-util-visit";
4+
5+
import type { Node } from "unist";
6+
import type { VFile } from "vfile";
7+
8+
interface ImageNode extends Node {
9+
type: "image";
10+
url: string;
11+
position?: {
12+
start: { line: number; column: number };
13+
end: { line: number; column: number };
14+
};
15+
}
16+
17+
export default function validateImages() {
18+
const rootDir = process.cwd();
19+
20+
const assetsDir = join(rootDir, "src", "assets");
21+
const publicDir = join(rootDir, "public");
22+
23+
return (tree: Node, file: VFile) => {
24+
visit(tree, "image", (node: ImageNode) => {
25+
const { url } = node;
26+
let fullPath: string;
27+
28+
if (url.startsWith("~/assets/")) {
29+
fullPath = join(assetsDir, url.slice(9));
30+
} else if (url.startsWith("/")) {
31+
fullPath = join(publicDir, url);
32+
} else {
33+
// Remote image or unrecognised URL
34+
return;
35+
}
36+
37+
if (!existsSync(fullPath)) {
38+
const position = node.position
39+
? ` at line ${node.position.start.line}, column ${node.position.start.column}`
40+
: "";
41+
42+
const error = new Error(
43+
`Image not found: "${url}"${position} in ${file.path}\n` +
44+
`Expected to find at: ${fullPath}`,
45+
) as Error & { file?: string };
46+
47+
error.file = file.path;
48+
throw error;
49+
}
50+
});
51+
};
52+
}

0 commit comments

Comments
 (0)