@docusaurus/mdx-loader 2.0.0-beta.0f144213d → 2.0.0-beta.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/.tsbuildinfo +1 -0
- package/lib/index.d.ts +23 -0
- package/lib/index.js +167 -0
- package/lib/remark/headings/index.d.ts +9 -0
- package/lib/remark/headings/index.js +60 -0
- package/lib/remark/toc/index.d.ts +12 -0
- package/lib/remark/toc/index.js +67 -0
- package/lib/remark/toc/search.d.ts +13 -0
- package/lib/remark/toc/search.js +66 -0
- package/lib/remark/transformImage/index.d.ts +13 -0
- package/lib/remark/transformImage/index.js +90 -0
- package/lib/remark/transformLinks/index.d.ts +14 -0
- package/lib/remark/transformLinks/index.js +106 -0
- package/lib/remark/unwrapMdxCodeBlocks/index.d.ts +9 -0
- package/lib/remark/unwrapMdxCodeBlocks/index.js +28 -0
- package/lib/remark/utils/index.d.ts +10 -0
- package/lib/remark/utils/index.js +39 -0
- package/package.json +16 -12
- package/src/deps.d.ts +29 -0
- package/src/index.ts +216 -0
- package/src/{index.d.ts → mdx-loader.d.ts} +7 -8
- package/src/remark/headings/__tests__/{index.test.js → index.test.ts} +0 -2
- package/src/remark/headings/{index.js → index.ts} +21 -16
- package/src/remark/toc/__tests__/__snapshots__/{index.test.js.snap → index.test.ts.snap} +20 -10
- package/src/remark/toc/__tests__/{index.test.js → index.test.ts} +29 -15
- package/src/remark/toc/__tests__/search.test.ts +182 -0
- package/src/remark/toc/{index.js → index.ts} +24 -16
- package/src/remark/toc/search.ts +82 -0
- package/src/remark/transformImage/__tests__/{fixtures → __fixtures__}/fail.md +0 -0
- package/src/remark/transformImage/__tests__/__fixtures__/img.md +19 -0
- package/src/remark/transformImage/__tests__/{fixtures → __fixtures__}/noUrl.md +0 -0
- package/src/remark/transformImage/__tests__/{fixtures → __fixtures__}/pathname.md +0 -0
- package/src/remark/transformImage/__tests__/{fixtures → __fixtures__/static}/img.png +0 -0
- package/src/remark/{transformLinks/__tests__/fixtures/asset.pdf → transformImage/__tests__/__fixtures__/static2/img2.png} +0 -0
- package/src/remark/transformImage/__tests__/__snapshots__/index.test.ts.snap +33 -0
- package/src/remark/transformImage/__tests__/{index.test.js → index.test.ts} +23 -19
- package/src/remark/transformImage/{index.js → index.ts} +52 -24
- package/src/remark/transformLinks/__tests__/{fixtures → __fixtures__}/asset.md +6 -0
- package/src/remark/transformLinks/__tests__/{fixtures/static/staticAsset.pdf → __fixtures__/asset.pdf} +0 -0
- package/src/remark/transformLinks/__tests__/{fixtures → __fixtures__}/noUrl.md +0 -0
- package/src/remark/transformLinks/__tests__/{fixtures → __fixtures__}/pathname.md +0 -0
- package/src/remark/transformLinks/__tests__/__fixtures__/static/staticAsset.pdf +0 -0
- package/src/remark/transformLinks/__tests__/{fixtures → __fixtures__}/static/staticAssetImage.png +0 -0
- package/src/remark/transformLinks/__tests__/__fixtures__/static2/asset2.pdf +0 -0
- package/src/remark/transformLinks/__tests__/__snapshots__/index.test.ts.snap +47 -0
- package/src/remark/transformLinks/__tests__/{index.test.js → index.test.ts} +19 -8
- package/src/remark/transformLinks/{index.js → index.ts} +66 -44
- package/src/remark/unwrapMdxCodeBlocks/__tests__/__snapshots__/{index.test.js.snap → index.test.ts.snap} +0 -0
- package/src/remark/unwrapMdxCodeBlocks/__tests__/{index.test.js → index.test.ts} +0 -0
- package/src/remark/unwrapMdxCodeBlocks/{index.js → index.ts} +11 -9
- package/src/remark/utils/index.ts +39 -0
- package/tsconfig.json +5 -5
- package/src/index.js +0 -107
- package/src/remark/toc/search.js +0 -73
- package/src/remark/transformImage/__tests__/__snapshots__/index.test.js.snap +0 -31
- package/src/remark/transformImage/__tests__/fixtures/img.md +0 -17
- package/src/remark/transformLinks/__tests__/__snapshots__/index.test.js.snap +0 -41
- package/src/remark/utils/index.js +0 -39
|
@@ -5,55 +5,59 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import
|
|
8
|
+
import path from 'path';
|
|
9
9
|
import remark from 'remark';
|
|
10
10
|
import mdx from 'remark-mdx';
|
|
11
11
|
import vfile from 'to-vfile';
|
|
12
12
|
import plugin from '../index';
|
|
13
13
|
import headings from '../../headings/index';
|
|
14
|
+
import {posixPath} from '@docusaurus/utils';
|
|
14
15
|
|
|
15
16
|
const processFixture = async (name, options) => {
|
|
16
|
-
const
|
|
17
|
-
const file = await vfile.read(
|
|
17
|
+
const filePath = path.join(__dirname, `__fixtures__/${name}.md`);
|
|
18
|
+
const file = await vfile.read(filePath);
|
|
18
19
|
const result = await remark()
|
|
19
20
|
.use(headings)
|
|
20
21
|
.use(mdx)
|
|
21
|
-
.use(plugin, {...options, filePath
|
|
22
|
+
.use(plugin, {...options, filePath})
|
|
22
23
|
.process(file);
|
|
23
24
|
|
|
24
|
-
return result
|
|
25
|
+
return result
|
|
26
|
+
.toString()
|
|
27
|
+
.replace(new RegExp(posixPath(process.cwd()), 'g'), '[CWD]');
|
|
25
28
|
};
|
|
26
29
|
|
|
27
|
-
|
|
28
|
-
|
|
30
|
+
const staticDirs = [
|
|
31
|
+
// avoid hardcoding absolute in the snapshot
|
|
32
|
+
`./${path.relative(
|
|
33
|
+
process.cwd(),
|
|
34
|
+
path.join(__dirname, '__fixtures__/static'),
|
|
35
|
+
)}`,
|
|
36
|
+
`./${path.relative(
|
|
37
|
+
process.cwd(),
|
|
38
|
+
path.join(__dirname, '__fixtures__/static2'),
|
|
39
|
+
)}`,
|
|
40
|
+
];
|
|
29
41
|
|
|
30
42
|
describe('transformImage plugin', () => {
|
|
31
43
|
test('fail if image does not exist', async () => {
|
|
32
44
|
await expect(
|
|
33
|
-
processFixture('fail', {
|
|
34
|
-
staticDir,
|
|
35
|
-
}),
|
|
45
|
+
processFixture('fail', {staticDirs}),
|
|
36
46
|
).rejects.toThrowErrorMatchingSnapshot();
|
|
37
47
|
});
|
|
38
48
|
test('fail if image url is absent', async () => {
|
|
39
49
|
await expect(
|
|
40
|
-
processFixture('noUrl', {
|
|
41
|
-
staticDir,
|
|
42
|
-
}),
|
|
50
|
+
processFixture('noUrl', {staticDirs}),
|
|
43
51
|
).rejects.toThrowErrorMatchingSnapshot();
|
|
44
52
|
});
|
|
45
53
|
|
|
46
54
|
test('transform md images to <img />', async () => {
|
|
47
|
-
const result = await processFixture('img', {
|
|
48
|
-
staticDir,
|
|
49
|
-
});
|
|
55
|
+
const result = await processFixture('img', {staticDirs});
|
|
50
56
|
expect(result).toMatchSnapshot();
|
|
51
57
|
});
|
|
52
58
|
|
|
53
59
|
test('pathname protocol', async () => {
|
|
54
|
-
const result = await processFixture('pathname', {
|
|
55
|
-
staticDir,
|
|
56
|
-
});
|
|
60
|
+
const result = await processFixture('pathname', {staticDirs});
|
|
57
61
|
expect(result).toMatchSnapshot();
|
|
58
62
|
});
|
|
59
63
|
});
|
|
@@ -5,26 +5,35 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const {
|
|
8
|
+
import visit from 'unist-util-visit';
|
|
9
|
+
import path from 'path';
|
|
10
|
+
import url from 'url';
|
|
11
|
+
import fs from 'fs-extra';
|
|
12
|
+
import escapeHtml from 'escape-html';
|
|
13
|
+
import {
|
|
15
14
|
posixPath,
|
|
16
15
|
escapePath,
|
|
17
16
|
toMessageRelativeFilePath,
|
|
18
|
-
|
|
17
|
+
getFileLoaderUtils,
|
|
18
|
+
} from '@docusaurus/utils';
|
|
19
|
+
import type {Plugin, Transformer} from 'unified';
|
|
20
|
+
import type {Image, Literal} from 'mdast';
|
|
19
21
|
|
|
20
22
|
const {
|
|
21
23
|
loaders: {inlineMarkdownImageFileLoader},
|
|
22
24
|
} = getFileLoaderUtils();
|
|
23
25
|
|
|
24
|
-
|
|
26
|
+
interface PluginOptions {
|
|
27
|
+
filePath: string;
|
|
28
|
+
staticDirs: string[];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const createJSX = (node: Image, pathUrl: string) => {
|
|
25
32
|
const jsxNode = node;
|
|
26
|
-
jsxNode.type = 'jsx';
|
|
27
|
-
jsxNode.value = `<img ${
|
|
33
|
+
(jsxNode as unknown as Literal).type = 'jsx';
|
|
34
|
+
(jsxNode as unknown as Literal).value = `<img ${
|
|
35
|
+
node.alt ? `alt={"${escapeHtml(node.alt)}"} ` : ''
|
|
36
|
+
}${
|
|
28
37
|
node.url
|
|
29
38
|
? `src={require("${inlineMarkdownImageFileLoader}${escapePath(
|
|
30
39
|
pathUrl,
|
|
@@ -33,7 +42,7 @@ const createJSX = (node, pathUrl) => {
|
|
|
33
42
|
}${node.title ? ` title="${escapeHtml(node.title)}"` : ''} />`;
|
|
34
43
|
|
|
35
44
|
if (jsxNode.url) {
|
|
36
|
-
delete jsxNode.url;
|
|
45
|
+
delete (jsxNode as Partial<Image>).url;
|
|
37
46
|
}
|
|
38
47
|
if (jsxNode.alt) {
|
|
39
48
|
delete jsxNode.alt;
|
|
@@ -43,7 +52,7 @@ const createJSX = (node, pathUrl) => {
|
|
|
43
52
|
}
|
|
44
53
|
};
|
|
45
54
|
|
|
46
|
-
async function ensureImageFileExist(imagePath, sourceFilePath) {
|
|
55
|
+
async function ensureImageFileExist(imagePath: string, sourceFilePath: string) {
|
|
47
56
|
const imageExists = await fs.pathExists(imagePath);
|
|
48
57
|
if (!imageExists) {
|
|
49
58
|
throw new Error(
|
|
@@ -54,7 +63,26 @@ async function ensureImageFileExist(imagePath, sourceFilePath) {
|
|
|
54
63
|
}
|
|
55
64
|
}
|
|
56
65
|
|
|
57
|
-
async function
|
|
66
|
+
async function findImage(possiblePaths: string[], sourceFilePath: string) {
|
|
67
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
68
|
+
for (const possiblePath of possiblePaths) {
|
|
69
|
+
if (await fs.pathExists(possiblePath)) {
|
|
70
|
+
return possiblePath;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
throw new Error(
|
|
74
|
+
`Image ${possiblePaths
|
|
75
|
+
.map((p) => toMessageRelativeFilePath(p))
|
|
76
|
+
.join(' or ')} used in ${toMessageRelativeFilePath(
|
|
77
|
+
sourceFilePath,
|
|
78
|
+
)} not found.`,
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async function processImageNode(
|
|
83
|
+
node: Image,
|
|
84
|
+
{filePath, staticDirs}: PluginOptions,
|
|
85
|
+
) {
|
|
58
86
|
if (!node.url) {
|
|
59
87
|
throw new Error(
|
|
60
88
|
`Markdown image URL is mandatory in "${toMessageRelativeFilePath(
|
|
@@ -71,16 +99,16 @@ async function processImageNode(node, {filePath, staticDir}) {
|
|
|
71
99
|
// it's mostly to make next release less risky (2.0.0-alpha.59)
|
|
72
100
|
if (parsedUrl.protocol === 'pathname:') {
|
|
73
101
|
node.url = node.url.replace('pathname://', '');
|
|
74
|
-
} else {
|
|
75
|
-
// noop
|
|
76
102
|
}
|
|
77
103
|
}
|
|
78
104
|
// images without protocol
|
|
79
105
|
else if (path.isAbsolute(node.url)) {
|
|
80
106
|
// absolute paths are expected to exist in the static folder
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
107
|
+
const possibleImagePaths = staticDirs.map((dir) =>
|
|
108
|
+
path.join(dir, node.url),
|
|
109
|
+
);
|
|
110
|
+
const imagePath = await findImage(possibleImagePaths, filePath);
|
|
111
|
+
createJSX(node, posixPath(imagePath));
|
|
84
112
|
}
|
|
85
113
|
// We try to convert image urls without protocol to images with require calls
|
|
86
114
|
// going through webpack ensures that image assets exist at build time
|
|
@@ -92,10 +120,10 @@ async function processImageNode(node, {filePath, staticDir}) {
|
|
|
92
120
|
}
|
|
93
121
|
}
|
|
94
122
|
|
|
95
|
-
const plugin = (options) => {
|
|
96
|
-
const transformer = async (root) => {
|
|
97
|
-
const promises = [];
|
|
98
|
-
visit(root, 'image', (node) => {
|
|
123
|
+
const plugin: Plugin<[PluginOptions]> = (options) => {
|
|
124
|
+
const transformer: Transformer = async (root) => {
|
|
125
|
+
const promises: Promise<void>[] = [];
|
|
126
|
+
visit(root, 'image', (node: Image) => {
|
|
99
127
|
promises.push(processImageNode(node, options));
|
|
100
128
|
});
|
|
101
129
|
await Promise.all(promises);
|
|
@@ -103,4 +131,4 @@ const plugin = (options) => {
|
|
|
103
131
|
return transformer;
|
|
104
132
|
};
|
|
105
133
|
|
|
106
|
-
|
|
134
|
+
export default plugin;
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
[asset](./asset.pdf)
|
|
6
6
|
|
|
7
|
+
[asset with hash](./asset.pdf#page=2)
|
|
8
|
+
|
|
7
9
|
[asset](asset.pdf 'Title')
|
|
8
10
|
|
|
9
11
|
## Heading
|
|
@@ -18,10 +20,14 @@
|
|
|
18
20
|
|
|
19
21
|
[asset](asset.pdf)
|
|
20
22
|
|
|
23
|
+
[asset2](/asset2.pdf)
|
|
24
|
+
|
|
21
25
|
[staticAsset.pdf](/staticAsset.pdf)
|
|
22
26
|
|
|
23
27
|
[@site/static/staticAsset.pdf](@site/static/staticAsset.pdf)
|
|
24
28
|
|
|
29
|
+
[@site/static/staticAsset.pdf](@site/static/staticAsset.pdf#page=2 'Title')
|
|
30
|
+
|
|
25
31
|
[Just staticAsset.pdf](/staticAsset.pdf), and [**awesome** staticAsset 2.pdf 'It is really "AWESOME"'](/staticAsset.pdf), but also [coded `staticAsset 3.pdf`](/staticAsset.pdf)
|
|
26
32
|
|
|
27
33
|
[](/staticAssetImage.png)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/src/remark/transformLinks/__tests__/{fixtures → __fixtures__}/static/staticAssetImage.png
RENAMED
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
+
|
|
3
|
+
exports[`transformAsset plugin fail if asset url is absent 1`] = `"Markdown link URL is mandatory in \\"packages/docusaurus-mdx-loader/src/remark/transformLinks/__tests__/__fixtures__/noUrl.md\\" file (title: asset, line: 1)."`;
|
|
4
|
+
|
|
5
|
+
exports[`transformAsset plugin pathname protocol 1`] = `
|
|
6
|
+
"[asset](pathname:///asset/unchecked.pdf)
|
|
7
|
+
"
|
|
8
|
+
`;
|
|
9
|
+
|
|
10
|
+
exports[`transformAsset plugin transform md links to <a /> 1`] = `
|
|
11
|
+
"[asset](https://example.com/asset.pdf)
|
|
12
|
+
|
|
13
|
+
<a target=\\"_blank\\" href={require('![CWD]/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[hash].[ext]!./asset.pdf').default}></a>
|
|
14
|
+
|
|
15
|
+
<a target=\\"_blank\\" href={require('![CWD]/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[hash].[ext]!./asset.pdf').default}>asset</a>
|
|
16
|
+
|
|
17
|
+
<a target=\\"_blank\\" href={require('![CWD]/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[hash].[ext]!./asset.pdf').default + '#page=2'}>asset with hash</a>
|
|
18
|
+
|
|
19
|
+
<a target=\\"_blank\\" href={require('![CWD]/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[hash].[ext]!./asset.pdf').default} title=\\"Title\\">asset</a>
|
|
20
|
+
|
|
21
|
+
## Heading
|
|
22
|
+
|
|
23
|
+
\`\`\`md
|
|
24
|
+
[asset](./asset.pdf)
|
|
25
|
+
\`\`\`
|
|
26
|
+
|
|
27
|
+
[assets](!file-loader!./asset.pdf)
|
|
28
|
+
|
|
29
|
+
[assets](/github/!file-loader!/assets.pdf)
|
|
30
|
+
|
|
31
|
+
<a target=\\"_blank\\" href={require('![CWD]/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[hash].[ext]!./asset.pdf').default}>asset</a>
|
|
32
|
+
|
|
33
|
+
<a target=\\"_blank\\" href={require('![CWD]/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[hash].[ext]!./static2/asset2.pdf').default}>asset2</a>
|
|
34
|
+
|
|
35
|
+
<a target=\\"_blank\\" href={require('![CWD]/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[hash].[ext]!./static/staticAsset.pdf').default}>staticAsset.pdf</a>
|
|
36
|
+
|
|
37
|
+
<a target=\\"_blank\\" href={require('![CWD]/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[hash].[ext]!./static/staticAsset.pdf').default}>@site/static/staticAsset.pdf</a>
|
|
38
|
+
|
|
39
|
+
<a target=\\"_blank\\" href={require('![CWD]/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[hash].[ext]!./static/staticAsset.pdf').default + '#page=2'} title=\\"Title\\">@site/static/staticAsset.pdf</a>
|
|
40
|
+
|
|
41
|
+
<a target=\\"_blank\\" href={require('![CWD]/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[hash].[ext]!./static/staticAsset.pdf').default}>Just staticAsset.pdf</a>, and <a target=\\"_blank\\" href={require('![CWD]/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[hash].[ext]!./static/staticAsset.pdf').default}><strong>awesome</strong> staticAsset 2.pdf 'It is really "AWESOME"'</a>, but also <a target=\\"_blank\\" href={require('![CWD]/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[hash].[ext]!./static/staticAsset.pdf').default}>coded <code>staticAsset 3.pdf</code></a>
|
|
42
|
+
|
|
43
|
+
<a target=\\"_blank\\" href={require('![CWD]/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[hash].[ext]!./static/staticAssetImage.png').default}><img alt={\\"Clickable Docusaurus logo\\"} src={require(\\"![CWD]/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[hash].[ext]&fallback=[CWD]/node_modules/file-loader/dist/cjs.js!./static/staticAssetImage.png\\").default} /></a>
|
|
44
|
+
|
|
45
|
+
<a target=\\"_blank\\" href={require('![CWD]/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[hash].[ext]!./asset.pdf').default}><span style={{color: \\"red\\"}}>Stylized link to asset file</span></a>
|
|
46
|
+
"
|
|
47
|
+
`;
|
|
@@ -5,24 +5,35 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import
|
|
8
|
+
import path from 'path';
|
|
9
9
|
import remark from 'remark';
|
|
10
10
|
import mdx from 'remark-mdx';
|
|
11
11
|
import vfile from 'to-vfile';
|
|
12
12
|
import plugin from '..';
|
|
13
13
|
import transformImage from '../../transformImage';
|
|
14
|
+
import {posixPath} from '@docusaurus/utils';
|
|
14
15
|
|
|
15
|
-
const processFixture = async (name, options) => {
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
|
|
16
|
+
const processFixture = async (name: string, options?) => {
|
|
17
|
+
const filePath = path.join(__dirname, `__fixtures__/${name}.md`);
|
|
18
|
+
const staticDirs = [
|
|
19
|
+
path.join(__dirname, '__fixtures__/static'),
|
|
20
|
+
path.join(__dirname, '__fixtures__/static2'),
|
|
21
|
+
];
|
|
22
|
+
const file = await vfile.read(filePath);
|
|
19
23
|
const result = await remark()
|
|
20
24
|
.use(mdx)
|
|
21
|
-
.use(transformImage, {...options, filePath
|
|
22
|
-
.use(plugin, {
|
|
25
|
+
.use(transformImage, {...options, filePath, staticDirs})
|
|
26
|
+
.use(plugin, {
|
|
27
|
+
...options,
|
|
28
|
+
filePath,
|
|
29
|
+
staticDirs,
|
|
30
|
+
siteDir: path.join(__dirname, '__fixtures__'),
|
|
31
|
+
})
|
|
23
32
|
.process(file);
|
|
24
33
|
|
|
25
|
-
return result
|
|
34
|
+
return result
|
|
35
|
+
.toString()
|
|
36
|
+
.replace(new RegExp(posixPath(process.cwd()), 'g'), '[CWD]');
|
|
26
37
|
};
|
|
27
38
|
|
|
28
39
|
describe('transformAsset plugin', () => {
|
|
@@ -5,25 +5,36 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
import {
|
|
9
9
|
toMessageRelativeFilePath,
|
|
10
10
|
posixPath,
|
|
11
11
|
escapePath,
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
12
|
+
getFileLoaderUtils,
|
|
13
|
+
} from '@docusaurus/utils';
|
|
14
|
+
import visit from 'unist-util-visit';
|
|
15
|
+
import path from 'path';
|
|
16
|
+
import url from 'url';
|
|
17
|
+
import fs from 'fs-extra';
|
|
18
|
+
import escapeHtml from 'escape-html';
|
|
19
|
+
import {stringifyContent} from '../utils';
|
|
20
|
+
import type {Plugin, Transformer} from 'unified';
|
|
21
|
+
import type {Link, Literal} from 'mdast';
|
|
21
22
|
|
|
22
23
|
const {
|
|
23
24
|
loaders: {inlineMarkdownLinkFileLoader},
|
|
24
25
|
} = getFileLoaderUtils();
|
|
26
|
+
const hashRegex = /#.*$/;
|
|
27
|
+
|
|
28
|
+
interface PluginOptions {
|
|
29
|
+
filePath: string;
|
|
30
|
+
staticDirs: string[];
|
|
31
|
+
siteDir: string;
|
|
32
|
+
}
|
|
25
33
|
|
|
26
|
-
async function ensureAssetFileExist(
|
|
34
|
+
async function ensureAssetFileExist(
|
|
35
|
+
fileSystemAssetPath: string,
|
|
36
|
+
sourceFilePath: string,
|
|
37
|
+
) {
|
|
27
38
|
const assetExists = await fs.pathExists(fileSystemAssetPath);
|
|
28
39
|
if (!assetExists) {
|
|
29
40
|
throw new Error(
|
|
@@ -35,12 +46,21 @@ async function ensureAssetFileExist(fileSystemAssetPath, sourceFilePath) {
|
|
|
35
46
|
}
|
|
36
47
|
|
|
37
48
|
// transform the link node to a jsx link with a require() call
|
|
38
|
-
function toAssetRequireNode({
|
|
39
|
-
|
|
40
|
-
|
|
49
|
+
function toAssetRequireNode({
|
|
50
|
+
node,
|
|
51
|
+
filePath,
|
|
52
|
+
requireAssetPath,
|
|
53
|
+
}: {
|
|
54
|
+
node: Link;
|
|
55
|
+
filePath: string;
|
|
56
|
+
requireAssetPath: string;
|
|
57
|
+
}) {
|
|
41
58
|
let relativeRequireAssetPath = posixPath(
|
|
42
59
|
path.relative(path.dirname(filePath), requireAssetPath),
|
|
43
60
|
);
|
|
61
|
+
const hash = hashRegex.test(node.url)
|
|
62
|
+
? node.url.substr(node.url.indexOf('#'))
|
|
63
|
+
: '';
|
|
44
64
|
|
|
45
65
|
// nodejs does not like require("assets/file.pdf")
|
|
46
66
|
relativeRequireAssetPath = relativeRequireAssetPath.startsWith('.')
|
|
@@ -49,19 +69,24 @@ function toAssetRequireNode({node, filePath, requireAssetPath}) {
|
|
|
49
69
|
|
|
50
70
|
const href = `require('${inlineMarkdownLinkFileLoader}${escapePath(
|
|
51
71
|
relativeRequireAssetPath,
|
|
52
|
-
)}').default`;
|
|
53
|
-
const children = (node
|
|
54
|
-
const title = node.title ? `title="${escapeHtml(node.title)}"` : '';
|
|
55
|
-
|
|
56
|
-
node.type = 'jsx';
|
|
57
|
-
|
|
72
|
+
)}').default${hash ? ` + '${hash}'` : ''}`;
|
|
73
|
+
const children = stringifyContent(node);
|
|
74
|
+
const title = node.title ? ` title="${escapeHtml(node.title)}"` : '';
|
|
75
|
+
|
|
76
|
+
(node as unknown as Literal).type = 'jsx';
|
|
77
|
+
(
|
|
78
|
+
node as unknown as Literal
|
|
79
|
+
).value = `<a target="_blank" href={${href}}${title}>${children}</a>`;
|
|
58
80
|
}
|
|
59
81
|
|
|
60
82
|
// If the link looks like an asset link, we'll link to the asset,
|
|
61
83
|
// and use a require("assetUrl") (using webpack url-loader/file-loader)
|
|
62
84
|
// instead of navigating to such link
|
|
63
|
-
async function convertToAssetLinkIfNeeded(
|
|
64
|
-
|
|
85
|
+
async function convertToAssetLinkIfNeeded(
|
|
86
|
+
node: Link,
|
|
87
|
+
{filePath, siteDir, staticDirs}: PluginOptions,
|
|
88
|
+
) {
|
|
89
|
+
const assetPath = node.url.replace(hashRegex, '');
|
|
65
90
|
|
|
66
91
|
const hasSiteAlias = assetPath.startsWith('@site/');
|
|
67
92
|
const hasAssetLikeExtension =
|
|
@@ -73,7 +98,7 @@ async function convertToAssetLinkIfNeeded({node, staticDir, filePath}) {
|
|
|
73
98
|
return;
|
|
74
99
|
}
|
|
75
100
|
|
|
76
|
-
function toAssetLinkNode(requireAssetPath) {
|
|
101
|
+
function toAssetLinkNode(requireAssetPath: string) {
|
|
77
102
|
toAssetRequireNode({
|
|
78
103
|
node,
|
|
79
104
|
filePath,
|
|
@@ -82,7 +107,6 @@ async function convertToAssetLinkIfNeeded({node, staticDir, filePath}) {
|
|
|
82
107
|
}
|
|
83
108
|
|
|
84
109
|
if (assetPath.startsWith('@site/')) {
|
|
85
|
-
const siteDir = path.join(staticDir, '..');
|
|
86
110
|
const fileSystemAssetPath = path.join(
|
|
87
111
|
siteDir,
|
|
88
112
|
assetPath.replace('@site/', ''),
|
|
@@ -90,9 +114,13 @@ async function convertToAssetLinkIfNeeded({node, staticDir, filePath}) {
|
|
|
90
114
|
await ensureAssetFileExist(fileSystemAssetPath, filePath);
|
|
91
115
|
toAssetLinkNode(fileSystemAssetPath);
|
|
92
116
|
} else if (path.isAbsolute(assetPath)) {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
117
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
118
|
+
for (const staticDir of staticDirs) {
|
|
119
|
+
const fileSystemAssetPath = path.join(staticDir, assetPath);
|
|
120
|
+
if (await fs.pathExists(fileSystemAssetPath)) {
|
|
121
|
+
toAssetLinkNode(fileSystemAssetPath);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
96
124
|
}
|
|
97
125
|
} else {
|
|
98
126
|
const fileSystemAssetPath = path.join(path.dirname(filePath), assetPath);
|
|
@@ -102,17 +130,15 @@ async function convertToAssetLinkIfNeeded({node, staticDir, filePath}) {
|
|
|
102
130
|
}
|
|
103
131
|
}
|
|
104
132
|
|
|
105
|
-
async function processLinkNode(
|
|
133
|
+
async function processLinkNode(node: Link, options: PluginOptions) {
|
|
106
134
|
if (!node.url) {
|
|
107
135
|
// try to improve error feedback
|
|
108
136
|
// see https://github.com/facebook/docusaurus/issues/3309#issuecomment-690371675
|
|
109
|
-
const title =
|
|
110
|
-
|
|
111
|
-
const line =
|
|
112
|
-
(node.position && node.position.start && node.position.start.line) || '?';
|
|
137
|
+
const title = node.title || (node.children[0] as Literal)?.value || '?';
|
|
138
|
+
const line = node?.position?.start?.line || '?';
|
|
113
139
|
throw new Error(
|
|
114
140
|
`Markdown link URL is mandatory in "${toMessageRelativeFilePath(
|
|
115
|
-
filePath,
|
|
141
|
+
options.filePath,
|
|
116
142
|
)}" file (title: ${title}, line: ${line}).`,
|
|
117
143
|
);
|
|
118
144
|
}
|
|
@@ -122,22 +148,18 @@ async function processLinkNode({node, _index, _parent, filePath, staticDir}) {
|
|
|
122
148
|
return;
|
|
123
149
|
}
|
|
124
150
|
|
|
125
|
-
await convertToAssetLinkIfNeeded(
|
|
126
|
-
node,
|
|
127
|
-
staticDir,
|
|
128
|
-
filePath,
|
|
129
|
-
});
|
|
151
|
+
await convertToAssetLinkIfNeeded(node, options);
|
|
130
152
|
}
|
|
131
153
|
|
|
132
|
-
const plugin = (options) => {
|
|
133
|
-
const transformer = async (root) => {
|
|
134
|
-
const promises = [];
|
|
135
|
-
visit(root, 'link', (node
|
|
136
|
-
promises.push(processLinkNode(
|
|
154
|
+
const plugin: Plugin<[PluginOptions]> = (options) => {
|
|
155
|
+
const transformer: Transformer = async (root) => {
|
|
156
|
+
const promises: Promise<void>[] = [];
|
|
157
|
+
visit(root, 'link', (node: Link) => {
|
|
158
|
+
promises.push(processLinkNode(node, options));
|
|
137
159
|
});
|
|
138
160
|
await Promise.all(promises);
|
|
139
161
|
};
|
|
140
162
|
return transformer;
|
|
141
163
|
};
|
|
142
164
|
|
|
143
|
-
|
|
165
|
+
export default plugin;
|
|
File without changes
|
|
File without changes
|
|
@@ -5,24 +5,26 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
import visit from 'unist-util-visit';
|
|
9
|
+
import type {Transformer, Processor} from 'unified';
|
|
10
|
+
import type {Code, Parent} from 'mdast';
|
|
9
11
|
|
|
10
12
|
// This plugin is mostly to help integrating Docusaurus with translation systems
|
|
11
13
|
// that do not support well MDX embedded JSX syntax (like Crowdin)
|
|
12
14
|
// We wrap the JSX syntax in code blocks so that translation tools don't mess-up with the markup
|
|
13
15
|
// But the JSX inside such code blocks should still be evaluated as JSX
|
|
14
16
|
// See https://github.com/facebook/docusaurus/pull/4278
|
|
15
|
-
function plugin() {
|
|
16
|
-
const transformer = (root) => {
|
|
17
|
-
visit(root, 'code', (node, _index, parent) => {
|
|
17
|
+
function plugin(this: Processor): Transformer {
|
|
18
|
+
const transformer: Transformer = (root) => {
|
|
19
|
+
visit(root, 'code', (node: Code, _index, parent) => {
|
|
18
20
|
if (node.lang === 'mdx-code-block') {
|
|
19
|
-
const
|
|
21
|
+
const newChildren = (this!.parse(node.value) as Parent).children;
|
|
20
22
|
|
|
21
23
|
// Replace the mdx code block by its content, parsed
|
|
22
|
-
parent
|
|
23
|
-
parent
|
|
24
|
+
parent!.children.splice(
|
|
25
|
+
parent!.children.indexOf(node),
|
|
24
26
|
1,
|
|
25
|
-
...
|
|
27
|
+
...newChildren,
|
|
26
28
|
);
|
|
27
29
|
}
|
|
28
30
|
});
|
|
@@ -31,4 +33,4 @@ function plugin() {
|
|
|
31
33
|
return transformer;
|
|
32
34
|
}
|
|
33
35
|
|
|
34
|
-
|
|
36
|
+
export default plugin;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import escapeHtml from 'escape-html';
|
|
9
|
+
import toString from 'mdast-util-to-string';
|
|
10
|
+
import type {Parent} from 'unist';
|
|
11
|
+
import type {StaticPhrasingContent, Heading} from 'mdast';
|
|
12
|
+
|
|
13
|
+
export function stringifyContent(node: Parent): string {
|
|
14
|
+
return ((node.children || []) as StaticPhrasingContent[])
|
|
15
|
+
.map(toValue)
|
|
16
|
+
.join('');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function toValue(node: StaticPhrasingContent | Heading): string {
|
|
20
|
+
if (node && node.type) {
|
|
21
|
+
switch (node.type) {
|
|
22
|
+
case 'text':
|
|
23
|
+
return escapeHtml(node.value);
|
|
24
|
+
case 'heading':
|
|
25
|
+
return stringifyContent(node);
|
|
26
|
+
case 'inlineCode':
|
|
27
|
+
return `<code>${escapeHtml(node.value)}</code>`;
|
|
28
|
+
case 'emphasis':
|
|
29
|
+
return `<em>${stringifyContent(node)}</em>`;
|
|
30
|
+
case 'strong':
|
|
31
|
+
return `<strong>${stringifyContent(node)}</strong>`;
|
|
32
|
+
case 'delete':
|
|
33
|
+
return `<del>${stringifyContent(node)}</del>`;
|
|
34
|
+
default:
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return toString(node);
|
|
39
|
+
}
|
package/tsconfig.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"extends": "../../tsconfig.json",
|
|
3
3
|
"compilerOptions": {
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
"incremental": true,
|
|
5
|
+
"tsBuildInfoFile": "./lib/.tsbuildinfo",
|
|
6
|
+
"rootDir": "src",
|
|
7
|
+
"outDir": "lib"
|
|
8
|
+
}
|
|
9
9
|
}
|