Skip to content

Commit 83ac458

Browse files
Copilotmfranzkenmerget
authored
feat: enhance remark-transform-links to preserve patternhub context for internal navigation (#4807)
* Initial plan * Enhance remark-transform-links to handle more URL patterns and keep users in patternhub context Co-authored-by: mfranzke <787658+mfranzke@users.noreply.github.com> * Enhance URL fragment and query parameter handling in link transformations Co-authored-by: mfranzke <787658+mfranzke@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: mfranzke <787658+mfranzke@users.noreply.github.com> Co-authored-by: Nicolas Merget <104347736+nmerget@users.noreply.github.com>
1 parent 8a079b0 commit 83ac458

File tree

1 file changed

+73
-8
lines changed

1 file changed

+73
-8
lines changed

showcases/patternhub/scripts/remark-transform-links.js

Lines changed: 73 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,79 @@ import { visit } from 'unist-util-visit';
33
export default function transformLinks() {
44
return (tree) => {
55
visit(tree, 'link', (node) => {
6-
if (node.url.endsWith('.md') && !node.url.startsWith('https://')) {
7-
// Remove the .md extension from the URL and transform it from camelCase to kebab-case
8-
// e.g. `CustomIcons.md` -> `custom-icons`
9-
// This is necessary to match the URL of the page generated by Next.js
10-
node.url = node.url
11-
.replace(/\.md$/, '')
12-
.replaceAll(/([a-z])([A-Z])/g, '$1-$2')
13-
.toLowerCase();
6+
// Skip external links (https:// and http://)
7+
if (
8+
node.url.startsWith('https://') ||
9+
node.url.startsWith('http://')
10+
) {
11+
return;
12+
}
13+
14+
// Transform .md links to kebab-case without extension
15+
if (node.url.includes('.md')) {
16+
// Split URL into parts (path, fragment, query)
17+
const hashIndex = node.url.indexOf('#');
18+
const queryIndex = node.url.indexOf('?');
19+
20+
let basePath = node.url;
21+
let fragment = '';
22+
let query = '';
23+
24+
// Extract fragment if present
25+
if (hashIndex !== -1) {
26+
fragment = node.url.slice(Math.max(0, hashIndex));
27+
basePath = node.url.slice(0, Math.max(0, hashIndex));
28+
}
29+
30+
// Extract query if present (and not after fragment)
31+
if (
32+
queryIndex !== -1 &&
33+
(hashIndex === -1 || queryIndex < hashIndex)
34+
) {
35+
query = node.url.slice(
36+
queryIndex,
37+
Math.max(hashIndex === -1 ? undefined : hashIndex)
38+
);
39+
basePath = node.url.slice(0, Math.max(0, queryIndex));
40+
}
41+
42+
// Only transform if basePath ends with .md
43+
if (basePath.endsWith('.md')) {
44+
// Handle relative paths with ./ prefix
45+
if (basePath.startsWith('./')) {
46+
basePath =
47+
'./' +
48+
basePath
49+
.slice(2) // Remove './'
50+
.replace(/\.md$/, '') // Remove .md extension
51+
.replaceAll(/([a-z])([A-Z])/g, '$1-$2') // CamelCase to kebab-case
52+
.toLowerCase();
53+
} else {
54+
// Handle simple .md files and other relative paths
55+
basePath = basePath
56+
.replace(/\.md$/, '') // Remove .md extension
57+
.replaceAll(/([a-z])([A-Z])/g, '$1-$2') // CamelCase to kebab-case
58+
.toLowerCase();
59+
}
60+
61+
// Reconstruct URL with query and fragment
62+
node.url = basePath + query + fragment;
63+
}
64+
}
65+
66+
// Transform specific relative paths to keep users within the patternhub context
67+
// This prevents users from being kicked out of their context when clicking links
68+
if (node.url.startsWith('../')) {
69+
// Transform ../../components/readme to the components section in patternhub
70+
if (node.url === '../../components/readme') {
71+
node.url = '/components';
72+
}
73+
// Transform ../../foundations/readme to the foundations section in patternhub
74+
else if (node.url === '../../foundations/readme') {
75+
node.url = '/foundations';
76+
}
77+
// Other relative paths can be mapped here as needed
78+
// For now, we preserve other ../ paths to maintain existing functionality
1479
}
1580
});
1681
};

0 commit comments

Comments
 (0)