test(v2): add tests for docs markdown link replacement (#1944)

* refactor(v2): simplify & add tests for docs markdown link replacement

* nits
This commit is contained in:
Endi 2019-11-06 22:54:37 +07:00 committed by Yangshun Tay
parent 3048942aef
commit feb804cb83
9 changed files with 248 additions and 52 deletions

View file

@ -285,7 +285,6 @@ export default function pluginContentDocs(
{ {
loader: path.resolve(__dirname, './markdown/index.js'), loader: path.resolve(__dirname, './markdown/index.js'),
options: { options: {
siteConfig: context.siteConfig,
siteDir: context.siteDir, siteDir: context.siteDir,
docsDir: contentPath, docsDir: contentPath,
sourceToPermalink: sourceToPermalink, sourceToPermalink: sourceToPermalink,

View file

@ -0,0 +1,11 @@
# Don't transform any link here
![image1](assets/image1.png)
# Don't replace inside fenced codeblock
```md
![doc4](doc4.md)
```
### Non-existing Docs
- [hahaha](hahaha.md)

View file

@ -0,0 +1,10 @@
### Existing Docs
- [doc1](doc1.md)
- [doc2](./doc2.md)
- [doc3](subdir/doc3.md)
## Repeating Docs
- [doc1](doc1.md)
- [doc2](./doc2.md)

View file

@ -0,0 +1,18 @@
### Existing Docs
- [doc1][doc1]
- [doc2][doc2]
## Repeating Docs
- [doc1][doc1]
- [doc2][doc2]
## Do not replace this
```md
![image1][image1]
```
[doc1]: doc1.md
[doc2]: ./doc2.md
[image1]: assets/image1.png

View file

@ -0,0 +1,2 @@
### Relative linking
- [doc1](../doc2.md)

View file

@ -0,0 +1,57 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`transform nothing 1`] = `
"# Don't transform any link here
![image1](assets/image1.png)
# Don't replace inside fenced codeblock
\`\`\`md
![doc4](doc4.md)
\`\`\`
### Non-existing Docs
- [hahaha](hahaha.md)
"
`;
exports[`transform relative links 1`] = `
"### Relative linking
- [doc1](/docs/doc2)
"
`;
exports[`transform to correct links 1`] = `
"### Existing Docs
- [doc1](/docs/doc1)
- [doc2](/docs/doc2)
- [doc3](/docs/subdir/doc3)
## Repeating Docs
- [doc1](/docs/doc1)
- [doc2](/docs/doc2)"
`;
exports[`transforms reference links 1`] = `
"### Existing Docs
- [doc1][doc1]
- [doc2][doc2]
## Repeating Docs
- [doc1][doc1]
- [doc2][doc2]
## Do not replace this
\`\`\`md
![image1][image1]
\`\`\`
[doc1]: /docs/doc1
[doc2]: /docs/doc2
[image1]: assets/image1.png
"
`;

View file

@ -0,0 +1,72 @@
/**
* Copyright (c) 2017-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import fs from 'fs-extra';
import path from 'path';
import linkify from '../linkify';
import {SourceToPermalink} from '../../types';
const siteDir = path.join(__dirname, '__fixtures__');
const docsDir = path.join(siteDir, 'docs');
const sourceToPermalink: SourceToPermalink = {
'@site/docs/doc1.md': '/docs/doc1',
'@site/docs/doc2.md': '/docs/doc2',
'@site/docs/subdir/doc3.md': '/docs/subdir/doc3',
'@site/docs/doc4.md': '/docs/doc4',
};
const transform = filepath => {
const content = fs.readFileSync(filepath, 'utf-8');
const transformedContent = linkify(
content,
filepath,
docsDir,
siteDir,
sourceToPermalink,
);
return [content, transformedContent];
};
test('transform nothing', () => {
const doc1 = path.join(docsDir, 'doc1.md');
const [content, transformedContent] = transform(doc1);
expect(transformedContent).toMatchSnapshot();
expect(content).toEqual(transformedContent);
});
test('transform to correct links', () => {
const doc2 = path.join(docsDir, 'doc2.md');
const [content, transformedContent] = transform(doc2);
expect(transformedContent).toMatchSnapshot();
expect(transformedContent).toContain('](/docs/doc1');
expect(transformedContent).toContain('](/docs/doc2');
expect(transformedContent).toContain('](/docs/subdir/doc3');
expect(transformedContent).not.toContain('](doc1.md)');
expect(transformedContent).not.toContain('](./doc2.md)');
expect(transformedContent).not.toContain('](subdir/doc3.md)');
expect(content).not.toEqual(transformedContent);
});
test('transform relative links', () => {
const doc3 = path.join(docsDir, 'subdir', 'doc3.md');
const [content, transformedContent] = transform(doc3);
expect(transformedContent).toMatchSnapshot();
expect(transformedContent).toContain('](/docs/doc2');
expect(transformedContent).not.toContain('](../doc2.md)');
expect(content).not.toEqual(transformedContent);
});
test('transforms reference links', () => {
const doc4 = path.join(docsDir, 'doc4.md');
const [content, transformedContent] = transform(doc4);
expect(transformedContent).toMatchSnapshot();
expect(transformedContent).toContain('[doc1]: /docs/doc1');
expect(transformedContent).toContain('[doc2]: /docs/doc2');
expect(transformedContent).not.toContain('[doc1]: doc1.md');
expect(transformedContent).not.toContain('[doc2]: ./doc2.md');
expect(content).not.toEqual(transformedContent);
});

View file

@ -5,60 +5,24 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import path from 'path';
import {getOptions} from 'loader-utils'; import {getOptions} from 'loader-utils';
import {resolve} from 'url';
import {loader} from 'webpack'; import {loader} from 'webpack';
import linkify from './linkify';
export = function(fileString: string) { export = function(fileString: string) {
const callback = this.async(); const callback = this.async();
const options = Object.assign({}, getOptions(this), { const {docsDir, siteDir, sourceToPermalink} = getOptions(this);
filepath: this.resourcePath, return (
}); callback &&
const {docsDir, siteDir, sourceToPermalink} = options; callback(
null,
// Determine the source dir. e.g: /docs, /website/versioned_docs/version-1.0.0 linkify(
let sourceDir: string | undefined; fileString,
const thisSource = this.resourcePath; this.resourcePath,
if (thisSource.startsWith(docsDir)) { docsDir,
sourceDir = docsDir; siteDir,
} sourceToPermalink,
),
let content = fileString; )
);
// Replace internal markdown linking (except in fenced blocks).
if (sourceDir) {
let fencedBlock = false;
const lines = content.split('\n').map(line => {
if (line.trim().startsWith('```')) {
fencedBlock = !fencedBlock;
}
if (fencedBlock) return line;
let modifiedLine = line;
// Replace inline-style links or reference-style links e.g:
// This is [Document 1](doc1.md) -> we replace this doc1.md with correct link
// [doc1]: doc1.md -> we replace this doc1.md with correct link
const mdRegex = /(?:(?:\]\()|(?:\]:\s?))(?!https)([^'")\]\s>]+\.mdx?)/g;
let mdMatch = mdRegex.exec(modifiedLine);
while (mdMatch !== null) {
// Replace it to correct html link.
const mdLink = mdMatch[1];
const targetSource = `${sourceDir}/${mdLink}`;
const aliasedSource = (source: string) =>
`@site/${path.relative(siteDir, source)}`;
const permalink =
sourceToPermalink[aliasedSource(resolve(thisSource, mdLink))] ||
sourceToPermalink[aliasedSource(targetSource)];
if (permalink) {
modifiedLine = modifiedLine.replace(mdLink, permalink);
}
mdMatch = mdRegex.exec(modifiedLine);
}
return modifiedLine;
});
content = lines.join('\n');
}
return callback && callback(null, content);
} as loader.Loader; } as loader.Loader;

View file

@ -0,0 +1,63 @@
/**
* Copyright (c) 2017-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import path from 'path';
import {resolve} from 'url';
import {SourceToPermalink} from '../types';
export default function(
fileString: string,
filePath: string,
docsDir: string,
siteDir: string,
sourceToPermalink: SourceToPermalink,
) {
// Determine the source dir. e.g: /website/docs, /website/versioned_docs/version-1.0.0
let sourceDir: string | undefined;
const thisSource = filePath;
if (thisSource.startsWith(docsDir)) {
sourceDir = docsDir;
}
let content = fileString;
// Replace internal markdown linking (except in fenced blocks).
if (sourceDir) {
let fencedBlock = false;
const lines = content.split('\n').map(line => {
if (line.trim().startsWith('```')) {
fencedBlock = !fencedBlock;
}
if (fencedBlock) return line;
let modifiedLine = line;
// Replace inline-style links or reference-style links e.g:
// This is [Document 1](doc1.md) -> we replace this doc1.md with correct link
// [doc1]: doc1.md -> we replace this doc1.md with correct link
const mdRegex = /(?:(?:\]\()|(?:\]:\s?))(?!https)([^'")\]\s>]+\.mdx?)/g;
let mdMatch = mdRegex.exec(modifiedLine);
while (mdMatch !== null) {
// Replace it to correct html link.
const mdLink = mdMatch[1];
const targetSource = `${sourceDir}/${mdLink}`;
const aliasedSource = (source: string) =>
`@site/${path.relative(siteDir, source)}`;
const permalink =
sourceToPermalink[aliasedSource(resolve(thisSource, mdLink))] ||
sourceToPermalink[aliasedSource(targetSource)];
if (permalink) {
modifiedLine = modifiedLine.replace(mdLink, permalink);
}
mdMatch = mdRegex.exec(modifiedLine);
}
return modifiedLine;
});
content = lines.join('\n');
}
return content;
}