@docusaurus/mdx-loader 2.0.0-beta.7babfe036 → 2.0.0-beta.8

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 (43) hide show
  1. package/lib/.tsbuildinfo +1 -0
  2. package/lib/index.d.ts +12 -0
  3. package/lib/index.js +161 -0
  4. package/lib/remark/headings/index.d.ts +9 -0
  5. package/lib/remark/headings/index.js +62 -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 +80 -0
  12. package/lib/remark/transformLinks/index.d.ts +13 -0
  13. package/lib/remark/transformLinks/index.js +104 -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 +13 -8
  19. package/src/index.ts +200 -0
  20. package/src/remark/headings/__tests__/{index.test.js → index.test.ts} +0 -2
  21. package/src/remark/headings/{index.js → index.ts} +22 -14
  22. package/src/remark/toc/__tests__/__snapshots__/{index.test.js.snap → index.test.ts.snap} +20 -10
  23. package/src/remark/toc/__tests__/{index.test.js → index.test.ts} +29 -15
  24. package/src/remark/toc/__tests__/search.test.ts +182 -0
  25. package/src/remark/toc/{index.js → index.ts} +24 -16
  26. package/src/remark/toc/search.ts +82 -0
  27. package/src/remark/transformImage/__tests__/__snapshots__/{index.test.js.snap → index.test.ts.snap} +0 -0
  28. package/src/remark/transformImage/__tests__/{index.test.js → index.test.ts} +0 -0
  29. package/src/remark/transformImage/{index.js → index.ts} +31 -21
  30. package/src/remark/transformLinks/__tests__/__snapshots__/{index.test.js.snap → index.test.ts.snap} +5 -1
  31. package/src/remark/transformLinks/__tests__/fixtures/asset.md +4 -0
  32. package/src/remark/transformLinks/__tests__/{index.test.js → index.test.ts} +0 -0
  33. package/src/remark/transformLinks/{index.js → index.ts} +62 -39
  34. package/src/remark/unwrapMdxCodeBlocks/__tests__/__snapshots__/{index.test.js.snap → index.test.ts.snap} +0 -0
  35. package/src/remark/unwrapMdxCodeBlocks/__tests__/{index.test.js → index.test.ts} +0 -0
  36. package/src/remark/unwrapMdxCodeBlocks/{index.js → index.ts} +11 -9
  37. package/src/remark/utils/index.ts +39 -0
  38. package/src/types.d.ts +40 -0
  39. package/tsconfig.json +4 -3
  40. package/src/index.d.ts +0 -19
  41. package/src/index.js +0 -107
  42. package/src/remark/toc/search.js +0 -73
  43. package/src/remark/utils/index.js +0 -39
@@ -5,25 +5,35 @@
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
+ } from '@docusaurus/utils';
13
+ import visit from 'unist-util-visit';
14
+ import path from 'path';
15
+ import url from 'url';
16
+ import fs from 'fs-extra';
17
+ import escapeHtml from 'escape-html';
18
+ import {stringifyContent} from '../utils';
19
+ import {getFileLoaderUtils} from '@docusaurus/core/lib/webpack/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
+ staticDir: string;
31
+ }
25
32
 
