@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.
Files changed (58) hide show
  1. package/lib/.tsbuildinfo +1 -0
  2. package/lib/index.d.ts +23 -0
  3. package/lib/index.js +167 -0
  4. package/lib/remark/headings/index.d.ts +9 -0
  5. package/lib/remark/headings/index.js +60 -0
  6. package/lib/remark/toc/index.d.ts +12 -0
  7. package/lib/remark/toc/index.js +67 -0
  8. package/lib/remark/toc/search.d.ts +13 -0
  9. package/lib/remark/toc/search.js +66 -0
  10. package/lib/remark/transformImage/index.d.ts +13 -0
  11. package/lib/remark/transformImage/index.js +90 -0
  12. package/lib/remark/transformLinks/index.d.ts +14 -0
  13. package/lib/remark/transformLinks/index.js +106 -0
  14. package/lib/remark/unwrapMdxCodeBlocks/index.d.ts +9 -0
  15. package/lib/remark/unwrapMdxCodeBlocks/index.js +28 -0
  16. package/lib/remark/utils/index.d.ts +10 -0
  17. package/lib/remark/utils/index.js +39 -0
  18. package/package.json +16 -12
  19. package/src/deps.d.ts +29 -0
  20. package/src/index.ts +216 -0
  21. package/src/{index.d.ts → mdx-loader.d.ts} +7 -8
  22. package/src/remark/headings/__tests__/{index.test.js → index.test.ts} +0 -2
  23. package/src/remark/headings/{index.js → index.ts} +21 -16
  24. package/src/remark/toc/__tests__/__snapshots__/{index.test.js.snap → index.test.ts.snap} +20 -10
  25. package/src/remark/toc/__tests__/{index.test.js → index.test.ts} +29 -15
  26. package/src/remark/toc/__tests__/search.test.ts +182 -0
  27. package/src/remark/toc/{index.js → index.ts} +24 -16
  28. package/src/remark/toc/search.ts +82 -0
  29. package/src/remark/transformImage/__tests__/{fixtures → __fixtures__}/fail.md +0 -0
  30. package/src/remark/transformImage/__tests__/__fixtures__/img.md +19 -0
  31. package/src/remark/transformImage/__tests__/{fixtures → __fixtures__}/noUrl.md +0 -0
  32. package/src/remark/transformImage/__tests__/{fixtures → __fixtures__}/pathname.md +0 -0
  33. package/src/remark/transformImage/__tests__/{fixtures → __fixtures__/static}/img.png +0 -0
  34. package/src/remark/{transformLinks/__tests__/fixtures/asset.pdf → transformImage/__tests__/__fixtures__/static2/img2.png} +0 -0
  35. package/src/remark/transformImage/__tests__/__snapshots__/index.test.ts.snap +33 -0
  36. package/src/remark/transformImage/__tests__/{index.test.js → index.test.ts} +23 -19
  37. package/src/remark/transformImage/{index.js → index.ts} +52 -24
  38. package/src/remark/transformLinks/__tests__/{fixtures → __fixtures__}/asset.md +6 -0
  39. package/src/remark/transformLinks/__tests__/{fixtures/static/staticAsset.pdf → __fixtures__/asset.pdf} +0 -0
  40. package/src/remark/transformLinks/__tests__/{fixtures → __fixtures__}/noUrl.md +0 -0
  41. package/src/remark/transformLinks/__tests__/{fixtures → __fixtures__}/pathname.md +0 -0
  42. package/src/remark/transformLinks/__tests__/__fixtures__/static/staticAsset.pdf +0 -0
  43. package/src/remark/transformLinks/__tests__/{fixtures → __fixtures__}/static/staticAssetImage.png +0 -0
  44. package/src/remark/transformLinks/__tests__/__fixtures__/static2/asset2.pdf +0 -0
  45. package/src/remark/transformLinks/__tests__/__snapshots__/index.test.ts.snap +47 -0
  46. package/src/remark/transformLinks/__tests__/{index.test.js → index.test.ts} +19 -8
  47. package/src/remark/transformLinks/{index.js → index.ts} +66 -44
  48. package/src/remark/unwrapMdxCodeBlocks/__tests__/__snapshots__/{index.test.js.snap → index.test.ts.snap} +0 -0
  49. package/src/remark/unwrapMdxCodeBlocks/__tests__/{index.test.js → index.test.ts} +0 -0
  50. package/src/remark/unwrapMdxCodeBlocks/{index.js → index.ts} +11 -9
  51. package/src/remark/utils/index.ts +39 -0
  52. package/tsconfig.json +5 -5
  53. package/src/index.js +0 -107
  54. package/src/remark/toc/search.js +0 -73
  55. package/src/remark/transformImage/__tests__/__snapshots__/index.test.js.snap +0 -31
  56. package/src/remark/transformImage/__tests__/fixtures/img.md +0 -17
  57. package/src/remark/transformLinks/__tests__/__snapshots__/index.test.js.snap +0 -41
  58. 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 {join, relative} from 'path';
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 path = join(__dirname, 'fixtures', `${name}.md`);
17
- const file = await vfile.read(path);
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: path})
22
+ .use(plugin, {...options, filePath})
22
23
  .process(file);
