@docusaurus/mdx-loader 2.0.0-beta.138b4c997 → 2.0.0-beta.14

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 (74) hide show
  1. package/lib/index.d.ts +24 -0
  2. package/lib/index.d.ts.map +1 -0
  3. package/lib/index.js +168 -0
  4. package/lib/index.js.map +1 -0
  5. package/lib/remark/headings/index.d.ts +10 -0
  6. package/lib/remark/headings/index.d.ts.map +1 -0
  7. package/lib/remark/headings/index.js +61 -0
  8. package/lib/remark/headings/index.js.map +1 -0
  9. package/lib/remark/toc/index.d.ts +13 -0
  10. package/lib/remark/toc/index.d.ts.map +1 -0
  11. package/lib/remark/toc/index.js +68 -0
  12. package/lib/remark/toc/index.js.map +1 -0
  13. package/lib/remark/toc/search.d.ts +14 -0
  14. package/lib/remark/toc/search.d.ts.map +1 -0
  15. package/lib/remark/toc/search.js +67 -0
  16. package/lib/remark/toc/search.js.map +1 -0
  17. package/lib/remark/transformImage/index.d.ts +14 -0
  18. package/lib/remark/transformImage/index.d.ts.map +1 -0
  19. package/lib/remark/transformImage/index.js +91 -0
  20. package/lib/remark/transformImage/index.js.map +1 -0
  21. package/lib/remark/transformLinks/index.d.ts +15 -0
  22. package/lib/remark/transformLinks/index.d.ts.map +1 -0
  23. package/lib/remark/transformLinks/index.js +107 -0
  24. package/lib/remark/transformLinks/index.js.map +1 -0
  25. package/lib/remark/unwrapMdxCodeBlocks/index.d.ts +10 -0
  26. package/lib/remark/unwrapMdxCodeBlocks/index.d.ts.map +1 -0
  27. package/lib/remark/unwrapMdxCodeBlocks/index.js +29 -0
  28. package/lib/remark/unwrapMdxCodeBlocks/index.js.map +1 -0
  29. package/lib/remark/utils/index.d.ts +11 -0
  30. package/lib/remark/utils/index.d.ts.map +1 -0
  31. package/lib/remark/utils/index.js +40 -0
  32. package/lib/remark/utils/index.js.map +1 -0
  33. package/package.json +16 -12
  34. package/src/deps.d.ts +29 -0
  35. package/src/index.ts +216 -0
  36. package/src/{index.d.ts → mdx-loader.d.ts} +7 -8
  37. package/src/remark/headings/{index.js → index.ts} +21 -16
  38. package/src/remark/toc/{index.js → index.ts} +24 -16
  39. package/src/remark/toc/search.ts +82 -0
  40. package/src/remark/transformImage/{index.js → index.ts} +52 -24
  41. package/src/remark/transformLinks/{index.js → index.ts} +66 -44
  42. package/src/remark/unwrapMdxCodeBlocks/{index.js → index.ts} +11 -9
  43. package/src/remark/utils/index.ts +39 -0
  44. package/src/index.js +0 -107
  45. package/src/remark/headings/__tests__/index.test.js +0 -315
  46. package/src/remark/toc/__tests__/__snapshots__/index.test.js.snap +0 -85
  47. package/src/remark/toc/__tests__/fixtures/empty-headings.md +0 -5
  48. package/src/remark/toc/__tests__/fixtures/inline-code.md +0 -9
  49. package/src/remark/toc/__tests__/fixtures/insert-below-imports.md +0 -11
  50. package/src/remark/toc/__tests__/fixtures/just-content.md +0 -15
  51. package/src/remark/toc/__tests__/fixtures/name-exist.md +0 -7
  52. package/src/remark/toc/__tests__/fixtures/non-text-content.md +0 -9
  53. package/src/remark/toc/__tests__/index.test.js +0 -212
  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/fail.md +0 -1
  57. package/src/remark/transformImage/__tests__/fixtures/img.md +0 -17
  58. package/src/remark/transformImage/__tests__/fixtures/img.png +0 -0
  59. package/src/remark/transformImage/__tests__/fixtures/noUrl.md +0 -1
  60. package/src/remark/transformImage/__tests__/fixtures/pathname.md +0 -1
  61. package/src/remark/transformImage/__tests__/index.test.js +0 -59
  62. package/src/remark/transformLinks/__tests__/__snapshots__/index.test.js.snap +0 -41
  63. package/src/remark/transformLinks/__tests__/fixtures/asset.md +0 -29
  64. package/src/remark/transformLinks/__tests__/fixtures/asset.pdf +0 -0
  65. package/src/remark/transformLinks/__tests__/fixtures/noUrl.md +0 -1
  66. package/src/remark/transformLinks/__tests__/fixtures/pathname.md +0 -1
  67. package/src/remark/transformLinks/__tests__/fixtures/static/staticAsset.pdf +0 -0
  68. package/src/remark/transformLinks/__tests__/fixtures/static/staticAssetImage.png +0 -0
  69. package/src/remark/transformLinks/__tests__/index.test.js +0 -44
  70. package/src/remark/unwrapMdxCodeBlocks/__tests__/__snapshots__/index.test.js.snap +0 -819
  71. package/src/remark/unwrapMdxCodeBlocks/__tests__/fixtures/has-mdx-code-blocks.mdx +0 -95
  72. package/src/remark/unwrapMdxCodeBlocks/__tests__/index.test.js +0 -38
  73. package/src/remark/utils/index.js +0 -39
  74. package/tsconfig.json +0 -9
