@astrojs/mdx 0.11.6 → 0.12.1
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 +16 -0
- package/README.md +21 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +25 -5
- package/package.json +3 -2
- package/src/index.ts +35 -6
- package/test/fixtures/mdx-astro-markdown-remarkRehype/src/pages/index.mdx +5 -0
- package/test/fixtures/mdx-component/src/components/WithFragment.mdx +3 -0
- package/test/fixtures/mdx-component/src/pages/glob.astro +11 -2
- package/test/fixtures/mdx-component/src/pages/w-fragment.astro +5 -0
- package/test/fixtures/mdx-slots/src/components/Slotted.astro +4 -0
- package/test/fixtures/mdx-slots/src/components/Test.mdx +15 -0
- package/test/fixtures/mdx-slots/src/pages/glob.astro +11 -0
- package/test/fixtures/mdx-slots/src/pages/index.astro +5 -0
- package/test/mdx-astro-markdown-remarkRehype.test.js +85 -0
- package/test/mdx-component.test.js +79 -0
- package/test/mdx-slots.js +124 -0
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
[
|
|
2
|
-
[
|
|
3
|
-
[
|
|
4
|
-
[
|
|
5
|
-
[
|
|
1
|
+
[36m@astrojs/mdx:build: [0mcache hit, replaying output [2m55f97c81b614ef9c[0m
|
|
2
|
+
[36m@astrojs/mdx:build: [0m
|
|
3
|
+
[36m@astrojs/mdx:build: [0m> @astrojs/mdx@0.12.1 build /home/runner/work/astro/astro/packages/integrations/mdx
|
|
4
|
+
[36m@astrojs/mdx:build: [0m> astro-scripts build "src/**/*.ts" && tsc
|
|
5
|
+
[36m@astrojs/mdx:build: [0m
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# @astrojs/mdx
|
|
2
2
|
|
|
3
|
+
## 0.12.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#5522](https://github.com/withastro/astro/pull/5522) [`efc4363e0`](https://github.com/withastro/astro/commit/efc4363e0baf7f92900e20af339811bb3df42b0e) Thanks [@delucis](https://github.com/delucis)! - Support use of `<Fragment>` in MDX files rendered with `<Content />` component
|
|
8
|
+
|
|
9
|
+
## 0.12.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- [#5427](https://github.com/withastro/astro/pull/5427) [`2a1c085b1`](https://github.com/withastro/astro/commit/2a1c085b199f24e34424ec8c19041c03602c53c5) Thanks [@backflip](https://github.com/backflip)! - Uses remark-rehype options from astro.config.mjs
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- [#5448](https://github.com/withastro/astro/pull/5448) [`ef2ffc7ae`](https://github.com/withastro/astro/commit/ef2ffc7ae9ff554860238ecd2fb3bf6d82b5801b) Thanks [@delucis](https://github.com/delucis)! - Fix broken link in README
|
|
18
|
+
|
|
3
19
|
## 0.11.6
|
|
4
20
|
|
|
5
21
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -191,7 +191,7 @@ export default {
|
|
|
191
191
|
};
|
|
192
192
|
```
|
|
193
193
|
|
|
194
|
-
…every MDX file will have `customProperty` in its frontmatter! See [our Markdown documentation](https://docs.astro.build/en/guides/markdown-content/#injecting-frontmatter) for more usage instructions and a [reading time plugin example](https://docs.astro.build/en/guides/markdown-content/#example-calculate-reading-time).
|
|
194
|
+
…every MDX file will have `customProperty` in its frontmatter! See [our Markdown documentation](https://docs.astro.build/en/guides/markdown-content/#example-injecting-frontmatter) for more usage instructions and a [reading time plugin example](https://docs.astro.build/en/guides/markdown-content/#example-calculate-reading-time).
|
|
195
195
|
|
|
196
196
|
### Layouts
|
|
197
197
|
Layouts can be applied [in the same way as standard Astro Markdown](https://docs.astro.build/en/guides/markdown-content/#frontmatter-layout). You can add a `layout` to [your frontmatter](#frontmatter) like so:
|
|
@@ -518,6 +518,26 @@ These are plugins that modify the output [estree](https://github.com/estree/estr
|
|
|
518
518
|
|
|
519
519
|
We suggest [using AST Explorer](https://astexplorer.net/) to play with estree outputs, and trying [`estree-util-visit`](https://unifiedjs.com/explore/package/estree-util-visit/) for searching across JavaScript nodes.
|
|
520
520
|
|
|
521
|
+
### remarkRehype
|
|
522
|
+
|
|
523
|
+
Markdown content is transformed into HTML through remark-rehype which has [a number of options](https://github.com/remarkjs/remark-rehype#options).
|
|
524
|
+
|
|
525
|
+
You can use remark-rehype options in your MDX integration config file like so:
|
|
526
|
+
|
|
527
|
+
```js
|
|
528
|
+
// astro.config.mjs
|
|
529
|
+
export default {
|
|
530
|
+
integrations: [mdx({
|
|
531
|
+
remarkRehype: {
|
|
532
|
+
footnoteLabel: 'Catatan kaki',
|
|
533
|
+
footnoteBackLabel: 'Kembali ke konten',
|
|
534
|
+
},
|
|
535
|
+
})],
|
|
536
|
+
};
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
This inherits the configuration of `markdown.remarkRehype`. This behavior can be changed by configuring `extendPlugins`.
|
|
540
|
+
|
|
521
541
|
## Examples
|
|
522
542
|
|
|
523
543
|
- The [Astro MDX example](https://github.com/withastro/astro/tree/latest/examples/with-mdx) shows how to use MDX files in your Astro project.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { PluggableList } from '@mdx-js/mdx/lib/core.js';
|
|
2
2
|
import type { AstroIntegration } from 'astro';
|
|
3
|
+
import type { Options as RemarkRehypeOptions } from 'remark-rehype';
|
|
3
4
|
export declare type MdxOptions = {
|
|
4
5
|
remarkPlugins?: PluggableList;
|
|
5
6
|
rehypePlugins?: PluggableList;
|
|
@@ -12,5 +13,6 @@ export declare type MdxOptions = {
|
|
|
12
13
|
* - false - do not inherit any plugins
|
|
13
14
|
*/
|
|
14
15
|
extendPlugins?: 'markdown' | 'astroDefaults' | false;
|
|
16
|
+
remarkRehype?: RemarkRehypeOptions;
|
|
15
17
|
};
|
|
16
18
|
export default function mdx(mdxOptions?: MdxOptions): AstroIntegration;
|
package/dist/index.js
CHANGED
|
@@ -34,6 +34,13 @@ function mdx(mdxOptions = {}) {
|
|
|
34
34
|
);
|
|
35
35
|
console.info(`See "extendPlugins" option to configure this behavior.`);
|
|
36
36
|
}
|
|
37
|
+
let remarkRehypeOptions = mdxOptions.remarkRehype;
|
|
38
|
+
if (mdxOptions.extendPlugins === "markdown") {
|
|
39
|
+
remarkRehypeOptions = {
|
|
40
|
+
...config.markdown.remarkRehype,
|
|
41
|
+
...remarkRehypeOptions
|
|
42
|
+
};
|
|
43
|
+
}
|
|
37
44
|
const mdxPluginOpts = {
|
|
38
45
|
remarkPlugins: await getRemarkPlugins(mdxOptions, config),
|
|
39
46
|
rehypePlugins: getRehypePlugins(mdxOptions, config),
|
|
@@ -41,7 +48,8 @@ function mdx(mdxOptions = {}) {
|
|
|
41
48
|
jsx: true,
|
|
42
49
|
jsxImportSource: "astro",
|
|
43
50
|
format: "mdx",
|
|
44
|
-
mdExtensions: []
|
|
51
|
+
mdExtensions: [],
|
|
52
|
+
remarkRehypeOptions
|
|
45
53
|
};
|
|
46
54
|
let importMetaEnv = {
|
|
47
55
|
SITE: config.site
|
|
@@ -83,9 +91,14 @@ function mdx(mdxOptions = {}) {
|
|
|
83
91
|
transform(code, id) {
|
|
84
92
|
if (!id.endsWith(".mdx"))
|
|
85
93
|
return;
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
const
|
|
94
|
+
const [moduleImports, moduleExports] = parseESM(code);
|
|
95
|
+
const importsFromJSXRuntime = moduleImports.filter(({ n }) => n === "astro/jsx-runtime").map(({ ss, se }) => code.substring(ss, se));
|
|
96
|
+
const hasFragmentImport = importsFromJSXRuntime.some(
|
|
97
|
+
(statement) => /[\s,{](Fragment,|Fragment\s*})/.test(statement)
|
|
98
|
+
);
|
|
99
|
+
if (!hasFragmentImport) {
|
|
100
|
+
code = 'import { Fragment } from "astro/jsx-runtime"\n' + code;
|
|
101
|
+
}
|
|
89
102
|
const { fileUrl, fileId } = getFileInfo(id, config);
|
|
90
103
|
if (!moduleExports.includes("url")) {
|
|
91
104
|
code += `
|
|
@@ -108,9 +121,16 @@ export function compiledContent() { throw new Error(${JSON.stringify(
|
|
|
108
121
|
)}) };`;
|
|
109
122
|
}
|
|
110
123
|
if (!moduleExports.includes("Content")) {
|
|
124
|
+
code = code.replace("export default MDXContent;", "");
|
|
111
125
|
code += `
|
|
112
|
-
export const Content = MDXContent
|
|
126
|
+
export const Content = (props = {}) => MDXContent({
|
|
127
|
+
...props,
|
|
128
|
+
components: { Fragment, ...props.components },
|
|
129
|
+
});
|
|
130
|
+
export default Content;`;
|
|
113
131
|
}
|
|
132
|
+
code += `
|
|
133
|
+
Content[Symbol.for('astro.needsHeadRendering')] = !Boolean(frontmatter.layout);`;
|
|
114
134
|
if (command === "dev") {
|
|
115
135
|
code += `
|
|
116
136
|
if (import.meta.hot) {
|
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.12.1",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
7
7
|
"author": "withastro",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"@types/github-slugger": "^1.3.0",
|
|
47
47
|
"@types/mocha": "^9.1.1",
|
|
48
48
|
"@types/yargs-parser": "^21.0.0",
|
|
49
|
-
"astro": "1.6.
|
|
49
|
+
"astro": "1.6.13",
|
|
50
50
|
"astro-scripts": "0.0.9",
|
|
51
51
|
"chai": "^4.3.6",
|
|
52
52
|
"cheerio": "^1.0.0-rc.11",
|
|
@@ -56,6 +56,7 @@
|
|
|
56
56
|
"mocha": "^9.2.2",
|
|
57
57
|
"reading-time": "^1.5.0",
|
|
58
58
|
"rehype-pretty-code": "^0.4.0",
|
|
59
|
+
"remark-rehype": "^10.1.0",
|
|
59
60
|
"remark-shiki-twoslash": "^3.1.0",
|
|
60
61
|
"remark-toc": "^8.0.1",
|
|
61
62
|
"vite": "^3.0.0"
|
package/src/index.ts
CHANGED
|
@@ -5,6 +5,7 @@ import type { AstroIntegration } from 'astro';
|
|
|
5
5
|
import { parse as parseESM } from 'es-module-lexer';
|
|
6
6
|
import { blue, bold } from 'kleur/colors';
|
|
7
7
|
import fs from 'node:fs/promises';
|
|
8
|
+
import type { Options as RemarkRehypeOptions } from 'remark-rehype';
|
|
8
9
|
import { VFile } from 'vfile';
|
|
9
10
|
import type { Plugin as VitePlugin } from 'vite';
|
|
10
11
|
import {
|
|
@@ -33,6 +34,7 @@ export type MdxOptions = {
|
|
|
33
34
|
* - false - do not inherit any plugins
|
|
34
35
|
*/
|
|
35
36
|
extendPlugins?: 'markdown' | 'astroDefaults' | false;
|
|
37
|
+
remarkRehype?: RemarkRehypeOptions;
|
|
36
38
|
};
|
|
37
39
|
|
|
38
40
|
export default function mdx(mdxOptions: MdxOptions = {}): AstroIntegration {
|
|
@@ -62,6 +64,15 @@ export default function mdx(mdxOptions: MdxOptions = {}): AstroIntegration {
|
|
|
62
64
|
console.info(`See "extendPlugins" option to configure this behavior.`);
|
|
63
65
|
}
|
|
64
66
|
|
|
67
|
+
let remarkRehypeOptions = mdxOptions.remarkRehype;
|
|
68
|
+
|
|
69
|
+
if (mdxOptions.extendPlugins === 'markdown') {
|
|
70
|
+
remarkRehypeOptions = {
|
|
71
|
+
...config.markdown.remarkRehype,
|
|
72
|
+
...remarkRehypeOptions,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
65
76
|
const mdxPluginOpts: MdxRollupPluginOptions = {
|
|
66
77
|
remarkPlugins: await getRemarkPlugins(mdxOptions, config),
|
|
67
78
|
rehypePlugins: getRehypePlugins(mdxOptions, config),
|
|
@@ -71,6 +82,7 @@ export default function mdx(mdxOptions: MdxOptions = {}): AstroIntegration {
|
|
|
71
82
|
// Note: disable `.md` (and other alternative extensions for markdown files like `.markdown`) support
|
|
72
83
|
format: 'mdx',
|
|
73
84
|
mdExtensions: [],
|
|
85
|
+
remarkRehypeOptions,
|
|
74
86
|
};
|
|
75
87
|
|
|
76
88
|
let importMetaEnv: Record<string, any> = {
|
|
@@ -120,11 +132,18 @@ export default function mdx(mdxOptions: MdxOptions = {}): AstroIntegration {
|
|
|
120
132
|
transform(code, id) {
|
|
121
133
|
if (!id.endsWith('.mdx')) return;
|
|
122
134
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
135
|
+
const [moduleImports, moduleExports] = parseESM(code);
|
|
136
|
+
|
|
137
|
+
// Fragment import should already be injected, but check just to be safe.
|
|
138
|
+
const importsFromJSXRuntime = moduleImports
|
|
139
|
+
.filter(({ n }) => n === 'astro/jsx-runtime')
|
|
140
|
+
.map(({ ss, se }) => code.substring(ss, se));
|
|
141
|
+
const hasFragmentImport = importsFromJSXRuntime.some((statement) =>
|
|
142
|
+
/[\s,{](Fragment,|Fragment\s*})/.test(statement)
|
|
143
|
+
);
|
|
144
|
+
if (!hasFragmentImport) {
|
|
145
|
+
code = 'import { Fragment } from "astro/jsx-runtime"\n' + code;
|
|
146
|
+
}
|
|
128
147
|
|
|
129
148
|
const { fileUrl, fileId } = getFileInfo(id, config);
|
|
130
149
|
if (!moduleExports.includes('url')) {
|
|
@@ -144,9 +163,19 @@ export default function mdx(mdxOptions: MdxOptions = {}): AstroIntegration {
|
|
|
144
163
|
)}) };`;
|
|
145
164
|
}
|
|
146
165
|
if (!moduleExports.includes('Content')) {
|
|
147
|
-
|
|
166
|
+
// Make `Content` the default export so we can wrap `MDXContent` and pass in `Fragment`
|
|
167
|
+
code = code.replace('export default MDXContent;', '');
|
|
168
|
+
code += `\nexport const Content = (props = {}) => MDXContent({
|
|
169
|
+
...props,
|
|
170
|
+
components: { Fragment, ...props.components },
|
|
171
|
+
});
|
|
172
|
+
export default Content;`;
|
|
148
173
|
}
|
|
149
174
|
|
|
175
|
+
// Ensures styles and scripts are injected into a `<head>`
|
|
176
|
+
// When a layout is not applied
|
|
177
|
+
code += `\nContent[Symbol.for('astro.needsHeadRendering')] = !Boolean(frontmatter.layout);`;
|
|
178
|
+
|
|
150
179
|
if (command === 'dev') {
|
|
151
180
|
// TODO: decline HMR updates until we have a stable approach
|
|
152
181
|
code += `\nif (import.meta.hot) {
|
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
---
|
|
2
|
+
import { parse } from 'node:path';
|
|
2
3
|
const components = await Astro.glob('../components/*.mdx');
|
|
3
4
|
---
|
|
4
5
|
|
|
5
6
|
<div data-default-export>
|
|
6
|
-
{components.map(Component =>
|
|
7
|
+
{components.map(Component => (
|
|
8
|
+
<div data-file={parse(Component.file).base}>
|
|
9
|
+
<Component.default />
|
|
10
|
+
</div>
|
|
11
|
+
))}
|
|
7
12
|
</div>
|
|
8
13
|
|
|
9
14
|
<div data-content-export>
|
|
10
|
-
{components.map(({ Content }) =>
|
|
15
|
+
{components.map(({ Content, file }) => (
|
|
16
|
+
<div data-file={parse(file).base}>
|
|
17
|
+
<Content />
|
|
18
|
+
</div>
|
|
19
|
+
))}
|
|
11
20
|
</div>
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import mdx from '@astrojs/mdx';
|
|
2
|
+
|
|
3
|
+
import { expect } from 'chai';
|
|
4
|
+
import { parseHTML } from 'linkedom';
|
|
5
|
+
import { loadFixture } from '../../../astro/test/test-utils.js';
|
|
6
|
+
|
|
7
|
+
describe('MDX with Astro Markdown remark-rehype config', () => {
|
|
8
|
+
it('Renders footnotes with values from the default configuration', async () => {
|
|
9
|
+
const fixture = await loadFixture({
|
|
10
|
+
root: new URL('./fixtures/mdx-astro-markdown-remarkRehype/', import.meta.url),
|
|
11
|
+
integrations: [mdx()],
|
|
12
|
+
markdown: {
|
|
13
|
+
remarkRehype: {
|
|
14
|
+
footnoteLabel: 'Catatan kaki',
|
|
15
|
+
footnoteBackLabel: 'Kembali ke konten',
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
await fixture.build();
|
|
21
|
+
const html = await fixture.readFile('/index.html');
|
|
22
|
+
const { document } = parseHTML(html);
|
|
23
|
+
|
|
24
|
+
expect(document.querySelector('#footnote-label').textContent).to.equal('Catatan kaki');
|
|
25
|
+
expect(document.querySelector('.data-footnote-backref').getAttribute('aria-label')).to.equal(
|
|
26
|
+
'Kembali ke konten'
|
|
27
|
+
);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('Renders footnotes with values from custom configuration extending the default', async () => {
|
|
31
|
+
const fixture = await loadFixture({
|
|
32
|
+
root: new URL('./fixtures/mdx-astro-markdown-remarkRehype/', import.meta.url),
|
|
33
|
+
integrations: [
|
|
34
|
+
mdx({
|
|
35
|
+
remarkRehype: {
|
|
36
|
+
footnoteLabel: 'Catatan kaki',
|
|
37
|
+
footnoteBackLabel: 'Kembali ke konten',
|
|
38
|
+
},
|
|
39
|
+
}),
|
|
40
|
+
],
|
|
41
|
+
markdown: {
|
|
42
|
+
remarkRehype: {
|
|
43
|
+
footnoteBackLabel: 'Replace me',
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
await fixture.build();
|
|
49
|
+
const html = await fixture.readFile('/index.html');
|
|
50
|
+
const { document } = parseHTML(html);
|
|
51
|
+
|
|
52
|
+
expect(document.querySelector('#footnote-label').textContent).to.equal('Catatan kaki');
|
|
53
|
+
expect(document.querySelector('.data-footnote-backref').getAttribute('aria-label')).to.equal(
|
|
54
|
+
'Kembali ke konten'
|
|
55
|
+
);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('Renders footnotes with values from custom configuration without extending the default', async () => {
|
|
59
|
+
const fixture = await loadFixture({
|
|
60
|
+
root: new URL('./fixtures/mdx-astro-markdown-remarkRehype/', import.meta.url),
|
|
61
|
+
integrations: [
|
|
62
|
+
mdx({
|
|
63
|
+
extendPlugins: 'astroDefaults',
|
|
64
|
+
remarkRehype: {
|
|
65
|
+
footnoteLabel: 'Catatan kaki',
|
|
66
|
+
},
|
|
67
|
+
}),
|
|
68
|
+
],
|
|
69
|
+
markdown: {
|
|
70
|
+
remarkRehype: {
|
|
71
|
+
footnoteBackLabel: 'Kembali ke konten',
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
await fixture.build();
|
|
77
|
+
const html = await fixture.readFile('/index.html');
|
|
78
|
+
const { document } = parseHTML(html);
|
|
79
|
+
|
|
80
|
+
expect(document.querySelector('#footnote-label').textContent).to.equal('Catatan kaki');
|
|
81
|
+
expect(document.querySelector('.data-footnote-backref').getAttribute('aria-label')).to.equal(
|
|
82
|
+
'Back to content'
|
|
83
|
+
);
|
|
84
|
+
});
|
|
85
|
+
});
|
|
@@ -51,6 +51,41 @@ describe('MDX Component', () => {
|
|
|
51
51
|
expect(h1.textContent).to.equal('Hello component!');
|
|
52
52
|
expect(foo.textContent).to.equal('bar');
|
|
53
53
|
});
|
|
54
|
+
|
|
55
|
+
describe('with <Fragment>', () => {
|
|
56
|
+
it('supports top-level imports', async () => {
|
|
57
|
+
const html = await fixture.readFile('/w-fragment/index.html');
|
|
58
|
+
const { document } = parseHTML(html);
|
|
59
|
+
|
|
60
|
+
const h1 = document.querySelector('h1');
|
|
61
|
+
const p = document.querySelector('p');
|
|
62
|
+
|
|
63
|
+
expect(h1.textContent).to.equal('MDX containing <Fragment />');
|
|
64
|
+
expect(p.textContent).to.equal('bar');
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('supports glob imports - <Component.default />', async () => {
|
|
68
|
+
const html = await fixture.readFile('/glob/index.html');
|
|
69
|
+
const { document } = parseHTML(html);
|
|
70
|
+
|
|
71
|
+
const h = document.querySelector('[data-default-export] [data-file="WithFragment.mdx"] h1');
|
|
72
|
+
const p = document.querySelector('[data-default-export] [data-file="WithFragment.mdx"] p');
|
|
73
|
+
|
|
74
|
+
expect(h.textContent).to.equal('MDX containing <Fragment />');
|
|
75
|
+
expect(p.textContent).to.equal('bar');
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('supports glob imports - <Content />', async () => {
|
|
79
|
+
const html = await fixture.readFile('/glob/index.html');
|
|
80
|
+
const { document } = parseHTML(html);
|
|
81
|
+
|
|
82
|
+
const h = document.querySelector('[data-content-export] [data-file="WithFragment.mdx"] h1');
|
|
83
|
+
const p = document.querySelector('[data-content-export] [data-file="WithFragment.mdx"] p');
|
|
84
|
+
|
|
85
|
+
expect(h.textContent).to.equal('MDX containing <Fragment />');
|
|
86
|
+
expect(p.textContent).to.equal('bar');
|
|
87
|
+
});
|
|
88
|
+
});
|
|
54
89
|
});
|
|
55
90
|
|
|
56
91
|
describe('dev', () => {
|
|
@@ -108,5 +143,49 @@ describe('MDX Component', () => {
|
|
|
108
143
|
expect(h1.textContent).to.equal('Hello component!');
|
|
109
144
|
expect(foo.textContent).to.equal('bar');
|
|
110
145
|
});
|
|
146
|
+
|
|
147
|
+
describe('with <Fragment>', () => {
|
|
148
|
+
it('supports top-level imports', async () => {
|
|
149
|
+
const res = await fixture.fetch('/w-fragment');
|
|
150
|
+
expect(res.status).to.equal(200);
|
|
151
|
+
|
|
152
|
+
const html = await res.text();
|
|
153
|
+
const { document } = parseHTML(html);
|
|
154
|
+
|
|
155
|
+
const h1 = document.querySelector('h1');
|
|
156
|
+
const p = document.querySelector('p');
|
|
157
|
+
|
|
158
|
+
expect(h1.textContent).to.equal('MDX containing <Fragment />');
|
|
159
|
+
expect(p.textContent).to.equal('bar');
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it('supports glob imports - <Component.default />', async () => {
|
|
163
|
+
const res = await fixture.fetch('/glob');
|
|
164
|
+
expect(res.status).to.equal(200);
|
|
165
|
+
|
|
166
|
+
const html = await res.text();
|
|
167
|
+
const { document } = parseHTML(html);
|
|
168
|
+
|
|
169
|
+
const h = document.querySelector('[data-default-export] [data-file="WithFragment.mdx"] h1');
|
|
170
|
+
const p = document.querySelector('[data-default-export] [data-file="WithFragment.mdx"] p');
|
|
171
|
+
|
|
172
|
+
expect(h.textContent).to.equal('MDX containing <Fragment />');
|
|
173
|
+
expect(p.textContent).to.equal('bar');
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
it('supports glob imports - <Content />', async () => {
|
|
177
|
+
const res = await fixture.fetch('/glob');
|
|
178
|
+
expect(res.status).to.equal(200);
|
|
179
|
+
|
|
180
|
+
const html = await res.text();
|
|
181
|
+
const { document } = parseHTML(html);
|
|
182
|
+
|
|
183
|
+
const h = document.querySelector('[data-content-export] [data-file="WithFragment.mdx"] h1');
|
|
184
|
+
const p = document.querySelector('[data-content-export] [data-file="WithFragment.mdx"] p');
|
|
185
|
+
|
|
186
|
+
expect(h.textContent).to.equal('MDX containing <Fragment />');
|
|
187
|
+
expect(p.textContent).to.equal('bar');
|
|
188
|
+
});
|
|
189
|
+
});
|
|
111
190
|
});
|
|
112
191
|
});
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import mdx from '@astrojs/mdx';
|
|
2
|
+
|
|
3
|
+
import { expect } from 'chai';
|
|
4
|
+
import { parseHTML } from 'linkedom';
|
|
5
|
+
import { loadFixture } from '../../../astro/test/test-utils.js';
|
|
6
|
+
|
|
7
|
+
describe('MDX slots', () => {
|
|
8
|
+
let fixture;
|
|
9
|
+
|
|
10
|
+
before(async () => {
|
|
11
|
+
fixture = await loadFixture({
|
|
12
|
+
root: new URL('./fixtures/mdx-slots/', import.meta.url),
|
|
13
|
+
integrations: [mdx()],
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
describe('build', () => {
|
|
18
|
+
before(async () => {
|
|
19
|
+
await fixture.build();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('supports top-level imports', async () => {
|
|
23
|
+
const html = await fixture.readFile('/index.html');
|
|
24
|
+
const { document } = parseHTML(html);
|
|
25
|
+
|
|
26
|
+
const h1 = document.querySelector('h1');
|
|
27
|
+
const defaultSlot = document.querySelector('[data-default-slot]');
|
|
28
|
+
const namedSlot = document.querySelector('[data-named-slot]');
|
|
29
|
+
|
|
30
|
+
expect(h1.textContent).to.equal('Hello slotted component!');
|
|
31
|
+
expect(defaultSlot.textContent).to.equal('Default content.');
|
|
32
|
+
expect(namedSlot.textContent).to.equal('Content for named slot.');
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('supports glob imports - <Component.default />', async () => {
|
|
36
|
+
const html = await fixture.readFile('/glob/index.html');
|
|
37
|
+
const { document } = parseHTML(html);
|
|
38
|
+
|
|
39
|
+
const h1 = document.querySelector('[data-default-export] h1');
|
|
40
|
+
const defaultSlot = document.querySelector('[data-default-export] [data-default-slot]');
|
|
41
|
+
const namedSlot = document.querySelector('[data-default-export] [data-named-slot]');
|
|
42
|
+
|
|
43
|
+
expect(h1.textContent).to.equal('Hello slotted component!');
|
|
44
|
+
expect(defaultSlot.textContent).to.equal('Default content.');
|
|
45
|
+
expect(namedSlot.textContent).to.equal('Content for named slot.');
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('supports glob imports - <Content />', async () => {
|
|
49
|
+
const html = await fixture.readFile('/glob/index.html');
|
|
50
|
+
const { document } = parseHTML(html);
|
|
51
|
+
|
|
52
|
+
const h1 = document.querySelector('[data-content-export] h1');
|
|
53
|
+
const defaultSlot = document.querySelector('[data-content-export] [data-default-slot]');
|
|
54
|
+
const namedSlot = document.querySelector('[data-content-export] [data-named-slot]');
|
|
55
|
+
|
|
56
|
+
expect(h1.textContent).to.equal('Hello slotted component!');
|
|
57
|
+
expect(defaultSlot.textContent).to.equal('Default content.');
|
|
58
|
+
expect(namedSlot.textContent).to.equal('Content for named slot.');
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
describe('dev', () => {
|
|
63
|
+
let devServer;
|
|
64
|
+
|
|
65
|
+
before(async () => {
|
|
66
|
+
devServer = await fixture.startDevServer();
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
after(async () => {
|
|
70
|
+
await devServer.stop();
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('supports top-level imports', async () => {
|
|
74
|
+
const res = await fixture.fetch('/');
|
|
75
|
+
|
|
76
|
+
expect(res.status).to.equal(200);
|
|
77
|
+
|
|
78
|
+
const html = await res.text();
|
|
79
|
+
const { document } = parseHTML(html);
|
|
80
|
+
|
|
81
|
+
const h1 = document.querySelector('h1');
|
|
82
|
+
const defaultSlot = document.querySelector('[data-default-slot]');
|
|
83
|
+
const namedSlot = document.querySelector('[data-named-slot]');
|
|
84
|
+
|
|
85
|
+
expect(h1.textContent).to.equal('Hello slotted component!');
|
|
86
|
+
expect(defaultSlot.textContent).to.equal('Default content.');
|
|
87
|
+
expect(namedSlot.textContent).to.equal('Content for named slot.');
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('supports glob imports - <Component.default />', async () => {
|
|
91
|
+
const res = await fixture.fetch('/glob');
|
|
92
|
+
|
|
93
|
+
expect(res.status).to.equal(200);
|
|
94
|
+
|
|
95
|
+
const html = await res.text();
|
|
96
|
+
const { document } = parseHTML(html);
|
|
97
|
+
|
|
98
|
+
const h1 = document.querySelector('[data-default-export] h1');
|
|
99
|
+
const defaultSlot = document.querySelector('[data-default-export] [data-default-slot]');
|
|
100
|
+
const namedSlot = document.querySelector('[data-default-export] [data-named-slot]');
|
|
101
|
+
|
|
102
|
+
expect(h1.textContent).to.equal('Hello slotted component!');
|
|
103
|
+
expect(defaultSlot.textContent).to.equal('Default content.');
|
|
104
|
+
expect(namedSlot.textContent).to.equal('Content for named slot.');
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('supports glob imports - <Content />', async () => {
|
|
108
|
+
const res = await fixture.fetch('/glob');
|
|
109
|
+
|
|
110
|
+
expect(res.status).to.equal(200);
|
|
111
|
+
|
|
112
|
+
const html = await res.text();
|
|
113
|
+
const { document } = parseHTML(html);
|
|
114
|
+
|
|
115
|
+
const h1 = document.querySelector('[data-content-export] h1');
|
|
116
|
+
const defaultSlot = document.querySelector('[data-content-export] [data-default-slot]');
|
|
117
|
+
const namedSlot = document.querySelector('[data-content-export] [data-named-slot]');
|
|
118
|
+
|
|
119
|
+
expect(h1.textContent).to.equal('Hello slotted component!');
|
|
120
|
+
expect(defaultSlot.textContent).to.equal('Default content.');
|
|
121
|
+
expect(namedSlot.textContent).to.equal('Content for named slot.');
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
});
|