@astrojs/mdx 0.8.2 → 0.10.0
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/.turbo/turbo-build.log +5 -5
- package/CHANGELOG.md +30 -0
- package/README.md +20 -3
- package/dist/astro-data-utils.js +37 -0
- package/dist/index.js +28 -24
- package/dist/remark-shiki.d.ts +3 -0
- package/dist/remark-shiki.js +58 -0
- package/package.json +4 -4
- package/src/astro-data-utils.ts +38 -0
- package/src/index.ts +30 -25
- package/src/remark-shiki.ts +85 -0
- package/test/fixtures/mdx-component/src/pages/glob.astro +11 -0
- package/test/fixtures/mdx-frontmatter/src/layouts/Base.astro +7 -1
- package/test/fixtures/mdx-frontmatter-injection/node_modules/.bin/astro +2 -2
- package/test/fixtures/mdx-frontmatter-injection/src/layouts/Base.astro +17 -0
- package/test/fixtures/mdx-frontmatter-injection/src/pages/page-1.mdx +4 -0
- package/test/fixtures/mdx-frontmatter-injection/src/pages/page-2.mdx +4 -0
- package/test/fixtures/mdx-namespace/astro.config.mjs +6 -0
- package/test/fixtures/mdx-namespace/node_modules/.bin/astro +17 -0
- package/test/fixtures/mdx-namespace/package.json +8 -0
- package/test/fixtures/mdx-namespace/src/components/Component.jsx +6 -0
- package/test/fixtures/mdx-namespace/src/pages/object.mdx +3 -0
- package/test/fixtures/mdx-namespace/src/pages/star.mdx +3 -0
- package/test/fixtures/mdx-page/node_modules/.bin/astro +2 -2
- package/test/fixtures/mdx-plus-react/node_modules/.bin/astro +2 -2
- package/test/mdx-component.test.js +54 -2
- package/test/mdx-frontmatter-injection.test.js +12 -0
- package/test/mdx-frontmatter.test.js +14 -0
- package/test/mdx-namespace.test.js +83 -0
- package/test/mdx-syntax-highlighting.test.js +26 -2
- package/test/fixtures/mdx-component/dist/index.html +0 -3
- package/test/fixtures/mdx-component/node_modules/.vite/deps_temp/package.json +0 -1
- package/test/fixtures/mdx-custom-frontmatter-name/dist/glob.json +0 -1
- package/test/fixtures/mdx-custom-frontmatter-name/dist/index.html +0 -1
- package/test/fixtures/mdx-custom-frontmatter-name/node_modules/.vite/deps_temp/package.json +0 -1
- package/test/fixtures/mdx-frontmatter/dist/glob.json +0 -1
- package/test/fixtures/mdx-frontmatter/dist/index.html +0 -17
- package/test/fixtures/mdx-frontmatter/dist/with-headings/index.html +0 -18
- package/test/fixtures/mdx-frontmatter/node_modules/.vite/deps_temp/package.json +0 -1
- package/test/fixtures/mdx-get-headings/dist/pages.json +0 -1
- package/test/fixtures/mdx-get-headings/dist/test/index.html +0 -5
- package/test/fixtures/mdx-get-headings/dist/test-with-jsx-expressions/index.html +0 -3
- package/test/fixtures/mdx-get-headings/node_modules/.vite/deps_temp/package.json +0 -1
- package/test/fixtures/mdx-get-static-paths/dist/one/index.html +0 -13
- package/test/fixtures/mdx-page/dist/index.html +0 -1
- package/test/fixtures/mdx-page/node_modules/.vite/deps_temp/package.json +0 -1
- package/test/fixtures/mdx-plus-react/dist/client.0d691cb3.js +0 -32
- package/test/fixtures/mdx-plus-react/dist/index.html +0 -8
- package/test/fixtures/mdx-plus-react/node_modules/.vite/deps_temp/@astrojs_react_client__js.js +0 -95
- package/test/fixtures/mdx-plus-react/node_modules/.vite/deps_temp/@astrojs_react_client__js.js.map +0 -7
- package/test/fixtures/mdx-plus-react/node_modules/.vite/deps_temp/_metadata.json +0 -47
- package/test/fixtures/mdx-plus-react/node_modules/.vite/deps_temp/chunk-CDYRCHBX.js +0 -7480
- package/test/fixtures/mdx-plus-react/node_modules/.vite/deps_temp/chunk-CDYRCHBX.js.map +0 -7
- package/test/fixtures/mdx-plus-react/node_modules/.vite/deps_temp/chunk-RRXZ3AUC.js +0 -326
- package/test/fixtures/mdx-plus-react/node_modules/.vite/deps_temp/chunk-RRXZ3AUC.js.map +0 -7
- package/test/fixtures/mdx-plus-react/node_modules/.vite/deps_temp/chunk-TWLJ45QX.js +0 -27
- package/test/fixtures/mdx-plus-react/node_modules/.vite/deps_temp/chunk-TWLJ45QX.js.map +0 -7
- package/test/fixtures/mdx-plus-react/node_modules/.vite/deps_temp/package.json +0 -1
- package/test/fixtures/mdx-plus-react/node_modules/.vite/deps_temp/react-dom.js +0 -12
- package/test/fixtures/mdx-plus-react/node_modules/.vite/deps_temp/react-dom.js.map +0 -7
- package/test/fixtures/mdx-plus-react/node_modules/.vite/deps_temp/react.js +0 -11
- package/test/fixtures/mdx-plus-react/node_modules/.vite/deps_temp/react.js.map +0 -7
- package/test/fixtures/mdx-plus-react/node_modules/.vite/deps_temp/react_jsx-dev-runtime.js +0 -41
- package/test/fixtures/mdx-plus-react/node_modules/.vite/deps_temp/react_jsx-dev-runtime.js.map +0 -7
- package/test/fixtures/mdx-plus-react/node_modules/.vite/deps_temp/react_jsx-runtime.js +0 -62
- package/test/fixtures/mdx-plus-react/node_modules/.vite/deps_temp/react_jsx-runtime.js.map +0 -7
- package/test/fixtures/mdx-rehype-plugins/dist/reading-time.json +0 -1
- package/test/fixtures/mdx-rehype-plugins/dist/space-ipsum/index.html +0 -13
- package/test/fixtures/mdx-rehype-plugins/node_modules/.vite/deps_temp/package.json +0 -1
- package/test/fixtures/mdx-remark-plugins/dist/with-gfm/index.html +0 -2
- package/test/fixtures/mdx-remark-plugins/dist/with-toc/index.html +0 -22
- package/test/fixtures/mdx-remark-plugins/node_modules/.vite/deps_temp/package.json +0 -1
- package/test/fixtures/mdx-syntax-hightlighting/dist/index.html +0 -6
- package/test/fixtures/mdx-syntax-hightlighting/node_modules/.vite/deps_temp/package.json +0 -1
- package/test/fixtures/mdx-url-export/dist/pages.json +0 -1
- package/test/fixtures/mdx-url-export/dist/test-1/index.html +0 -1
- package/test/fixtures/mdx-url-export/dist/test-2/index.html +0 -1
- package/test/fixtures/mdx-url-export/dist/with-url-override/index.html +0 -1
- package/test/fixtures/mdx-url-export/node_modules/.vite/deps_temp/package.json +0 -1
- package/test/fixtures/node_modules/.vite/deps_temp/package.json +0 -1
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
[
|
|
2
|
-
[
|
|
3
|
-
[
|
|
4
|
-
[
|
|
5
|
-
[
|
|
1
|
+
[34m@astrojs/mdx:build: [0mcache hit, replaying output [2m9de770958d53d2f8[0m
|
|
2
|
+
[34m@astrojs/mdx:build: [0m
|
|
3
|
+
[34m@astrojs/mdx:build: [0m> @astrojs/mdx@0.10.0 build /home/runner/work/astro/astro/packages/integrations/mdx
|
|
4
|
+
[34m@astrojs/mdx:build: [0m> astro-scripts build "src/**/*.ts" && tsc
|
|
5
|
+
[34m@astrojs/mdx:build: [0m
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# @astrojs/mdx
|
|
2
2
|
|
|
3
|
+
## 0.10.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#4292](https://github.com/withastro/astro/pull/4292) [`f1a52c18a`](https://github.com/withastro/astro/commit/f1a52c18afe66e6d310743ae6884be76f69be265) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Switch from Shiki Twoslash to Astro's Shiki Markdown highlighter
|
|
8
|
+
|
|
9
|
+
## 0.9.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- [#4268](https://github.com/withastro/astro/pull/4268) [`f7afdb889`](https://github.com/withastro/astro/commit/f7afdb889fe4e97177958c8ec92f80c5f6e5cb51) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Align MD with MDX on layout props and "glob" import results:
|
|
14
|
+
- Add `Content` to MDX
|
|
15
|
+
- Add `file` and `url` to MDX frontmatter (layout import only)
|
|
16
|
+
- Update glob types to reflect differences (lack of `rawContent` and `compiledContent`)
|
|
17
|
+
|
|
18
|
+
### Patch Changes
|
|
19
|
+
|
|
20
|
+
- [#4272](https://github.com/withastro/astro/pull/4272) [`24d2f7a6e`](https://github.com/withastro/astro/commit/24d2f7a6e6700c10c863f826f37bb653d70e3a83) Thanks [@natemoo-re](https://github.com/natemoo-re)! - Properly handle hydration for namespaced components
|
|
21
|
+
|
|
22
|
+
## 0.8.3
|
|
23
|
+
|
|
24
|
+
### Patch Changes
|
|
25
|
+
|
|
26
|
+
- [#4248](https://github.com/withastro/astro/pull/4248) [`869d00935`](https://github.com/withastro/astro/commit/869d0093596b709cfcc1a1a95ee631b48d6d1c26) Thanks [@svemat01](https://github.com/svemat01)! - Load builtin rehype plugins before user plugins instead of after
|
|
27
|
+
|
|
28
|
+
* [#4255](https://github.com/withastro/astro/pull/4255) [`411612808`](https://github.com/withastro/astro/commit/4116128082121ee276d51cb245bf8095be4728a1) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Pass injected frontmatter from remark and rehype plugins to layouts
|
|
29
|
+
|
|
30
|
+
* Updated dependencies [[`1f0dd31d9`](https://github.com/withastro/astro/commit/1f0dd31d9239b5e3dca99c88d021e7a9a3e2054d)]:
|
|
31
|
+
- @astrojs/prism@1.0.1
|
|
32
|
+
|
|
3
33
|
## 0.8.2
|
|
4
34
|
|
|
5
35
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -26,11 +26,11 @@ The `astro add` command-line tool automates the installation for you. Run one of
|
|
|
26
26
|
|
|
27
27
|
```sh
|
|
28
28
|
# Using NPM
|
|
29
|
-
|
|
29
|
+
npm run astro add mdx
|
|
30
30
|
# Using Yarn
|
|
31
31
|
yarn astro add mdx
|
|
32
32
|
# Using PNPM
|
|
33
|
-
|
|
33
|
+
pnpm astro add mdx
|
|
34
34
|
```
|
|
35
35
|
|
|
36
36
|
Then, restart the dev server by typing `CTRL-C` and then `npm run astro dev` in the terminal window that was running Astro.
|
|
@@ -253,7 +253,7 @@ const { title, fancyJsHelper } = Astro.props;
|
|
|
253
253
|
|
|
254
254
|
The MDX integration respects [your project's `markdown.syntaxHighlight` configuration](https://docs.astro.build/en/guides/markdown-content/#syntax-highlighting).
|
|
255
255
|
|
|
256
|
-
We will highlight your code blocks with [Shiki](https://github.com/shikijs/shiki) by default
|
|
256
|
+
We will highlight your code blocks with [Shiki](https://github.com/shikijs/shiki) by default. You can customize this highlighter using the `markdown.shikiConfig` option in your `astro.config`. For example, you can apply a different built-in theme like so:
|
|
257
257
|
|
|
258
258
|
```js
|
|
259
259
|
// astro.config.mjs
|
|
@@ -285,6 +285,23 @@ export default {
|
|
|
285
285
|
|
|
286
286
|
This applies a minimal Prism renderer with added support for `astro` code blocks. Visit [our "Prism configuration" docs](https://docs.astro.build/en/guides/markdown-content/#prism-configuration) for more on using Prism with Astro.
|
|
287
287
|
|
|
288
|
+
#### Switch to a custom syntax highlighter
|
|
289
|
+
|
|
290
|
+
You may want to apply your own syntax highlighter too. If your highlighter offers a remark or rehype plugin, you can flip off our syntax highlighting by setting `markdown.syntaxHighlight: false` and wiring up your plugin. For example, say you want to apply [Shiki Twoslash's remark plugin](https://www.npmjs.com/package/remark-shiki-twoslash):
|
|
291
|
+
|
|
292
|
+
```js
|
|
293
|
+
// astro.config.mjs
|
|
294
|
+
import shikiTwoslash from 'remark-shiki-twoslash';
|
|
295
|
+
|
|
296
|
+
export default {
|
|
297
|
+
markdown: {
|
|
298
|
+
syntaxHighlight: false,
|
|
299
|
+
},
|
|
300
|
+
integrations: [mdx({
|
|
301
|
+
remarkPlugins: [shikiTwoslash, { /* Shiki Twoslash config */ }],
|
|
302
|
+
})],
|
|
303
|
+
```
|
|
304
|
+
|
|
288
305
|
## Configuration
|
|
289
306
|
|
|
290
307
|
### remarkPlugins
|
package/dist/astro-data-utils.js
CHANGED
|
@@ -14,6 +14,43 @@ function rehypeApplyFrontmatterExport(pageFrontmatter) {
|
|
|
14
14
|
const exportNodes = [
|
|
15
15
|
jsToTreeNode(`export const ${EXPORT_NAME} = ${JSON.stringify(frontmatter)};`)
|
|
16
16
|
];
|
|
17
|
+
if (frontmatter.layout) {
|
|
18
|
+
exportNodes.unshift(
|
|
19
|
+
jsToTreeNode(
|
|
20
|
+
`import { jsx as layoutJsx } from 'astro/jsx-runtime';
|
|
21
|
+
import Layout from ${JSON.stringify(frontmatter.layout)};
|
|
22
|
+
|
|
23
|
+
export default function ({ children }) {
|
|
24
|
+
const { layout, ...content } = frontmatter;
|
|
25
|
+
content.file = file;
|
|
26
|
+
content.url = url;
|
|
27
|
+
content.astro = {};
|
|
28
|
+
Object.defineProperty(content.astro, 'headings', {
|
|
29
|
+
get() {
|
|
30
|
+
throw new Error('The "astro" property is no longer supported! To access "headings" from your layout, try using "Astro.props.headings."')
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
Object.defineProperty(content.astro, 'html', {
|
|
34
|
+
get() {
|
|
35
|
+
throw new Error('The "astro" property is no longer supported! To access "html" from your layout, try using "Astro.props.compiledContent()."')
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
Object.defineProperty(content.astro, 'source', {
|
|
39
|
+
get() {
|
|
40
|
+
throw new Error('The "astro" property is no longer supported! To access "source" from your layout, try using "Astro.props.rawContent()."')
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
return layoutJsx(Layout, {
|
|
44
|
+
content,
|
|
45
|
+
frontmatter: content,
|
|
46
|
+
headings: getHeadings(),
|
|
47
|
+
'server:root': true,
|
|
48
|
+
children,
|
|
49
|
+
});
|
|
50
|
+
};`
|
|
51
|
+
)
|
|
52
|
+
);
|
|
53
|
+
}
|
|
17
54
|
tree.children = exportNodes.concat(tree.children);
|
|
18
55
|
};
|
|
19
56
|
}
|
package/dist/index.js
CHANGED
|
@@ -3,31 +3,32 @@ import mdxPlugin from "@mdx-js/rollup";
|
|
|
3
3
|
import { parse as parseESM } from "es-module-lexer";
|
|
4
4
|
import rehypeRaw from "rehype-raw";
|
|
5
5
|
import remarkGfm from "remark-gfm";
|
|
6
|
-
import remarkShikiTwoslash from "remark-shiki-twoslash";
|
|
7
6
|
import remarkSmartypants from "remark-smartypants";
|
|
8
7
|
import { VFile } from "vfile";
|
|
9
8
|
import { rehypeApplyFrontmatterExport, remarkInitializeAstroData } from "./astro-data-utils.js";
|
|
10
9
|
import rehypeCollectHeadings from "./rehype-collect-headings.js";
|
|
11
10
|
import remarkPrism from "./remark-prism.js";
|
|
11
|
+
import remarkShiki from "./remark-shiki.js";
|
|
12
12
|
import { getFileInfo, parseFrontmatter } from "./utils.js";
|
|
13
13
|
const DEFAULT_REMARK_PLUGINS = [
|
|
14
14
|
remarkGfm,
|
|
15
15
|
remarkSmartypants
|
|
16
16
|
];
|
|
17
17
|
const DEFAULT_REHYPE_PLUGINS = [];
|
|
18
|
+
const RAW_CONTENT_ERROR = "MDX does not support rawContent()! If you need to read the Markdown contents to calculate values (ex. reading time), we suggest injecting frontmatter via remark plugins. Learn more on our docs: https://docs.astro.build/en/guides/integrations-guide/mdx/#inject-frontmatter-via-remark-or-rehype-plugins";
|
|
19
|
+
const COMPILED_CONTENT_ERROR = "MDX does not support compiledContent()! If you need to read the HTML contents to calculate values (ex. reading time), we suggest injecting frontmatter via rehype plugins. Learn more on our docs: https://docs.astro.build/en/guides/integrations-guide/mdx/#inject-frontmatter-via-remark-or-rehype-plugins";
|
|
18
20
|
function handleExtends(config, defaults = []) {
|
|
19
21
|
if (Array.isArray(config))
|
|
20
22
|
return config;
|
|
21
23
|
return [...defaults, ...(config == null ? void 0 : config.extends) ?? []];
|
|
22
24
|
}
|
|
23
|
-
function getRemarkPlugins(mdxOptions, config) {
|
|
25
|
+
async function getRemarkPlugins(mdxOptions, config) {
|
|
24
26
|
let remarkPlugins = [
|
|
25
27
|
remarkInitializeAstroData,
|
|
26
28
|
...handleExtends(mdxOptions.remarkPlugins, DEFAULT_REMARK_PLUGINS)
|
|
27
29
|
];
|
|
28
30
|
if (config.markdown.syntaxHighlight === "shiki") {
|
|
29
|
-
|
|
30
|
-
remarkPlugins.push([shikiTwoslash, config.markdown.shikiConfig]);
|
|
31
|
+
remarkPlugins.push([await remarkShiki(config.markdown.shikiConfig)]);
|
|
31
32
|
}
|
|
32
33
|
if (config.markdown.syntaxHighlight === "prism") {
|
|
33
34
|
remarkPlugins.push(remarkPrism);
|
|
@@ -35,10 +36,10 @@ function getRemarkPlugins(mdxOptions, config) {
|
|
|
35
36
|
return remarkPlugins;
|
|
36
37
|
}
|
|
37
38
|
function getRehypePlugins(mdxOptions, config) {
|
|
38
|
-
let rehypePlugins =
|
|
39
|
-
|
|
40
|
-
rehypePlugins
|
|
41
|
-
|
|
39
|
+
let rehypePlugins = [
|
|
40
|
+
[rehypeRaw, { passThrough: nodeTypes }],
|
|
41
|
+
...handleExtends(mdxOptions.rehypePlugins, DEFAULT_REHYPE_PLUGINS)
|
|
42
|
+
];
|
|
42
43
|
rehypePlugins.unshift(rehypeCollectHeadings);
|
|
43
44
|
return rehypePlugins;
|
|
44
45
|
}
|
|
@@ -46,10 +47,10 @@ function mdx(mdxOptions = {}) {
|
|
|
46
47
|
return {
|
|
47
48
|
name: "@astrojs/mdx",
|
|
48
49
|
hooks: {
|
|
49
|
-
"astro:config:setup": ({ updateConfig, config, addPageExtension, command }) => {
|
|
50
|
+
"astro:config:setup": async ({ updateConfig, config, addPageExtension, command }) => {
|
|
50
51
|
addPageExtension(".mdx");
|
|
51
52
|
const mdxPluginOpts = {
|
|
52
|
-
remarkPlugins: getRemarkPlugins(mdxOptions, config),
|
|
53
|
+
remarkPlugins: await getRemarkPlugins(mdxOptions, config),
|
|
53
54
|
rehypePlugins: getRehypePlugins(mdxOptions, config),
|
|
54
55
|
jsx: true,
|
|
55
56
|
jsxImportSource: "astro",
|
|
@@ -65,20 +66,7 @@ function mdx(mdxOptions = {}) {
|
|
|
65
66
|
async transform(code, id) {
|
|
66
67
|
if (!id.endsWith("mdx"))
|
|
67
68
|
return;
|
|
68
|
-
|
|
69
|
-
if (frontmatter.layout) {
|
|
70
|
-
const { layout, ...contentProp } = frontmatter;
|
|
71
|
-
pageContent += `
|
|
72
|
-
|
|
73
|
-
export default async function({ children }) {
|
|
74
|
-
const Layout = (await import(${JSON.stringify(
|
|
75
|
-
frontmatter.layout
|
|
76
|
-
)})).default;
|
|
77
|
-
const frontmatter=${JSON.stringify(
|
|
78
|
-
contentProp
|
|
79
|
-
)};
|
|
80
|
-
return <Layout frontmatter={frontmatter} content={frontmatter} headings={getHeadings()}>{children}</Layout> }`;
|
|
81
|
-
}
|
|
69
|
+
const { data: frontmatter, content: pageContent } = parseFrontmatter(code, id);
|
|
82
70
|
const compiled = await mdxCompile(new VFile({ value: pageContent, path: id }), {
|
|
83
71
|
...mdxPluginOpts,
|
|
84
72
|
rehypePlugins: [
|
|
@@ -106,6 +94,22 @@ export const url = ${JSON.stringify(fileUrl)};`;
|
|
|
106
94
|
if (!moduleExports.includes("file")) {
|
|
107
95
|
code += `
|
|
108
96
|
export const file = ${JSON.stringify(fileId)};`;
|
|
97
|
+
}
|
|
98
|
+
if (!moduleExports.includes("rawContent")) {
|
|
99
|
+
code += `
|
|
100
|
+
export function rawContent() { throw new Error(${JSON.stringify(
|
|
101
|
+
RAW_CONTENT_ERROR
|
|
102
|
+
)}) };`;
|
|
103
|
+
}
|
|
104
|
+
if (!moduleExports.includes("compiledContent")) {
|
|
105
|
+
code += `
|
|
106
|
+
export function compiledContent() { throw new Error(${JSON.stringify(
|
|
107
|
+
COMPILED_CONTENT_ERROR
|
|
108
|
+
)}) };`;
|
|
109
|
+
}
|
|
110
|
+
if (!moduleExports.includes("Content")) {
|
|
111
|
+
code += `
|
|
112
|
+
export const Content = MDXContent;`;
|
|
109
113
|
}
|
|
110
114
|
if (command === "dev") {
|
|
111
115
|
code += `
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { getHighlighter } from "shiki";
|
|
2
|
+
import { visit } from "unist-util-visit";
|
|
3
|
+
const highlighterCacheAsync = /* @__PURE__ */ new Map();
|
|
4
|
+
const remarkShiki = async ({ langs = [], theme = "github-dark", wrap = false }) => {
|
|
5
|
+
const cacheID = typeof theme === "string" ? theme : theme.name;
|
|
6
|
+
let highlighterAsync = highlighterCacheAsync.get(cacheID);
|
|
7
|
+
if (!highlighterAsync) {
|
|
8
|
+
highlighterAsync = getHighlighter({ theme });
|
|
9
|
+
highlighterCacheAsync.set(cacheID, highlighterAsync);
|
|
10
|
+
}
|
|
11
|
+
const highlighter = await highlighterAsync;
|
|
12
|
+
for (const lang of langs) {
|
|
13
|
+
await highlighter.loadLanguage(lang);
|
|
14
|
+
}
|
|
15
|
+
return () => (tree) => {
|
|
16
|
+
visit(tree, "code", (node) => {
|
|
17
|
+
let lang;
|
|
18
|
+
if (typeof node.lang === "string") {
|
|
19
|
+
const langExists = highlighter.getLoadedLanguages().includes(node.lang);
|
|
20
|
+
if (langExists) {
|
|
21
|
+
lang = node.lang;
|
|
22
|
+
} else {
|
|
23
|
+
console.warn(`The language "${node.lang}" doesn't exist, falling back to plaintext.`);
|
|
24
|
+
lang = "plaintext";
|
|
25
|
+
}
|
|
26
|
+
} else {
|
|
27
|
+
lang = "plaintext";
|
|
28
|
+
}
|
|
29
|
+
let html = highlighter.codeToHtml(node.value, { lang });
|
|
30
|
+
html = html.replace('<pre class="shiki"', `<pre class="astro-code"`);
|
|
31
|
+
html = html.replace(
|
|
32
|
+
/style="(background-)?color: var\(--shiki-/g,
|
|
33
|
+
'style="$1color: var(--astro-code-'
|
|
34
|
+
);
|
|
35
|
+
if (node.lang === "diff") {
|
|
36
|
+
html = html.replace(
|
|
37
|
+
/<span class="line"><span style="(.*?)">([\+|\-])/g,
|
|
38
|
+
'<span class="line"><span style="$1"><span style="user-select: none;">$2</span>'
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
if (wrap === false) {
|
|
42
|
+
html = html.replace(/style="(.*?)"/, 'style="$1; overflow-x: auto;"');
|
|
43
|
+
} else if (wrap === true) {
|
|
44
|
+
html = html.replace(
|
|
45
|
+
/style="(.*?)"/,
|
|
46
|
+
'style="$1; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;"'
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
node.type = "html";
|
|
50
|
+
node.value = html;
|
|
51
|
+
node.children = [];
|
|
52
|
+
});
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
var remark_shiki_default = remarkShiki;
|
|
56
|
+
export {
|
|
57
|
+
remark_shiki_default as default
|
|
58
|
+
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astrojs/mdx",
|
|
3
3
|
"description": "Use MDX within Astro",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.10.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
7
7
|
"author": "withastro",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"./package.json": "./package.json"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@astrojs/prism": "^1.0.
|
|
26
|
+
"@astrojs/prism": "^1.0.1",
|
|
27
27
|
"@mdx-js/mdx": "^2.1.2",
|
|
28
28
|
"@mdx-js/rollup": "^2.1.1",
|
|
29
29
|
"acorn": "^8.8.0",
|
|
@@ -33,7 +33,6 @@
|
|
|
33
33
|
"rehype-raw": "^6.1.1",
|
|
34
34
|
"remark-frontmatter": "^4.0.1",
|
|
35
35
|
"remark-gfm": "^3.0.1",
|
|
36
|
-
"remark-shiki-twoslash": "^3.1.0",
|
|
37
36
|
"remark-smartypants": "^2.0.0",
|
|
38
37
|
"shiki": "^0.10.1",
|
|
39
38
|
"unist-util-visit": "^4.1.0",
|
|
@@ -43,13 +42,14 @@
|
|
|
43
42
|
"@types/chai": "^4.3.1",
|
|
44
43
|
"@types/mocha": "^9.1.1",
|
|
45
44
|
"@types/yargs-parser": "^21.0.0",
|
|
46
|
-
"astro": "1.0.
|
|
45
|
+
"astro": "1.0.6",
|
|
47
46
|
"astro-scripts": "0.0.7",
|
|
48
47
|
"chai": "^4.3.6",
|
|
49
48
|
"linkedom": "^0.14.12",
|
|
50
49
|
"mdast-util-to-string": "^3.1.0",
|
|
51
50
|
"mocha": "^9.2.2",
|
|
52
51
|
"reading-time": "^1.5.0",
|
|
52
|
+
"remark-shiki-twoslash": "^3.1.0",
|
|
53
53
|
"remark-toc": "^8.0.1"
|
|
54
54
|
},
|
|
55
55
|
"engines": {
|
package/src/astro-data-utils.ts
CHANGED
|
@@ -19,6 +19,44 @@ export function rehypeApplyFrontmatterExport(pageFrontmatter: Record<string, any
|
|
|
19
19
|
const exportNodes = [
|
|
20
20
|
jsToTreeNode(`export const ${EXPORT_NAME} = ${JSON.stringify(frontmatter)};`),
|
|
21
21
|
];
|
|
22
|
+
if (frontmatter.layout) {
|
|
23
|
+
exportNodes.unshift(
|
|
24
|
+
jsToTreeNode(
|
|
25
|
+
/** @see 'vite-plugin-markdown' for layout props reference */
|
|
26
|
+
`import { jsx as layoutJsx } from 'astro/jsx-runtime';
|
|
27
|
+
import Layout from ${JSON.stringify(frontmatter.layout)};
|
|
28
|
+
|
|
29
|
+
export default function ({ children }) {
|
|
30
|
+
const { layout, ...content } = frontmatter;
|
|
31
|
+
content.file = file;
|
|
32
|
+
content.url = url;
|
|
33
|
+
content.astro = {};
|
|
34
|
+
Object.defineProperty(content.astro, 'headings', {
|
|
35
|
+
get() {
|
|
36
|
+
throw new Error('The "astro" property is no longer supported! To access "headings" from your layout, try using "Astro.props.headings."')
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
Object.defineProperty(content.astro, 'html', {
|
|
40
|
+
get() {
|
|
41
|
+
throw new Error('The "astro" property is no longer supported! To access "html" from your layout, try using "Astro.props.compiledContent()."')
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
Object.defineProperty(content.astro, 'source', {
|
|
45
|
+
get() {
|
|
46
|
+
throw new Error('The "astro" property is no longer supported! To access "source" from your layout, try using "Astro.props.rawContent()."')
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
return layoutJsx(Layout, {
|
|
50
|
+
content,
|
|
51
|
+
frontmatter: content,
|
|
52
|
+
headings: getHeadings(),
|
|
53
|
+
'server:root': true,
|
|
54
|
+
children,
|
|
55
|
+
});
|
|
56
|
+
};`
|
|
57
|
+
)
|
|
58
|
+
);
|
|
59
|
+
}
|
|
22
60
|
tree.children = exportNodes.concat(tree.children);
|
|
23
61
|
};
|
|
24
62
|
}
|
package/src/index.ts
CHANGED
|
@@ -4,13 +4,13 @@ import type { AstroConfig, AstroIntegration } from 'astro';
|
|
|
4
4
|
import { parse as parseESM } from 'es-module-lexer';
|
|
5
5
|
import rehypeRaw from 'rehype-raw';
|
|
6
6
|
import remarkGfm from 'remark-gfm';
|
|
7
|
-
import remarkShikiTwoslash from 'remark-shiki-twoslash';
|
|
8
7
|
import remarkSmartypants from 'remark-smartypants';
|
|
9
8
|
import { VFile } from 'vfile';
|
|
10
9
|
import type { Plugin as VitePlugin } from 'vite';
|
|
11
10
|
import { rehypeApplyFrontmatterExport, remarkInitializeAstroData } from './astro-data-utils.js';
|
|
12
11
|
import rehypeCollectHeadings from './rehype-collect-headings.js';
|
|
13
12
|
import remarkPrism from './remark-prism.js';
|
|
13
|
+
import remarkShiki from './remark-shiki.js';
|
|
14
14
|
import { getFileInfo, parseFrontmatter } from './utils.js';
|
|
15
15
|
|
|
16
16
|
type WithExtends<T> = T | { extends: T };
|
|
@@ -26,28 +26,29 @@ const DEFAULT_REMARK_PLUGINS: MdxRollupPluginOptions['remarkPlugins'] = [
|
|
|
26
26
|
];
|
|
27
27
|
const DEFAULT_REHYPE_PLUGINS: MdxRollupPluginOptions['rehypePlugins'] = [];
|
|
28
28
|
|
|
29
|
+
const RAW_CONTENT_ERROR =
|
|
30
|
+
'MDX does not support rawContent()! If you need to read the Markdown contents to calculate values (ex. reading time), we suggest injecting frontmatter via remark plugins. Learn more on our docs: https://docs.astro.build/en/guides/integrations-guide/mdx/#inject-frontmatter-via-remark-or-rehype-plugins';
|
|
31
|
+
|
|
32
|
+
const COMPILED_CONTENT_ERROR =
|
|
33
|
+
'MDX does not support compiledContent()! If you need to read the HTML contents to calculate values (ex. reading time), we suggest injecting frontmatter via rehype plugins. Learn more on our docs: https://docs.astro.build/en/guides/integrations-guide/mdx/#inject-frontmatter-via-remark-or-rehype-plugins';
|
|
34
|
+
|
|
29
35
|
function handleExtends<T>(config: WithExtends<T[] | undefined>, defaults: T[] = []): T[] {
|
|
30
36
|
if (Array.isArray(config)) return config;
|
|
31
37
|
|
|
32
38
|
return [...defaults, ...(config?.extends ?? [])];
|
|
33
39
|
}
|
|
34
40
|
|
|
35
|
-
function getRemarkPlugins(
|
|
41
|
+
async function getRemarkPlugins(
|
|
36
42
|
mdxOptions: MdxOptions,
|
|
37
43
|
config: AstroConfig
|
|
38
|
-
): MdxRollupPluginOptions['remarkPlugins'] {
|
|
44
|
+
): Promise<MdxRollupPluginOptions['remarkPlugins']> {
|
|
39
45
|
let remarkPlugins = [
|
|
40
46
|
// Initialize vfile.data.astroExports before all plugins are run
|
|
41
47
|
remarkInitializeAstroData,
|
|
42
48
|
...handleExtends(mdxOptions.remarkPlugins, DEFAULT_REMARK_PLUGINS),
|
|
43
49
|
];
|
|
44
50
|
if (config.markdown.syntaxHighlight === 'shiki') {
|
|
45
|
-
|
|
46
|
-
// Workarounds tried:
|
|
47
|
-
// - "import * as remarkShikiTwoslash"
|
|
48
|
-
// - "import { default as remarkShikiTwoslash }"
|
|
49
|
-
const shikiTwoslash = (remarkShikiTwoslash as any).default ?? remarkShikiTwoslash;
|
|
50
|
-
remarkPlugins.push([shikiTwoslash, config.markdown.shikiConfig]);
|
|
51
|
+
remarkPlugins.push([await remarkShiki(config.markdown.shikiConfig)]);
|
|
51
52
|
}
|
|
52
53
|
if (config.markdown.syntaxHighlight === 'prism') {
|
|
53
54
|
remarkPlugins.push(remarkPrism);
|
|
@@ -59,11 +60,11 @@ function getRehypePlugins(
|
|
|
59
60
|
mdxOptions: MdxOptions,
|
|
60
61
|
config: AstroConfig
|
|
61
62
|
): MdxRollupPluginOptions['rehypePlugins'] {
|
|
62
|
-
let rehypePlugins =
|
|
63
|
+
let rehypePlugins = [
|
|
64
|
+
[rehypeRaw, { passThrough: nodeTypes }] as any,
|
|
65
|
+
...handleExtends(mdxOptions.rehypePlugins, DEFAULT_REHYPE_PLUGINS),
|
|
66
|
+
];
|
|
63
67
|
|
|
64
|
-
if (config.markdown.syntaxHighlight === 'shiki' || config.markdown.syntaxHighlight === 'prism') {
|
|
65
|
-
rehypePlugins.unshift([rehypeRaw, { passThrough: nodeTypes }]);
|
|
66
|
-
}
|
|
67
68
|
// getHeadings() is guaranteed by TS, so we can't allow user to override
|
|
68
69
|
rehypePlugins.unshift(rehypeCollectHeadings);
|
|
69
70
|
|
|
@@ -74,11 +75,11 @@ export default function mdx(mdxOptions: MdxOptions = {}): AstroIntegration {
|
|
|
74
75
|
return {
|
|
75
76
|
name: '@astrojs/mdx',
|
|
76
77
|
hooks: {
|
|
77
|
-
'astro:config:setup': ({ updateConfig, config, addPageExtension, command }: any) => {
|
|
78
|
+
'astro:config:setup': async ({ updateConfig, config, addPageExtension, command }: any) => {
|
|
78
79
|
addPageExtension('.mdx');
|
|
79
80
|
|
|
80
81
|
const mdxPluginOpts: MdxRollupPluginOptions = {
|
|
81
|
-
remarkPlugins: getRemarkPlugins(mdxOptions, config),
|
|
82
|
+
remarkPlugins: await getRemarkPlugins(mdxOptions, config),
|
|
82
83
|
rehypePlugins: getRehypePlugins(mdxOptions, config),
|
|
83
84
|
jsx: true,
|
|
84
85
|
jsxImportSource: 'astro',
|
|
@@ -98,16 +99,7 @@ export default function mdx(mdxOptions: MdxOptions = {}): AstroIntegration {
|
|
|
98
99
|
async transform(code, id) {
|
|
99
100
|
if (!id.endsWith('mdx')) return;
|
|
100
101
|
|
|
101
|
-
|
|
102
|
-
if (frontmatter.layout) {
|
|
103
|
-
const { layout, ...contentProp } = frontmatter;
|
|
104
|
-
pageContent += `\n\nexport default async function({ children }) {\nconst Layout = (await import(${JSON.stringify(
|
|
105
|
-
frontmatter.layout
|
|
106
|
-
)})).default;\nconst frontmatter=${JSON.stringify(
|
|
107
|
-
contentProp
|
|
108
|
-
)};\nreturn <Layout frontmatter={frontmatter} content={frontmatter} headings={getHeadings()}>{children}</Layout> }`;
|
|
109
|
-
}
|
|
110
|
-
|
|
102
|
+
const { data: frontmatter, content: pageContent } = parseFrontmatter(code, id);
|
|
111
103
|
const compiled = await mdxCompile(new VFile({ value: pageContent, path: id }), {
|
|
112
104
|
...mdxPluginOpts,
|
|
113
105
|
rehypePlugins: [
|
|
@@ -136,6 +128,19 @@ export default function mdx(mdxOptions: MdxOptions = {}): AstroIntegration {
|
|
|
136
128
|
if (!moduleExports.includes('file')) {
|
|
137
129
|
code += `\nexport const file = ${JSON.stringify(fileId)};`;
|
|
138
130
|
}
|
|
131
|
+
if (!moduleExports.includes('rawContent')) {
|
|
132
|
+
code += `\nexport function rawContent() { throw new Error(${JSON.stringify(
|
|
133
|
+
RAW_CONTENT_ERROR
|
|
134
|
+
)}) };`;
|
|
135
|
+
}
|
|
136
|
+
if (!moduleExports.includes('compiledContent')) {
|
|
137
|
+
code += `\nexport function compiledContent() { throw new Error(${JSON.stringify(
|
|
138
|
+
COMPILED_CONTENT_ERROR
|
|
139
|
+
)}) };`;
|
|
140
|
+
}
|
|
141
|
+
if (!moduleExports.includes('Content')) {
|
|
142
|
+
code += `\nexport const Content = MDXContent;`;
|
|
143
|
+
}
|
|
139
144
|
|
|
140
145
|
if (command === 'dev') {
|
|
141
146
|
// TODO: decline HMR updates until we have a stable approach
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import type { ShikiConfig } from 'astro';
|
|
2
|
+
import type * as shiki from 'shiki';
|
|
3
|
+
import { getHighlighter } from 'shiki';
|
|
4
|
+
import { visit } from 'unist-util-visit';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* getHighlighter() is the most expensive step of Shiki. Instead of calling it on every page,
|
|
8
|
+
* cache it here as much as possible. Make sure that your highlighters can be cached, state-free.
|
|
9
|
+
* We make this async, so that multiple calls to parse markdown still share the same highlighter.
|
|
10
|
+
*/
|
|
11
|
+
const highlighterCacheAsync = new Map<string, Promise<shiki.Highlighter>>();
|
|
12
|
+
|
|
13
|
+
const remarkShiki = async ({ langs = [], theme = 'github-dark', wrap = false }: ShikiConfig) => {
|
|
14
|
+
const cacheID: string = typeof theme === 'string' ? theme : theme.name;
|
|
15
|
+
let highlighterAsync = highlighterCacheAsync.get(cacheID);
|
|
16
|
+
if (!highlighterAsync) {
|
|
17
|
+
highlighterAsync = getHighlighter({ theme });
|
|
18
|
+
highlighterCacheAsync.set(cacheID, highlighterAsync);
|
|
19
|
+
}
|
|
20
|
+
const highlighter = await highlighterAsync;
|
|
21
|
+
|
|
22
|
+
// NOTE: There may be a performance issue here for large sites that use `lang`.
|
|
23
|
+
// Since this will be called on every page load. Unclear how to fix this.
|
|
24
|
+
for (const lang of langs) {
|
|
25
|
+
await highlighter.loadLanguage(lang);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return () => (tree: any) => {
|
|
29
|
+
visit(tree, 'code', (node) => {
|
|
30
|
+
let lang: string;
|
|
31
|
+
|
|
32
|
+
if (typeof node.lang === 'string') {
|
|
33
|
+
const langExists = highlighter.getLoadedLanguages().includes(node.lang);
|
|
34
|
+
if (langExists) {
|
|
35
|
+
lang = node.lang;
|
|
36
|
+
} else {
|
|
37
|
+
// eslint-disable-next-line no-console
|
|
38
|
+
console.warn(`The language "${node.lang}" doesn't exist, falling back to plaintext.`);
|
|
39
|
+
lang = 'plaintext';
|
|
40
|
+
}
|
|
41
|
+
} else {
|
|
42
|
+
lang = 'plaintext';
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
let html = highlighter!.codeToHtml(node.value, { lang });
|
|
46
|
+
|
|
47
|
+
// Q: Couldn't these regexes match on a user's inputted code blocks?
|
|
48
|
+
// A: Nope! All rendered HTML is properly escaped.
|
|
49
|
+
// Ex. If a user typed `<span class="line"` into a code block,
|
|
50
|
+
// It would become this before hitting our regexes:
|
|
51
|
+
// <span class="line"
|
|
52
|
+
|
|
53
|
+
// Replace "shiki" class naming with "astro".
|
|
54
|
+
html = html.replace('<pre class="shiki"', `<pre class="astro-code"`);
|
|
55
|
+
// Replace "shiki" css variable naming with "astro".
|
|
56
|
+
html = html.replace(
|
|
57
|
+
/style="(background-)?color: var\(--shiki-/g,
|
|
58
|
+
'style="$1color: var(--astro-code-'
|
|
59
|
+
);
|
|
60
|
+
// Add "user-select: none;" for "+"/"-" diff symbols
|
|
61
|
+
if (node.lang === 'diff') {
|
|
62
|
+
html = html.replace(
|
|
63
|
+
/<span class="line"><span style="(.*?)">([\+|\-])/g,
|
|
64
|
+
'<span class="line"><span style="$1"><span style="user-select: none;">$2</span>'
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
// Handle code wrapping
|
|
68
|
+
// if wrap=null, do nothing.
|
|
69
|
+
if (wrap === false) {
|
|
70
|
+
html = html.replace(/style="(.*?)"/, 'style="$1; overflow-x: auto;"');
|
|
71
|
+
} else if (wrap === true) {
|
|
72
|
+
html = html.replace(
|
|
73
|
+
/style="(.*?)"/,
|
|
74
|
+
'style="$1; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;"'
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
node.type = 'html';
|
|
79
|
+
node.value = html;
|
|
80
|
+
node.children = [];
|
|
81
|
+
});
|
|
82
|
+
};
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
export default remarkShiki;
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
const {
|
|
3
3
|
content = { title: "content didn't work" },
|
|
4
|
-
frontmatter = {
|
|
4
|
+
frontmatter = {
|
|
5
|
+
title: "frontmatter didn't work",
|
|
6
|
+
file: "file didn't work",
|
|
7
|
+
url: "url didn't work",
|
|
8
|
+
},
|
|
5
9
|
headings = [],
|
|
6
10
|
} = Astro.props;
|
|
7
11
|
---
|
|
@@ -18,6 +22,8 @@ const {
|
|
|
18
22
|
<body>
|
|
19
23
|
<p data-content-title>{content.title}</p>
|
|
20
24
|
<p data-frontmatter-title>{frontmatter.title}</p>
|
|
25
|
+
<p data-frontmatter-file>{frontmatter.file}</p>
|
|
26
|
+
<p data-frontmatter-url>{frontmatter.url}</p>
|
|
21
27
|
<p data-layout-rendered>Layout rendered!</p>
|
|
22
28
|
<ul data-headings>
|
|
23
29
|
{headings.map(heading => <li>{heading.slug}</li>)}
|
|
@@ -6,9 +6,9 @@ case `uname` in
|
|
|
6
6
|
esac
|
|
7
7
|
|
|
8
8
|
if [ -z "$NODE_PATH" ]; then
|
|
9
|
-
export NODE_PATH="/
|
|
9
|
+
export NODE_PATH="/home/runner/work/astro/astro/node_modules/.pnpm/node_modules"
|
|
10
10
|
else
|
|
11
|
-
export NODE_PATH="$NODE_PATH:/
|
|
11
|
+
export NODE_PATH="$NODE_PATH:/home/runner/work/astro/astro/node_modules/.pnpm/node_modules"
|
|
12
12
|
fi
|
|
13
13
|
if [ -x "$basedir/node" ]; then
|
|
14
14
|
exec "$basedir/node" "$basedir/../../../../../../../astro/astro.js" "$@"
|