mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-14 09:37:37 +02:00
feat: support reference-style linking in documents (#1048)
feat: support reference-style linking in documents
This commit is contained in:
parent
7488de266f
commit
bbf355fdc7
7 changed files with 180 additions and 14 deletions
|
@ -51,6 +51,21 @@ module.exports = {
|
||||||
previous_title: 'Document 2',
|
previous_title: 'Document 2',
|
||||||
sort: 3,
|
sort: 3,
|
||||||
},
|
},
|
||||||
|
'en-reflinks': {
|
||||||
|
id: 'en-reflinks',
|
||||||
|
title: 'Reference Links',
|
||||||
|
source: 'reflinks.md',
|
||||||
|
version: 'next',
|
||||||
|
permalink: 'docs/en/next/reflinks.html',
|
||||||
|
localized_id: 'reflinks',
|
||||||
|
language: 'en',
|
||||||
|
sidebar: 'docs',
|
||||||
|
category: 'Test 2',
|
||||||
|
previous_id: 'doc3',
|
||||||
|
previous: 'en-doc3',
|
||||||
|
previous_title: 'Document 3',
|
||||||
|
sort: 4,
|
||||||
|
},
|
||||||
'ko-doc1': {
|
'ko-doc1': {
|
||||||
id: 'ko-doc1',
|
id: 'ko-doc1',
|
||||||
title: '문서 1',
|
title: '문서 1',
|
||||||
|
|
36
v1/lib/server/__tests__/__fixtures__/reflinks.md
Normal file
36
v1/lib/server/__tests__/__fixtures__/reflinks.md
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
---
|
||||||
|
id: reflinks
|
||||||
|
title: Reference Links
|
||||||
|
---
|
||||||
|
|
||||||
|
### Existing Docs
|
||||||
|
|
||||||
|
- [doc1][doc1]
|
||||||
|
- [doc2][doc2]
|
||||||
|
|
||||||
|
### Non-existing Docs
|
||||||
|
|
||||||
|
- [hahaha][hahaha]
|
||||||
|
|
||||||
|
## Repeating Docs
|
||||||
|
|
||||||
|
- [doc1][doc1]
|
||||||
|
- [doc2][doc2]
|
||||||
|
|
||||||
|
## Do not replace this
|
||||||
|
```md
|
||||||
|
![image1][image1]
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
const doc1 = foo();
|
||||||
|
console.log("[image2][image2]");
|
||||||
|
const testStr = `![image3][image3]`;
|
||||||
|
```
|
||||||
|
|
||||||
|
[doc1]: doc1.md
|
||||||
|
[doc2]: ./doc2.md
|
||||||
|
[hahaha]: hahaha.md
|
||||||
|
[image1]: assets/image1.png
|
||||||
|
[image2]: assets/image2.jpg
|
||||||
|
[image3]: assets/image3.gif
|
|
@ -57,6 +57,42 @@ const testStr = \`\`;
|
||||||
\`\`\`"
|
\`\`\`"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`mdToHtmlify transforms reference links 1`] = `
|
||||||
|
"
|
||||||
|
### Existing Docs
|
||||||
|
|
||||||
|
- [doc1][doc1]
|
||||||
|
- [doc2][doc2]
|
||||||
|
|
||||||
|
### Non-existing Docs
|
||||||
|
|
||||||
|
- [hahaha][hahaha]
|
||||||
|
|
||||||
|
## Repeating Docs
|
||||||
|
|
||||||
|
- [doc1][doc1]
|
||||||
|
- [doc2][doc2]
|
||||||
|
|
||||||
|
## Do not replace this
|
||||||
|
\`\`\`md
|
||||||
|
![image1][image1]
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
\`\`\`js
|
||||||
|
const doc1 = foo();
|
||||||
|
console.log(\\"[image2][image2]\\");
|
||||||
|
const testStr = \`![image3][image3]\`;
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
[doc1]: /docs/en/next/doc1
|
||||||
|
[doc2]: /docs/en/next/doc2
|
||||||
|
[hahaha]: hahaha.md
|
||||||
|
[image1]: assets/image1.png
|
||||||
|
[image2]: assets/image2.jpg
|
||||||
|
[image3]: assets/image3.gif
|
||||||
|
"
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`replaceAssetsLink does not transform document without valid assets link 1`] = `
|
exports[`replaceAssetsLink does not transform document without valid assets link 1`] = `
|
||||||
"
|
"
|
||||||
### Existing Docs
|
### Existing Docs
|
||||||
|
|
|
@ -64,6 +64,24 @@ Array [
|
||||||
},
|
},
|
||||||
"type": "LINK",
|
"type": "LINK",
|
||||||
},
|
},
|
||||||
|
Object {
|
||||||
|
"item": Object {
|
||||||
|
"category": "Test 2",
|
||||||
|
"id": "en-reflinks",
|
||||||
|
"language": "en",
|
||||||
|
"localized_id": "reflinks",
|
||||||
|
"permalink": "docs/en/next/reflinks.html",
|
||||||
|
"previous": "en-doc3",
|
||||||
|
"previous_id": "doc3",
|
||||||
|
"previous_title": "Document 3",
|
||||||
|
"sidebar": "docs",
|
||||||
|
"sort": 4,
|
||||||
|
"source": "reflinks.md",
|
||||||
|
"title": "Reference Links",
|
||||||
|
"version": "next",
|
||||||
|
},
|
||||||
|
"type": "LINK",
|
||||||
|
},
|
||||||
],
|
],
|
||||||
"title": "Test 2",
|
"title": "Test 2",
|
||||||
"type": "CATEGORY",
|
"type": "CATEGORY",
|
||||||
|
|
|
@ -55,9 +55,15 @@ const doc3 = fs.readFileSync(
|
||||||
'utf8',
|
'utf8',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const refLinks = fs.readFileSync(
|
||||||
|
path.join(__dirname, '__fixtures__', 'reflinks.md'),
|
||||||
|
'utf8',
|
||||||
|
);
|
||||||
|
|
||||||
const rawContent1 = metadataUtils.extractMetadata(doc1).rawContent;
|
const rawContent1 = metadataUtils.extractMetadata(doc1).rawContent;
|
||||||
const rawContent2 = metadataUtils.extractMetadata(doc2).rawContent;
|
const rawContent2 = metadataUtils.extractMetadata(doc2).rawContent;
|
||||||
const rawContent3 = metadataUtils.extractMetadata(doc3).rawContent;
|
const rawContent3 = metadataUtils.extractMetadata(doc3).rawContent;
|
||||||
|
const rawContentRefLinks = metadataUtils.extractMetadata(refLinks).rawContent;
|
||||||
|
|
||||||
describe('mdToHtmlify', () => {
|
describe('mdToHtmlify', () => {
|
||||||
const mdToHtml = metadataUtils.mdToHtml(Metadata, '/');
|
const mdToHtml = metadataUtils.mdToHtml(Metadata, '/');
|
||||||
|
@ -105,6 +111,17 @@ describe('mdToHtmlify', () => {
|
||||||
expect(content3).toMatchSnapshot();
|
expect(content3).toMatchSnapshot();
|
||||||
expect(content3).not.toEqual(rawContent3);
|
expect(content3).not.toEqual(rawContent3);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('transforms reference links', () => {
|
||||||
|
const contentRefLinks = docs.mdToHtmlify(
|
||||||
|
rawContentRefLinks,
|
||||||
|
mdToHtml,
|
||||||
|
Metadata['en-reflinks'],
|
||||||
|
);
|
||||||
|
expect(contentRefLinks).toContain('/docs/en/next/');
|
||||||
|
expect(contentRefLinks).toMatchSnapshot();
|
||||||
|
expect(contentRefLinks).not.toEqual(rawContentRefLinks);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('getFile', () => {
|
describe('getFile', () => {
|
||||||
|
|
|
@ -48,16 +48,24 @@ function getFile(metadata) {
|
||||||
function mdToHtmlify(oldContent, mdToHtml, metadata) {
|
function mdToHtmlify(oldContent, mdToHtml, metadata) {
|
||||||
let content = oldContent;
|
let content = oldContent;
|
||||||
const mdLinks = [];
|
const mdLinks = [];
|
||||||
|
const mdReferences = [];
|
||||||
|
|
||||||
// find any links to markdown files
|
// find any inline-style links to markdown files
|
||||||
const regex = /(?:\]\()(?:\.\/)?([^'")\]\s>]+\.md)/g;
|
const linkRegex = /(?:\]\()(?:\.\/)?([^'")\]\s>]+\.md)/g;
|
||||||
let match = regex.exec(content);
|
let linkMatch = linkRegex.exec(content);
|
||||||
while (match !== null) {
|
while (linkMatch !== null) {
|
||||||
mdLinks.push(match[1]);
|
mdLinks.push(linkMatch[1]);
|
||||||
match = regex.exec(content);
|
linkMatch = linkRegex.exec(content);
|
||||||
|
}
|
||||||
|
// find any reference-style links to markdown files
|
||||||
|
const refRegex = /(?:\]:)(?:\s)?(?:\.\/|\.\.\/)?([^'")\]\s>]+\.md)/g;
|
||||||
|
let refMatch = refRegex.exec(content);
|
||||||
|
while (refMatch !== null) {
|
||||||
|
mdReferences.push(refMatch[1]);
|
||||||
|
refMatch = refRegex.exec(content);
|
||||||
}
|
}
|
||||||
|
|
||||||
// replace to their website html links
|
// replace markdown links to their website html links
|
||||||
new Set(mdLinks).forEach(mdLink => {
|
new Set(mdLinks).forEach(mdLink => {
|
||||||
let htmlLink = mdToHtml[mdLink];
|
let htmlLink = mdToHtml[mdLink];
|
||||||
if (htmlLink) {
|
if (htmlLink) {
|
||||||
|
@ -75,6 +83,25 @@ function mdToHtmlify(oldContent, mdToHtml, metadata) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// replace markdown refernces to their website html links
|
||||||
|
new Set(mdReferences).forEach(refLink => {
|
||||||
|
let htmlLink = mdToHtml[refLink];
|
||||||
|
if (htmlLink) {
|
||||||
|
htmlLink = getPath(htmlLink, siteConfig.cleanUrl);
|
||||||
|
htmlLink = htmlLink.replace('/en/', `/${metadata.language}/`);
|
||||||
|
htmlLink = htmlLink.replace(
|
||||||
|
'/VERSION/',
|
||||||
|
metadata.version && metadata.version !== env.versioning.latestVersion
|
||||||
|
? `/${metadata.version}/`
|
||||||
|
: '/',
|
||||||
|
);
|
||||||
|
content = content.replace(
|
||||||
|
new RegExp(`\\]:(?:\\s)?(\\./|\\.\\./)?${refLink}`, 'g'),
|
||||||
|
`]: ${htmlLink}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,14 +52,31 @@ module.exports = function(fileString) {
|
||||||
if (fencedBlock) return line;
|
if (fencedBlock) return line;
|
||||||
|
|
||||||
let modifiedLine = line;
|
let modifiedLine = line;
|
||||||
const mdLinks = [];
|
const inlineLinks = [];
|
||||||
const mdRegex = /(?:\]\()(?:\.\/)?([^'")\]\s>]+\.md)/g;
|
const refLinks = [];
|
||||||
let match = mdRegex.exec(content);
|
|
||||||
while (match !== null) {
|
/* Replace inline-style links e.g:
|
||||||
mdLinks.push(match[1]);
|
This is [Document 1](doc1.md) -> we replace this doc1.md with correct link
|
||||||
match = mdRegex.exec(content);
|
*/
|
||||||
|
const inlineRegex = /(?:\]\()(?:\.\/)?([^'")\]\s>]+\.md)/g;
|
||||||
|
let inlineMatch = inlineRegex.exec(content);
|
||||||
|
while (inlineMatch !== null) {
|
||||||
|
inlineLinks.push(inlineMatch[1]);
|
||||||
|
inlineMatch = inlineRegex.exec(content);
|
||||||
}
|
}
|
||||||
mdLinks.forEach(mdLink => {
|
|
||||||
|
/* Replace reference-style links e.g:
|
||||||
|
This is [Document 1][doc1].
|
||||||
|
[doc1]: doc1.md -> we replace this doc1.md with correct link
|
||||||
|
*/
|
||||||
|
const refRegex = /(?:\]:)(?:\s)?(?:\.\/|\.\.\/)?([^'")\]\s>]+\.md)/g;
|
||||||
|
let refMatch = refRegex.exec(content);
|
||||||
|
while (refMatch !== null) {
|
||||||
|
refLinks.push(refMatch[1]);
|
||||||
|
refMatch = refRegex.exec(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
[...refLinks, ...inlineLinks].forEach(mdLink => {
|
||||||
const targetSource = `${sourceDir}/${mdLink}`;
|
const targetSource = `${sourceDir}/${mdLink}`;
|
||||||
const {permalink} = sourceToMetadata[targetSource] || {};
|
const {permalink} = sourceToMetadata[targetSource] || {};
|
||||||
if (permalink) {
|
if (permalink) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue