@astrojs/mdx 0.4.0 → 0.7.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 +37 -0
- package/README.md +21 -3
- package/dist/astro-data-utils.d.ts +9 -0
- package/dist/astro-data-utils.js +66 -0
- package/dist/index.js +64 -47
- package/dist/rehype-collect-headings.d.ts +6 -0
- package/dist/rehype-collect-headings.js +47 -0
- package/dist/remark-prism.js +2 -34
- package/dist/utils.d.ts +5 -3
- package/dist/utils.js +22 -3
- package/package.json +9 -6
- package/src/astro-data-utils.ts +81 -0
- package/src/index.ts +83 -63
- package/src/rehype-collect-headings.ts +50 -0
- package/src/remark-prism.ts +2 -44
- package/src/utils.ts +27 -2
- package/test/fixtures/mdx-escape/src/components/Em.astro +7 -0
- package/test/fixtures/mdx-escape/src/components/P.astro +1 -0
- package/test/fixtures/mdx-escape/src/components/Title.astro +1 -0
- package/test/fixtures/mdx-escape/src/pages/html-tag.mdx +5 -0
- package/test/fixtures/mdx-escape/src/pages/index.mdx +13 -0
- package/test/fixtures/mdx-frontmatter/src/layouts/Base.astro +13 -3
- package/test/fixtures/mdx-frontmatter/src/pages/index.mdx +3 -0
- package/test/fixtures/mdx-frontmatter/src/pages/with-headings.mdx +7 -0
- package/test/fixtures/mdx-frontmatter-injection/astro.config.mjs +12 -0
- package/test/fixtures/mdx-frontmatter-injection/node_modules/.bin/astro +17 -0
- package/test/fixtures/mdx-frontmatter-injection/package.json +12 -0
- package/test/fixtures/mdx-frontmatter-injection/src/markdown-plugins.mjs +20 -0
- package/test/fixtures/mdx-frontmatter-injection/src/pages/glob.json.js +6 -0
- package/test/fixtures/mdx-frontmatter-injection/src/pages/page-1.mdx +3 -0
- package/test/fixtures/mdx-frontmatter-injection/src/pages/page-2.mdx +19 -0
- package/test/fixtures/mdx-frontmatter-injection/src/pages/with-overrides.mdx +7 -0
- package/test/fixtures/mdx-get-headings/src/pages/pages.json.js +11 -0
- package/test/fixtures/mdx-get-headings/src/pages/test-with-jsx-expressions.mdx +8 -0
- package/test/fixtures/mdx-get-headings/src/pages/test.mdx +9 -0
- package/test/fixtures/mdx-page/astro.config.ts +5 -0
- package/test/fixtures/mdx-page/node_modules/.bin/astro +17 -0
- package/test/fixtures/mdx-page/package.json +7 -0
- package/test/fixtures/mdx-plus-react/astro.config.mjs +6 -0
- package/test/fixtures/mdx-plus-react/node_modules/.bin/astro +17 -0
- package/test/fixtures/mdx-plus-react/package.json +8 -0
- package/test/fixtures/mdx-plus-react/src/components/Component.jsx +5 -0
- package/test/fixtures/mdx-plus-react/src/pages/index.astro +11 -0
- package/test/fixtures/mdx-rehype-plugins/src/pages/reading-time.json.js +7 -0
- package/test/fixtures/mdx-rehype-plugins/src/pages/space-ipsum.mdx +25 -0
- package/test/fixtures/mdx-remark-plugins/src/pages/headings-glob.json.js +6 -0
- package/test/mdx-escape.test.js +32 -0
- package/test/mdx-frontmatter-injection.test.js +44 -0
- package/test/mdx-frontmatter.test.js +26 -26
- package/test/mdx-get-headings.test.js +60 -0
- package/test/mdx-page.test.js +0 -1
- package/test/mdx-plus-react.test.js +25 -0
- package/test/mdx-rehype-plugins.test.js +70 -0
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
[
|
|
2
|
-
[
|
|
3
|
-
[
|
|
4
|
-
[
|
|
5
|
-
[
|
|
1
|
+
[32m@astrojs/mdx:build: [0mcache hit, replaying output [2mfbb8fed20a6e13e0[0m
|
|
2
|
+
[32m@astrojs/mdx:build: [0m
|
|
3
|
+
[32m@astrojs/mdx:build: [0m> @astrojs/mdx@0.7.0 build /home/runner/work/astro/astro/packages/integrations/mdx
|
|
4
|
+
[32m@astrojs/mdx:build: [0m> astro-scripts build "src/**/*.ts" && tsc
|
|
5
|
+
[32m@astrojs/mdx:build: [0m
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,42 @@
|
|
|
1
1
|
# @astrojs/mdx
|
|
2
2
|
|
|
3
|
+
## 0.7.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#4176](https://github.com/withastro/astro/pull/4176) [`2675b8633`](https://github.com/withastro/astro/commit/2675b8633c5d5c45b237ec87940d5eaf1bfb1b4b) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Support frontmatter injection for MD and MDX using remark and rehype plugins
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- [#4181](https://github.com/withastro/astro/pull/4181) [`77cede720`](https://github.com/withastro/astro/commit/77cede720b09bce34f29c3d2d8b505311ce876b1) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Make collect-headings rehype plugin non-overridable
|
|
12
|
+
|
|
13
|
+
* [#4174](https://github.com/withastro/astro/pull/4174) [`8eb3a8c6d`](https://github.com/withastro/astro/commit/8eb3a8c6d9554707963c3a3bc36ed8b68d3cf0fb) Thanks [@matthewp](https://github.com/matthewp)! - Allows using React with automatic imports alongside MDX
|
|
14
|
+
|
|
15
|
+
- [#4145](https://github.com/withastro/astro/pull/4145) [`c7efcf57e`](https://github.com/withastro/astro/commit/c7efcf57e00a0fcde3bc9f813e3cc59902bd484c) Thanks [@FredKSchott](https://github.com/FredKSchott)! - Fix a missing newline bug when `layout` was set.
|
|
16
|
+
|
|
17
|
+
## 0.6.0
|
|
18
|
+
|
|
19
|
+
### Minor Changes
|
|
20
|
+
|
|
21
|
+
- [#4134](https://github.com/withastro/astro/pull/4134) [`2968ba2b6`](https://github.com/withastro/astro/commit/2968ba2b6f00775b6e9872681b390cb466fdbfa2) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Add `headings` and `frontmatter` properties to layout props
|
|
22
|
+
|
|
23
|
+
## 0.5.0
|
|
24
|
+
|
|
25
|
+
### Minor Changes
|
|
26
|
+
|
|
27
|
+
- [#4095](https://github.com/withastro/astro/pull/4095) [`40ef43a59`](https://github.com/withastro/astro/commit/40ef43a59b08a1a8fbcd9f4a53745a9636a4fbb9) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Add IDs to MDX headings and expose via getHeadings() export
|
|
28
|
+
|
|
29
|
+
* [#4114](https://github.com/withastro/astro/pull/4114) [`64432bcb8`](https://github.com/withastro/astro/commit/64432bcb873efd0e4297c00fc9583a1fe516dfe7) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Refactor `@astrojs/mdx` and `@astrojs/markdown-remark` to use `@astrojs/prism` instead of duplicating the code
|
|
30
|
+
|
|
31
|
+
### Patch Changes
|
|
32
|
+
|
|
33
|
+
- [#4112](https://github.com/withastro/astro/pull/4112) [`e33fc9bc4`](https://github.com/withastro/astro/commit/e33fc9bc46ff0a30013deb6dc76e545e70cc3a3e) Thanks [@matthewp](https://github.com/matthewp)! - Fix MDX working with a ts config file
|
|
34
|
+
|
|
35
|
+
* [#4049](https://github.com/withastro/astro/pull/4049) [`b60cc0538`](https://github.com/withastro/astro/commit/b60cc0538bc5c68dd411117780d20d892530789d) Thanks [@natemoo-re](https://github.com/natemoo-re)! - Improve `injectScript` handling for non-Astro pages
|
|
36
|
+
|
|
37
|
+
* Updated dependencies [[`64432bcb8`](https://github.com/withastro/astro/commit/64432bcb873efd0e4297c00fc9583a1fe516dfe7)]:
|
|
38
|
+
- @astrojs/prism@0.7.0
|
|
39
|
+
|
|
3
40
|
## 0.4.0
|
|
4
41
|
|
|
5
42
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -103,6 +103,24 @@ const posts = await Astro.glob('./*.mdx');
|
|
|
103
103
|
|
|
104
104
|
See [the official "how MDX works" guide](https://mdxjs.com/docs/using-mdx/#how-mdx-works) for more on MDX variables.
|
|
105
105
|
|
|
106
|
+
### Exported properties
|
|
107
|
+
|
|
108
|
+
Alongside your [MDX variable exports](#variables), we generate a few helpful exports as well. These are accessible when importing an MDX file via `import` statements or [`Astro.glob`](https://docs.astro.build/en/reference/api-reference/#astroglob).
|
|
109
|
+
|
|
110
|
+
#### `file`
|
|
111
|
+
|
|
112
|
+
The absolute path to the MDX file (e.g. `home/user/projects/.../file.md`).
|
|
113
|
+
|
|
114
|
+
#### `url`
|
|
115
|
+
|
|
116
|
+
The browser-ready URL for MDX files under `src/pages/`. For example, `src/pages/en/about.mdx` will provide a `url` of `/en/about/`. For MDX files outside of `src/pages`, `url` will be `undefined`.
|
|
117
|
+
|
|
118
|
+
#### `getHeadings()`
|
|
119
|
+
|
|
120
|
+
**Returns:** `{ depth: number; slug: string; text: string }[]`
|
|
121
|
+
|
|
122
|
+
A function that returns an array of all headings (i.e. `h1 -> h6` elements) in the MDX file. Each heading’s `slug` corresponds to the generated ID for a given heading and can be used for anchor links.
|
|
123
|
+
|
|
106
124
|
### Frontmatter
|
|
107
125
|
|
|
108
126
|
Astro also supports YAML-based frontmatter out-of-the-box using the [remark-mdx-frontmatter](https://github.com/remcohaszing/remark-mdx-frontmatter) plugin. By default, all variables declared in a frontmatter fence (`---`) will be accessible via the `frontmatter` export. See the `frontmatterOptions` configuration to customize this behavior.
|
|
@@ -279,11 +297,11 @@ export default {
|
|
|
279
297
|
<details>
|
|
280
298
|
<summary><strong>rehypePlugins</strong></summary>
|
|
281
299
|
|
|
282
|
-
**Default plugins:** none
|
|
283
|
-
|
|
284
300
|
[Rehype plugins](https://github.com/rehypejs/rehype/blob/main/doc/plugins.md) allow you to transform the HTML that your Markdown generates. We recommend checking the [Remark plugin](https://github.com/remarkjs/remark/blob/main/doc/plugins.md) catalog first _before_ considering rehype plugins, since most users want to transform their Markdown syntax instead. If HTML transforms are what you need, we encourage you to browse [awesome-rehype](https://github.com/rehypejs/awesome-rehype) for a full curated list of plugins!
|
|
285
301
|
|
|
286
|
-
|
|
302
|
+
We apply our own (non-overridable) [`collect-headings`](https://github.com/withastro/astro/blob/main/packages/integrations/mdx/src/rehype-collect-headings.ts) plugin. This applies IDs to all headings (i.e. `h1 -> h6`) in your MDX files to [link to headings via anchor tags](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#linking_to_an_element_on_the_same_page).
|
|
303
|
+
|
|
304
|
+
To apply additional rehype plugins, pass an array to the `rehypePlugins` option like so:
|
|
287
305
|
|
|
288
306
|
```js
|
|
289
307
|
// astro.config.mjs
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { MarkdownAstroData } from 'astro';
|
|
2
|
+
import type { Data, VFile } from 'vfile';
|
|
3
|
+
export declare function remarkInitializeAstroData(): (tree: any, vfile: VFile) => void;
|
|
4
|
+
export declare function rehypeApplyFrontmatterExport(pageFrontmatter: Record<string, any>, exportName?: string): (tree: any, vfile: VFile) => void;
|
|
5
|
+
/**
|
|
6
|
+
* Copied from markdown utils
|
|
7
|
+
* @see "vite-plugin-utils"
|
|
8
|
+
*/
|
|
9
|
+
export declare function safelyGetAstroData(vfileData: Data): MarkdownAstroData;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { name as isValidIdentifierName } from "estree-util-is-identifier-name";
|
|
2
|
+
import { jsToTreeNode } from "./utils.js";
|
|
3
|
+
function remarkInitializeAstroData() {
|
|
4
|
+
return function(tree, vfile) {
|
|
5
|
+
if (!vfile.data.astro) {
|
|
6
|
+
vfile.data.astro = { frontmatter: {} };
|
|
7
|
+
}
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
function rehypeApplyFrontmatterExport(pageFrontmatter, exportName = "frontmatter") {
|
|
11
|
+
return function(tree, vfile) {
|
|
12
|
+
if (!isValidIdentifierName(exportName)) {
|
|
13
|
+
throw new Error(
|
|
14
|
+
`[MDX] ${JSON.stringify(
|
|
15
|
+
exportName
|
|
16
|
+
)} is not a valid frontmatter export name! Make sure "frontmatterOptions.name" could be used as a JS export (i.e. "export const frontmatterName = ...")`
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
const { frontmatter: injectedFrontmatter } = safelyGetAstroData(vfile.data);
|
|
20
|
+
const frontmatter = { ...injectedFrontmatter, ...pageFrontmatter };
|
|
21
|
+
let exportNodes = [];
|
|
22
|
+
if (!exportName) {
|
|
23
|
+
exportNodes = Object.entries(frontmatter).map(([k, v]) => {
|
|
24
|
+
if (!isValidIdentifierName(k)) {
|
|
25
|
+
throw new Error(
|
|
26
|
+
`[MDX] A remark or rehype plugin tried to inject ${JSON.stringify(
|
|
27
|
+
k
|
|
28
|
+
)} as a top-level export, which is not a valid export name.`
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
return jsToTreeNode(`export const ${k} = ${JSON.stringify(v)};`);
|
|
32
|
+
});
|
|
33
|
+
} else {
|
|
34
|
+
exportNodes = [jsToTreeNode(`export const ${exportName} = ${JSON.stringify(frontmatter)};`)];
|
|
35
|
+
}
|
|
36
|
+
tree.children = exportNodes.concat(tree.children);
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function isValidAstroData(obj) {
|
|
40
|
+
if (typeof obj === "object" && obj !== null && obj.hasOwnProperty("frontmatter")) {
|
|
41
|
+
const { frontmatter } = obj;
|
|
42
|
+
try {
|
|
43
|
+
JSON.stringify(frontmatter);
|
|
44
|
+
} catch {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
return typeof frontmatter === "object" && frontmatter !== null;
|
|
48
|
+
}
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
function safelyGetAstroData(vfileData) {
|
|
52
|
+
const { astro } = vfileData;
|
|
53
|
+
if (!astro)
|
|
54
|
+
return { frontmatter: {} };
|
|
55
|
+
if (!isValidAstroData(astro)) {
|
|
56
|
+
throw Error(
|
|
57
|
+
`[MDX] A remark or rehype plugin tried to add invalid frontmatter. Ensure "astro.frontmatter" is a JSON object!`
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
return astro;
|
|
61
|
+
}
|
|
62
|
+
export {
|
|
63
|
+
rehypeApplyFrontmatterExport,
|
|
64
|
+
remarkInitializeAstroData,
|
|
65
|
+
safelyGetAstroData
|
|
66
|
+
};
|
package/dist/index.js
CHANGED
|
@@ -1,92 +1,109 @@
|
|
|
1
|
-
import { nodeTypes } from "@mdx-js/mdx";
|
|
1
|
+
import { compile as mdxCompile, nodeTypes } from "@mdx-js/mdx";
|
|
2
2
|
import mdxPlugin from "@mdx-js/rollup";
|
|
3
3
|
import { parse as parseESM } from "es-module-lexer";
|
|
4
4
|
import rehypeRaw from "rehype-raw";
|
|
5
|
-
import remarkFrontmatter from "remark-frontmatter";
|
|
6
5
|
import remarkGfm from "remark-gfm";
|
|
7
|
-
import remarkMdxFrontmatter from "remark-mdx-frontmatter";
|
|
8
6
|
import remarkShikiTwoslash from "remark-shiki-twoslash";
|
|
9
7
|
import remarkSmartypants from "remark-smartypants";
|
|
8
|
+
import { VFile } from "vfile";
|
|
9
|
+
import { rehypeApplyFrontmatterExport, remarkInitializeAstroData } from "./astro-data-utils.js";
|
|
10
|
+
import rehypeCollectHeadings from "./rehype-collect-headings.js";
|
|
10
11
|
import remarkPrism from "./remark-prism.js";
|
|
11
|
-
import { getFileInfo,
|
|
12
|
-
const DEFAULT_REMARK_PLUGINS = [
|
|
12
|
+
import { getFileInfo, parseFrontmatter } from "./utils.js";
|
|
13
|
+
const DEFAULT_REMARK_PLUGINS = [
|
|
14
|
+
remarkGfm,
|
|
15
|
+
remarkSmartypants
|
|
16
|
+
];
|
|
17
|
+
const DEFAULT_REHYPE_PLUGINS = [];
|
|
13
18
|
function handleExtends(config, defaults = []) {
|
|
14
19
|
if (Array.isArray(config))
|
|
15
20
|
return config;
|
|
16
21
|
return [...defaults, ...(config == null ? void 0 : config.extends) ?? []];
|
|
17
22
|
}
|
|
23
|
+
function getRemarkPlugins(mdxOptions, config) {
|
|
24
|
+
let remarkPlugins = [
|
|
25
|
+
remarkInitializeAstroData,
|
|
26
|
+
...handleExtends(mdxOptions.remarkPlugins, DEFAULT_REMARK_PLUGINS)
|
|
27
|
+
];
|
|
28
|
+
if (config.markdown.syntaxHighlight === "shiki") {
|
|
29
|
+
const shikiTwoslash = remarkShikiTwoslash.default ?? remarkShikiTwoslash;
|
|
30
|
+
remarkPlugins.push([shikiTwoslash, config.markdown.shikiConfig]);
|
|
31
|
+
}
|
|
32
|
+
if (config.markdown.syntaxHighlight === "prism") {
|
|
33
|
+
remarkPlugins.push(remarkPrism);
|
|
34
|
+
}
|
|
35
|
+
return remarkPlugins;
|
|
36
|
+
}
|
|
37
|
+
function getRehypePlugins(mdxOptions, config) {
|
|
38
|
+
let rehypePlugins = handleExtends(mdxOptions.rehypePlugins, DEFAULT_REHYPE_PLUGINS);
|
|
39
|
+
if (config.markdown.syntaxHighlight === "shiki" || config.markdown.syntaxHighlight === "prism") {
|
|
40
|
+
rehypePlugins.push([rehypeRaw, { passThrough: nodeTypes }]);
|
|
41
|
+
}
|
|
42
|
+
rehypePlugins.push(rehypeCollectHeadings);
|
|
43
|
+
return rehypePlugins;
|
|
44
|
+
}
|
|
18
45
|
function mdx(mdxOptions = {}) {
|
|
19
46
|
return {
|
|
20
47
|
name: "@astrojs/mdx",
|
|
21
48
|
hooks: {
|
|
22
49
|
"astro:config:setup": ({ updateConfig, config, addPageExtension, command }) => {
|
|
23
50
|
addPageExtension(".mdx");
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
remarkPlugins.push([
|
|
28
|
-
remarkShikiTwoslash.default,
|
|
29
|
-
config.markdown.shikiConfig
|
|
30
|
-
]);
|
|
31
|
-
rehypePlugins.push([rehypeRaw, { passThrough: nodeTypes }]);
|
|
32
|
-
}
|
|
33
|
-
if (config.markdown.syntaxHighlight === "prism") {
|
|
34
|
-
remarkPlugins.push(remarkPrism);
|
|
35
|
-
rehypePlugins.push([rehypeRaw, { passThrough: nodeTypes }]);
|
|
36
|
-
}
|
|
37
|
-
remarkPlugins.push(remarkFrontmatter);
|
|
38
|
-
remarkPlugins.push([
|
|
39
|
-
remarkMdxFrontmatter,
|
|
40
|
-
{
|
|
41
|
-
name: "frontmatter",
|
|
42
|
-
...mdxOptions.frontmatterOptions
|
|
43
|
-
}
|
|
44
|
-
]);
|
|
45
|
-
const configuredMdxPlugin = mdxPlugin({
|
|
46
|
-
remarkPlugins,
|
|
47
|
-
rehypePlugins,
|
|
51
|
+
const mdxPluginOpts = {
|
|
52
|
+
remarkPlugins: getRemarkPlugins(mdxOptions, config),
|
|
53
|
+
rehypePlugins: getRehypePlugins(mdxOptions, config),
|
|
48
54
|
jsx: true,
|
|
49
55
|
jsxImportSource: "astro",
|
|
50
56
|
format: "mdx",
|
|
51
57
|
mdExtensions: []
|
|
52
|
-
}
|
|
58
|
+
};
|
|
53
59
|
updateConfig({
|
|
54
60
|
vite: {
|
|
55
61
|
plugins: [
|
|
56
62
|
{
|
|
57
63
|
enforce: "pre",
|
|
58
|
-
...
|
|
64
|
+
...mdxPlugin(mdxPluginOpts),
|
|
59
65
|
async transform(code, id) {
|
|
60
|
-
|
|
61
|
-
if (!id.endsWith(".mdx"))
|
|
66
|
+
if (!id.endsWith("mdx"))
|
|
62
67
|
return;
|
|
63
|
-
|
|
64
|
-
if ((_b = mdxOptions.frontmatterOptions) == null ? void 0 : _b.parsers) {
|
|
65
|
-
return mdxPluginTransform == null ? void 0 : mdxPluginTransform(code, id);
|
|
66
|
-
}
|
|
67
|
-
const frontmatter = getFrontmatter(code, id);
|
|
68
|
+
let { data: frontmatter, content: pageContent } = parseFrontmatter(code, id);
|
|
68
69
|
if (frontmatter.layout) {
|
|
69
|
-
const { layout, ...
|
|
70
|
-
|
|
70
|
+
const { layout, ...contentProp } = frontmatter;
|
|
71
|
+
pageContent += `
|
|
72
|
+
|
|
71
73
|
export default async function({ children }) {
|
|
72
74
|
const Layout = (await import(${JSON.stringify(
|
|
73
75
|
frontmatter.layout
|
|
74
76
|
)})).default;
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
)}
|
|
77
|
+
const frontmatter=${JSON.stringify(
|
|
78
|
+
contentProp
|
|
79
|
+
)};
|
|
80
|
+
return <Layout frontmatter={frontmatter} content={frontmatter} headings={getHeadings()}>{children}</Layout> }`;
|
|
78
81
|
}
|
|
79
|
-
|
|
82
|
+
const compiled = await mdxCompile(new VFile({ value: pageContent, path: id }), {
|
|
83
|
+
...mdxPluginOpts,
|
|
84
|
+
rehypePlugins: [
|
|
85
|
+
...mdxPluginOpts.rehypePlugins ?? [],
|
|
86
|
+
() => {
|
|
87
|
+
var _a;
|
|
88
|
+
return rehypeApplyFrontmatterExport(
|
|
89
|
+
frontmatter,
|
|
90
|
+
(_a = mdxOptions.frontmatterOptions) == null ? void 0 : _a.name
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
]
|
|
94
|
+
});
|
|
95
|
+
return {
|
|
96
|
+
code: String(compiled.value),
|
|
97
|
+
map: compiled.map
|
|
98
|
+
};
|
|
80
99
|
}
|
|
81
100
|
},
|
|
82
101
|
{
|
|
83
|
-
name: "@astrojs/mdx",
|
|
102
|
+
name: "@astrojs/mdx-postprocess",
|
|
84
103
|
transform(code, id) {
|
|
85
104
|
if (!id.endsWith(".mdx"))
|
|
86
105
|
return;
|
|
87
106
|
const [, moduleExports] = parseESM(code);
|
|
88
|
-
code += `
|
|
89
|
-
import "${"astro:scripts/page-ssr.js"}";`;
|
|
90
107
|
const { fileUrl, fileId } = getFileInfo(id, config);
|
|
91
108
|
if (!moduleExports.includes("url")) {
|
|
92
109
|
code += `
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import Slugger from "github-slugger";
|
|
2
|
+
import { visit } from "unist-util-visit";
|
|
3
|
+
import { jsToTreeNode } from "./utils.js";
|
|
4
|
+
function rehypeCollectHeadings() {
|
|
5
|
+
const slugger = new Slugger();
|
|
6
|
+
return function(tree) {
|
|
7
|
+
const headings = [];
|
|
8
|
+
visit(tree, (node) => {
|
|
9
|
+
if (node.type !== "element")
|
|
10
|
+
return;
|
|
11
|
+
const { tagName } = node;
|
|
12
|
+
if (tagName[0] !== "h")
|
|
13
|
+
return;
|
|
14
|
+
const [_, level] = tagName.match(/h([0-6])/) ?? [];
|
|
15
|
+
if (!level)
|
|
16
|
+
return;
|
|
17
|
+
const depth = Number.parseInt(level);
|
|
18
|
+
let text = "";
|
|
19
|
+
visit(node, (child, __, parent) => {
|
|
20
|
+
if (child.type === "element" || parent == null) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
if (child.type === "raw" && child.value.match(/^\n?<.*>\n?$/)) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
if ((/* @__PURE__ */ new Set(["text", "raw", "mdxTextExpression"])).has(child.type)) {
|
|
27
|
+
text += child.value;
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
node.properties = node.properties || {};
|
|
31
|
+
if (typeof node.properties.id !== "string") {
|
|
32
|
+
let slug = slugger.slug(text);
|
|
33
|
+
if (slug.endsWith("-")) {
|
|
34
|
+
slug = slug.slice(0, -1);
|
|
35
|
+
}
|
|
36
|
+
node.properties.id = slug;
|
|
37
|
+
}
|
|
38
|
+
headings.push({ depth, slug: node.properties.id, text });
|
|
39
|
+
});
|
|
40
|
+
tree.children.unshift(
|
|
41
|
+
jsToTreeNode(`export function getHeadings() { return ${JSON.stringify(headings)} }`)
|
|
42
|
+
);
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
export {
|
|
46
|
+
rehypeCollectHeadings as default
|
|
47
|
+
};
|
package/dist/remark-prism.js
CHANGED
|
@@ -1,42 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import Prism from "prismjs";
|
|
3
|
-
import loadLanguages from "prismjs/components/index.js";
|
|
1
|
+
import { runHighlighterWithAstro } from "@astrojs/prism/dist/highlighter";
|
|
4
2
|
import { visit } from "unist-util-visit";
|
|
5
|
-
const languageMap = /* @__PURE__ */ new Map([["ts", "typescript"]]);
|
|
6
|
-
function runHighlighter(lang, code) {
|
|
7
|
-
let classLanguage = `language-${lang}`;
|
|
8
|
-
if (lang == null) {
|
|
9
|
-
lang = "plaintext";
|
|
10
|
-
}
|
|
11
|
-
const ensureLoaded = (language) => {
|
|
12
|
-
if (language && !Prism.languages[language]) {
|
|
13
|
-
loadLanguages([language]);
|
|
14
|
-
}
|
|
15
|
-
};
|
|
16
|
-
if (languageMap.has(lang)) {
|
|
17
|
-
ensureLoaded(languageMap.get(lang));
|
|
18
|
-
} else if (lang === "astro") {
|
|
19
|
-
ensureLoaded("typescript");
|
|
20
|
-
addAstro(Prism);
|
|
21
|
-
} else {
|
|
22
|
-
ensureLoaded("markup-templating");
|
|
23
|
-
ensureLoaded(lang);
|
|
24
|
-
}
|
|
25
|
-
if (lang && !Prism.languages[lang]) {
|
|
26
|
-
console.warn(`Unable to load the language: ${lang}`);
|
|
27
|
-
}
|
|
28
|
-
const grammar = Prism.languages[lang];
|
|
29
|
-
let html = code;
|
|
30
|
-
if (grammar) {
|
|
31
|
-
html = Prism.highlight(code, grammar, lang);
|
|
32
|
-
}
|
|
33
|
-
return { classLanguage, html };
|
|
34
|
-
}
|
|
35
3
|
function remarkPrism() {
|
|
36
4
|
return (tree) => visit(tree, "code", (node) => {
|
|
37
5
|
let { lang, value } = node;
|
|
38
6
|
node.type = "html";
|
|
39
|
-
let { html, classLanguage } =
|
|
7
|
+
let { html, classLanguage } = runHighlighterWithAstro(lang, value);
|
|
40
8
|
let classes = [classLanguage];
|
|
41
9
|
node.value = `<pre class="${classes.join(
|
|
42
10
|
" "
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
import type { Options as AcornOpts } from 'acorn';
|
|
1
2
|
import type { AstroConfig } from 'astro';
|
|
3
|
+
import type { MdxjsEsm } from 'mdast-util-mdx';
|
|
4
|
+
import matter from 'gray-matter';
|
|
2
5
|
interface FileInfo {
|
|
3
6
|
fileId: string;
|
|
4
7
|
fileUrl: string;
|
|
@@ -9,7 +12,6 @@ export declare function getFileInfo(id: string, config: AstroConfig): FileInfo;
|
|
|
9
12
|
* Match YAML exception handling from Astro core errors
|
|
10
13
|
* @see 'astro/src/core/errors.ts'
|
|
11
14
|
*/
|
|
12
|
-
export declare function
|
|
13
|
-
|
|
14
|
-
};
|
|
15
|
+
export declare function parseFrontmatter(code: string, id: string): matter.GrayMatterFile<string>;
|
|
16
|
+
export declare function jsToTreeNode(jsString: string, acornOpts?: AcornOpts): MdxjsEsm;
|
|
15
17
|
export {};
|
package/dist/utils.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { parse } from "acorn";
|
|
1
2
|
import matter from "gray-matter";
|
|
2
3
|
function appendForwardSlash(path) {
|
|
3
4
|
return path.endsWith("/") ? path : path + "/";
|
|
@@ -26,9 +27,9 @@ function getFileInfo(id, config) {
|
|
|
26
27
|
}
|
|
27
28
|
return { fileId, fileUrl };
|
|
28
29
|
}
|
|
29
|
-
function
|
|
30
|
+
function parseFrontmatter(code, id) {
|
|
30
31
|
try {
|
|
31
|
-
return matter(code)
|
|
32
|
+
return matter(code);
|
|
32
33
|
} catch (e) {
|
|
33
34
|
if (e.name === "YAMLException") {
|
|
34
35
|
const err = e;
|
|
@@ -41,7 +42,25 @@ function getFrontmatter(code, id) {
|
|
|
41
42
|
}
|
|
42
43
|
}
|
|
43
44
|
}
|
|
45
|
+
function jsToTreeNode(jsString, acornOpts = {
|
|
46
|
+
ecmaVersion: "latest",
|
|
47
|
+
sourceType: "module"
|
|
48
|
+
}) {
|
|
49
|
+
return {
|
|
50
|
+
type: "mdxjsEsm",
|
|
51
|
+
value: "",
|
|
52
|
+
data: {
|
|
53
|
+
estree: {
|
|
54
|
+
body: [],
|
|
55
|
+
...parse(jsString, acornOpts),
|
|
56
|
+
type: "Program",
|
|
57
|
+
sourceType: "module"
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
}
|
|
44
62
|
export {
|
|
45
63
|
getFileInfo,
|
|
46
|
-
|
|
64
|
+
jsToTreeNode,
|
|
65
|
+
parseFrontmatter
|
|
47
66
|
};
|
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.7.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
7
7
|
"author": "withastro",
|
|
@@ -14,7 +14,6 @@
|
|
|
14
14
|
"keywords": [
|
|
15
15
|
"astro-integration",
|
|
16
16
|
"astro-component",
|
|
17
|
-
"renderer",
|
|
18
17
|
"mdx"
|
|
19
18
|
],
|
|
20
19
|
"bugs": "https://github.com/withastro/astro/issues",
|
|
@@ -24,12 +23,13 @@
|
|
|
24
23
|
"./package.json": "./package.json"
|
|
25
24
|
},
|
|
26
25
|
"dependencies": {
|
|
27
|
-
"@astrojs/prism": "^0.
|
|
26
|
+
"@astrojs/prism": "^0.7.0",
|
|
28
27
|
"@mdx-js/mdx": "^2.1.2",
|
|
29
28
|
"@mdx-js/rollup": "^2.1.1",
|
|
29
|
+
"acorn": "^8.8.0",
|
|
30
30
|
"es-module-lexer": "^0.10.5",
|
|
31
|
+
"github-slugger": "^1.4.0",
|
|
31
32
|
"gray-matter": "^4.0.3",
|
|
32
|
-
"prismjs": "^1.28.0",
|
|
33
33
|
"rehype-raw": "^6.1.1",
|
|
34
34
|
"remark-frontmatter": "^4.0.1",
|
|
35
35
|
"remark-gfm": "^3.0.1",
|
|
@@ -37,17 +37,20 @@
|
|
|
37
37
|
"remark-shiki-twoslash": "^3.1.0",
|
|
38
38
|
"remark-smartypants": "^2.0.0",
|
|
39
39
|
"shiki": "^0.10.1",
|
|
40
|
-
"unist-util-visit": "^4.1.0"
|
|
40
|
+
"unist-util-visit": "^4.1.0",
|
|
41
|
+
"vfile": "^5.3.2"
|
|
41
42
|
},
|
|
42
43
|
"devDependencies": {
|
|
43
44
|
"@types/chai": "^4.3.1",
|
|
44
45
|
"@types/mocha": "^9.1.1",
|
|
45
46
|
"@types/yargs-parser": "^21.0.0",
|
|
46
|
-
"astro": "1.0.0-rc.
|
|
47
|
+
"astro": "1.0.0-rc.7",
|
|
47
48
|
"astro-scripts": "0.0.6",
|
|
48
49
|
"chai": "^4.3.6",
|
|
49
50
|
"linkedom": "^0.14.12",
|
|
51
|
+
"mdast-util-to-string": "^3.1.0",
|
|
50
52
|
"mocha": "^9.2.2",
|
|
53
|
+
"reading-time": "^1.5.0",
|
|
51
54
|
"remark-toc": "^8.0.1"
|
|
52
55
|
},
|
|
53
56
|
"engines": {
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { MarkdownAstroData } from 'astro';
|
|
2
|
+
import { name as isValidIdentifierName } from 'estree-util-is-identifier-name';
|
|
3
|
+
import type { MdxjsEsm } from 'mdast-util-mdx';
|
|
4
|
+
import type { Data, VFile } from 'vfile';
|
|
5
|
+
import { jsToTreeNode } from './utils.js';
|
|
6
|
+
|
|
7
|
+
export function remarkInitializeAstroData() {
|
|
8
|
+
return function (tree: any, vfile: VFile) {
|
|
9
|
+
if (!vfile.data.astro) {
|
|
10
|
+
vfile.data.astro = { frontmatter: {} };
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function rehypeApplyFrontmatterExport(
|
|
16
|
+
pageFrontmatter: Record<string, any>,
|
|
17
|
+
exportName = 'frontmatter'
|
|
18
|
+
) {
|
|
19
|
+
return function (tree: any, vfile: VFile) {
|
|
20
|
+
if (!isValidIdentifierName(exportName)) {
|
|
21
|
+
throw new Error(
|
|
22
|
+
`[MDX] ${JSON.stringify(
|
|
23
|
+
exportName
|
|
24
|
+
)} is not a valid frontmatter export name! Make sure "frontmatterOptions.name" could be used as a JS export (i.e. "export const frontmatterName = ...")`
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
const { frontmatter: injectedFrontmatter } = safelyGetAstroData(vfile.data);
|
|
28
|
+
const frontmatter = { ...injectedFrontmatter, ...pageFrontmatter };
|
|
29
|
+
let exportNodes: MdxjsEsm[] = [];
|
|
30
|
+
if (!exportName) {
|
|
31
|
+
exportNodes = Object.entries(frontmatter).map(([k, v]) => {
|
|
32
|
+
if (!isValidIdentifierName(k)) {
|
|
33
|
+
throw new Error(
|
|
34
|
+
`[MDX] A remark or rehype plugin tried to inject ${JSON.stringify(
|
|
35
|
+
k
|
|
36
|
+
)} as a top-level export, which is not a valid export name.`
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
return jsToTreeNode(`export const ${k} = ${JSON.stringify(v)};`);
|
|
40
|
+
});
|
|
41
|
+
} else {
|
|
42
|
+
exportNodes = [jsToTreeNode(`export const ${exportName} = ${JSON.stringify(frontmatter)};`)];
|
|
43
|
+
}
|
|
44
|
+
tree.children = exportNodes.concat(tree.children);
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Copied from markdown utils
|
|
50
|
+
* @see "vite-plugin-utils"
|
|
51
|
+
*/
|
|
52
|
+
function isValidAstroData(obj: unknown): obj is MarkdownAstroData {
|
|
53
|
+
if (typeof obj === 'object' && obj !== null && obj.hasOwnProperty('frontmatter')) {
|
|
54
|
+
const { frontmatter } = obj as any;
|
|
55
|
+
try {
|
|
56
|
+
// ensure frontmatter is JSON-serializable
|
|
57
|
+
JSON.stringify(frontmatter);
|
|
58
|
+
} catch {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
return typeof frontmatter === 'object' && frontmatter !== null;
|
|
62
|
+
}
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Copied from markdown utils
|
|
68
|
+
* @see "vite-plugin-utils"
|
|
69
|
+
*/
|
|
70
|
+
export function safelyGetAstroData(vfileData: Data): MarkdownAstroData {
|
|
71
|
+
const { astro } = vfileData;
|
|
72
|
+
|
|
73
|
+
if (!astro) return { frontmatter: {} };
|
|
74
|
+
if (!isValidAstroData(astro)) {
|
|
75
|
+
throw Error(
|
|
76
|
+
`[MDX] A remark or rehype plugin tried to add invalid frontmatter. Ensure "astro.frontmatter" is a JSON object!`
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return astro;
|
|
81
|
+
}
|