@astrojs/mdx 0.17.2 → 0.18.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 +33 -0
- package/dist/index.d.ts +12 -2
- package/dist/index.js +40 -10
- package/dist/plugins.js +19 -61
- package/dist/rehype-meta-string.js +1 -1
- package/dist/utils.d.ts +2 -1
- package/dist/utils.js +22 -14
- package/package.json +5 -5
- package/src/index.ts +58 -11
- package/src/plugins.ts +22 -73
- package/src/utils.ts +22 -16
- package/template/content-module-types.d.ts +9 -0
- package/tsconfig.json +2 -2
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
[
|
|
2
|
-
[
|
|
3
|
-
[
|
|
4
|
-
[
|
|
5
|
-
[
|
|
1
|
+
[35m@astrojs/mdx:build: [0mcache hit, replaying output [2m61e81c86fa4b4798[0m
|
|
2
|
+
[35m@astrojs/mdx:build: [0m
|
|
3
|
+
[35m@astrojs/mdx:build: [0m> @astrojs/mdx@0.18.0 build /home/runner/work/astro/astro/packages/integrations/mdx
|
|
4
|
+
[35m@astrojs/mdx:build: [0m> astro-scripts build "src/**/*.ts" && tsc
|
|
5
|
+
[35m@astrojs/mdx:build: [0m
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,38 @@
|
|
|
1
1
|
# @astrojs/mdx
|
|
2
2
|
|
|
3
|
+
## 0.18.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#6344](https://github.com/withastro/astro/pull/6344) [`694918a56`](https://github.com/withastro/astro/commit/694918a56b01104831296be0c25456135a63c784) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Add a new experimental flag (`experimental.assets`) to enable our new core Assets story.
|
|
8
|
+
|
|
9
|
+
This unlocks a few features:
|
|
10
|
+
|
|
11
|
+
- A new built-in image component and JavaScript API to transform and optimize images.
|
|
12
|
+
- Relative images with automatic optimization in Markdown.
|
|
13
|
+
- Support for validating assets using content collections.
|
|
14
|
+
- and more!
|
|
15
|
+
|
|
16
|
+
See [Assets (Experimental)](https://docs.astro.build/en/guides/assets/) on our docs site for more information on how to use this feature!
|
|
17
|
+
|
|
18
|
+
- [#6213](https://github.com/withastro/astro/pull/6213) [`afbbc4d5b`](https://github.com/withastro/astro/commit/afbbc4d5bfafc1779bac00b41c2a1cb1c90f2808) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Updated compilation settings to disable downlevelling for Node 14
|
|
19
|
+
|
|
20
|
+
### Patch Changes
|
|
21
|
+
|
|
22
|
+
- [#6209](https://github.com/withastro/astro/pull/6209) [`fec583909`](https://github.com/withastro/astro/commit/fec583909ab62829dc0c1600e2387979365f2b94) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Introduce the (experimental) `@astrojs/markdoc` integration. This unlocks Markdoc inside your Content Collections, bringing support for Astro and UI components in your content. This also improves Astro core internals to make Content Collections extensible to more file types in the future.
|
|
23
|
+
|
|
24
|
+
You can install this integration using the `astro add` command:
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
astro add markdoc
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
[Read the `@astrojs/markdoc` documentation](https://docs.astro.build/en/guides/integrations-guide/markdoc/) for usage instructions, and browse the [new `with-markdoc` starter](https://astro.new/with-markdoc) to try for yourself.
|
|
31
|
+
|
|
32
|
+
- Updated dependencies [[`694918a56`](https://github.com/withastro/astro/commit/694918a56b01104831296be0c25456135a63c784), [`afbbc4d5b`](https://github.com/withastro/astro/commit/afbbc4d5bfafc1779bac00b41c2a1cb1c90f2808)]:
|
|
33
|
+
- @astrojs/markdown-remark@2.1.0
|
|
34
|
+
- @astrojs/prism@2.1.0
|
|
35
|
+
|
|
3
36
|
## 0.17.2
|
|
4
37
|
|
|
5
38
|
### Patch Changes
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { markdownConfigDefaults } from '@astrojs/markdown-remark';
|
|
2
2
|
import { PluggableList } from '@mdx-js/mdx/lib/core.js';
|
|
3
|
-
import type { AstroIntegration } from 'astro';
|
|
3
|
+
import type { AstroIntegration, ContentEntryType, HookParameters } from 'astro';
|
|
4
4
|
import type { Options as RemarkRehypeOptions } from 'remark-rehype';
|
|
5
5
|
export declare type MdxOptions = Omit<typeof markdownConfigDefaults, 'remarkPlugins' | 'rehypePlugins'> & {
|
|
6
6
|
extendMarkdownConfig: boolean;
|
|
@@ -9,4 +9,14 @@ export declare type MdxOptions = Omit<typeof markdownConfigDefaults, 'remarkPlug
|
|
|
9
9
|
rehypePlugins: PluggableList;
|
|
10
10
|
remarkRehype: RemarkRehypeOptions;
|
|
11
11
|
};
|
|
12
|
-
|
|
12
|
+
declare type IntegrationWithPrivateHooks = {
|
|
13
|
+
name: string;
|
|
14
|
+
hooks: Omit<AstroIntegration['hooks'], 'astro:config:setup'> & {
|
|
15
|
+
'astro:config:setup': (params: HookParameters<'astro:config:setup'> & {
|
|
16
|
+
addPageExtension: (extension: string) => void;
|
|
17
|
+
addContentEntryType: (contentEntryType: ContentEntryType) => void;
|
|
18
|
+
}) => void | Promise<void>;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
export default function mdx(partialMdxOptions?: Partial<MdxOptions>): IntegrationWithPrivateHooks;
|
|
22
|
+
export {};
|
package/dist/index.js
CHANGED
|
@@ -4,19 +4,44 @@ import { compile as mdxCompile } from "@mdx-js/mdx";
|
|
|
4
4
|
import mdxPlugin from "@mdx-js/rollup";
|
|
5
5
|
import { parse as parseESM } from "es-module-lexer";
|
|
6
6
|
import fs from "node:fs/promises";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
7
8
|
import { VFile } from "vfile";
|
|
8
9
|
import { getRehypePlugins, getRemarkPlugins, recmaInjectImportMetaEnvPlugin } from "./plugins.js";
|
|
9
|
-
import { getFileInfo, parseFrontmatter } from "./utils.js";
|
|
10
|
+
import { getFileInfo, ignoreStringPlugins, parseFrontmatter } from "./utils.js";
|
|
10
11
|
function mdx(partialMdxOptions = {}) {
|
|
11
12
|
return {
|
|
12
13
|
name: "@astrojs/mdx",
|
|
13
14
|
hooks: {
|
|
14
|
-
"astro:config:setup": async ({
|
|
15
|
+
"astro:config:setup": async ({
|
|
16
|
+
updateConfig,
|
|
17
|
+
config,
|
|
18
|
+
addPageExtension,
|
|
19
|
+
addContentEntryType,
|
|
20
|
+
command
|
|
21
|
+
}) => {
|
|
15
22
|
addPageExtension(".mdx");
|
|
16
|
-
|
|
23
|
+
addContentEntryType({
|
|
24
|
+
extensions: [".mdx"],
|
|
25
|
+
async getEntryInfo({ fileUrl, contents }) {
|
|
26
|
+
const parsed = parseFrontmatter(contents, fileURLToPath(fileUrl));
|
|
27
|
+
return {
|
|
28
|
+
data: parsed.data,
|
|
29
|
+
body: parsed.content,
|
|
30
|
+
slug: parsed.data.slug,
|
|
31
|
+
rawData: parsed.matter
|
|
32
|
+
};
|
|
33
|
+
},
|
|
34
|
+
contentModuleTypes: await fs.readFile(
|
|
35
|
+
new URL("../template/content-module-types.d.ts", import.meta.url),
|
|
36
|
+
"utf-8"
|
|
37
|
+
)
|
|
38
|
+
});
|
|
39
|
+
const extendMarkdownConfig = partialMdxOptions.extendMarkdownConfig ?? defaultMdxOptions.extendMarkdownConfig;
|
|
17
40
|
const mdxOptions = applyDefaultOptions({
|
|
18
41
|
options: partialMdxOptions,
|
|
19
|
-
defaults:
|
|
42
|
+
defaults: markdownConfigToMdxOptions(
|
|
43
|
+
extendMarkdownConfig ? config.markdown : markdownConfigDefaults
|
|
44
|
+
)
|
|
20
45
|
});
|
|
21
46
|
const mdxPluginOpts = {
|
|
22
47
|
remarkPlugins: await getRemarkPlugins(mdxOptions, config),
|
|
@@ -113,14 +138,19 @@ if (import.meta.hot) {
|
|
|
113
138
|
}
|
|
114
139
|
};
|
|
115
140
|
}
|
|
116
|
-
const
|
|
117
|
-
...markdownConfigDefaults,
|
|
141
|
+
const defaultMdxOptions = {
|
|
118
142
|
extendMarkdownConfig: true,
|
|
119
|
-
recmaPlugins: []
|
|
120
|
-
remarkPlugins: [],
|
|
121
|
-
rehypePlugins: [],
|
|
122
|
-
remarkRehype: {}
|
|
143
|
+
recmaPlugins: []
|
|
123
144
|
};
|
|
145
|
+
function markdownConfigToMdxOptions(markdownConfig) {
|
|
146
|
+
return {
|
|
147
|
+
...defaultMdxOptions,
|
|
148
|
+
...markdownConfig,
|
|
149
|
+
remarkPlugins: ignoreStringPlugins(markdownConfig.remarkPlugins),
|
|
150
|
+
rehypePlugins: ignoreStringPlugins(markdownConfig.rehypePlugins),
|
|
151
|
+
remarkRehype: markdownConfig.remarkRehype ?? {}
|
|
152
|
+
};
|
|
153
|
+
}
|
|
124
154
|
function applyDefaultOptions({
|
|
125
155
|
options,
|
|
126
156
|
defaults
|
package/dist/plugins.js
CHANGED
|
@@ -5,17 +5,15 @@ import {
|
|
|
5
5
|
} from "@astrojs/markdown-remark/dist/internal.js";
|
|
6
6
|
import { nodeTypes } from "@mdx-js/mdx";
|
|
7
7
|
import { visit as estreeVisit } from "estree-util-visit";
|
|
8
|
-
import { bold, yellow } from "kleur/colors";
|
|
9
|
-
import { pathToFileURL } from "node:url";
|
|
10
8
|
import rehypeRaw from "rehype-raw";
|
|
11
9
|
import remarkGfm from "remark-gfm";
|
|
12
10
|
import remarkSmartypants from "remark-smartypants";
|
|
13
|
-
import { visit } from "unist-util-visit";
|
|
14
11
|
import { rehypeInjectHeadingsExport } from "./rehype-collect-headings.js";
|
|
15
12
|
import rehypeMetaString from "./rehype-meta-string.js";
|
|
16
13
|
import remarkPrism from "./remark-prism.js";
|
|
17
14
|
import remarkShiki from "./remark-shiki.js";
|
|
18
|
-
import {
|
|
15
|
+
import { jsToTreeNode } from "./utils.js";
|
|
16
|
+
const isPerformanceBenchmark = Boolean(process.env.ASTRO_PERFORMANCE_BENCHMARK);
|
|
19
17
|
function recmaInjectImportMetaEnvPlugin({
|
|
20
18
|
importMetaEnv
|
|
21
19
|
}) {
|
|
@@ -75,43 +73,25 @@ function rehypeApplyFrontmatterExport() {
|
|
|
75
73
|
tree.children = exportNodes.concat(tree.children);
|
|
76
74
|
};
|
|
77
75
|
}
|
|
78
|
-
function toRemarkContentRelImageError({ srcDir }) {
|
|
79
|
-
const contentDir = new URL("content/", srcDir);
|
|
80
|
-
return function remarkContentRelImageError() {
|
|
81
|
-
return (tree, vfile) => {
|
|
82
|
-
const isContentFile = pathToFileURL(vfile.path).href.startsWith(contentDir.href);
|
|
83
|
-
if (!isContentFile)
|
|
84
|
-
return;
|
|
85
|
-
const relImagePaths = /* @__PURE__ */ new Set();
|
|
86
|
-
visit(tree, "image", function raiseError(node) {
|
|
87
|
-
if (isRelativePath(node.url)) {
|
|
88
|
-
relImagePaths.add(node.url);
|
|
89
|
-
}
|
|
90
|
-
});
|
|
91
|
-
if (relImagePaths.size === 0)
|
|
92
|
-
return;
|
|
93
|
-
const errorMessage = `Relative image paths are not supported in the content/ directory. Place local images in the public/ directory and use absolute paths (see https://docs.astro.build/en/guides/images/#in-markdown-files):
|
|
94
|
-
` + [...relImagePaths].map((path) => JSON.stringify(path)).join(",\n");
|
|
95
|
-
throw new Error(errorMessage);
|
|
96
|
-
};
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
76
|
async function getRemarkPlugins(mdxOptions, config) {
|
|
100
77
|
let remarkPlugins = [];
|
|
101
|
-
if (
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
if (mdxOptions.syntaxHighlight === "shiki") {
|
|
109
|
-
remarkPlugins.push([await remarkShiki(mdxOptions.shikiConfig)]);
|
|
78
|
+
if (!isPerformanceBenchmark) {
|
|
79
|
+
if (mdxOptions.gfm) {
|
|
80
|
+
remarkPlugins.push(remarkGfm);
|
|
81
|
+
}
|
|
82
|
+
if (mdxOptions.smartypants) {
|
|
83
|
+
remarkPlugins.push(remarkSmartypants);
|
|
84
|
+
}
|
|
110
85
|
}
|
|
111
|
-
|
|
112
|
-
|
|
86
|
+
remarkPlugins = [...remarkPlugins, ...mdxOptions.remarkPlugins];
|
|
87
|
+
if (!isPerformanceBenchmark) {
|
|
88
|
+
if (mdxOptions.syntaxHighlight === "shiki") {
|
|
89
|
+
remarkPlugins.push([await remarkShiki(mdxOptions.shikiConfig)]);
|
|
90
|
+
}
|
|
91
|
+
if (mdxOptions.syntaxHighlight === "prism") {
|
|
92
|
+
remarkPlugins.push(remarkPrism);
|
|
93
|
+
}
|
|
113
94
|
}
|
|
114
|
-
remarkPlugins.push(toRemarkContentRelImageError(config));
|
|
115
95
|
return remarkPlugins;
|
|
116
96
|
}
|
|
117
97
|
function getRehypePlugins(mdxOptions) {
|
|
@@ -121,34 +101,12 @@ function getRehypePlugins(mdxOptions) {
|
|
|
121
101
|
];
|
|
122
102
|
rehypePlugins = [
|
|
123
103
|
...rehypePlugins,
|
|
124
|
-
...
|
|
125
|
-
rehypeHeadingIds,
|
|
126
|
-
rehypeInjectHeadingsExport,
|
|
104
|
+
...mdxOptions.rehypePlugins,
|
|
105
|
+
...isPerformanceBenchmark ? [] : [rehypeHeadingIds, rehypeInjectHeadingsExport],
|
|
127
106
|
rehypeApplyFrontmatterExport
|
|
128
107
|
];
|
|
129
108
|
return rehypePlugins;
|
|
130
109
|
}
|
|
131
|
-
function ignoreStringPlugins(plugins) {
|
|
132
|
-
let validPlugins = [];
|
|
133
|
-
let hasInvalidPlugin = false;
|
|
134
|
-
for (const plugin of plugins) {
|
|
135
|
-
if (typeof plugin === "string") {
|
|
136
|
-
console.warn(yellow(`[MDX] ${bold(plugin)} not applied.`));
|
|
137
|
-
hasInvalidPlugin = true;
|
|
138
|
-
} else if (Array.isArray(plugin) && typeof plugin[0] === "string") {
|
|
139
|
-
console.warn(yellow(`[MDX] ${bold(plugin[0])} not applied.`));
|
|
140
|
-
hasInvalidPlugin = true;
|
|
141
|
-
} else {
|
|
142
|
-
validPlugins.push(plugin);
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
if (hasInvalidPlugin) {
|
|
146
|
-
console.warn(
|
|
147
|
-
`To inherit Markdown plugins in MDX, please use explicit imports in your config instead of "strings." See Markdown docs: https://docs.astro.build/en/guides/markdown-content/#markdown-plugins`
|
|
148
|
-
);
|
|
149
|
-
}
|
|
150
|
-
return validPlugins;
|
|
151
|
-
}
|
|
152
110
|
function getImportMetaEnvVariableName(node) {
|
|
153
111
|
try {
|
|
154
112
|
if (node.object.type !== "MemberExpression" || node.property.type !== "Identifier")
|
|
@@ -4,7 +4,7 @@ function rehypeMetaString() {
|
|
|
4
4
|
visit(tree, (node) => {
|
|
5
5
|
var _a;
|
|
6
6
|
if (node.type === "element" && node.tagName === "code" && ((_a = node.data) == null ? void 0 : _a.meta)) {
|
|
7
|
-
node.properties
|
|
7
|
+
node.properties ??= {};
|
|
8
8
|
node.properties.metastring = node.data.meta;
|
|
9
9
|
}
|
|
10
10
|
});
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { PluggableList } from '@mdx-js/mdx/lib/core.js';
|
|
1
2
|
import type { Options as AcornOpts } from 'acorn';
|
|
2
3
|
import type { AstroConfig } from 'astro';
|
|
3
4
|
import matter from 'gray-matter';
|
|
@@ -14,5 +15,5 @@ export declare function getFileInfo(id: string, config: AstroConfig): FileInfo;
|
|
|
14
15
|
*/
|
|
15
16
|
export declare function parseFrontmatter(code: string, id: string): matter.GrayMatterFile<string>;
|
|
16
17
|
export declare function jsToTreeNode(jsString: string, acornOpts?: AcornOpts): MdxjsEsm;
|
|
17
|
-
export declare function
|
|
18
|
+
export declare function ignoreStringPlugins(plugins: any[]): PluggableList;
|
|
18
19
|
export {};
|
package/dist/utils.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { parse } from "acorn";
|
|
2
2
|
import matter from "gray-matter";
|
|
3
|
+
import { bold, yellow } from "kleur/colors";
|
|
3
4
|
function appendForwardSlash(path) {
|
|
4
5
|
return path.endsWith("/") ? path : path + "/";
|
|
5
6
|
}
|
|
@@ -59,23 +60,30 @@ function jsToTreeNode(jsString, acornOpts = {
|
|
|
59
60
|
}
|
|
60
61
|
};
|
|
61
62
|
}
|
|
62
|
-
function
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
63
|
+
function ignoreStringPlugins(plugins) {
|
|
64
|
+
let validPlugins = [];
|
|
65
|
+
let hasInvalidPlugin = false;
|
|
66
|
+
for (const plugin of plugins) {
|
|
67
|
+
if (typeof plugin === "string") {
|
|
68
|
+
console.warn(yellow(`[MDX] ${bold(plugin)} not applied.`));
|
|
69
|
+
hasInvalidPlugin = true;
|
|
70
|
+
} else if (Array.isArray(plugin) && typeof plugin[0] === "string") {
|
|
71
|
+
console.warn(yellow(`[MDX] ${bold(plugin[0])} not applied.`));
|
|
72
|
+
hasInvalidPlugin = true;
|
|
73
|
+
} else {
|
|
74
|
+
validPlugins.push(plugin);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (hasInvalidPlugin) {
|
|
78
|
+
console.warn(
|
|
79
|
+
`To inherit Markdown plugins in MDX, please use explicit imports in your config instead of "strings." See Markdown docs: https://docs.astro.build/en/guides/markdown-content/#markdown-plugins`
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
return validPlugins;
|
|
75
83
|
}
|
|
76
84
|
export {
|
|
77
85
|
getFileInfo,
|
|
78
|
-
|
|
86
|
+
ignoreStringPlugins,
|
|
79
87
|
jsToTreeNode,
|
|
80
88
|
parseFrontmatter
|
|
81
89
|
};
|
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.18.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
7
7
|
"author": "withastro",
|
|
@@ -23,8 +23,8 @@
|
|
|
23
23
|
"./package.json": "./package.json"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@astrojs/markdown-remark": "^2.0
|
|
27
|
-
"@astrojs/prism": "^2.
|
|
26
|
+
"@astrojs/markdown-remark": "^2.1.0",
|
|
27
|
+
"@astrojs/prism": "^2.1.0",
|
|
28
28
|
"@mdx-js/mdx": "^2.3.0",
|
|
29
29
|
"@mdx-js/rollup": "^2.3.0",
|
|
30
30
|
"acorn": "^8.8.0",
|
|
@@ -48,8 +48,8 @@
|
|
|
48
48
|
"@types/mdast": "^3.0.10",
|
|
49
49
|
"@types/mocha": "^9.1.1",
|
|
50
50
|
"@types/yargs-parser": "^21.0.0",
|
|
51
|
-
"astro": "2.0
|
|
52
|
-
"astro-scripts": "0.0.
|
|
51
|
+
"astro": "2.1.0",
|
|
52
|
+
"astro-scripts": "0.0.14",
|
|
53
53
|
"chai": "^4.3.6",
|
|
54
54
|
"cheerio": "^1.0.0-rc.11",
|
|
55
55
|
"linkedom": "^0.14.12",
|
package/src/index.ts
CHANGED
|
@@ -3,14 +3,15 @@ import { toRemarkInitializeAstroData } from '@astrojs/markdown-remark/dist/inter
|
|
|
3
3
|
import { compile as mdxCompile } from '@mdx-js/mdx';
|
|
4
4
|
import { PluggableList } from '@mdx-js/mdx/lib/core.js';
|
|
5
5
|
import mdxPlugin, { Options as MdxRollupPluginOptions } from '@mdx-js/rollup';
|
|
6
|
-
import type { AstroIntegration } from 'astro';
|
|
6
|
+
import type { AstroIntegration, ContentEntryType, HookParameters } from 'astro';
|
|
7
7
|
import { parse as parseESM } from 'es-module-lexer';
|
|
8
8
|
import fs from 'node:fs/promises';
|
|
9
|
+
import { fileURLToPath } from 'node:url';
|
|
9
10
|
import type { Options as RemarkRehypeOptions } from 'remark-rehype';
|
|
10
11
|
import { VFile } from 'vfile';
|
|
11
12
|
import type { Plugin as VitePlugin } from 'vite';
|
|
12
13
|
import { getRehypePlugins, getRemarkPlugins, recmaInjectImportMetaEnvPlugin } from './plugins.js';
|
|
13
|
-
import { getFileInfo, parseFrontmatter } from './utils.js';
|
|
14
|
+
import { getFileInfo, ignoreStringPlugins, parseFrontmatter } from './utils.js';
|
|
14
15
|
|
|
15
16
|
export type MdxOptions = Omit<typeof markdownConfigDefaults, 'remarkPlugins' | 'rehypePlugins'> & {
|
|
16
17
|
extendMarkdownConfig: boolean;
|
|
@@ -22,19 +23,59 @@ export type MdxOptions = Omit<typeof markdownConfigDefaults, 'remarkPlugins' | '
|
|
|
22
23
|
remarkRehype: RemarkRehypeOptions;
|
|
23
24
|
};
|
|
24
25
|
|
|
25
|
-
|
|
26
|
+
type IntegrationWithPrivateHooks = {
|
|
27
|
+
name: string;
|
|
28
|
+
hooks: Omit<AstroIntegration['hooks'], 'astro:config:setup'> & {
|
|
29
|
+
'astro:config:setup': (
|
|
30
|
+
params: HookParameters<'astro:config:setup'> & {
|
|
31
|
+
// `addPageExtension` and `contentEntryType` are not a public APIs
|
|
32
|
+
// Add type defs here
|
|
33
|
+
addPageExtension: (extension: string) => void;
|
|
34
|
+
addContentEntryType: (contentEntryType: ContentEntryType) => void;
|
|
35
|
+
}
|
|
36
|
+
) => void | Promise<void>;
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export default function mdx(
|
|
41
|
+
partialMdxOptions: Partial<MdxOptions> = {}
|
|
42
|
+
): IntegrationWithPrivateHooks {
|
|
26
43
|
return {
|
|
27
44
|
name: '@astrojs/mdx',
|
|
28
45
|
hooks: {
|
|
29
|
-
'astro:config:setup': async ({
|
|
46
|
+
'astro:config:setup': async ({
|
|
47
|
+
updateConfig,
|
|
48
|
+
config,
|
|
49
|
+
addPageExtension,
|
|
50
|
+
addContentEntryType,
|
|
51
|
+
command,
|
|
52
|
+
}) => {
|
|
30
53
|
addPageExtension('.mdx');
|
|
54
|
+
addContentEntryType({
|
|
55
|
+
extensions: ['.mdx'],
|
|
56
|
+
async getEntryInfo({ fileUrl, contents }: { fileUrl: URL; contents: string }) {
|
|
57
|
+
const parsed = parseFrontmatter(contents, fileURLToPath(fileUrl));
|
|
58
|
+
return {
|
|
59
|
+
data: parsed.data,
|
|
60
|
+
body: parsed.content,
|
|
61
|
+
slug: parsed.data.slug,
|
|
62
|
+
rawData: parsed.matter,
|
|
63
|
+
};
|
|
64
|
+
},
|
|
65
|
+
contentModuleTypes: await fs.readFile(
|
|
66
|
+
new URL('../template/content-module-types.d.ts', import.meta.url),
|
|
67
|
+
'utf-8'
|
|
68
|
+
),
|
|
69
|
+
});
|
|
31
70
|
|
|
32
71
|
const extendMarkdownConfig =
|
|
33
|
-
partialMdxOptions.extendMarkdownConfig ??
|
|
72
|
+
partialMdxOptions.extendMarkdownConfig ?? defaultMdxOptions.extendMarkdownConfig;
|
|
34
73
|
|
|
35
74
|
const mdxOptions = applyDefaultOptions({
|
|
36
75
|
options: partialMdxOptions,
|
|
37
|
-
defaults:
|
|
76
|
+
defaults: markdownConfigToMdxOptions(
|
|
77
|
+
extendMarkdownConfig ? config.markdown : markdownConfigDefaults
|
|
78
|
+
),
|
|
38
79
|
});
|
|
39
80
|
|
|
40
81
|
const mdxPluginOpts: MdxRollupPluginOptions = {
|
|
@@ -149,15 +190,21 @@ export default function mdx(partialMdxOptions: Partial<MdxOptions> = {}): AstroI
|
|
|
149
190
|
};
|
|
150
191
|
}
|
|
151
192
|
|
|
152
|
-
const
|
|
153
|
-
...markdownConfigDefaults,
|
|
193
|
+
const defaultMdxOptions = {
|
|
154
194
|
extendMarkdownConfig: true,
|
|
155
195
|
recmaPlugins: [],
|
|
156
|
-
remarkPlugins: [],
|
|
157
|
-
rehypePlugins: [],
|
|
158
|
-
remarkRehype: {},
|
|
159
196
|
};
|
|
160
197
|
|
|
198
|
+
function markdownConfigToMdxOptions(markdownConfig: typeof markdownConfigDefaults): MdxOptions {
|
|
199
|
+
return {
|
|
200
|
+
...defaultMdxOptions,
|
|
201
|
+
...markdownConfig,
|
|
202
|
+
remarkPlugins: ignoreStringPlugins(markdownConfig.remarkPlugins),
|
|
203
|
+
rehypePlugins: ignoreStringPlugins(markdownConfig.rehypePlugins),
|
|
204
|
+
remarkRehype: (markdownConfig.remarkRehype as any) ?? {},
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
|
|
161
208
|
function applyDefaultOptions({
|
|
162
209
|
options,
|
|
163
210
|
defaults,
|
package/src/plugins.ts
CHANGED
|
@@ -9,20 +9,19 @@ import type { Options as MdxRollupPluginOptions } from '@mdx-js/rollup';
|
|
|
9
9
|
import type { AstroConfig } from 'astro';
|
|
10
10
|
import type { Literal, MemberExpression } from 'estree';
|
|
11
11
|
import { visit as estreeVisit } from 'estree-util-visit';
|
|
12
|
-
import { bold, yellow } from 'kleur/colors';
|
|
13
|
-
import type { Image } from 'mdast';
|
|
14
|
-
import { pathToFileURL } from 'node:url';
|
|
15
12
|
import rehypeRaw from 'rehype-raw';
|
|
16
13
|
import remarkGfm from 'remark-gfm';
|
|
17
14
|
import remarkSmartypants from 'remark-smartypants';
|
|
18
|
-
import { visit } from 'unist-util-visit';
|
|
19
15
|
import type { VFile } from 'vfile';
|
|
20
16
|
import { MdxOptions } from './index.js';
|
|
21
17
|
import { rehypeInjectHeadingsExport } from './rehype-collect-headings.js';
|
|
22
18
|
import rehypeMetaString from './rehype-meta-string.js';
|
|
23
19
|
import remarkPrism from './remark-prism.js';
|
|
24
20
|
import remarkShiki from './remark-shiki.js';
|
|
25
|
-
import {
|
|
21
|
+
import { jsToTreeNode } from './utils.js';
|
|
22
|
+
|
|
23
|
+
// Skip nonessential plugins during performance benchmark runs
|
|
24
|
+
const isPerformanceBenchmark = Boolean(process.env.ASTRO_PERFORMANCE_BENCHMARK);
|
|
26
25
|
|
|
27
26
|
export function recmaInjectImportMetaEnvPlugin({
|
|
28
27
|
importMetaEnv,
|
|
@@ -96,60 +95,33 @@ export function rehypeApplyFrontmatterExport() {
|
|
|
96
95
|
};
|
|
97
96
|
}
|
|
98
97
|
|
|
99
|
-
/**
|
|
100
|
-
* `src/content/` does not support relative image paths.
|
|
101
|
-
* This plugin throws an error if any are found
|
|
102
|
-
*/
|
|
103
|
-
function toRemarkContentRelImageError({ srcDir }: { srcDir: URL }) {
|
|
104
|
-
const contentDir = new URL('content/', srcDir);
|
|
105
|
-
return function remarkContentRelImageError() {
|
|
106
|
-
return (tree: any, vfile: VFile) => {
|
|
107
|
-
const isContentFile = pathToFileURL(vfile.path).href.startsWith(contentDir.href);
|
|
108
|
-
if (!isContentFile) return;
|
|
109
|
-
|
|
110
|
-
const relImagePaths = new Set<string>();
|
|
111
|
-
visit(tree, 'image', function raiseError(node: Image) {
|
|
112
|
-
if (isRelativePath(node.url)) {
|
|
113
|
-
relImagePaths.add(node.url);
|
|
114
|
-
}
|
|
115
|
-
});
|
|
116
|
-
if (relImagePaths.size === 0) return;
|
|
117
|
-
|
|
118
|
-
const errorMessage =
|
|
119
|
-
`Relative image paths are not supported in the content/ directory. Place local images in the public/ directory and use absolute paths (see https://docs.astro.build/en/guides/images/#in-markdown-files):\n` +
|
|
120
|
-
[...relImagePaths].map((path) => JSON.stringify(path)).join(',\n');
|
|
121
|
-
|
|
122
|
-
throw new Error(errorMessage);
|
|
123
|
-
};
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
|
|
127
98
|
export async function getRemarkPlugins(
|
|
128
99
|
mdxOptions: MdxOptions,
|
|
129
100
|
config: AstroConfig
|
|
130
101
|
): Promise<MdxRollupPluginOptions['remarkPlugins']> {
|
|
131
102
|
let remarkPlugins: PluggableList = [];
|
|
132
103
|
|
|
133
|
-
if (
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
104
|
+
if (!isPerformanceBenchmark) {
|
|
105
|
+
if (mdxOptions.gfm) {
|
|
106
|
+
remarkPlugins.push(remarkGfm);
|
|
107
|
+
}
|
|
108
|
+
if (mdxOptions.smartypants) {
|
|
109
|
+
remarkPlugins.push(remarkSmartypants);
|
|
110
|
+
}
|
|
138
111
|
}
|
|
139
112
|
|
|
140
|
-
remarkPlugins = [...remarkPlugins, ...
|
|
113
|
+
remarkPlugins = [...remarkPlugins, ...mdxOptions.remarkPlugins];
|
|
141
114
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
115
|
+
if (!isPerformanceBenchmark) {
|
|
116
|
+
// Apply syntax highlighters after user plugins to match `markdown/remark` behavior
|
|
117
|
+
if (mdxOptions.syntaxHighlight === 'shiki') {
|
|
118
|
+
remarkPlugins.push([await remarkShiki(mdxOptions.shikiConfig)]);
|
|
119
|
+
}
|
|
120
|
+
if (mdxOptions.syntaxHighlight === 'prism') {
|
|
121
|
+
remarkPlugins.push(remarkPrism);
|
|
122
|
+
}
|
|
148
123
|
}
|
|
149
124
|
|
|
150
|
-
// Apply last in case user plugins resolve relative image paths
|
|
151
|
-
remarkPlugins.push(toRemarkContentRelImageError(config));
|
|
152
|
-
|
|
153
125
|
return remarkPlugins;
|
|
154
126
|
}
|
|
155
127
|
|
|
@@ -163,39 +135,16 @@ export function getRehypePlugins(mdxOptions: MdxOptions): MdxRollupPluginOptions
|
|
|
163
135
|
|
|
164
136
|
rehypePlugins = [
|
|
165
137
|
...rehypePlugins,
|
|
166
|
-
...
|
|
138
|
+
...mdxOptions.rehypePlugins,
|
|
167
139
|
// getHeadings() is guaranteed by TS, so this must be included.
|
|
168
140
|
// We run `rehypeHeadingIds` _last_ to respect any custom IDs set by user plugins.
|
|
169
|
-
rehypeHeadingIds,
|
|
170
|
-
rehypeInjectHeadingsExport,
|
|
141
|
+
...(isPerformanceBenchmark ? [] : [rehypeHeadingIds, rehypeInjectHeadingsExport]),
|
|
171
142
|
// computed from `astro.data.frontmatter` in VFile data
|
|
172
143
|
rehypeApplyFrontmatterExport,
|
|
173
144
|
];
|
|
174
145
|
return rehypePlugins;
|
|
175
146
|
}
|
|
176
147
|
|
|
177
|
-
function ignoreStringPlugins(plugins: any[]) {
|
|
178
|
-
let validPlugins: PluggableList = [];
|
|
179
|
-
let hasInvalidPlugin = false;
|
|
180
|
-
for (const plugin of plugins) {
|
|
181
|
-
if (typeof plugin === 'string') {
|
|
182
|
-
console.warn(yellow(`[MDX] ${bold(plugin)} not applied.`));
|
|
183
|
-
hasInvalidPlugin = true;
|
|
184
|
-
} else if (Array.isArray(plugin) && typeof plugin[0] === 'string') {
|
|
185
|
-
console.warn(yellow(`[MDX] ${bold(plugin[0])} not applied.`));
|
|
186
|
-
hasInvalidPlugin = true;
|
|
187
|
-
} else {
|
|
188
|
-
validPlugins.push(plugin);
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
if (hasInvalidPlugin) {
|
|
192
|
-
console.warn(
|
|
193
|
-
`To inherit Markdown plugins in MDX, please use explicit imports in your config instead of "strings." See Markdown docs: https://docs.astro.build/en/guides/markdown-content/#markdown-plugins`
|
|
194
|
-
);
|
|
195
|
-
}
|
|
196
|
-
return validPlugins;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
148
|
/**
|
|
200
149
|
* Check if estree entry is "import.meta.env.VARIABLE"
|
|
201
150
|
* If it is, return the variable name (i.e. "VARIABLE")
|
package/src/utils.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import type { PluggableList } from '@mdx-js/mdx/lib/core.js';
|
|
1
2
|
import type { Options as AcornOpts } from 'acorn';
|
|
2
3
|
import { parse } from 'acorn';
|
|
3
4
|
import type { AstroConfig, SSRError } from 'astro';
|
|
4
5
|
import matter from 'gray-matter';
|
|
6
|
+
import { bold, yellow } from 'kleur/colors';
|
|
5
7
|
import type { MdxjsEsm } from 'mdast-util-mdx';
|
|
6
8
|
|
|
7
9
|
function appendForwardSlash(path: string) {
|
|
@@ -83,20 +85,24 @@ export function jsToTreeNode(
|
|
|
83
85
|
};
|
|
84
86
|
}
|
|
85
87
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
88
|
+
export function ignoreStringPlugins(plugins: any[]): PluggableList {
|
|
89
|
+
let validPlugins: PluggableList = [];
|
|
90
|
+
let hasInvalidPlugin = false;
|
|
91
|
+
for (const plugin of plugins) {
|
|
92
|
+
if (typeof plugin === 'string') {
|
|
93
|
+
console.warn(yellow(`[MDX] ${bold(plugin)} not applied.`));
|
|
94
|
+
hasInvalidPlugin = true;
|
|
95
|
+
} else if (Array.isArray(plugin) && typeof plugin[0] === 'string') {
|
|
96
|
+
console.warn(yellow(`[MDX] ${bold(plugin[0])} not applied.`));
|
|
97
|
+
hasInvalidPlugin = true;
|
|
98
|
+
} else {
|
|
99
|
+
validPlugins.push(plugin);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if (hasInvalidPlugin) {
|
|
103
|
+
console.warn(
|
|
104
|
+
`To inherit Markdown plugins in MDX, please use explicit imports in your config instead of "strings." See Markdown docs: https://docs.astro.build/en/guides/markdown-content/#markdown-plugins`
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
return validPlugins;
|
|
102
108
|
}
|