Skip to content

Commit e6b3f12

Browse files
authored
Update generate-integration-doc.mjs
1 parent c2e3c37 commit e6b3f12

File tree

1 file changed

+194
-0
lines changed

1 file changed

+194
-0
lines changed
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,195 @@
1+
import fs from "node:fs";
2+
import path from "node:path";
3+
4+
function fail(msg) {
5+
console.error(msg);
6+
process.exit(1);
7+
}
8+
9+
// Parses GitHub Issue Form body: "### Field\nvalue"
10+
function parseIssueBody(body) {
11+
const re = /^###\s+(.*?)\n([\s\S]*?)(?=\n###\s+|\n?$)/gm;
12+
const out = {};
13+
let m;
14+
while ((m = re.exec(body)) !== null) {
15+
const key = m[1].trim().toLowerCase().replace(/[^a-z0-9]+/g, "_");
16+
const value = m[2].trim();
17+
out[key] = value === "_No response_" ? "" : value;
18+
}
19+
return out;
20+
}
21+
22+
function slugify(input) {
23+
const s = (input || "").trim().toLowerCase();
24+
if (!s) return "";
25+
return s
26+
.replace(/['"]/g, "")
27+
.replace(/[^a-z0-9]+/g, "-")
28+
.replace(/^-+|-+$/g, "");
29+
}
30+
31+
// Tiny templater: {{key}} and {{#key}}...{{/key}} for optional blocks
32+
function renderTemplate(tpl, data) {
33+
tpl = tpl.replace(/{{#([a-zA-Z0-9_]+)}}([\s\S]*?){{\/\1}}/g, (_, key, block) => {
34+
const v = data[key];
35+
if (!v) return "";
36+
return block.replace(/{{\s*([a-zA-Z0-9_]+)\s*}}/g, (_, k) => (data[k] ?? ""));
37+
});
38+
39+
return tpl.replace(/{{\s*([a-zA-Z0-9_]+)\s*}}/g, (_, key) => (data[key] ?? ""));
40+
}
41+
42+
function writeGithubOutput(name, value) {
43+
const outPath = process.env.GITHUB_OUTPUT;
44+
if (!outPath) return;
45+
fs.appendFileSync(outPath, `${name}=${value}\n`, "utf8");
46+
}
47+
48+
const TEMPLATE = `---
49+
title: {{title}}
50+
---
51+
52+
{{learn_about_sentence}}
53+
54+
{{overview}}
55+
56+
**Maintained by:** {{maintainedby}}
57+
58+
**Support:** {{supportcontact}}
59+
60+
---
61+
62+
## Install and Configure
63+
64+
{{installsteps}}
65+
66+
---
67+
68+
## Configuration
69+
70+
{{configurationdetails}}
71+
72+
{{#verify}}
73+
## Verify It Works
74+
75+
{{verify}}
76+
{{/verify}}
77+
78+
{{#troubleshooting}}
79+
## Troubleshooting
80+
81+
{{troubleshooting}}
82+
{{/troubleshooting}}
83+
84+
{{#include_platform_link}}
85+
---
86+
87+
For more details, check out our [Integration Platform documentation](/organization/integrations/integration-platform/).
88+
{{/include_platform_link}}
89+
`;
90+
91+
const issueBodyPath = process.argv[2];
92+
if (!issueBodyPath) fail("Usage: node scripts/generate-integration-doc.mjs <issue-body-file>");
93+
94+
const issueBody = fs.readFileSync(issueBodyPath, "utf8");
95+
const fields = parseIssueBody(issueBody);
96+
97+
/**
98+
* IMPORTANT:
99+
* These keys depend on the exact *labels* in your issue form.
100+
* If your labels match the ones below, you're good.
101+
* If not, tell me your label text and I’ll map them cleanly.
102+
*/
103+
const title = fields.integration_name || fields.title;
104+
const learn_about_sentence = fields.lead_sentence_learn_about || fields.learn_about_sentence;
105+
const overview = fields.overview;
106+
const maintainedby = fields.maintainedby || fields.maintained_by;
107+
const supportcontact = fields.supportcontact || fields.support_contact;
108+
const installsteps = fields.installsteps || fields.install_and_configure_steps || fields.install_and_configure_steps_;
109+
const configurationdetails = fields.configurationdetails || fields.configuration_details;
110+
111+
const verify = fields.verify || fields.verify_it_works;
112+
const troubleshooting = fields.troubleshooting;
113+
const include_platform_link =
114+
(fields.include_platform_link || "").toLowerCase().includes("integration platform");
115+
116+
const category = (fields.category || fields.integration_category || "other").trim() || "other";
117+
const slug = (fields.slug || "").trim() ? slugify(fields.slug) : slugify(title);
118+
119+
if (!title || !learn_about_sentence || !overview || !maintainedby || !supportcontact || !installsteps || !configurationdetails) {
120+
fail(
121+
`Missing required fields. I parsed these keys: ${Object.keys(fields).join(", ")}\n` +
122+
`Tip: field keys are derived from your issue-form labels.`
123+
);
124+
}
125+
if (!slug) fail("Could not derive a slug. Provide slug, or ensure title is non-empty.");
126+
127+
const categoryDir = path.join("docs", "organization", "integrations", category);
128+
if (!fs.existsSync(categoryDir)) {
129+
fail(`Category folder does not exist: ${categoryDir}`);
130+
}
131+
132+
// Existing structure: single file per integration in the category folder
133+
const docPath = path.join(categoryDir, `${slug}.mdx`);
134+
if (fs.existsSync(docPath)) fail(`Doc already exists: ${docPath}`);
135+
136+
const rendered = renderTemplate(TEMPLATE, {
137+
title,
138+
learn_about_sentence,
139+
overview,
140+
maintainedby,
141+
supportcontact,
142+
installsteps,
143+
configurationdetails,
144+
verify,
145+
troubleshooting,
146+
include_platform_link: include_platform_link ? "yes" : "",
147+
});
148+
149+
fs.writeFileSync(docPath, rendered, "utf8");
150+
console.log(`Wrote ${docPath}`);
151+
152+
// Update existing category index page (index.mdx preferred, fallback index.md)
153+
const indexMdx = path.join(categoryDir, "index.mdx");
154+
const indexMd = path.join(categoryDir, "index.md");
155+
const indexPath = fs.existsSync(indexMdx) ? indexMdx : (fs.existsSync(indexMd) ? indexMd : null);
156+
157+
if (!indexPath) {
158+
console.warn(`No category index found at ${indexMdx} or ${indexMd}; skipping index update.`);
159+
} else {
160+
const before = fs.readFileSync(indexPath, "utf8");
161+
162+
// Use the most common relative link style for file-based pages:
163+
// - [Title](/organization/integrations/<category>/<slug>/) sometimes works too,
164+
// but this is safe relative-in-folder for many index pages:
165+
const linkLine = `- [${title}](./${slug}/)`;
166+
167+
if (!before.includes(linkLine)) {
168+
const lines = before.split("\n");
169+
170+
// Insert after the last bullet list item "- ["
171+
let insertAt = -1;
172+
for (let i = lines.length - 1; i >= 0; i--) {
173+
if (lines[i].trim().startsWith("- [")) {
174+
insertAt = i + 1;
175+
break;
176+
}
177+
}
178+
if (insertAt === -1) {
179+
// If there wasn't a list, append a new one
180+
lines.push("", linkLine, "");
181+
} else {
182+
lines.splice(insertAt, 0, linkLine);
183+
}
184+
185+
fs.writeFileSync(indexPath, lines.join("\n"), "utf8");
186+
console.log(`Updated ${indexPath}`);
187+
} else {
188+
console.log(`Index already contains link: ${linkLine}`);
189+
}
190+
}
191+
192+
// Expose slug for branch naming in workflow
193+
writeGithubOutput("slug", slug);
194+
writeGithubOutput("category", category);
1195

0 commit comments

Comments
 (0)