23
24
 
24
- return result.toString();
25
+ return result
26
+ .toString()
27
+ .replace(new RegExp(posixPath(process.cwd()), 'g'), '[CWD]');
25
28
  };
26
29
 
27
- // avoid hardcoding absolute
28
- const staticDir = `./${relative(process.cwd(), join(__dirname, 'fixtures'))}`;
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
- const visit = require('unist-util-visit');
9
- const path = require('path');
10
- const url = require('url');
11
- const fs = require('fs-extra');
12
- const escapeHtml = require('escape-html');
13
- const {getFileLoaderUtils} = require('@docusaurus/core/lib/webpack/utils');
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
- } = require('@docusaurus/utils');
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
- const createJSX = (node, pathUrl) => {
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 ${node.alt ? `alt={"${escapeHtml(node.alt)}"} ` : ''}${
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 processImageNode(node, {filePath, staticDir}) {
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 expectedImagePath = path.join(staticDir, node.url);
82
- await ensureImageFileExist(expectedImagePath, filePath);
83
- createJSX(node, posixPath(expectedImagePath));
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
- module.exports = plugin;
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
  [![Clickable Docusaurus logo](./static/staticAssetImage.png)](/staticAssetImage.png)
@@ -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 &#39;It is really &quot;AWESOME&quot;&#39;</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 {join} from 'path';
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 path = join(__dirname, 'fixtures', `${name}.md`);
17
- const staticDir = join(__dirname, 'fixtures', 'static');
18
- const file = await vfile.read(path);
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: path, staticDir})
22
- .use(plugin, {...options, filePath: path, staticDir})
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.toString();
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
- const {
8
+ import {
9
9
  toMessageRelativeFilePath,
10
10
  posixPath,
11
11
  escapePath,
12
- } = require('@docusaurus/utils');
13
-
14
- const visit = require('unist-util-visit');
15
- const path = require('path');
16
- const url = require('url');
17
- const fs = require('fs-extra');
18
- const escapeHtml = require('escape-html');
19
- const {toValue} = require('../utils');
20
- const {getFileLoaderUtils} = require('@docusaurus/core/lib/webpack/utils');
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(fileSystemAssetPath, sourceFilePath) {
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({node, filePath, requireAssetPath}) {
39
- /* eslint-disable no-param-reassign */
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.children || []).map((n) => toValue(n)).join('');
54
- const title = node.title ? `title="${escapeHtml(node.title)}"` : '';
55
-
56
- node.type = 'jsx';
57
- node.value = `<a target="_blank" href={${href}}${title}>${children}</a>`;
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({node, staticDir, filePath}) {
64
- const assetPath = node.url;
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
- const fileSystemAssetPath = path.join(staticDir, assetPath);
94
- if (await fs.pathExists(fileSystemAssetPath)) {
95
- toAssetLinkNode(fileSystemAssetPath);
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({node, _index, _parent, filePath, staticDir}) {
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
- node.title || (node.children[0] && node.children[0].value) || '?';
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, index, parent) => {
136
- promises.push(processLinkNode({node, index, parent, ...options}));
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
- module.exports = plugin;
165
+ export default plugin;
@@ -5,24 +5,26 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
- const visit = require('unist-util-visit');
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 newChildrens = this.parse(node.value).children;
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.children.splice(
23
- parent.children.indexOf(node),
24
+ parent!.children.splice(
25
+ parent!.children.indexOf(node),
24
26
  1,
25
- ...newChildrens,
27
+ ...newChildren,
26
28
  );
27
29
  }
28
30
  });
@@ -31,4 +33,4 @@ function plugin() {
31
33
  return transformer;
32
34
  }
33
35
 
34
- module.exports = plugin;
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
- "allowJs": true,
5
- "noEmit": true,
6
- "noImplicitAny": false
7
- },
8
- "include": ["src/"]
4
+ "incremental": true,
5
+ "tsBuildInfoFile": "./lib/.tsbuildinfo",
6
+ "rootDir": "src",
7
+ "outDir": "lib"
8
+ }
9
9
  }