@astrojs/mdx 2.3.0 → 3.0.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/dist/index.js +18 -118
- package/dist/plugins.js +10 -5
- package/dist/{remark-images-to-component.d.ts → rehype-images-to-component.d.ts} +2 -1
- package/dist/rehype-images-to-component.js +135 -0
- package/dist/rehype-optimize-static.d.ts +3 -2
- package/dist/rehype-optimize-static.js +108 -17
- package/dist/utils.d.ts +1 -2
- package/dist/vite-plugin-mdx-postprocess.d.ts +3 -0
- package/dist/vite-plugin-mdx-postprocess.js +93 -0
- package/dist/vite-plugin-mdx.d.ts +3 -0
- package/dist/vite-plugin-mdx.js +78 -0
- package/package.json +16 -16
- package/dist/remark-images-to-component.js +0 -137
package/dist/index.js
CHANGED
|
@@ -1,17 +1,12 @@
|
|
|
1
1
|
import fs from "node:fs/promises";
|
|
2
2
|
import { fileURLToPath } from "node:url";
|
|
3
|
-
import { markdownConfigDefaults
|
|
3
|
+
import { markdownConfigDefaults } from "@astrojs/markdown-remark";
|
|
4
4
|
import astroJSXRenderer from "astro/jsx/renderer.js";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
ASTRO_IMAGE_ELEMENT,
|
|
10
|
-
ASTRO_IMAGE_IMPORT,
|
|
11
|
-
USES_ASTRO_IMAGE_FLAG
|
|
12
|
-
} from "./remark-images-to-component.js";
|
|
13
|
-
import { getFileInfo, ignoreStringPlugins, parseFrontmatter } from "./utils.js";
|
|
5
|
+
import { ignoreStringPlugins, parseFrontmatter } from "./utils.js";
|
|
6
|
+
import { vitePluginMdxPostprocess } from "./vite-plugin-mdx-postprocess.js";
|
|
7
|
+
import { vitePluginMdx } from "./vite-plugin-mdx.js";
|
|
14
8
|
function mdx(partialMdxOptions = {}) {
|
|
9
|
+
let mdxOptions = {};
|
|
15
10
|
return {
|
|
16
11
|
name: "@astrojs/mdx",
|
|
17
12
|
hooks: {
|
|
@@ -38,124 +33,30 @@ function mdx(partialMdxOptions = {}) {
|
|
|
38
33
|
// so wrap all MDX files with script / style propagation checks
|
|
39
34
|
handlePropagation: true
|
|
40
35
|
});
|
|
36
|
+
updateConfig({
|
|
37
|
+
vite: {
|
|
38
|
+
plugins: [vitePluginMdx(mdxOptions), vitePluginMdxPostprocess(config)]
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
},
|
|
42
|
+
"astro:config:done": ({ config }) => {
|
|
41
43
|
const extendMarkdownConfig = partialMdxOptions.extendMarkdownConfig ?? defaultMdxOptions.extendMarkdownConfig;
|
|
42
|
-
const
|
|
44
|
+
const resolvedMdxOptions = applyDefaultOptions({
|
|
43
45
|
options: partialMdxOptions,
|
|
44
46
|
defaults: markdownConfigToMdxOptions(
|
|
45
47
|
extendMarkdownConfig ? config.markdown : markdownConfigDefaults
|
|
46
48
|
)
|
|
47
49
|
});
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
vite: {
|
|
51
|
-
plugins: [
|
|
52
|
-
{
|
|
53
|
-
name: "@mdx-js/rollup",
|
|
54
|
-
enforce: "pre",
|
|
55
|
-
configResolved(resolved) {
|
|
56
|
-
processor = createMdxProcessor(mdxOptions, {
|
|
57
|
-
sourcemap: !!resolved.build.sourcemap
|
|
58
|
-
});
|
|
59
|
-
const jsxPluginIndex = resolved.plugins.findIndex((p) => p.name === "astro:jsx");
|
|
60
|
-
if (jsxPluginIndex !== -1) {
|
|
61
|
-
const myPluginIndex = resolved.plugins.findIndex(
|
|
62
|
-
(p) => p.name === "@mdx-js/rollup"
|
|
63
|
-
);
|
|
64
|
-
if (myPluginIndex !== -1) {
|
|
65
|
-
const myPlugin = resolved.plugins[myPluginIndex];
|
|
66
|
-
resolved.plugins.splice(myPluginIndex, 1);
|
|
67
|
-
resolved.plugins.splice(jsxPluginIndex, 0, myPlugin);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
},
|
|
71
|
-
// Override transform to alter code before MDX compilation
|
|
72
|
-
// ex. inject layouts
|
|
73
|
-
async transform(_, id) {
|
|
74
|
-
if (!id.endsWith(".mdx"))
|
|
75
|
-
return;
|
|
76
|
-
const { fileId } = getFileInfo(id, config);
|
|
77
|
-
const code = await fs.readFile(fileId, "utf-8");
|
|
78
|
-
const { data: frontmatter, content: pageContent } = parseFrontmatter(code, id);
|
|
79
|
-
const vfile = new VFile({ value: pageContent, path: id });
|
|
80
|
-
setVfileFrontmatter(vfile, frontmatter);
|
|
81
|
-
try {
|
|
82
|
-
const compiled = await processor.process(vfile);
|
|
83
|
-
return {
|
|
84
|
-
code: String(compiled.value),
|
|
85
|
-
map: compiled.map
|
|
86
|
-
};
|
|
87
|
-
} catch (e) {
|
|
88
|
-
const err = e;
|
|
89
|
-
err.name = "MDXError";
|
|
90
|
-
err.loc = { file: fileId, line: e.line, column: e.column };
|
|
91
|
-
Error.captureStackTrace(err);
|
|
92
|
-
throw err;
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
},
|
|
96
|
-
{
|
|
97
|
-
name: "@astrojs/mdx-postprocess",
|
|
98
|
-
// These transforms must happen *after* JSX runtime transformations
|
|
99
|
-
transform(code, id) {
|
|
100
|
-
if (!id.endsWith(".mdx"))
|
|
101
|
-
return;
|
|
102
|
-
const [moduleImports, moduleExports] = parseESM(code);
|
|
103
|
-
const importsFromJSXRuntime = moduleImports.filter(({ n }) => n === "astro/jsx-runtime").map(({ ss, se }) => code.substring(ss, se));
|
|
104
|
-
const hasFragmentImport = importsFromJSXRuntime.some(
|
|
105
|
-
(statement) => /[\s,{](?:Fragment,|Fragment\s*\})/.test(statement)
|
|
106
|
-
);
|
|
107
|
-
if (!hasFragmentImport) {
|
|
108
|
-
code = 'import { Fragment } from "astro/jsx-runtime"\n' + code;
|
|
109
|
-
}
|
|
110
|
-
const { fileUrl, fileId } = getFileInfo(id, config);
|
|
111
|
-
if (!moduleExports.find(({ n }) => n === "url")) {
|
|
112
|
-
code += `
|
|
113
|
-
export const url = ${JSON.stringify(fileUrl)};`;
|
|
114
|
-
}
|
|
115
|
-
if (!moduleExports.find(({ n }) => n === "file")) {
|
|
116
|
-
code += `
|
|
117
|
-
export const file = ${JSON.stringify(fileId)};`;
|
|
118
|
-
}
|
|
119
|
-
if (!moduleExports.find(({ n }) => n === "Content")) {
|
|
120
|
-
const hasComponents = moduleExports.find(({ n }) => n === "components");
|
|
121
|
-
const usesAstroImage = moduleExports.find(
|
|
122
|
-
({ n }) => n === USES_ASTRO_IMAGE_FLAG
|
|
123
|
-
);
|
|
124
|
-
let componentsCode = `{ Fragment${hasComponents ? ", ...components" : ""}, ...props.components,`;
|
|
125
|
-
if (usesAstroImage) {
|
|
126
|
-
componentsCode += ` ${JSON.stringify(ASTRO_IMAGE_ELEMENT)}: ${hasComponents ? "components.img ?? " : ""} props.components?.img ?? ${ASTRO_IMAGE_IMPORT}`;
|
|
127
|
-
}
|
|
128
|
-
componentsCode += " }";
|
|
129
|
-
code = code.replace(
|
|
130
|
-
"export default function MDXContent",
|
|
131
|
-
"function MDXContent"
|
|
132
|
-
);
|
|
133
|
-
code += `
|
|
134
|
-
export const Content = (props = {}) => MDXContent({
|
|
135
|
-
...props,
|
|
136
|
-
components: ${componentsCode},
|
|
137
|
-
});
|
|
138
|
-
export default Content;`;
|
|
139
|
-
}
|
|
140
|
-
code += `
|
|
141
|
-
Content[Symbol.for('mdx-component')] = true`;
|
|
142
|
-
code += `
|
|
143
|
-
Content[Symbol.for('astro.needsHeadRendering')] = !Boolean(frontmatter.layout);`;
|
|
144
|
-
code += `
|
|
145
|
-
Content.moduleId = ${JSON.stringify(id)};`;
|
|
146
|
-
return { code, map: null };
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
]
|
|
150
|
-
}
|
|
151
|
-
});
|
|
50
|
+
Object.assign(mdxOptions, resolvedMdxOptions);
|
|
51
|
+
mdxOptions = {};
|
|
152
52
|
}
|
|
153
53
|
}
|
|
154
54
|
};
|
|
155
55
|
}
|
|
156
56
|
const defaultMdxOptions = {
|
|
157
57
|
extendMarkdownConfig: true,
|
|
158
|
-
recmaPlugins: []
|
|
58
|
+
recmaPlugins: [],
|
|
59
|
+
optimize: false
|
|
159
60
|
};
|
|
160
61
|
function markdownConfigToMdxOptions(markdownConfig) {
|
|
161
62
|
return {
|
|
@@ -163,8 +64,7 @@ function markdownConfigToMdxOptions(markdownConfig) {
|
|
|
163
64
|
...markdownConfig,
|
|
164
65
|
remarkPlugins: ignoreStringPlugins(markdownConfig.remarkPlugins),
|
|
165
66
|
rehypePlugins: ignoreStringPlugins(markdownConfig.rehypePlugins),
|
|
166
|
-
remarkRehype: markdownConfig.remarkRehype ?? {}
|
|
167
|
-
optimize: false
|
|
67
|
+
remarkRehype: markdownConfig.remarkRehype ?? {}
|
|
168
68
|
};
|
|
169
69
|
}
|
|
170
70
|
function applyDefaultOptions({
|
package/dist/plugins.js
CHANGED
|
@@ -5,15 +5,16 @@ import {
|
|
|
5
5
|
remarkCollectImages
|
|
6
6
|
} from "@astrojs/markdown-remark";
|
|
7
7
|
import { createProcessor, nodeTypes } from "@mdx-js/mdx";
|
|
8
|
+
import { rehypeAnalyzeAstroMetadata } from "astro/jsx/rehype.js";
|
|
8
9
|
import rehypeRaw from "rehype-raw";
|
|
9
10
|
import remarkGfm from "remark-gfm";
|
|
10
11
|
import remarkSmartypants from "remark-smartypants";
|
|
11
12
|
import { SourceMapGenerator } from "source-map";
|
|
12
13
|
import { rehypeApplyFrontmatterExport } from "./rehype-apply-frontmatter-export.js";
|
|
13
14
|
import { rehypeInjectHeadingsExport } from "./rehype-collect-headings.js";
|
|
15
|
+
import { rehypeImageToComponent } from "./rehype-images-to-component.js";
|
|
14
16
|
import rehypeMetaString from "./rehype-meta-string.js";
|
|
15
17
|
import { rehypeOptimizeStatic } from "./rehype-optimize-static.js";
|
|
16
|
-
import { remarkImageToComponent } from "./remark-images-to-component.js";
|
|
17
18
|
const isPerformanceBenchmark = Boolean(process.env.ASTRO_PERFORMANCE_BENCHMARK);
|
|
18
19
|
function createMdxProcessor(mdxOptions, extraOptions) {
|
|
19
20
|
return createProcessor({
|
|
@@ -21,7 +22,6 @@ function createMdxProcessor(mdxOptions, extraOptions) {
|
|
|
21
22
|
rehypePlugins: getRehypePlugins(mdxOptions),
|
|
22
23
|
recmaPlugins: mdxOptions.recmaPlugins,
|
|
23
24
|
remarkRehypeOptions: mdxOptions.remarkRehype,
|
|
24
|
-
jsx: true,
|
|
25
25
|
jsxImportSource: "astro",
|
|
26
26
|
// Note: disable `.md` (and other alternative extensions for markdown files like `.markdown`) support
|
|
27
27
|
format: "mdx",
|
|
@@ -40,7 +40,7 @@ function getRemarkPlugins(mdxOptions) {
|
|
|
40
40
|
remarkPlugins.push(remarkSmartypants);
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
|
-
remarkPlugins.push(...mdxOptions.remarkPlugins, remarkCollectImages
|
|
43
|
+
remarkPlugins.push(...mdxOptions.remarkPlugins, remarkCollectImages);
|
|
44
44
|
return remarkPlugins;
|
|
45
45
|
}
|
|
46
46
|
function getRehypePlugins(mdxOptions) {
|
|
@@ -57,11 +57,16 @@ function getRehypePlugins(mdxOptions) {
|
|
|
57
57
|
rehypePlugins.push(rehypePrism);
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
|
-
rehypePlugins.push(...mdxOptions.rehypePlugins);
|
|
60
|
+
rehypePlugins.push(...mdxOptions.rehypePlugins, rehypeImageToComponent);
|
|
61
61
|
if (!isPerformanceBenchmark) {
|
|
62
62
|
rehypePlugins.push(rehypeHeadingIds, rehypeInjectHeadingsExport);
|
|
63
63
|
}
|
|
64
|
-
rehypePlugins.push(
|
|
64
|
+
rehypePlugins.push(
|
|
65
|
+
// Render info from `vfile.data.astro.data.frontmatter` as JS
|
|
66
|
+
rehypeApplyFrontmatterExport,
|
|
67
|
+
// Analyze MDX nodes and attach to `vfile.data.__astroMetadata`
|
|
68
|
+
rehypeAnalyzeAstroMetadata
|
|
69
|
+
);
|
|
65
70
|
if (mdxOptions.optimize) {
|
|
66
71
|
const options = mdxOptions.optimize === true ? void 0 : mdxOptions.optimize;
|
|
67
72
|
rehypePlugins.push([rehypeOptimizeStatic, options]);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { MarkdownVFile } from '@astrojs/markdown-remark';
|
|
2
|
+
import type { Root } from 'hast';
|
|
2
3
|
export declare const ASTRO_IMAGE_ELEMENT = "astro-image";
|
|
3
4
|
export declare const ASTRO_IMAGE_IMPORT = "__AstroImage__";
|
|
4
5
|
export declare const USES_ASTRO_IMAGE_FLAG = "__usesAstroImage";
|
|
5
|
-
export declare function
|
|
6
|
+
export declare function rehypeImageToComponent(): (tree: Root, file: MarkdownVFile) => void;
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { visit } from "unist-util-visit";
|
|
2
|
+
import { jsToTreeNode } from "./utils.js";
|
|
3
|
+
const ASTRO_IMAGE_ELEMENT = "astro-image";
|
|
4
|
+
const ASTRO_IMAGE_IMPORT = "__AstroImage__";
|
|
5
|
+
const USES_ASTRO_IMAGE_FLAG = "__usesAstroImage";
|
|
6
|
+
function createArrayAttribute(name, values) {
|
|
7
|
+
return {
|
|
8
|
+
type: "mdxJsxAttribute",
|
|
9
|
+
name,
|
|
10
|
+
value: {
|
|
11
|
+
type: "mdxJsxAttributeValueExpression",
|
|
12
|
+
value: name,
|
|
13
|
+
data: {
|
|
14
|
+
estree: {
|
|
15
|
+
type: "Program",
|
|
16
|
+
body: [
|
|
17
|
+
{
|
|
18
|
+
type: "ExpressionStatement",
|
|
19
|
+
expression: {
|
|
20
|
+
type: "ArrayExpression",
|
|
21
|
+
elements: values.map((value) => ({
|
|
22
|
+
type: "Literal",
|
|
23
|
+
value,
|
|
24
|
+
raw: String(value)
|
|
25
|
+
}))
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
],
|
|
29
|
+
sourceType: "module",
|
|
30
|
+
comments: []
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
function getImageComponentAttributes(props) {
|
|
37
|
+
const attrs = [];
|
|
38
|
+
for (const [prop, value] of Object.entries(props)) {
|
|
39
|
+
if (prop === "src") continue;
|
|
40
|
+
if (prop === "widths" || prop === "densities") {
|
|
41
|
+
attrs.push(createArrayAttribute(prop, String(value).split(" ")));
|
|
42
|
+
} else {
|
|
43
|
+
attrs.push({
|
|
44
|
+
name: prop,
|
|
45
|
+
type: "mdxJsxAttribute",
|
|
46
|
+
value: String(value)
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return attrs;
|
|
51
|
+
}
|
|
52
|
+
function rehypeImageToComponent() {
|
|
53
|
+
return function(tree, file) {
|
|
54
|
+
if (!file.data.imagePaths) return;
|
|
55
|
+
const importsStatements = [];
|
|
56
|
+
const importedImages = /* @__PURE__ */ new Map();
|
|
57
|
+
visit(tree, "element", (node, index, parent) => {
|
|
58
|
+
if (!file.data.imagePaths || node.tagName !== "img" || !node.properties.src) return;
|
|
59
|
+
const src = decodeURI(String(node.properties.src));
|
|
60
|
+
if (!file.data.imagePaths.has(src)) return;
|
|
61
|
+
let importName = importedImages.get(src);
|
|
62
|
+
if (!importName) {
|
|
63
|
+
importName = `__${importedImages.size}_${src.replace(/\W/g, "_")}__`;
|
|
64
|
+
importsStatements.push({
|
|
65
|
+
type: "mdxjsEsm",
|
|
66
|
+
value: "",
|
|
67
|
+
data: {
|
|
68
|
+
estree: {
|
|
69
|
+
type: "Program",
|
|
70
|
+
sourceType: "module",
|
|
71
|
+
body: [
|
|
72
|
+
{
|
|
73
|
+
type: "ImportDeclaration",
|
|
74
|
+
source: {
|
|
75
|
+
type: "Literal",
|
|
76
|
+
value: src,
|
|
77
|
+
raw: JSON.stringify(src)
|
|
78
|
+
},
|
|
79
|
+
specifiers: [
|
|
80
|
+
{
|
|
81
|
+
type: "ImportDefaultSpecifier",
|
|
82
|
+
local: { type: "Identifier", name: importName }
|
|
83
|
+
}
|
|
84
|
+
]
|
|
85
|
+
}
|
|
86
|
+
]
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
importedImages.set(src, importName);
|
|
91
|
+
}
|
|
92
|
+
const componentElement = {
|
|
93
|
+
name: ASTRO_IMAGE_ELEMENT,
|
|
94
|
+
type: "mdxJsxFlowElement",
|
|
95
|
+
attributes: [
|
|
96
|
+
...getImageComponentAttributes(node.properties),
|
|
97
|
+
{
|
|
98
|
+
name: "src",
|
|
99
|
+
type: "mdxJsxAttribute",
|
|
100
|
+
value: {
|
|
101
|
+
type: "mdxJsxAttributeValueExpression",
|
|
102
|
+
value: importName,
|
|
103
|
+
data: {
|
|
104
|
+
estree: {
|
|
105
|
+
type: "Program",
|
|
106
|
+
sourceType: "module",
|
|
107
|
+
comments: [],
|
|
108
|
+
body: [
|
|
109
|
+
{
|
|
110
|
+
type: "ExpressionStatement",
|
|
111
|
+
expression: { type: "Identifier", name: importName }
|
|
112
|
+
}
|
|
113
|
+
]
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
],
|
|
119
|
+
children: []
|
|
120
|
+
};
|
|
121
|
+
parent.children.splice(index, 1, componentElement);
|
|
122
|
+
});
|
|
123
|
+
tree.children.unshift(...importsStatements);
|
|
124
|
+
tree.children.unshift(
|
|
125
|
+
jsToTreeNode(`import { Image as ${ASTRO_IMAGE_IMPORT} } from "astro:assets";`)
|
|
126
|
+
);
|
|
127
|
+
tree.children.push(jsToTreeNode(`export const ${USES_ASTRO_IMAGE_FLAG} = true`));
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
export {
|
|
131
|
+
ASTRO_IMAGE_ELEMENT,
|
|
132
|
+
ASTRO_IMAGE_IMPORT,
|
|
133
|
+
USES_ASTRO_IMAGE_FLAG,
|
|
134
|
+
rehypeImageToComponent
|
|
135
|
+
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import type { RehypePlugin } from '@astrojs/markdown-remark';
|
|
1
2
|
export interface OptimizeOptions {
|
|
2
|
-
|
|
3
|
+
ignoreElementNames?: string[];
|
|
3
4
|
}
|
|
4
5
|
/**
|
|
5
6
|
* For MDX only, collapse static subtrees of the hast into `set:html`. Subtrees
|
|
@@ -8,4 +9,4 @@ export interface OptimizeOptions {
|
|
|
8
9
|
* This optimization reduces the JS output as more content are represented as a
|
|
9
10
|
* string instead, which also reduces the AST size that Rollup holds in memory.
|
|
10
11
|
*/
|
|
11
|
-
export declare
|
|
12
|
+
export declare const rehypeOptimizeStatic: RehypePlugin<[OptimizeOptions?]>;
|
|
@@ -1,40 +1,49 @@
|
|
|
1
|
-
import { visit } from "estree-util-visit";
|
|
1
|
+
import { SKIP, visit } from "estree-util-visit";
|
|
2
2
|
import { toHtml } from "hast-util-to-html";
|
|
3
3
|
const exportConstComponentsRe = /export\s+const\s+components\s*=/;
|
|
4
|
-
|
|
4
|
+
const rehypeOptimizeStatic = (options) => {
|
|
5
5
|
return (tree) => {
|
|
6
|
-
const
|
|
6
|
+
const ignoreElementNames = new Set(options?.ignoreElementNames);
|
|
7
7
|
for (const child of tree.children) {
|
|
8
8
|
if (child.type === "mdxjsEsm" && exportConstComponentsRe.test(child.value)) {
|
|
9
|
-
const
|
|
10
|
-
if (
|
|
11
|
-
for (const
|
|
12
|
-
|
|
13
|
-
if (componentName) {
|
|
14
|
-
customComponentNames.add(componentName);
|
|
15
|
-
}
|
|
9
|
+
const keys = getExportConstComponentObjectKeys(child);
|
|
10
|
+
if (keys) {
|
|
11
|
+
for (const key of keys) {
|
|
12
|
+
ignoreElementNames.add(key);
|
|
16
13
|
}
|
|
17
14
|
}
|
|
15
|
+
break;
|
|
18
16
|
}
|
|
19
17
|
}
|
|
20
18
|
const allPossibleElements = /* @__PURE__ */ new Set();
|
|
21
19
|
const elementStack = [];
|
|
20
|
+
const elementMetadatas = /* @__PURE__ */ new WeakMap();
|
|
21
|
+
const isNodeNonStatic = (node) => {
|
|
22
|
+
return node.type.startsWith("mdx") || ignoreElementNames.has(node.tagName);
|
|
23
|
+
};
|
|
22
24
|
visit(tree, {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
if (
|
|
25
|
+
// @ts-expect-error Force coerce node as hast node
|
|
26
|
+
enter(node, key, index, parents) {
|
|
27
|
+
if (key != null && key !== "children") return SKIP;
|
|
28
|
+
simplifyPlainMdxComponentNode(node, ignoreElementNames);
|
|
29
|
+
if (isNodeNonStatic(node)) {
|
|
26
30
|
for (const el of elementStack) {
|
|
27
31
|
allPossibleElements.delete(el);
|
|
28
32
|
}
|
|
29
33
|
elementStack.length = 0;
|
|
30
34
|
}
|
|
31
|
-
if (node.type === "element" || node
|
|
35
|
+
if (node.type === "element" || isMdxComponentNode(node)) {
|
|
32
36
|
elementStack.push(node);
|
|
33
37
|
allPossibleElements.add(node);
|
|
38
|
+
if (index != null && node.type === "element") {
|
|
39
|
+
elementMetadatas.set(node, { parent: parents[parents.length - 1], index });
|
|
40
|
+
}
|
|
34
41
|
}
|
|
35
42
|
},
|
|
36
|
-
|
|
37
|
-
|
|
43
|
+
// @ts-expect-error Force coerce node as hast node
|
|
44
|
+
leave(node, key, _, parents) {
|
|
45
|
+
if (key != null && key !== "children") return SKIP;
|
|
46
|
+
if (node.type === "element" || isMdxComponentNode(node)) {
|
|
38
47
|
elementStack.pop();
|
|
39
48
|
const parent = parents[parents.length - 1];
|
|
40
49
|
if (allPossibleElements.has(parent)) {
|
|
@@ -43,8 +52,10 @@ function rehypeOptimizeStatic(options) {
|
|
|
43
52
|
}
|
|
44
53
|
}
|
|
45
54
|
});
|
|
55
|
+
const elementGroups = findElementGroups(allPossibleElements, elementMetadatas, isNodeNonStatic);
|
|
46
56
|
for (const el of allPossibleElements) {
|
|
47
|
-
if (el.
|
|
57
|
+
if (el.children.length === 0) continue;
|
|
58
|
+
if (isMdxComponentNode(el)) {
|
|
48
59
|
el.attributes.push({
|
|
49
60
|
type: "mdxJsxAttribute",
|
|
50
61
|
name: "set:html",
|
|
@@ -55,7 +66,87 @@ function rehypeOptimizeStatic(options) {
|
|
|
55
66
|
}
|
|
56
67
|
el.children = [];
|
|
57
68
|
}
|
|
69
|
+
for (let i = elementGroups.length - 1; i >= 0; i--) {
|
|
70
|
+
const group = elementGroups[i];
|
|
71
|
+
const fragmentNode = {
|
|
72
|
+
type: "mdxJsxFlowElement",
|
|
73
|
+
name: "Fragment",
|
|
74
|
+
attributes: [
|
|
75
|
+
{
|
|
76
|
+
type: "mdxJsxAttribute",
|
|
77
|
+
name: "set:html",
|
|
78
|
+
value: toHtml(group.children)
|
|
79
|
+
}
|
|
80
|
+
],
|
|
81
|
+
children: []
|
|
82
|
+
};
|
|
83
|
+
group.parent.children.splice(group.startIndex, group.children.length, fragmentNode);
|
|
84
|
+
}
|
|
58
85
|
};
|
|
86
|
+
};
|
|
87
|
+
function findElementGroups(allPossibleElements, elementMetadatas, isNodeNonStatic) {
|
|
88
|
+
const elementGroups = [];
|
|
89
|
+
for (const el of allPossibleElements) {
|
|
90
|
+
if (isNodeNonStatic(el)) continue;
|
|
91
|
+
const metadata = elementMetadatas.get(el);
|
|
92
|
+
if (!metadata) {
|
|
93
|
+
throw new Error(
|
|
94
|
+
"Internal MDX error: rehype-optimize-static should have metadata for element node"
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
const groupableElements = [el];
|
|
98
|
+
for (let i = metadata.index + 1; i < metadata.parent.children.length; i++) {
|
|
99
|
+
const node = metadata.parent.children[i];
|
|
100
|
+
if (isNodeNonStatic(node)) break;
|
|
101
|
+
if (node.type === "element") {
|
|
102
|
+
const existed = allPossibleElements.delete(node);
|
|
103
|
+
if (!existed) break;
|
|
104
|
+
}
|
|
105
|
+
groupableElements.push(node);
|
|
106
|
+
}
|
|
107
|
+
if (groupableElements.length > 1) {
|
|
108
|
+
elementGroups.push({
|
|
109
|
+
parent: metadata.parent,
|
|
110
|
+
startIndex: metadata.index,
|
|
111
|
+
children: groupableElements
|
|
112
|
+
});
|
|
113
|
+
allPossibleElements.delete(el);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return elementGroups;
|
|
117
|
+
}
|
|
118
|
+
function isMdxComponentNode(node) {
|
|
119
|
+
return node.type === "mdxJsxFlowElement" || node.type === "mdxJsxTextElement";
|
|
120
|
+
}
|
|
121
|
+
function getExportConstComponentObjectKeys(node) {
|
|
122
|
+
const exportNamedDeclaration = node.data?.estree?.body[0];
|
|
123
|
+
if (exportNamedDeclaration?.type !== "ExportNamedDeclaration") return;
|
|
124
|
+
const variableDeclaration = exportNamedDeclaration.declaration;
|
|
125
|
+
if (variableDeclaration?.type !== "VariableDeclaration") return;
|
|
126
|
+
const variableInit = variableDeclaration.declarations[0]?.init;
|
|
127
|
+
if (variableInit?.type !== "ObjectExpression") return;
|
|
128
|
+
const keys = [];
|
|
129
|
+
for (const propertyNode of variableInit.properties) {
|
|
130
|
+
if (propertyNode.type === "Property" && propertyNode.key.type === "Identifier") {
|
|
131
|
+
keys.push(propertyNode.key.name);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return keys;
|
|
135
|
+
}
|
|
136
|
+
function simplifyPlainMdxComponentNode(node, ignoreElementNames) {
|
|
137
|
+
if (!isMdxComponentNode(node) || // Attributes could be dynamic, so bail if so.
|
|
138
|
+
node.attributes.length > 0 || // Fragments are also dynamic
|
|
139
|
+
!node.name || // Ignore if the node name is in the ignore list
|
|
140
|
+
ignoreElementNames.has(node.name) || // If the node name has uppercase characters, it's likely an actual MDX component
|
|
141
|
+
node.name.toLowerCase() !== node.name) {
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
const newNode = node;
|
|
145
|
+
newNode.type = "element";
|
|
146
|
+
newNode.tagName = node.name;
|
|
147
|
+
newNode.properties = {};
|
|
148
|
+
node.attributes = void 0;
|
|
149
|
+
node.data = void 0;
|
|
59
150
|
}
|
|
60
151
|
export {
|
|
61
152
|
rehypeOptimizeStatic
|
package/dist/utils.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { AstroConfig } from 'astro';
|
|
|
3
3
|
import matter from 'gray-matter';
|
|
4
4
|
import type { MdxjsEsm } from 'mdast-util-mdx';
|
|
5
5
|
import type { PluggableList } from 'unified';
|
|
6
|
-
interface FileInfo {
|
|
6
|
+
export interface FileInfo {
|
|
7
7
|
fileId: string;
|
|
8
8
|
fileUrl: string;
|
|
9
9
|
}
|
|
@@ -16,4 +16,3 @@ export declare function getFileInfo(id: string, config: AstroConfig): FileInfo;
|
|
|
16
16
|
export declare function parseFrontmatter(code: string, id: string): matter.GrayMatterFile<string>;
|
|
17
17
|
export declare function jsToTreeNode(jsString: string, acornOpts?: AcornOpts): MdxjsEsm;
|
|
18
18
|
export declare function ignoreStringPlugins(plugins: any[]): PluggableList;
|
|
19
|
-
export {};
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { parse } from "es-module-lexer";
|
|
2
|
+
import {
|
|
3
|
+
ASTRO_IMAGE_ELEMENT,
|
|
4
|
+
ASTRO_IMAGE_IMPORT,
|
|
5
|
+
USES_ASTRO_IMAGE_FLAG
|
|
6
|
+
} from "./rehype-images-to-component.js";
|
|
7
|
+
import { getFileInfo } from "./utils.js";
|
|
8
|
+
const underscoreFragmentImportRegex = /[\s,{]_Fragment[\s,}]/;
|
|
9
|
+
const astroTagComponentImportRegex = /[\s,{]__astro_tag_component__[\s,}]/;
|
|
10
|
+
function vitePluginMdxPostprocess(astroConfig) {
|
|
11
|
+
return {
|
|
12
|
+
name: "@astrojs/mdx-postprocess",
|
|
13
|
+
transform(code, id, opts) {
|
|
14
|
+
if (!id.endsWith(".mdx")) return;
|
|
15
|
+
const fileInfo = getFileInfo(id, astroConfig);
|
|
16
|
+
const [imports, exports] = parse(code);
|
|
17
|
+
code = injectUnderscoreFragmentImport(code, imports);
|
|
18
|
+
code = injectMetadataExports(code, exports, fileInfo);
|
|
19
|
+
code = transformContentExport(code, exports);
|
|
20
|
+
code = annotateContentExport(code, id, !!opts?.ssr, imports);
|
|
21
|
+
return { code, map: null };
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
function injectUnderscoreFragmentImport(code, imports) {
|
|
26
|
+
if (!isSpecifierImported(code, imports, underscoreFragmentImportRegex, "astro/jsx-runtime")) {
|
|
27
|
+
code += `
|
|
28
|
+
import { Fragment as _Fragment } from 'astro/jsx-runtime';`;
|
|
29
|
+
}
|
|
30
|
+
return code;
|
|
31
|
+
}
|
|
32
|
+
function injectMetadataExports(code, exports, fileInfo) {
|
|
33
|
+
if (!exports.some(({ n }) => n === "url")) {
|
|
34
|
+
code += `
|
|
35
|
+
export const url = ${JSON.stringify(fileInfo.fileUrl)};`;
|
|
36
|
+
}
|
|
37
|
+
if (!exports.some(({ n }) => n === "file")) {
|
|
38
|
+
code += `
|
|
39
|
+
export const file = ${JSON.stringify(fileInfo.fileId)};`;
|
|
40
|
+
}
|
|
41
|
+
return code;
|
|
42
|
+
}
|
|
43
|
+
function transformContentExport(code, exports) {
|
|
44
|
+
if (exports.find(({ n }) => n === "Content")) return code;
|
|
45
|
+
const hasComponents = exports.find(({ n }) => n === "components");
|
|
46
|
+
const usesAstroImage = exports.find(({ n }) => n === USES_ASTRO_IMAGE_FLAG);
|
|
47
|
+
let componentsCode = `{ Fragment: _Fragment${hasComponents ? ", ...components" : ""}, ...props.components,`;
|
|
48
|
+
if (usesAstroImage) {
|
|
49
|
+
componentsCode += ` ${JSON.stringify(ASTRO_IMAGE_ELEMENT)}: ${hasComponents ? "components.img ?? " : ""} props.components?.img ?? ${ASTRO_IMAGE_IMPORT}`;
|
|
50
|
+
}
|
|
51
|
+
componentsCode += " }";
|
|
52
|
+
code = code.replace("export default function MDXContent", "function MDXContent");
|
|
53
|
+
code += `
|
|
54
|
+
export const Content = (props = {}) => MDXContent({
|
|
55
|
+
...props,
|
|
56
|
+
components: ${componentsCode},
|
|
57
|
+
});
|
|
58
|
+
export default Content;`;
|
|
59
|
+
return code;
|
|
60
|
+
}
|
|
61
|
+
function annotateContentExport(code, id, ssr, imports) {
|
|
62
|
+
code += `
|
|
63
|
+
Content[Symbol.for('mdx-component')] = true`;
|
|
64
|
+
code += `
|
|
65
|
+
Content[Symbol.for('astro.needsHeadRendering')] = !Boolean(frontmatter.layout);`;
|
|
66
|
+
code += `
|
|
67
|
+
Content.moduleId = ${JSON.stringify(id)};`;
|
|
68
|
+
if (ssr) {
|
|
69
|
+
if (!isSpecifierImported(
|
|
70
|
+
code,
|
|
71
|
+
imports,
|
|
72
|
+
astroTagComponentImportRegex,
|
|
73
|
+
"astro/runtime/server/index.js"
|
|
74
|
+
)) {
|
|
75
|
+
code += `
|
|
76
|
+
import { __astro_tag_component__ } from 'astro/runtime/server/index.js';`;
|
|
77
|
+
}
|
|
78
|
+
code += `
|
|
79
|
+
__astro_tag_component__(Content, 'astro:jsx');`;
|
|
80
|
+
}
|
|
81
|
+
return code;
|
|
82
|
+
}
|
|
83
|
+
function isSpecifierImported(code, imports, specifierRegex, source) {
|
|
84
|
+
for (const imp of imports) {
|
|
85
|
+
if (imp.n !== source) continue;
|
|
86
|
+
const importStatement = code.slice(imp.ss, imp.se);
|
|
87
|
+
if (specifierRegex.test(importStatement)) return true;
|
|
88
|
+
}
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
export {
|
|
92
|
+
vitePluginMdxPostprocess
|
|
93
|
+
};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { setVfileFrontmatter } from "@astrojs/markdown-remark";
|
|
2
|
+
import { getAstroMetadata } from "astro/jsx/rehype.js";
|
|
3
|
+
import { VFile } from "vfile";
|
|
4
|
+
import { createMdxProcessor } from "./plugins.js";
|
|
5
|
+
import { parseFrontmatter } from "./utils.js";
|
|
6
|
+
function vitePluginMdx(mdxOptions) {
|
|
7
|
+
let processor;
|
|
8
|
+
return {
|
|
9
|
+
name: "@mdx-js/rollup",
|
|
10
|
+
enforce: "pre",
|
|
11
|
+
buildEnd() {
|
|
12
|
+
processor = void 0;
|
|
13
|
+
},
|
|
14
|
+
configResolved(resolved) {
|
|
15
|
+
if (Object.keys(mdxOptions).length === 0) return;
|
|
16
|
+
processor = createMdxProcessor(mdxOptions, {
|
|
17
|
+
sourcemap: !!resolved.build.sourcemap
|
|
18
|
+
});
|
|
19
|
+
const jsxPluginIndex = resolved.plugins.findIndex((p) => p.name === "astro:jsx");
|
|
20
|
+
if (jsxPluginIndex !== -1) {
|
|
21
|
+
resolved.plugins.splice(jsxPluginIndex, 1);
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
async resolveId(source, importer, options) {
|
|
25
|
+
if (importer?.endsWith(".mdx") && source[0] !== "/") {
|
|
26
|
+
let resolved = await this.resolve(source, importer, options);
|
|
27
|
+
if (!resolved) resolved = await this.resolve("./" + source, importer, options);
|
|
28
|
+
return resolved;
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
// Override transform to alter code before MDX compilation
|
|
32
|
+
// ex. inject layouts
|
|
33
|
+
async transform(code, id) {
|
|
34
|
+
if (!id.endsWith(".mdx")) return;
|
|
35
|
+
const { data: frontmatter, content: pageContent } = parseFrontmatter(code, id);
|
|
36
|
+
const vfile = new VFile({ value: pageContent, path: id });
|
|
37
|
+
setVfileFrontmatter(vfile, frontmatter);
|
|
38
|
+
if (!processor) {
|
|
39
|
+
return this.error(
|
|
40
|
+
"MDX processor is not initialized. This is an internal error. Please file an issue."
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
try {
|
|
44
|
+
const compiled = await processor.process(vfile);
|
|
45
|
+
return {
|
|
46
|
+
code: String(compiled.value),
|
|
47
|
+
map: compiled.map,
|
|
48
|
+
meta: getMdxMeta(vfile)
|
|
49
|
+
};
|
|
50
|
+
} catch (e) {
|
|
51
|
+
const err = e;
|
|
52
|
+
err.name = "MDXError";
|
|
53
|
+
err.loc = { file: id, line: e.line, column: e.column };
|
|
54
|
+
Error.captureStackTrace(err);
|
|
55
|
+
throw err;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function getMdxMeta(vfile) {
|
|
61
|
+
const astroMetadata = getAstroMetadata(vfile);
|
|
62
|
+
if (!astroMetadata) {
|
|
63
|
+
throw new Error(
|
|
64
|
+
"Internal MDX error: Astro metadata is not set by rehype-analyze-astro-metadata"
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
astro: astroMetadata,
|
|
69
|
+
vite: {
|
|
70
|
+
// Setting this vite metadata to `ts` causes Vite to resolve .js
|
|
71
|
+
// extensions to .ts files.
|
|
72
|
+
lang: "ts"
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
export {
|
|
77
|
+
vitePluginMdx
|
|
78
|
+
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astrojs/mdx",
|
|
3
3
|
"description": "Add support for MDX pages in your Astro site",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "3.0.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
7
7
|
"author": "withastro",
|
|
@@ -27,45 +27,45 @@
|
|
|
27
27
|
"template"
|
|
28
28
|
],
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@mdx-js/mdx": "^3.0.
|
|
31
|
-
"acorn": "^8.11.
|
|
32
|
-
"es-module-lexer": "^1.
|
|
30
|
+
"@mdx-js/mdx": "^3.0.1",
|
|
31
|
+
"acorn": "^8.11.3",
|
|
32
|
+
"es-module-lexer": "^1.5.2",
|
|
33
33
|
"estree-util-visit": "^2.0.0",
|
|
34
34
|
"github-slugger": "^2.0.0",
|
|
35
35
|
"gray-matter": "^4.0.3",
|
|
36
|
-
"hast-util-to-html": "^9.0.
|
|
37
|
-
"kleur": "^4.1.
|
|
36
|
+
"hast-util-to-html": "^9.0.1",
|
|
37
|
+
"kleur": "^4.1.5",
|
|
38
38
|
"rehype-raw": "^7.0.0",
|
|
39
39
|
"remark-gfm": "^4.0.0",
|
|
40
|
-
"remark-smartypants": "^
|
|
40
|
+
"remark-smartypants": "^3.0.1",
|
|
41
41
|
"source-map": "^0.7.4",
|
|
42
42
|
"unist-util-visit": "^5.0.0",
|
|
43
43
|
"vfile": "^6.0.1",
|
|
44
44
|
"@astrojs/markdown-remark": "5.1.0"
|
|
45
45
|
},
|
|
46
46
|
"peerDependencies": {
|
|
47
|
-
"astro": "^4.
|
|
47
|
+
"astro": "^4.8.0"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
|
-
"@types/chai": "^4.3.10",
|
|
51
50
|
"@types/estree": "^1.0.5",
|
|
51
|
+
"@types/hast": "^3.0.4",
|
|
52
52
|
"@types/mdast": "^4.0.3",
|
|
53
|
-
"@types/mocha": "^10.0.4",
|
|
54
53
|
"@types/yargs-parser": "^21.0.3",
|
|
55
54
|
"cheerio": "1.0.0-rc.12",
|
|
56
|
-
"linkedom": "^0.16.
|
|
55
|
+
"linkedom": "^0.16.11",
|
|
57
56
|
"mdast-util-mdx": "^3.0.0",
|
|
57
|
+
"mdast-util-mdx-jsx": "^3.1.2",
|
|
58
58
|
"mdast-util-to-string": "^4.0.0",
|
|
59
59
|
"reading-time": "^1.5.0",
|
|
60
|
-
"rehype-mathjax": "^
|
|
61
|
-
"rehype-pretty-code": "^0.13.
|
|
60
|
+
"rehype-mathjax": "^6.0.0",
|
|
61
|
+
"rehype-pretty-code": "^0.13.1",
|
|
62
62
|
"remark-math": "^6.0.0",
|
|
63
|
-
"remark-rehype": "^11.
|
|
63
|
+
"remark-rehype": "^11.1.0",
|
|
64
64
|
"remark-shiki-twoslash": "^3.1.3",
|
|
65
65
|
"remark-toc": "^9.0.0",
|
|
66
66
|
"unified": "^11.0.4",
|
|
67
|
-
"vite": "^5.
|
|
68
|
-
"astro": "4.
|
|
67
|
+
"vite": "^5.2.11",
|
|
68
|
+
"astro": "4.8.0",
|
|
69
69
|
"astro-scripts": "0.0.14"
|
|
70
70
|
},
|
|
71
71
|
"engines": {
|
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
import { visit } from "unist-util-visit";
|
|
2
|
-
import { jsToTreeNode } from "./utils.js";
|
|
3
|
-
const ASTRO_IMAGE_ELEMENT = "astro-image";
|
|
4
|
-
const ASTRO_IMAGE_IMPORT = "__AstroImage__";
|
|
5
|
-
const USES_ASTRO_IMAGE_FLAG = "__usesAstroImage";
|
|
6
|
-
function remarkImageToComponent() {
|
|
7
|
-
return function(tree, file) {
|
|
8
|
-
if (!file.data.imagePaths)
|
|
9
|
-
return;
|
|
10
|
-
const importsStatements = [];
|
|
11
|
-
const importedImages = /* @__PURE__ */ new Map();
|
|
12
|
-
visit(tree, "image", (node, index, parent) => {
|
|
13
|
-
if (file.data.imagePaths?.has(node.url)) {
|
|
14
|
-
let importName = importedImages.get(node.url);
|
|
15
|
-
if (!importName) {
|
|
16
|
-
importName = `__${importedImages.size}_${node.url.replace(/\W/g, "_")}__`;
|
|
17
|
-
importsStatements.push({
|
|
18
|
-
type: "mdxjsEsm",
|
|
19
|
-
value: "",
|
|
20
|
-
data: {
|
|
21
|
-
estree: {
|
|
22
|
-
type: "Program",
|
|
23
|
-
sourceType: "module",
|
|
24
|
-
body: [
|
|
25
|
-
{
|
|
26
|
-
type: "ImportDeclaration",
|
|
27
|
-
source: { type: "Literal", value: node.url, raw: JSON.stringify(node.url) },
|
|
28
|
-
specifiers: [
|
|
29
|
-
{
|
|
30
|
-
type: "ImportDefaultSpecifier",
|
|
31
|
-
local: { type: "Identifier", name: importName }
|
|
32
|
-
}
|
|
33
|
-
]
|
|
34
|
-
}
|
|
35
|
-
]
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
});
|
|
39
|
-
importedImages.set(node.url, importName);
|
|
40
|
-
}
|
|
41
|
-
const componentElement = {
|
|
42
|
-
name: ASTRO_IMAGE_ELEMENT,
|
|
43
|
-
type: "mdxJsxFlowElement",
|
|
44
|
-
attributes: [
|
|
45
|
-
{
|
|
46
|
-
name: "src",
|
|
47
|
-
type: "mdxJsxAttribute",
|
|
48
|
-
value: {
|
|
49
|
-
type: "mdxJsxAttributeValueExpression",
|
|
50
|
-
value: importName,
|
|
51
|
-
data: {
|
|
52
|
-
estree: {
|
|
53
|
-
type: "Program",
|
|
54
|
-
sourceType: "module",
|
|
55
|
-
comments: [],
|
|
56
|
-
body: [
|
|
57
|
-
{
|
|
58
|
-
type: "ExpressionStatement",
|
|
59
|
-
expression: { type: "Identifier", name: importName }
|
|
60
|
-
}
|
|
61
|
-
]
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
},
|
|
66
|
-
{ name: "alt", type: "mdxJsxAttribute", value: node.alt || "" }
|
|
67
|
-
],
|
|
68
|
-
children: []
|
|
69
|
-
};
|
|
70
|
-
if (node.title) {
|
|
71
|
-
componentElement.attributes.push({
|
|
72
|
-
type: "mdxJsxAttribute",
|
|
73
|
-
name: "title",
|
|
74
|
-
value: node.title
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
if (node.data && node.data.hProperties) {
|
|
78
|
-
const createArrayAttribute = (name, values) => {
|
|
79
|
-
return {
|
|
80
|
-
type: "mdxJsxAttribute",
|
|
81
|
-
name,
|
|
82
|
-
value: {
|
|
83
|
-
type: "mdxJsxAttributeValueExpression",
|
|
84
|
-
value: name,
|
|
85
|
-
data: {
|
|
86
|
-
estree: {
|
|
87
|
-
type: "Program",
|
|
88
|
-
body: [
|
|
89
|
-
{
|
|
90
|
-
type: "ExpressionStatement",
|
|
91
|
-
expression: {
|
|
92
|
-
type: "ArrayExpression",
|
|
93
|
-
elements: values.map((value) => ({
|
|
94
|
-
type: "Literal",
|
|
95
|
-
value,
|
|
96
|
-
raw: String(value)
|
|
97
|
-
}))
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
],
|
|
101
|
-
sourceType: "module",
|
|
102
|
-
comments: []
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
};
|
|
107
|
-
};
|
|
108
|
-
Object.entries(node.data.hProperties).forEach(
|
|
109
|
-
([key, value]) => {
|
|
110
|
-
if (Array.isArray(value)) {
|
|
111
|
-
componentElement.attributes.push(createArrayAttribute(key, value));
|
|
112
|
-
} else {
|
|
113
|
-
componentElement.attributes.push({
|
|
114
|
-
name: key,
|
|
115
|
-
type: "mdxJsxAttribute",
|
|
116
|
-
value: String(value)
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
);
|
|
121
|
-
}
|
|
122
|
-
parent.children.splice(index, 1, componentElement);
|
|
123
|
-
}
|
|
124
|
-
});
|
|
125
|
-
tree.children.unshift(...importsStatements);
|
|
126
|
-
tree.children.unshift(
|
|
127
|
-
jsToTreeNode(`import { Image as ${ASTRO_IMAGE_IMPORT} } from "astro:assets";`)
|
|
128
|
-
);
|
|
129
|
-
tree.children.push(jsToTreeNode(`export const ${USES_ASTRO_IMAGE_FLAG} = true`));
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
export {
|
|
133
|
-
ASTRO_IMAGE_ELEMENT,
|
|
134
|
-
ASTRO_IMAGE_IMPORT,
|
|
135
|
-
USES_ASTRO_IMAGE_FLAG,
|
|
136
|
-
remarkImageToComponent
|
|
137
|
-
};
|