diff --git a/v1/lib/server/__tests__/__fixtures__/metadata.js b/v1/lib/server/__tests__/__fixtures__/metadata.js index 799694feeb70..07944047ac2b 100644 --- a/v1/lib/server/__tests__/__fixtures__/metadata.js +++ b/v1/lib/server/__tests__/__fixtures__/metadata.js @@ -51,6 +51,21 @@ module.exports = { previous_title: 'Document 2', 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': { id: 'ko-doc1', title: '문서 1', diff --git a/v1/lib/server/__tests__/__fixtures__/reflinks.md b/v1/lib/server/__tests__/__fixtures__/reflinks.md new file mode 100644 index 000000000000..1d0e8911f34f --- /dev/null +++ b/v1/lib/server/__tests__/__fixtures__/reflinks.md @@ -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 diff --git a/v1/lib/server/__tests__/__snapshots__/docs.test.js.snap b/v1/lib/server/__tests__/__snapshots__/docs.test.js.snap index cc1153c3f18a..bd7f6f9e6485 100644 --- a/v1/lib/server/__tests__/__snapshots__/docs.test.js.snap +++ b/v1/lib/server/__tests__/__snapshots__/docs.test.js.snap @@ -57,6 +57,42 @@ const testStr = \`![image3](assets/image3.gif)\`; \`\`\`" `; +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`] = ` " ### Existing Docs diff --git a/v1/lib/server/__tests__/__snapshots__/readCategories.test.js.snap b/v1/lib/server/__tests__/__snapshots__/readCategories.test.js.snap index 37480028cca7..6dea2956a49c 100644 --- a/v1/lib/server/__tests__/__snapshots__/readCategories.test.js.snap +++ b/v1/lib/server/__tests__/__snapshots__/readCategories.test.js.snap @@ -64,6 +64,24 @@ Array [ }, "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", "type": "CATEGORY", diff --git a/v1/lib/server/__tests__/docs.test.js b/v1/lib/server/__tests__/docs.test.js index 63e156963192..38d2664273a2 100644 --- a/v1/lib/server/__tests__/docs.test.js +++ b/v1/lib/server/__tests__/docs.test.js @@ -55,9 +55,15 @@ const doc3 = fs.readFileSync( 'utf8', ); +const refLinks = fs.readFileSync( + path.join(__dirname, '__fixtures__', 'reflinks.md'), + 'utf8', +); + const rawContent1 = metadataUtils.extractMetadata(doc1).rawContent; const rawContent2 = metadataUtils.extractMetadata(doc2).rawContent; const rawContent3 = metadataUtils.extractMetadata(doc3).rawContent; +const rawContentRefLinks = metadataUtils.extractMetadata(refLinks).rawContent; describe('mdToHtmlify', () => { const mdToHtml = metadataUtils.mdToHtml(Metadata, '/'); @@ -105,6 +111,17 @@ describe('mdToHtmlify', () => { expect(content3).toMatchSnapshot(); 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', () => { diff --git a/v1/lib/server/docs.js b/v1/lib/server/docs.js index dc650f3c1231..dae6b301c63f 100644 --- a/v1/lib/server/docs.js +++ b/v1/lib/server/docs.js @@ -48,16 +48,24 @@ function getFile(metadata) { function mdToHtmlify(oldContent, mdToHtml, metadata) { let content = oldContent; const mdLinks = []; + const mdReferences = []; - // find any links to markdown files - const regex = /(?:\]\()(?:\.\/)?([^'")\]\s>]+\.md)/g; - let match = regex.exec(content); - while (match !== null) { - mdLinks.push(match[1]); - match = regex.exec(content); + // find any inline-style links to markdown files + const linkRegex = /(?:\]\()(?:\.\/)?([^'")\]\s>]+\.md)/g; + let linkMatch = linkRegex.exec(content); + while (linkMatch !== null) { + mdLinks.push(linkMatch[1]); + 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 => { let htmlLink = mdToHtml[mdLink]; 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; } diff --git a/v2/lib/webpack/loader/markdown.js b/v2/lib/webpack/loader/markdown.js index df5df6489bf1..5097439e9add 100644 --- a/v2/lib/webpack/loader/markdown.js +++ b/v2/lib/webpack/loader/markdown.js @@ -52,14 +52,31 @@ module.exports = function(fileString) { if (fencedBlock) return line; let modifiedLine = line; - const mdLinks = []; - const mdRegex = /(?:\]\()(?:\.\/)?([^'")\]\s>]+\.md)/g; - let match = mdRegex.exec(content); - while (match !== null) { - mdLinks.push(match[1]); - match = mdRegex.exec(content); + const inlineLinks = []; + const refLinks = []; + + /* Replace inline-style links e.g: + This is [Document 1](doc1.md) -> we replace this doc1.md with correct link + */ + const inlineRegex = /(?:\]\()(?:\.\/)?([^'")\]\s>]+\.md)/g; + let inlineMatch = inlineRegex.exec(content); + while (inlineMatch !== null) { + inlineLinks.push(inlineMatch[1]); + inlineMatch = inlineRegex.exec(content); + } + + /* 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); } - mdLinks.forEach(mdLink => { + + [...refLinks, ...inlineLinks].forEach(mdLink => { const targetSource = `${sourceDir}/${mdLink}`; const {permalink} = sourceToMetadata[targetSource] || {}; if (permalink) {