26
- async function ensureAssetFileExist(fileSystemAssetPath, sourceFilePath) {
33
+ async function ensureAssetFileExist(
34
+ fileSystemAssetPath: string,
35
+ sourceFilePath: string,
36
+ ) {
27
37
  const assetExists = await fs.pathExists(fileSystemAssetPath);
28
38
  if (!assetExists) {
29
39
  throw new Error(
@@ -35,12 +45,21 @@ async function ensureAssetFileExist(fileSystemAssetPath, sourceFilePath) {
35
45
  }
36
46
 
37
47
  // 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
-
48
+ function toAssetRequireNode({
49
+ node,
50
+ filePath,
51
+ requireAssetPath,
52
+ }: {
53
+ node: Link;
54
+ filePath: string;
55
+ requireAssetPath: string;
56
+ }) {
41
57
  let relativeRequireAssetPath = posixPath(
42
58
  path.relative(path.dirname(filePath), requireAssetPath),
43
59
  );
60
+ const hash = hashRegex.test(node.url)
61
+ ? node.url.substr(node.url.indexOf('#'))
62
+ : '';
44
63
 
45
64
  // nodejs does not like require("assets/file.pdf")
46
65
  relativeRequireAssetPath = relativeRequireAssetPath.startsWith('.')
@@ -49,19 +68,25 @@ function toAssetRequireNode({node, filePath, requireAssetPath}) {
49
68
 
50
69
  const href = `require('${inlineMarkdownLinkFileLoader}${escapePath(
51
70
  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>`;
71
+ )}').default${hash ? ` + '${hash}'` : ''}`;
72
+ const children = stringifyContent(node);
73
+ const title = node.title ? ` title="${escapeHtml(node.title)}"` : '';
74
+
75
+ (node as unknown as Literal).type = 'jsx';
76
+ (
77
+ node as unknown as Literal
78
+ ).value = `<a target="_blank" href={${href}}${title}>${children}</a>`;
58
79
  }
59
80
 
60
81
  // If the link looks like an asset link, we'll link to the asset,
61
82
  // and use a require("assetUrl") (using webpack url-loader/file-loader)
62
83
  // instead of navigating to such link
63
- async function convertToAssetLinkIfNeeded({node, staticDir, filePath}) {
64
- const assetPath = node.url;
84
+ async function convertToAssetLinkIfNeeded({
85
+ node,
86
+ staticDir,
87
+ filePath,
88
+ }: {node: Link} & PluginOptions) {
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,
@@ -102,14 +127,16 @@ async function convertToAssetLinkIfNeeded({node, staticDir, filePath}) {
102
127
  }
103
128
  }
104
129
 
105
- async function processLinkNode({node, _index, _parent, filePath, staticDir}) {
130
+ async function processLinkNode({
131
+ node,
132
+ filePath,
133
+ staticDir,
134
+ }: {node: Link} & PluginOptions) {
106
135
  if (!node.url) {
107
136
  // try to improve error feedback
108
137
  // 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) || '?';
138
+ const title = node.title || (node.children[0] as Literal)?.value || '?';
139
+ const line = node?.position?.start?.line || '?';
113
140
  throw new Error(
114
141
  `Markdown link URL is mandatory in "${toMessageRelativeFilePath(
115
142
  filePath,
@@ -122,22 +149,18 @@ async function processLinkNode({node, _index, _parent, filePath, staticDir}) {
122
149
  return;
123
150
  }
124
151
 
125
- await convertToAssetLinkIfNeeded({
126
- node,
127
- staticDir,
128
- filePath,
129
- });
152
+ await convertToAssetLinkIfNeeded({node, staticDir, filePath});
130
153
  }
131
154
 
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}));
155
+ const plugin: Plugin<[PluginOptions]> = (options) => {
156
+ const transformer: Transformer = async (root) => {
157
+ const promises: Promise<void>[] = [];
158
+ visit(root, 'link', (node: Link) => {
159
+ promises.push(processLinkNode({node, ...options}));
137
160
  });
138
161
  await Promise.all(promises);
139
162
  };
140
163
  return transformer;
141
164
  };
142
165
 
143
- module.exports = plugin;
166
+ 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/types.d.ts ADDED
@@ -0,0 +1,40 @@
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
+ declare module '@docusaurus/mdx-loader' {
9
+ type RemarkOrRehypePlugin =
10
+ // eslint-disable-next-line @typescript-eslint/ban-types
11
+ [Function, Record<string, unknown>] | Function;
12
+ export type RemarkAndRehypePluginOptions = {
13
+ remarkPlugins: RemarkOrRehypePlugin[];
14
+ rehypePlugins: RemarkOrRehypePlugin[];
15
+ beforeDefaultRemarkPlugins: RemarkOrRehypePlugin[];
16
+ beforeDefaultRehypePlugins: RemarkOrRehypePlugin[];
17
+ };
18
+ }
19
+
20
+ // TODO Types provided by MDX 2.0 https://github.com/mdx-js/mdx/blob/main/packages/mdx/types/index.d.ts
21
+ declare module '@mdx-js/mdx' {
22
+ import type {Plugin, Processor} from 'unified';
23
+
24
+ namespace mdx {
25
+ interface Options {
26
+ filepath?: string;
27
+ skipExport?: boolean;
28
+ wrapExport?: string;
29
+ remarkPlugins?: Plugin[];
30
+ rehypePlugins?: Plugin[];
31
+ }
32
+
33
+ function sync(content: string, options?: Options): string;
34
+ function createMdxAstCompiler(options?: Options): Processor;
35
+ function createCompiler(options?: Options): Processor;
36
+ }
37
+ function mdx(content: string, options?: mdx.Options): Promise<string>;
38
+
39
+ export default mdx;
40
+ }
package/tsconfig.json CHANGED
@@ -1,9 +1,10 @@
1
1
  {
2
2
  "extends": "../../tsconfig.json",
3
3
  "compilerOptions": {
4
- "allowJs": true,
5
- "noEmit": true,
6
- "noImplicitAny": false
4
+ "incremental": true,
5
+ "tsBuildInfoFile": "./lib/.tsbuildinfo",
6
+ "rootDir": "src",
7
+ "outDir": "lib"
7
8
  },
8
9
  "include": ["src/"]
9
10
  }
package/src/index.d.ts DELETED
@@ -1,19 +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
- type RemarkOrRehypePlugin =
9
- // eslint-disable-next-line @typescript-eslint/ban-types
10
- [Function, Record<string, unknown>] | Function;
11
-
12
- declare function docusaurusMdxLoader(fileString: string): string;
13
-
14
- export interface RemarkAndRehypePluginOptions {
15
- remarkPlugins: RemarkOrRehypePlugin[];
16
- rehypePlugins: string[];
17
- beforeDefaultRemarkPlugins: RemarkOrRehypePlugin[];
18
- beforeDefaultRehypePlugins: RemarkOrRehypePlugin[];
19
- }
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
- };
@@ -1,73 +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
- // @ts-check
9
-
10
- const toString = require('mdast-util-to-string');
11
- const visit = require('unist-util-visit');
12
- // Destructuring require tslib
13
- // eslint-disable-next-line prefer-destructuring
14
- const toValue = require('../utils').toValue;
15
-
16
- /** @typedef {import('@docusaurus/types').TOCItem} TOC */
17
- /** @typedef {import('unist').Node} Node */
18
-
19
- /**
20
- * @typedef {Object} StringValuedNode
21
- * @property {string} type
22
- * @property {string} value
23
- * @property {number} depth
24
- * @property {Object} data
25
- * @property {StringValuedNode[]} children
26
- */
27
-
28
- // Visit all headings. We `slug` all headings (to account for
29
- // duplicates), but only take h2 and h3 headings.
30
- /**
31
- * @param {StringValuedNode} node
32
- * @returns {TOC[]}
33
- */
34
- function search(node) {
35
- /** @type {TOC[]} */
36
- const headings = [];
37
- let current = -1;
38
- let currentDepth = 0;
39
-
40
- /**
41
- * @param {StringValuedNode} child
42
- * @param {number} index
43
- * @param {Node | undefined} parent
44
- * @returns {void}
45
- */
46
- const onHeading = (child, index, parent) => {
47
- const value = toString(child);
48
-
49
- if (parent !== node || !value || child.depth > 3 || child.depth < 2) {
50
- return;
51
- }
52
-
53
- const entry = {
54
- value: toValue(child),
55
- id: child.data.id,
56
- children: [],
57
- };
58
-
59
- if (!headings.length || currentDepth >= child.depth) {
60
- headings.push(entry);
61
- current += 1;
62
- currentDepth = child.depth;
63
- } else {
64
- headings[current].children.push(entry);
65
- }
66
- };
67
-
68
- visit(node, 'heading', onHeading);
69
-
70
- return headings;
71
- }
72
-
73
- module.exports = search;
@@ -1,39 +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 escapeHtml = require('escape-html');
9
- const toString = require('mdast-util-to-string');
10
-
11
- /**
12
- * @param {StringValuedNode | undefined} node
13
- * @returns {string}
14
- */
15
- function toValue(node) {
16
- if (node && node.type) {
17
- switch (node.type) {
18
- case 'text':
19
- return escapeHtml(node.value);
20
- case 'heading':
21
- return node.children.map(toValue).join('');
22
- case 'inlineCode':
23
- return `<code>${escapeHtml(node.value)}</code>`;
24
- case 'emphasis':
25
- return `<em>${node.children.map(toValue).join('')}</em>`;
26
- case 'strong':
27
- return `<strong>${node.children.map(toValue).join('')}</strong>`;
28
- case 'delete':
29
- return `<del>${node.children.map(toValue).join('')}</del>`;
30
- default:
31
- }
32
- }
33
-
34
- return toString(node);
35
- }
36
-
37
- module.exports = {
38
- toValue,
39
- };