@@ -5,34 +5,42 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
- const {parse} = require('@babel/parser');
9
- const traverse = require('@babel/traverse').default;
10
- const stringifyObject = require('stringify-object');
11
- const search = require('./search');
8
+ import {parse, ParserOptions} from '@babel/parser';
9
+ import type {Identifier} from '@babel/types';
10
+ import traverse from '@babel/traverse';
11
+ import stringifyObject from 'stringify-object';
12
+ import search from './search';
13
+ import type {Plugin, Transformer} from 'unified';
14
+ import type {Node, Parent} from 'unist';
15
+ import type {Literal} from 'mdast';
12
16
 
13
- const parseOptions = {
17
+ const parseOptions: ParserOptions = {
14
18
  plugins: ['jsx'],
15
19
  sourceType: 'module',
16
20
  };
17
- const isImport = (child) => child.type === 'import';
18
- const hasImports = (index) => index > -1;
19
- const isExport = (child) => child.type === 'export';
20
21
 
21
- const isTarget = (child, name) => {
22
+ const isImport = (child: Node): child is Literal => child.type === 'import';
23
+ const hasImports = (index: number) => index > -1;
24
+ const isExport = (child: Node): child is Literal => child.type === 'export';
25
+
26
+ interface PluginOptions {
27
+ name?: string;
28
+ }
29
+
30
+ const isTarget = (child: Literal, name: string) => {
22
31
  let found = false;
23
32
  const ast = parse(child.value, parseOptions);
24
33
  traverse(ast, {
25
34
  VariableDeclarator: (path) => {
26
- if (path.node.id.name === name) {
35
+ if ((path.node.id as Identifier).name === name) {
27
36
  found = true;
28
37
  }
29
38
  },
30
39
  });
31
-
32
40
  return found;
33
41
  };
34
42
 
35
- const getOrCreateExistingTargetIndex = (children, name) => {
43
+ const getOrCreateExistingTargetIndex = (children: Node[], name: string) => {
36
44
  let importsIndex = -1;
37
45
  let targetIndex = -1;
38
46
 
@@ -58,12 +66,12 @@ const getOrCreateExistingTargetIndex = (children, name) => {
58
66
  return targetIndex;
59
67
  };
60
68
 
61
- const plugin = (options = {}) => {
69
+ const plugin: Plugin<[PluginOptions?]> = (options = {}) => {
62
70
  const name = options.name || 'toc';
63
71
 
64
- const transformer = (node) => {
72
+ const transformer: Transformer = (node) => {
65
73
  const headings = search(node);
66
- const {children} = node;
74
+ const {children} = node as Parent<Literal>;
67
75
  const targetIndex = getOrCreateExistingTargetIndex(children, name);
68
76
 
69
77
  if (headings && headings.length) {
@@ -76,4 +84,4 @@ const plugin = (options = {}) => {
76
84
  return transformer;
77
85
  };
78
86
 
79
- module.exports = plugin;
87
+ export default plugin;
@@ -0,0 +1,82 @@
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 toString from 'mdast-util-to-string';
9
+ import visit, {Visitor} from 'unist-util-visit';
10
+ import {toValue} from '../utils';
11
+ import type {TOCItem} from '@docusaurus/types';
12
+ import type {Node} from 'unist';
13
+ import type {Heading} from 'mdast';
14
+
15
+ // Intermediate interface for TOC algorithm
16
+ interface SearchItem {
17
+ node: TOCItem;
18
+ level: number;
19
+ parentIndex: number;
20
+ }
21
+
22
+ /**
23
+ *
24
+ * Generate a TOC AST from the raw Markdown contents
25
+ */
26
+ export default function search(node: Node): TOCItem[] {
27
+ const headings: SearchItem[] = [];
28
+
29
+ const visitor: Visitor<Heading> = (child, _index, parent) => {
30
+ const value = toString(child);
31
+
32
+ // depth:1 headings are titles and not included in the TOC
33
+ if (parent !== node || !value || child.depth < 2) {
34
+ return;
35
+ }
36
+
37
+ headings.push({
38
+ node: {
39
+ value: toValue(child),
40
+ id: child.data!.id as string,
41
+ children: [],
42
+ level: child.depth,
43
+ },
44
+ level: child.depth,
45
+ parentIndex: -1,
46
+ });
47
+ };
48
+
49
+ visit(node, 'heading', visitor);
50
+
51
+ // Keep track of which previous index would be the current heading's direcy parent.
52
+ // Each entry <i> is the last index of the `headings` array at heading level <i>.
53
+ // We will modify these indices as we iterate through all headings.
54
+ // e.g. if an ### H3 was last seen at index 2, then prevIndexForLevel[3] === 2
55
+ // indices 0 and 1 will remain unused.
56
+ const prevIndexForLevel = Array(7).fill(-1);
57
+
58
+ headings.forEach((curr, currIndex) => {
59
+ // take the last seen index for each ancestor level. the highest
60
+ // index will be the direct ancestor of the current heading.
61
+ const ancestorLevelIndexes = prevIndexForLevel.slice(2, curr.level);
62
+ curr.parentIndex = Math.max(...ancestorLevelIndexes);
63
+ // mark that curr.level was last seen at the current index
64
+ prevIndexForLevel[curr.level] = currIndex;
65
+ });
66
+
67
+ const rootNodeIndexes: number[] = [];
68
+
69
+ // For a given parentIndex, add each Node into that parent's `children` array
70
+ headings.forEach((heading, i) => {
71
+ if (heading.parentIndex >= 0) {
72
+ headings[heading.parentIndex].node.children.push(heading.node);
73
+ } else {
74
+ rootNodeIndexes.push(i);
75
+ }
76
+ });
77
+
78
+ const toc = headings
79
+ .filter((_, k) => rootNodeIndexes.includes(k)) // only return root nodes
80
+ .map((heading) => heading.node); // only return Node, no metadata
81
+ return toc;
82
+ }
@@ -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;
@@ -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/src/index.js DELETED
@@ -1,107 +0,0 @@
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
- const {readFile} = require('fs-extra');
9
- const mdx = require('@mdx-js/mdx');
10
- const emoji = require('remark-emoji');
11
- const {
12
- parseFrontMatter,
13
- parseMarkdownContentTitle,
14
- } = require('@docusaurus/utils');
15
- const stringifyObject = require('stringify-object');
16
- const headings = require('./remark/headings');
17
- const toc = require('./remark/toc');
18
- const unwrapMdxCodeBlocks = require('./remark/unwrapMdxCodeBlocks');
19
- const transformImage = require('./remark/transformImage');
20
- const transformLinks = require('./remark/transformLinks');
21
-
22
- const DEFAULT_OPTIONS = {
23
- rehypePlugins: [],
24
- remarkPlugins: [unwrapMdxCodeBlocks, emoji, headings, toc],
25
- };
26
-
27
- module.exports = async function docusaurusMdxLoader(fileString) {
28
- const callback = this.async();
29
-
30
- const reqOptions = this.getOptions() || {};
31
-
32
- const {frontMatter, content: contentWithTitle} = parseFrontMatter(fileString);
33
-
34
- const {content, contentTitle} = parseMarkdownContentTitle(contentWithTitle, {
35
- removeContentTitle: reqOptions.removeContentTitle,
36
- });
37
-
38
- const hasFrontMatter = Object.keys(frontMatter).length > 0;
39
-
40
- const options = {
41
- ...reqOptions,
42
- remarkPlugins: [
43
- ...(reqOptions.beforeDefaultRemarkPlugins || []),
44
- ...DEFAULT_OPTIONS.remarkPlugins,
45
- [
46
- transformImage,
47
- {staticDir: reqOptions.staticDir, filePath: this.resourcePath},
48
- ],
49
- [
50
- transformLinks,
51
- {staticDir: reqOptions.staticDir, filePath: this.resourcePath},
52
- ],
53
- ...(reqOptions.remarkPlugins || []),
54
- ],
55
- rehypePlugins: [
56
- ...(reqOptions.beforeDefaultRehypePlugins || []),
57
- ...DEFAULT_OPTIONS.rehypePlugins,
58
-
59
- ...(reqOptions.rehypePlugins || []),
60
- ],
61
- filepath: this.resourcePath,
62
- };
63
- let result;
64
-
65
- try {
66
- result = await mdx(content, options);
67
- } catch (err) {
68
- return callback(err);
69
- }
70
-
71
- let exportStr = ``;
72
- exportStr += `\nexport const frontMatter = ${stringifyObject(frontMatter)};`;
73
- exportStr += `\nexport const contentTitle = ${stringifyObject(
74
- contentTitle,
75
- )};`;
76
-
77
- // Read metadata for this MDX and export it.
78
- if (options.metadataPath && typeof options.metadataPath === 'function') {
79
- const metadataPath = options.metadataPath(this.resourcePath);
80
-
81
- if (metadataPath) {
82
- // Add as dependency of this loader result so that we can
83
- // recompile if metadata is changed.
84
- this.addDependency(metadataPath);
85
- const metadata = await readFile(metadataPath, 'utf8');
86
- exportStr += `\nexport const metadata = ${metadata};`;
87
- }
88
- }
89
-
90
- if (
91
- options.forbidFrontMatter &&
92
- typeof options.forbidFrontMatter === 'function'
93
- ) {
94
- if (options.forbidFrontMatter(this.resourcePath) && hasFrontMatter) {
95
- return callback(new Error(`Front matter is forbidden in this file`));
96
- }
97
- }
98
- const code = `
99
- import React from 'react';
100
- import { mdx } from '@mdx-js/react';
101
-
102
- ${exportStr}
103
- ${result}
104
- `;
105
-
106
- return callback(null, code);
107
- };