






















@@ -0,0 +1,49 @@
1+import fs from "node:fs";
2+import path from "node:path";
3+import JSON5 from "json5";
4+import { describe, expect, it } from "vitest";
5+6+const PLUGIN_DOCS_DIR = path.join(process.cwd(), "docs", "plugins");
7+8+function lineNumberAt(source: string, index: number): number {
9+return source.slice(0, index).split("\n").length;
10+}
11+12+function listMarkdownFiles(dir: string): string[] {
13+const files: string[] = [];
14+for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
15+const entryPath = path.join(dir, entry.name);
16+if (entry.isDirectory()) {
17+files.push(...listMarkdownFiles(entryPath));
18+} else if (entry.isFile() && entry.name.endsWith(".md")) {
19+files.push(entryPath);
20+}
21+}
22+return files;
23+}
24+25+describe("plugin docs examples", () => {
26+it("keeps plugin docs JSON fences parseable", () => {
27+const failures: string[] = [];
28+for (const docPath of listMarkdownFiles(PLUGIN_DOCS_DIR)) {
29+const markdown = fs.readFileSync(docPath, "utf8");
30+const blocks = markdown.matchAll(/```(json5|json)\n([\s\S]*?)```/g);
31+for (const match of blocks) {
32+const lang = match[1] ?? "";
33+const code = match[2] ?? "";
34+const relativePath = path.relative(process.cwd(), docPath).split(path.sep).join("/");
35+const location = `${relativePath}:${lineNumberAt(markdown, match.index ?? 0)}`;
36+try {
37+if (lang === "json") {
38+JSON.parse(code);
39+} else {
40+JSON5.parse(code);
41+}
42+} catch (error) {
43+failures.push(`${location} ${lang.toUpperCase()} parse failed: ${String(error)}`);
44+}
45+}
46+}
47+expect(failures).toEqual([]);
48+});
49+});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。