Skip to content

Commit bf89e3a

Browse files
authored
[docs] Fix hash-only internal linking (expo#11140)
* [docs] Add a test case with hash only link * [docs] Fix hash only internal links
1 parent 677e71f commit bf89e3a

File tree

2 files changed

+29
-19
lines changed

2 files changed

+29
-19
lines changed

docs/mdx-plugins/remark-link-rewrite.js

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ const DEFAULT_OPTIONS = {
88
trailingSlash: true,
99
};
1010

11+
// This is a fallback domain, used to parse URLs. If origin matches this, its an internal link
12+
const FAKE_DOMAIN = 'https://fake.domain';
13+
1114
/**
1215
* This rewrites internal MDX links to absolute URLs from the root domain.
1316
* It's the similar behavior of GitHub MDX linking, but for Next.
@@ -30,35 +33,30 @@ module.exports = function remarkLinkRewrite(options) {
3033
const ignoredIndex = 'index' + (settings.trailingSlash ? '/' : '');
3134

3235
visit(tree, 'link', node => {
36+
// parse the url with a fallback fake domain, used to determine if it's internal or not
37+
const ref = new URL(node.url, FAKE_DOMAIN);
3338
// only rewrite internal non-url nodes
34-
if (!isFullUrl(node)) {
39+
if (ref.origin === FAKE_DOMAIN) {
40+
// if only a hash is provided, we need to calculate from the same file
41+
const oldUrl =
42+
ref.hash && ref.pathname === '/'
43+
? `${path.basename(file.history[0])}${ref.hash}`
44+
: node.url;
45+
3546
// resolve the absolute path to the linked md file (supports hashes)
36-
const absolute = path.resolve(path.dirname(file.history[0]), node.url);
47+
const absolute = path.resolve(path.dirname(file.history[0]), oldUrl);
3748
// resolve the relative path between the linked file and our pages dir (root of the website)
3849
const relative = path.relative(path.join(file.cwd, settings.pagesDir), absolute);
3950
// rewrite the URL without the `.md` extension, using trailing slash or nothing
40-
let url = relative.replace(`.${settings.extension}`, settings.trailingSlash ? '/' : '');
51+
let newUrl = relative.replace(`.${settings.extension}`, settings.trailingSlash ? '/' : '');
4152

4253
// if the url is referencing the ignored index, remove it
43-
if (url.includes(ignoredIndex)) {
44-
url = url.replace(ignoredIndex, '');
54+
if (newUrl.includes(ignoredIndex)) {
55+
newUrl = newUrl.replace(ignoredIndex, '');
4556
}
4657

47-
node.url = `/${url}`;
58+
node.url = `/${newUrl}`;
4859
}
4960
});
5061
};
5162
};
52-
53-
/**
54-
* Determine if the node contains a valid URL.
55-
*/
56-
function isFullUrl(node) {
57-
try {
58-
// eslint-disable-next-line no-new
59-
new URL(node.url);
60-
return true;
61-
} catch {
62-
return false;
63-
}
64-
}

docs/mdx-plugins/remark-link-rewrite.test.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,3 +118,15 @@ describe('from pages/versions/latest/sdk/app-auth.md', () => {
118118
expect(rewrite(file, '../../../workflow/debugging.md')).toBe('/workflow/debugging/');
119119
});
120120
});
121+
122+
describe('from pages/workflow/debugging.md', () => {
123+
const file = makeFile('workflow/debugging.md');
124+
125+
it('resolves hash only to same file', () => {
126+
expect(rewrite(file, '#some-header')).toBe('/workflow/debugging/#some-header');
127+
});
128+
129+
it('resolves hash with ./ to same file', () => {
130+
expect(rewrite(file, './#some-header')).toBe('/workflow/debugging/#some-header');
131+
});
132+
});

0 commit comments

Comments
 (0)