Skip to content

Commit 984605c

Browse files
rashadismLakshanSS
authored andcommitted
refactor(markdown-export): generalize _constants.mdx parsing for arbitrary exports
`loadConstants` only knew the four `versions.*` keys, so any other `export const` block in `_constants.mdx` (e.g. `defaultCredentials`) slipped through the substitution pipeline and surfaced verbatim in the exported `.md`, like `<code>{defaultCredentials.username}</code>`. The parser now walks every `export const X = { ... }` block and extracts its string-valued properties into a nested map. A single `replaceConstantInterpolations` helper covers `{X.key}` and `${X.key}` patterns uniformly, replacing the version-specific code in `processCodeBlocks`, `replaceVersionInterpolations`, and `processLinks`. Adding a new constant to `_constants.mdx` now requires no plugin change. Signed-off-by: Rashad Sirajudeen <rashad@wso2.com>
1 parent d545a7f commit 984605c

1 file changed

Lines changed: 30 additions & 41 deletions

File tree

plugins/docusaurus-plugin-markdown-export/mdxProcessor.js

Lines changed: 30 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -4,33 +4,41 @@ const fs = require('fs');
44
* Load constants from _constants.mdx file
55
*/
66
async function loadConstants(constantsPath) {
7-
if (!fs.existsSync(constantsPath)) {
8-
return {};
9-
}
7+
if (!fs.existsSync(constantsPath)) return {};
108

119
const content = fs.readFileSync(constantsPath, 'utf-8');
12-
13-
// Parse the exported versions object
14-
const match = content.match(/export\s+const\s+versions\s*=\s*\{([^}]+)\}/s);
15-
if (!match) return {};
16-
17-
const versionsBlock = match[1];
1810
const constants = {};
1911

20-
// Extract key-value pairs
21-
const dockerTag = versionsBlock.match(/dockerTag:\s*['"]([^'"]+)['"]/);
22-
const githubRef = versionsBlock.match(/githubRef:\s*['"]([^'"]+)['"]/);
23-
const helmChart = versionsBlock.match(/helmChart:\s*['"]([^'"]+)['"]/);
24-
const helmSource = versionsBlock.match(/helmSource:\s*['"]([^'"]+)['"]/);
25-
26-
if (dockerTag) constants.dockerTag = dockerTag[1];
27-
if (githubRef) constants.githubRef = githubRef[1];
28-
if (helmChart) constants.helmChart = helmChart[1];
29-
if (helmSource) constants.helmSource = helmSource[1];
12+
const blockRegex = /export\s+const\s+(\w+)\s*=\s*\{([^}]+)\}/gs;
13+
let block;
14+
while ((block = blockRegex.exec(content)) !== null) {
15+
const [, name, body] = block;
16+
const obj = {};
17+
const propRegex = /(\w+):\s*['"]([^'"]+)['"]/g;
18+
let prop;
19+
while ((prop = propRegex.exec(body)) !== null) {
20+
obj[prop[1]] = prop[2];
21+
}
22+
if (Object.keys(obj).length > 0) constants[name] = obj;
23+
}
3024

3125
return constants;
3226
}
3327

28+
function replaceConstantInterpolations(content, constants) {
29+
let result = content;
30+
for (const [name, obj] of Object.entries(constants)) {
31+
if (!obj || typeof obj !== 'object') continue;
32+
for (const [key, value] of Object.entries(obj)) {
33+
const pattern = new RegExp(`\\$?\\{${name}\\.${key}\\}`, 'g');
34+
// Function replacer avoids `$&` / `$1` / etc. being treated as
35+
// backreferences if a constant value happens to contain `$`.
36+
result = result.replace(pattern, () => String(value));
37+
}
38+
}
39+
return result;
40+
}
41+
3442
/**
3543
* Process MDX content and convert to clean markdown.
3644
*
@@ -128,11 +136,7 @@ function processCodeBlocks(content, constants) {
128136
// Handle template literals with version interpolation
129137
code = code.replace(/\{`([\s\S]*?)`\}/g, '$1');
130138

131-
// Replace version placeholders in template literal syntax
132-
code = code.replace(/\$\{versions\.dockerTag\}/g, constants.dockerTag || 'latest');
133-
code = code.replace(/\$\{versions\.githubRef\}/g, constants.githubRef || 'main');
134-
code = code.replace(/\$\{versions\.helmChart\}/g, constants.helmChart || '');
135-
code = code.replace(/\$\{versions\.helmSource\}/g, constants.helmSource || '');
139+
code = replaceConstantInterpolations(code, constants);
136140

137141
// Clean up the code
138142
code = code.trim();
@@ -187,17 +191,7 @@ function processContentSections(content) {
187191
}
188192

189193
function replaceVersionInterpolations(content, constants) {
190-
let result = content;
191-
192-
// Match both `{versions.x}` (JSX interpolation in body text) and
193-
// `${versions.x}` (template-literal interpolation inside JSX attributes).
194-
// Without `\$?`, the `$` from `${...}` is left orphaned in the output.
195-
result = result.replace(/\$?\{versions\.dockerTag\}/g, constants.dockerTag || 'latest');
196-
result = result.replace(/\$?\{versions\.githubRef\}/g, constants.githubRef || 'main');
197-
result = result.replace(/\$?\{versions\.helmChart\}/g, constants.helmChart || '');
198-
result = result.replace(/\$?\{versions\.helmSource\}/g, constants.helmSource || '');
199-
200-
return result;
194+
return replaceConstantInterpolations(content, constants);
201195
}
202196

203197
function processImageTags(content) {
@@ -233,12 +227,7 @@ function processLinks(content, constants) {
233227
// Convert <Link to={`...`}>text</Link> to markdown links (template literals)
234228
result = result.replace(
235229
/<Link\s+to=\{`([^`]+)`\}>([^<]+)<\/Link>/g,
236-
(match, url, text) => {
237-
let resolvedUrl = url;
238-
resolvedUrl = resolvedUrl.replace(/\$\{versions\.githubRef\}/g, constants.githubRef || 'main');
239-
resolvedUrl = resolvedUrl.replace(/\$\{versions\.dockerTag\}/g, constants.dockerTag || 'latest');
240-
return `[${text}](${resolvedUrl})`;
241-
}
230+
(match, url, text) => `[${text}](${replaceConstantInterpolations(url, constants)})`
242231
);
243232

244233
// Convert <Link to="...">text</Link> to markdown links (static strings)

0 commit comments

Comments
 (0)