Skip to content

Commit 72ac059

Browse files
Update render-mermaid-from-readme.mjs
1 parent 82708d2 commit 72ac059

1 file changed

Lines changed: 52 additions & 36 deletions

File tree

scripts/render-mermaid-from-readme.mjs

Lines changed: 52 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -18,28 +18,41 @@ if (!fs.existsSync(readmePath)) die("README.md not found");
1818

1919
const readme = fs.readFileSync(readmePath, "utf8");
2020

21-
// Find the Mermaid block inside the "## Architecture" section.
22-
function extractArchitectureMermaid(md) {
23-
const sectionRe = /(^##\s+Architecture\s*$)([\s\S]*?)(?=^\s*##\s+|\s*$)/m;
24-
const sectionMatch = md.match(sectionRe);
25-
if (!sectionMatch) return null;
26-
27-
const sectionBody = sectionMatch[2];
28-
29-
const mermaidRe = /```mermaid\s*\n([\s\S]*?)\n```/m;
30-
const mermaidMatch = sectionBody.match(mermaidRe);
31-
if (!mermaidMatch) return null;
32-
33-
return {
34-
sectionHeader: sectionMatch[1],
35-
sectionBody,
36-
mermaidBody: mermaidMatch[1].trimEnd(),
37-
};
21+
// CRLF-safe helpers
22+
const NL = String.raw`\r?\n`;
23+
24+
function getArchitectureSection(md) {
25+
// Capture "## Architecture" section until next "## " heading or EOF
26+
const sectionRe = new RegExp(
27+
String.raw`(^##\s+Architecture\s*$)([\s\S]*?)(?=^\s*##\s+|\s*$)`,
28+
"m"
29+
);
30+
const m = md.match(sectionRe);
31+
if (!m) return null;
32+
return { header: m[1], body: m[2], fullMatch: m[0] };
3833
}
3934

40-
const arch = extractArchitectureMermaid(readme);
35+
function getFirstMermaidBlock(text) {
36+
// CRLF-safe fenced block capture
37+
const mermaidRe = new RegExp(
38+
String.raw"```mermaid\\s*" + NL + String.raw"([\\s\\S]*?)" + NL + String.raw"```",
39+
"m"
40+
);
41+
const m = text.match(mermaidRe);
42+
if (!m) return null;
43+
return m[1].trimEnd();
44+
}
45+
46+
const arch = getArchitectureSection(readme);
4147

4248
if (!arch) {
49+
console.log('No "## Architecture" section found in README.md. Nothing to do.');
50+
process.exit(0);
51+
}
52+
53+
const mermaidBody = getFirstMermaidBlock(arch.body);
54+
55+
if (!mermaidBody) {
4356
console.log('No Mermaid block found under "## Architecture". Nothing to do.');
4457
process.exit(0);
4558
}
@@ -50,14 +63,14 @@ fs.mkdirSync(docsDir, { recursive: true });
5063
const mmdFile = path.join(docsDir, "architecture.mmd");
5164
const svgFile = path.join(docsDir, "architecture.svg");
5265

53-
fs.writeFileSync(mmdFile, arch.mermaidBody + "\n", "utf8");
66+
fs.writeFileSync(mmdFile, mermaidBody + "\n", "utf8");
5467

5568
// Render using mermaid-cli (mmdc)
5669
run("mmdc", ["-i", mmdFile, "-o", svgFile, "-b", "transparent"]);
5770

5871
console.log("Rendered docs/architecture.svg");
5972

60-
// Raw GitHub URL so PyPI can render the image
73+
// Use raw GitHub URL so PyPI can load the image
6174
const imgUrl = "https://raw.githubusercontent.com/marcostfermin/GeoFabric/main/docs/architecture.svg";
6275

6376
const replacement =
@@ -70,30 +83,33 @@ const replacement =
7083
"<summary>Mermaid source</summary>",
7184
"",
7285
"```mermaid",
73-
arch.mermaidBody.trimEnd(),
86+
mermaidBody.trimEnd(),
7487
"```",
7588
"",
7689
"</details>",
7790
""
7891
].join("\n");
7992

80-
// Rewrite only the Mermaid block inside the Architecture section
81-
const sectionRe = /(^##\s+Architecture\s*$)([\s\S]*?)(?=^\s*##\s+|\s*$)/m;
82-
const rewritten = readme.replace(sectionRe, (full, headerLine, body) => {
83-
const mermaidRe = /```mermaid\s*\n[\s\S]*?\n```/m;
93+
// Replace the first Mermaid fenced block inside the Architecture section (CRLF-safe)
94+
const mermaidBlockRe = new RegExp(
95+
String.raw"```mermaid\\s*" + NL + String.raw"[\\s\\S]*?" + NL + String.raw"```",
96+
"m"
97+
);
98+
99+
const alreadyRendered = arch.body.includes(imgUrl) && arch.body.includes("<details>") && arch.body.includes("Mermaid source");
84100

85-
// Idempotency: don't churn commits if already rendered
86-
const alreadyHasImg = body.includes(imgUrl);
87-
const alreadyHasDetails = body.includes("<details>") && body.includes("Mermaid source");
88-
if (alreadyHasImg && alreadyHasDetails) return full;
101+
let rewritten = readme;
89102

90-
const newBody = body.replace(mermaidRe, replacement);
91-
return `${headerLine}${newBody}`;
92-
});
103+
if (!alreadyRendered) {
104+
const newArchBody = arch.body.replace(mermaidBlockRe, replacement);
105+
rewritten = readme.replace(arch.fullMatch, `${arch.header}${newArchBody}`);
93106

94-
if (rewritten !== readme) {
95-
fs.writeFileSync(readmePath, rewritten, "utf8");
96-
console.log('Updated README.md (Architecture section now uses rendered SVG and keeps Mermaid source).');
107+
if (rewritten !== readme) {
108+
fs.writeFileSync(readmePath, rewritten, "utf8");
109+
console.log("Updated README.md (Architecture now uses rendered SVG + keeps Mermaid source).");
110+
} else {
111+
console.log("README.md not modified (replacement did not apply).");
112+
}
97113
} else {
98-
console.log("README.md already up to date. No changes made.");
114+
console.log("README.md already contains rendered diagram markup. No rewrite needed.");
99115
}

0 commit comments

Comments
 (0)