@astrojs/mdx 1.0.0-beta.2 → 1.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/README.md +83 -19
- package/dist/index.d.ts +4 -2
- package/dist/index.js +83 -35
- package/dist/plugins.d.ts +4 -5
- package/dist/plugins.js +36 -80
- package/dist/rehype-collect-headings.d.ts +1 -1
- package/dist/rehype-meta-string.js +2 -3
- package/dist/rehype-optimize-static.d.ts +11 -0
- package/dist/rehype-optimize-static.js +62 -0
- package/dist/remark-images-to-component.d.ts +2 -0
- package/dist/remark-images-to-component.js +83 -0
- package/dist/utils.d.ts +2 -1
- package/dist/utils.js +23 -15
- package/package.json +39 -30
- package/template/content-module-types.d.ts +9 -0
- package/.turbo/turbo-build.log +0 -5
- package/CHANGELOG.md +0 -469
- package/src/index.ts +0 -201
- package/src/plugins.ts +0 -246
- package/src/rehype-collect-headings.ts +0 -11
- package/src/rehype-meta-string.ts +0 -17
- package/src/remark-prism.ts +0 -18
- package/src/remark-shiki.ts +0 -95
- package/src/utils.ts +0 -102
- package/test/fixtures/mdx-astro-markdown-remarkRehype/src/pages/index.mdx +0 -5
- package/test/fixtures/mdx-component/src/components/Test.mdx +0 -3
- package/test/fixtures/mdx-component/src/components/WithFragment.mdx +0 -3
- package/test/fixtures/mdx-component/src/pages/glob.astro +0 -20
- package/test/fixtures/mdx-component/src/pages/index.astro +0 -5
- package/test/fixtures/mdx-component/src/pages/w-fragment.astro +0 -5
- package/test/fixtures/mdx-escape/src/components/Em.astro +0 -7
- package/test/fixtures/mdx-escape/src/components/P.astro +0 -1
- package/test/fixtures/mdx-escape/src/components/Title.astro +0 -1
- package/test/fixtures/mdx-escape/src/pages/html-tag.mdx +0 -5
- package/test/fixtures/mdx-escape/src/pages/index.mdx +0 -13
- package/test/fixtures/mdx-frontmatter/src/layouts/Base.astro +0 -38
- package/test/fixtures/mdx-frontmatter/src/pages/glob.json.js +0 -9
- package/test/fixtures/mdx-frontmatter/src/pages/index.mdx +0 -10
- package/test/fixtures/mdx-frontmatter/src/pages/with-headings.mdx +0 -7
- package/test/fixtures/mdx-frontmatter-injection/astro.config.mjs +0 -12
- package/test/fixtures/mdx-frontmatter-injection/node_modules/.bin/astro +0 -17
- package/test/fixtures/mdx-frontmatter-injection/package.json +0 -12
- package/test/fixtures/mdx-frontmatter-injection/src/layouts/Base.astro +0 -17
- package/test/fixtures/mdx-frontmatter-injection/src/markdown-plugins.mjs +0 -27
- package/test/fixtures/mdx-frontmatter-injection/src/pages/glob.json.js +0 -6
- package/test/fixtures/mdx-frontmatter-injection/src/pages/page-1.mdx +0 -8
- package/test/fixtures/mdx-frontmatter-injection/src/pages/page-2.mdx +0 -24
- package/test/fixtures/mdx-get-headings/src/pages/pages.json.js +0 -11
- package/test/fixtures/mdx-get-headings/src/pages/test-with-jsx-expressions.mdx +0 -8
- package/test/fixtures/mdx-get-headings/src/pages/test.mdx +0 -9
- package/test/fixtures/mdx-get-static-paths/src/content/1.mdx +0 -5
- package/test/fixtures/mdx-get-static-paths/src/pages/[slug].astro +0 -34
- package/test/fixtures/mdx-infinite-loop/astro.config.ts +0 -6
- package/test/fixtures/mdx-infinite-loop/node_modules/.bin/astro +0 -17
- package/test/fixtures/mdx-infinite-loop/package.json +0 -10
- package/test/fixtures/mdx-infinite-loop/src/components/Test.js +0 -3
- package/test/fixtures/mdx-infinite-loop/src/pages/doc.mdx +0 -6
- package/test/fixtures/mdx-infinite-loop/src/pages/index.astro +0 -5
- package/test/fixtures/mdx-namespace/astro.config.mjs +0 -6
- package/test/fixtures/mdx-namespace/node_modules/.bin/astro +0 -17
- package/test/fixtures/mdx-namespace/package.json +0 -10
- package/test/fixtures/mdx-namespace/src/components/Component.jsx +0 -6
- package/test/fixtures/mdx-namespace/src/pages/object.mdx +0 -3
- package/test/fixtures/mdx-namespace/src/pages/star.mdx +0 -3
- package/test/fixtures/mdx-page/astro.config.ts +0 -5
- package/test/fixtures/mdx-page/node_modules/.bin/astro +0 -17
- package/test/fixtures/mdx-page/package.json +0 -9
- package/test/fixtures/mdx-page/src/pages/index.mdx +0 -3
- package/test/fixtures/mdx-page/src/styles.css +0 -3
- package/test/fixtures/mdx-plugins/src/pages/with-plugins.mdx +0 -25
- package/test/fixtures/mdx-plus-react/astro.config.mjs +0 -6
- package/test/fixtures/mdx-plus-react/node_modules/.bin/astro +0 -17
- package/test/fixtures/mdx-plus-react/package.json +0 -10
- package/test/fixtures/mdx-plus-react/src/components/Component.jsx +0 -5
- package/test/fixtures/mdx-plus-react/src/pages/index.astro +0 -11
- package/test/fixtures/mdx-slots/src/components/Slotted.astro +0 -4
- package/test/fixtures/mdx-slots/src/components/Test.mdx +0 -15
- package/test/fixtures/mdx-slots/src/pages/glob.astro +0 -11
- package/test/fixtures/mdx-slots/src/pages/index.astro +0 -5
- package/test/fixtures/mdx-syntax-hightlighting/src/pages/index.mdx +0 -9
- package/test/fixtures/mdx-url-export/src/pages/pages.json.js +0 -9
- package/test/fixtures/mdx-url-export/src/pages/test-1.mdx +0 -1
- package/test/fixtures/mdx-url-export/src/pages/test-2.mdx +0 -1
- package/test/fixtures/mdx-url-export/src/pages/with-url-override.mdx +0 -3
- package/test/fixtures/mdx-vite-env-vars/astro.config.mjs +0 -9
- package/test/fixtures/mdx-vite-env-vars/node_modules/.bin/astro +0 -17
- package/test/fixtures/mdx-vite-env-vars/package.json +0 -7
- package/test/fixtures/mdx-vite-env-vars/src/pages/frontmatter.json.js +0 -7
- package/test/fixtures/mdx-vite-env-vars/src/pages/vite-env-vars.mdx +0 -38
- package/test/mdx-astro-markdown-remarkRehype.test.js +0 -85
- package/test/mdx-component.test.js +0 -191
- package/test/mdx-escape.test.js +0 -32
- package/test/mdx-frontmatter-injection.test.js +0 -53
- package/test/mdx-frontmatter.test.js +0 -77
- package/test/mdx-get-headings.test.js +0 -151
- package/test/mdx-get-static-paths.test.js +0 -32
- package/test/mdx-infinite-loop.test.js +0 -30
- package/test/mdx-namespace.test.js +0 -83
- package/test/mdx-page.test.js +0 -64
- package/test/mdx-plugins.test.js +0 -250
- package/test/mdx-plus-react.test.js +0 -25
- package/test/mdx-slots.js +0 -124
- package/test/mdx-syntax-highlighting.test.js +0 -145
- package/test/mdx-url-export.test.js +0 -28
- package/test/mdx-vite-env-vars.test.js +0 -54
- package/tsconfig.json +0 -10
package/src/plugins.ts
DELETED
|
@@ -1,246 +0,0 @@
|
|
|
1
|
-
import { rehypeHeadingIds } from '@astrojs/markdown-remark';
|
|
2
|
-
import {
|
|
3
|
-
InvalidAstroDataError,
|
|
4
|
-
safelyGetAstroData,
|
|
5
|
-
} from '@astrojs/markdown-remark/dist/internal.js';
|
|
6
|
-
import { nodeTypes } from '@mdx-js/mdx';
|
|
7
|
-
import type { PluggableList } from '@mdx-js/mdx/lib/core.js';
|
|
8
|
-
import type { Options as MdxRollupPluginOptions } from '@mdx-js/rollup';
|
|
9
|
-
import type { AstroConfig } from 'astro';
|
|
10
|
-
import type { Literal, MemberExpression } from 'estree';
|
|
11
|
-
import { visit as estreeVisit } from 'estree-util-visit';
|
|
12
|
-
import { bold, yellow } from 'kleur/colors';
|
|
13
|
-
import type { Image } from 'mdast';
|
|
14
|
-
import { pathToFileURL } from 'node:url';
|
|
15
|
-
import rehypeRaw from 'rehype-raw';
|
|
16
|
-
import remarkGfm from 'remark-gfm';
|
|
17
|
-
import remarkSmartypants from 'remark-smartypants';
|
|
18
|
-
import { visit } from 'unist-util-visit';
|
|
19
|
-
import type { VFile } from 'vfile';
|
|
20
|
-
import { MdxOptions } from './index.js';
|
|
21
|
-
import { rehypeInjectHeadingsExport } from './rehype-collect-headings.js';
|
|
22
|
-
import rehypeMetaString from './rehype-meta-string.js';
|
|
23
|
-
import remarkPrism from './remark-prism.js';
|
|
24
|
-
import remarkShiki from './remark-shiki.js';
|
|
25
|
-
import { isRelativePath, jsToTreeNode } from './utils.js';
|
|
26
|
-
|
|
27
|
-
export function recmaInjectImportMetaEnvPlugin({
|
|
28
|
-
importMetaEnv,
|
|
29
|
-
}: {
|
|
30
|
-
importMetaEnv: Record<string, any>;
|
|
31
|
-
}) {
|
|
32
|
-
return (tree: any) => {
|
|
33
|
-
estreeVisit(tree, (node) => {
|
|
34
|
-
if (node.type === 'MemberExpression') {
|
|
35
|
-
// attempt to get "import.meta.env" variable name
|
|
36
|
-
const envVarName = getImportMetaEnvVariableName(node as MemberExpression);
|
|
37
|
-
if (typeof envVarName === 'string') {
|
|
38
|
-
// clear object keys to replace with envVarLiteral
|
|
39
|
-
for (const key in node) {
|
|
40
|
-
delete (node as any)[key];
|
|
41
|
-
}
|
|
42
|
-
const envVarLiteral: Literal = {
|
|
43
|
-
type: 'Literal',
|
|
44
|
-
value: importMetaEnv[envVarName],
|
|
45
|
-
raw: JSON.stringify(importMetaEnv[envVarName]),
|
|
46
|
-
};
|
|
47
|
-
Object.assign(node, envVarLiteral);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
});
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export function rehypeApplyFrontmatterExport() {
|
|
55
|
-
return function (tree: any, vfile: VFile) {
|
|
56
|
-
const astroData = safelyGetAstroData(vfile.data);
|
|
57
|
-
if (astroData instanceof InvalidAstroDataError)
|
|
58
|
-
throw new Error(
|
|
59
|
-
// Copied from Astro core `errors-data`
|
|
60
|
-
// TODO: find way to import error data from core
|
|
61
|
-
'[MDX] A remark or rehype plugin attempted to inject invalid frontmatter. Ensure "astro.frontmatter" is set to a valid JSON object that is not `null` or `undefined`.'
|
|
62
|
-
);
|
|
63
|
-
const { frontmatter } = astroData;
|
|
64
|
-
const exportNodes = [
|
|
65
|
-
jsToTreeNode(`export const frontmatter = ${JSON.stringify(frontmatter)};`),
|
|
66
|
-
];
|
|
67
|
-
if (frontmatter.layout) {
|
|
68
|
-
// NOTE(bholmesdev) 08-22-2022
|
|
69
|
-
// Using an async layout import (i.e. `const Layout = (await import...)`)
|
|
70
|
-
// Preserves the dev server import cache when globbing a large set of MDX files
|
|
71
|
-
// Full explanation: 'https://github.com/withastro/astro/pull/4428'
|
|
72
|
-
exportNodes.unshift(
|
|
73
|
-
jsToTreeNode(
|
|
74
|
-
/** @see 'vite-plugin-markdown' for layout props reference */
|
|
75
|
-
`import { jsx as layoutJsx } from 'astro/jsx-runtime';
|
|
76
|
-
|
|
77
|
-
export default async function ({ children }) {
|
|
78
|
-
const Layout = (await import(${JSON.stringify(frontmatter.layout)})).default;
|
|
79
|
-
const { layout, ...content } = frontmatter;
|
|
80
|
-
content.file = file;
|
|
81
|
-
content.url = url;
|
|
82
|
-
content.astro = {};
|
|
83
|
-
Object.defineProperty(content.astro, 'headings', {
|
|
84
|
-
get() {
|
|
85
|
-
throw new Error('The "astro" property is no longer supported! To access "headings" from your layout, try using "Astro.props.headings."')
|
|
86
|
-
}
|
|
87
|
-
});
|
|
88
|
-
Object.defineProperty(content.astro, 'html', {
|
|
89
|
-
get() {
|
|
90
|
-
throw new Error('The "astro" property is no longer supported! To access "html" from your layout, try using "Astro.props.compiledContent()."')
|
|
91
|
-
}
|
|
92
|
-
});
|
|
93
|
-
Object.defineProperty(content.astro, 'source', {
|
|
94
|
-
get() {
|
|
95
|
-
throw new Error('The "astro" property is no longer supported! To access "source" from your layout, try using "Astro.props.rawContent()."')
|
|
96
|
-
}
|
|
97
|
-
});
|
|
98
|
-
return layoutJsx(Layout, {
|
|
99
|
-
file,
|
|
100
|
-
url,
|
|
101
|
-
content,
|
|
102
|
-
frontmatter: content,
|
|
103
|
-
headings: getHeadings(),
|
|
104
|
-
'server:root': true,
|
|
105
|
-
children,
|
|
106
|
-
});
|
|
107
|
-
};`
|
|
108
|
-
)
|
|
109
|
-
);
|
|
110
|
-
}
|
|
111
|
-
tree.children = exportNodes.concat(tree.children);
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* `src/content/` does not support relative image paths.
|
|
117
|
-
* This plugin throws an error if any are found
|
|
118
|
-
*/
|
|
119
|
-
function toRemarkContentRelImageError({ srcDir }: { srcDir: URL }) {
|
|
120
|
-
const contentDir = new URL('content/', srcDir);
|
|
121
|
-
return function remarkContentRelImageError() {
|
|
122
|
-
return (tree: any, vfile: VFile) => {
|
|
123
|
-
const isContentFile = pathToFileURL(vfile.path).href.startsWith(contentDir.href);
|
|
124
|
-
if (!isContentFile) return;
|
|
125
|
-
|
|
126
|
-
const relImagePaths = new Set<string>();
|
|
127
|
-
visit(tree, 'image', function raiseError(node: Image) {
|
|
128
|
-
if (isRelativePath(node.url)) {
|
|
129
|
-
relImagePaths.add(node.url);
|
|
130
|
-
}
|
|
131
|
-
});
|
|
132
|
-
if (relImagePaths.size === 0) return;
|
|
133
|
-
|
|
134
|
-
const errorMessage =
|
|
135
|
-
`Relative image paths are not supported in the content/ directory. Place local images in the public/ directory and use absolute paths (see https://docs.astro.build/en/guides/images/#in-markdown-files):\n` +
|
|
136
|
-
[...relImagePaths].map((path) => JSON.stringify(path)).join(',\n');
|
|
137
|
-
|
|
138
|
-
throw new Error(errorMessage);
|
|
139
|
-
};
|
|
140
|
-
};
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
export async function getRemarkPlugins(
|
|
144
|
-
mdxOptions: MdxOptions,
|
|
145
|
-
config: AstroConfig
|
|
146
|
-
): Promise<MdxRollupPluginOptions['remarkPlugins']> {
|
|
147
|
-
let remarkPlugins: PluggableList = [];
|
|
148
|
-
if (mdxOptions.syntaxHighlight === 'shiki') {
|
|
149
|
-
remarkPlugins.push([await remarkShiki(mdxOptions.shikiConfig)]);
|
|
150
|
-
}
|
|
151
|
-
if (mdxOptions.syntaxHighlight === 'prism') {
|
|
152
|
-
remarkPlugins.push(remarkPrism);
|
|
153
|
-
}
|
|
154
|
-
if (mdxOptions.gfm) {
|
|
155
|
-
remarkPlugins.push(remarkGfm);
|
|
156
|
-
}
|
|
157
|
-
if (mdxOptions.smartypants) {
|
|
158
|
-
remarkPlugins.push(remarkSmartypants);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
remarkPlugins = [...remarkPlugins, ...ignoreStringPlugins(mdxOptions.remarkPlugins)];
|
|
162
|
-
|
|
163
|
-
// Apply last in case user plugins resolve relative image paths
|
|
164
|
-
remarkPlugins.push(toRemarkContentRelImageError(config));
|
|
165
|
-
|
|
166
|
-
return remarkPlugins;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
export function getRehypePlugins(mdxOptions: MdxOptions): MdxRollupPluginOptions['rehypePlugins'] {
|
|
170
|
-
let rehypePlugins: PluggableList = [
|
|
171
|
-
// ensure `data.meta` is preserved in `properties.metastring` for rehype syntax highlighters
|
|
172
|
-
rehypeMetaString,
|
|
173
|
-
// rehypeRaw allows custom syntax highlighters to work without added config
|
|
174
|
-
[rehypeRaw, { passThrough: nodeTypes }] as any,
|
|
175
|
-
];
|
|
176
|
-
|
|
177
|
-
rehypePlugins = [
|
|
178
|
-
...rehypePlugins,
|
|
179
|
-
...ignoreStringPlugins(mdxOptions.rehypePlugins),
|
|
180
|
-
// getHeadings() is guaranteed by TS, so this must be included.
|
|
181
|
-
// We run `rehypeHeadingIds` _last_ to respect any custom IDs set by user plugins.
|
|
182
|
-
rehypeHeadingIds,
|
|
183
|
-
rehypeInjectHeadingsExport,
|
|
184
|
-
// computed from `astro.data.frontmatter` in VFile data
|
|
185
|
-
rehypeApplyFrontmatterExport,
|
|
186
|
-
];
|
|
187
|
-
return rehypePlugins;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
function ignoreStringPlugins(plugins: any[]) {
|
|
191
|
-
let validPlugins: PluggableList = [];
|
|
192
|
-
let hasInvalidPlugin = false;
|
|
193
|
-
for (const plugin of plugins) {
|
|
194
|
-
if (typeof plugin === 'string') {
|
|
195
|
-
console.warn(yellow(`[MDX] ${bold(plugin)} not applied.`));
|
|
196
|
-
hasInvalidPlugin = true;
|
|
197
|
-
} else if (Array.isArray(plugin) && typeof plugin[0] === 'string') {
|
|
198
|
-
console.warn(yellow(`[MDX] ${bold(plugin[0])} not applied.`));
|
|
199
|
-
hasInvalidPlugin = true;
|
|
200
|
-
} else {
|
|
201
|
-
validPlugins.push(plugin);
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
if (hasInvalidPlugin) {
|
|
205
|
-
console.warn(
|
|
206
|
-
`To inherit Markdown plugins in MDX, please use explicit imports in your config instead of "strings." See Markdown docs: https://docs.astro.build/en/guides/markdown-content/#markdown-plugins`
|
|
207
|
-
);
|
|
208
|
-
}
|
|
209
|
-
return validPlugins;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
/**
|
|
213
|
-
* Check if estree entry is "import.meta.env.VARIABLE"
|
|
214
|
-
* If it is, return the variable name (i.e. "VARIABLE")
|
|
215
|
-
*/
|
|
216
|
-
function getImportMetaEnvVariableName(node: MemberExpression): string | Error {
|
|
217
|
-
try {
|
|
218
|
-
// check for ".[ANYTHING]"
|
|
219
|
-
if (node.object.type !== 'MemberExpression' || node.property.type !== 'Identifier')
|
|
220
|
-
return new Error();
|
|
221
|
-
|
|
222
|
-
const nestedExpression = node.object;
|
|
223
|
-
// check for ".env"
|
|
224
|
-
if (nestedExpression.property.type !== 'Identifier' || nestedExpression.property.name !== 'env')
|
|
225
|
-
return new Error();
|
|
226
|
-
|
|
227
|
-
const envExpression = nestedExpression.object;
|
|
228
|
-
// check for ".meta"
|
|
229
|
-
if (
|
|
230
|
-
envExpression.type !== 'MetaProperty' ||
|
|
231
|
-
envExpression.property.type !== 'Identifier' ||
|
|
232
|
-
envExpression.property.name !== 'meta'
|
|
233
|
-
)
|
|
234
|
-
return new Error();
|
|
235
|
-
|
|
236
|
-
// check for "import"
|
|
237
|
-
if (envExpression.meta.name !== 'import') return new Error();
|
|
238
|
-
|
|
239
|
-
return node.property.name;
|
|
240
|
-
} catch (e) {
|
|
241
|
-
if (e instanceof Error) {
|
|
242
|
-
return e;
|
|
243
|
-
}
|
|
244
|
-
return new Error('Unknown parsing error');
|
|
245
|
-
}
|
|
246
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { MarkdownHeading, MarkdownVFile } from '@astrojs/markdown-remark';
|
|
2
|
-
import { jsToTreeNode } from './utils.js';
|
|
3
|
-
|
|
4
|
-
export function rehypeInjectHeadingsExport() {
|
|
5
|
-
return function (tree: any, file: MarkdownVFile) {
|
|
6
|
-
const headings: MarkdownHeading[] = file.data.__astroHeadings || [];
|
|
7
|
-
tree.children.unshift(
|
|
8
|
-
jsToTreeNode(`export function getHeadings() { return ${JSON.stringify(headings)} }`)
|
|
9
|
-
);
|
|
10
|
-
};
|
|
11
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { visit } from 'unist-util-visit';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Moves `data.meta` to `properties.metastring` for the `code` element node
|
|
5
|
-
* as `rehype-raw` strips `data` from all nodes, which may contain useful information.
|
|
6
|
-
* e.g. ```js {1:3} => metastring: "{1:3}"
|
|
7
|
-
*/
|
|
8
|
-
export default function rehypeMetaString() {
|
|
9
|
-
return function (tree: any) {
|
|
10
|
-
visit(tree, (node) => {
|
|
11
|
-
if (node.type === 'element' && node.tagName === 'code' && node.data?.meta) {
|
|
12
|
-
node.properties ??= {};
|
|
13
|
-
node.properties.metastring = node.data.meta;
|
|
14
|
-
}
|
|
15
|
-
});
|
|
16
|
-
};
|
|
17
|
-
}
|
package/src/remark-prism.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { runHighlighterWithAstro } from '@astrojs/prism/dist/highlighter';
|
|
2
|
-
import { visit } from 'unist-util-visit';
|
|
3
|
-
|
|
4
|
-
/** */
|
|
5
|
-
export default function remarkPrism() {
|
|
6
|
-
return (tree: any) =>
|
|
7
|
-
visit(tree, 'code', (node: any) => {
|
|
8
|
-
let { lang, value } = node;
|
|
9
|
-
node.type = 'html';
|
|
10
|
-
|
|
11
|
-
let { html, classLanguage } = runHighlighterWithAstro(lang, value);
|
|
12
|
-
let classes = [classLanguage];
|
|
13
|
-
node.value = `<pre class="${classes.join(
|
|
14
|
-
' '
|
|
15
|
-
)}"><code class="${classLanguage}">${html}</code></pre>`;
|
|
16
|
-
return node;
|
|
17
|
-
});
|
|
18
|
-
}
|
package/src/remark-shiki.ts
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import type { ShikiConfig } from 'astro';
|
|
2
|
-
import type * as shiki from 'shiki';
|
|
3
|
-
import { getHighlighter } from 'shiki';
|
|
4
|
-
import { visit } from 'unist-util-visit';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* getHighlighter() is the most expensive step of Shiki. Instead of calling it on every page,
|
|
8
|
-
* cache it here as much as possible. Make sure that your highlighters can be cached, state-free.
|
|
9
|
-
* We make this async, so that multiple calls to parse markdown still share the same highlighter.
|
|
10
|
-
*/
|
|
11
|
-
const highlighterCacheAsync = new Map<string, Promise<shiki.Highlighter>>();
|
|
12
|
-
|
|
13
|
-
const remarkShiki = async ({ langs = [], theme = 'github-dark', wrap = false }: ShikiConfig) => {
|
|
14
|
-
const cacheID: string = typeof theme === 'string' ? theme : theme.name;
|
|
15
|
-
let highlighterAsync = highlighterCacheAsync.get(cacheID);
|
|
16
|
-
if (!highlighterAsync) {
|
|
17
|
-
highlighterAsync = getHighlighter({ theme }).then((hl) => {
|
|
18
|
-
hl.setColorReplacements({
|
|
19
|
-
'#000001': 'var(--astro-code-color-text)',
|
|
20
|
-
'#000002': 'var(--astro-code-color-background)',
|
|
21
|
-
'#000004': 'var(--astro-code-token-constant)',
|
|
22
|
-
'#000005': 'var(--astro-code-token-string)',
|
|
23
|
-
'#000006': 'var(--astro-code-token-comment)',
|
|
24
|
-
'#000007': 'var(--astro-code-token-keyword)',
|
|
25
|
-
'#000008': 'var(--astro-code-token-parameter)',
|
|
26
|
-
'#000009': 'var(--astro-code-token-function)',
|
|
27
|
-
'#000010': 'var(--astro-code-token-string-expression)',
|
|
28
|
-
'#000011': 'var(--astro-code-token-punctuation)',
|
|
29
|
-
'#000012': 'var(--astro-code-token-link)',
|
|
30
|
-
});
|
|
31
|
-
return hl;
|
|
32
|
-
});
|
|
33
|
-
highlighterCacheAsync.set(cacheID, highlighterAsync);
|
|
34
|
-
}
|
|
35
|
-
const highlighter = await highlighterAsync;
|
|
36
|
-
|
|
37
|
-
// NOTE: There may be a performance issue here for large sites that use `lang`.
|
|
38
|
-
// Since this will be called on every page load. Unclear how to fix this.
|
|
39
|
-
for (const lang of langs) {
|
|
40
|
-
await highlighter.loadLanguage(lang);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
return () => (tree: any) => {
|
|
44
|
-
visit(tree, 'code', (node) => {
|
|
45
|
-
let lang: string;
|
|
46
|
-
|
|
47
|
-
if (typeof node.lang === 'string') {
|
|
48
|
-
const langExists = highlighter.getLoadedLanguages().includes(node.lang);
|
|
49
|
-
if (langExists) {
|
|
50
|
-
lang = node.lang;
|
|
51
|
-
} else {
|
|
52
|
-
// eslint-disable-next-line no-console
|
|
53
|
-
console.warn(`The language "${node.lang}" doesn't exist, falling back to plaintext.`);
|
|
54
|
-
lang = 'plaintext';
|
|
55
|
-
}
|
|
56
|
-
} else {
|
|
57
|
-
lang = 'plaintext';
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
let html = highlighter!.codeToHtml(node.value, { lang });
|
|
61
|
-
|
|
62
|
-
// Q: Couldn't these regexes match on a user's inputted code blocks?
|
|
63
|
-
// A: Nope! All rendered HTML is properly escaped.
|
|
64
|
-
// Ex. If a user typed `<span class="line"` into a code block,
|
|
65
|
-
// It would become this before hitting our regexes:
|
|
66
|
-
// <span class="line"
|
|
67
|
-
|
|
68
|
-
// Replace "shiki" class naming with "astro".
|
|
69
|
-
html = html.replace(/<pre class="(.*?)shiki(.*?)"/, `<pre class="$1astro-code$2"`);
|
|
70
|
-
// Add "user-select: none;" for "+"/"-" diff symbols
|
|
71
|
-
if (node.lang === 'diff') {
|
|
72
|
-
html = html.replace(
|
|
73
|
-
/<span class="line"><span style="(.*?)">([\+|\-])/g,
|
|
74
|
-
'<span class="line"><span style="$1"><span style="user-select: none;">$2</span>'
|
|
75
|
-
);
|
|
76
|
-
}
|
|
77
|
-
// Handle code wrapping
|
|
78
|
-
// if wrap=null, do nothing.
|
|
79
|
-
if (wrap === false) {
|
|
80
|
-
html = html.replace(/style="(.*?)"/, 'style="$1; overflow-x: auto;"');
|
|
81
|
-
} else if (wrap === true) {
|
|
82
|
-
html = html.replace(
|
|
83
|
-
/style="(.*?)"/,
|
|
84
|
-
'style="$1; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;"'
|
|
85
|
-
);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
node.type = 'html';
|
|
89
|
-
node.value = html;
|
|
90
|
-
node.children = [];
|
|
91
|
-
});
|
|
92
|
-
};
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
export default remarkShiki;
|
package/src/utils.ts
DELETED
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
import type { Options as AcornOpts } from 'acorn';
|
|
2
|
-
import { parse } from 'acorn';
|
|
3
|
-
import type { AstroConfig, SSRError } from 'astro';
|
|
4
|
-
import matter from 'gray-matter';
|
|
5
|
-
import type { MdxjsEsm } from 'mdast-util-mdx';
|
|
6
|
-
|
|
7
|
-
function appendForwardSlash(path: string) {
|
|
8
|
-
return path.endsWith('/') ? path : path + '/';
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
interface FileInfo {
|
|
12
|
-
fileId: string;
|
|
13
|
-
fileUrl: string;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/** @see 'vite-plugin-utils' for source */
|
|
17
|
-
export function getFileInfo(id: string, config: AstroConfig): FileInfo {
|
|
18
|
-
const sitePathname = appendForwardSlash(
|
|
19
|
-
config.site ? new URL(config.base, config.site).pathname : config.base
|
|
20
|
-
);
|
|
21
|
-
|
|
22
|
-
// Try to grab the file's actual URL
|
|
23
|
-
let url: URL | undefined = undefined;
|
|
24
|
-
try {
|
|
25
|
-
url = new URL(`file://${id}`);
|
|
26
|
-
} catch {}
|
|
27
|
-
|
|
28
|
-
const fileId = id.split('?')[0];
|
|
29
|
-
let fileUrl: string;
|
|
30
|
-
const isPage = fileId.includes('/pages/');
|
|
31
|
-
if (isPage) {
|
|
32
|
-
fileUrl = fileId.replace(/^.*?\/pages\//, sitePathname).replace(/(\/index)?\.mdx$/, '');
|
|
33
|
-
} else if (url && url.pathname.startsWith(config.root.pathname)) {
|
|
34
|
-
fileUrl = url.pathname.slice(config.root.pathname.length);
|
|
35
|
-
} else {
|
|
36
|
-
fileUrl = fileId;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
if (fileUrl && config.trailingSlash === 'always') {
|
|
40
|
-
fileUrl = appendForwardSlash(fileUrl);
|
|
41
|
-
}
|
|
42
|
-
return { fileId, fileUrl };
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Match YAML exception handling from Astro core errors
|
|
47
|
-
* @see 'astro/src/core/errors.ts'
|
|
48
|
-
*/
|
|
49
|
-
export function parseFrontmatter(code: string, id: string) {
|
|
50
|
-
try {
|
|
51
|
-
return matter(code);
|
|
52
|
-
} catch (e: any) {
|
|
53
|
-
if (e.name === 'YAMLException') {
|
|
54
|
-
const err: SSRError = e;
|
|
55
|
-
err.id = id;
|
|
56
|
-
err.loc = { file: e.id, line: e.mark.line + 1, column: e.mark.column };
|
|
57
|
-
err.message = e.reason;
|
|
58
|
-
throw err;
|
|
59
|
-
} else {
|
|
60
|
-
throw e;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export function jsToTreeNode(
|
|
66
|
-
jsString: string,
|
|
67
|
-
acornOpts: AcornOpts = {
|
|
68
|
-
ecmaVersion: 'latest',
|
|
69
|
-
sourceType: 'module',
|
|
70
|
-
}
|
|
71
|
-
): MdxjsEsm {
|
|
72
|
-
return {
|
|
73
|
-
type: 'mdxjsEsm',
|
|
74
|
-
value: '',
|
|
75
|
-
data: {
|
|
76
|
-
estree: {
|
|
77
|
-
body: [],
|
|
78
|
-
...parse(jsString, acornOpts),
|
|
79
|
-
type: 'Program',
|
|
80
|
-
sourceType: 'module',
|
|
81
|
-
},
|
|
82
|
-
},
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// Following utils taken from `packages/astro/src/core/path.ts`:
|
|
87
|
-
export function isRelativePath(path: string) {
|
|
88
|
-
return startsWithDotDotSlash(path) || startsWithDotSlash(path);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
function startsWithDotDotSlash(path: string) {
|
|
92
|
-
const c1 = path[0];
|
|
93
|
-
const c2 = path[1];
|
|
94
|
-
const c3 = path[2];
|
|
95
|
-
return c1 === '.' && c2 === '.' && c3 === '/';
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
function startsWithDotSlash(path: string) {
|
|
99
|
-
const c1 = path[0];
|
|
100
|
-
const c2 = path[1];
|
|
101
|
-
return c1 === '.' && c2 === '/';
|
|
102
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
import { parse } from 'node:path';
|
|
3
|
-
const components = await Astro.glob('../components/*.mdx');
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
<div data-default-export>
|
|
7
|
-
{components.map(Component => (
|
|
8
|
-
<div data-file={parse(Component.file).base}>
|
|
9
|
-
<Component.default />
|
|
10
|
-
</div>
|
|
11
|
-
))}
|
|
12
|
-
</div>
|
|
13
|
-
|
|
14
|
-
<div data-content-export>
|
|
15
|
-
{components.map(({ Content, file }) => (
|
|
16
|
-
<div data-file={parse(file).base}>
|
|
17
|
-
<Content />
|
|
18
|
-
</div>
|
|
19
|
-
))}
|
|
20
|
-
</div>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<p><slot /></p>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<h1><slot/></h1>
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import P from '../components/P.astro';
|
|
2
|
-
import Em from '../components/Em.astro';
|
|
3
|
-
import Title from '../components/Title.astro';
|
|
4
|
-
|
|
5
|
-
export const components = { p: P, em: Em, h1: Title };
|
|
6
|
-
|
|
7
|
-
# Hello _there_
|
|
8
|
-
|
|
9
|
-
# _there_
|
|
10
|
-
|
|
11
|
-
Hello _there_
|
|
12
|
-
|
|
13
|
-
_there_
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
const {
|
|
3
|
-
content = { title: "content didn't work" },
|
|
4
|
-
file = "file didn't work",
|
|
5
|
-
url = "url didn't work",
|
|
6
|
-
frontmatter = {
|
|
7
|
-
title: "frontmatter didn't work",
|
|
8
|
-
file: "file didn't work",
|
|
9
|
-
url: "url didn't work",
|
|
10
|
-
},
|
|
11
|
-
headings = [],
|
|
12
|
-
} = Astro.props;
|
|
13
|
-
---
|
|
14
|
-
|
|
15
|
-
<!DOCTYPE html>
|
|
16
|
-
<html lang="en">
|
|
17
|
-
|
|
18
|
-
<head>
|
|
19
|
-
<meta charset="UTF-8">
|
|
20
|
-
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
21
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
22
|
-
</head>
|
|
23
|
-
|
|
24
|
-
<body>
|
|
25
|
-
<p data-content-title>{content.title}</p>
|
|
26
|
-
<p data-frontmatter-title>{frontmatter.title}</p>
|
|
27
|
-
<p data-frontmatter-file>{frontmatter.file}</p>
|
|
28
|
-
<p data-frontmatter-url>{frontmatter.url}</p>
|
|
29
|
-
<p data-file>{frontmatter.file}</p>
|
|
30
|
-
<p data-url>{frontmatter.url}</p>
|
|
31
|
-
<p data-layout-rendered>Layout rendered!</p>
|
|
32
|
-
<ul data-headings>
|
|
33
|
-
{headings.map(heading => <li>{heading.slug}</li>)}
|
|
34
|
-
</ul>
|
|
35
|
-
<slot />
|
|
36
|
-
</body>
|
|
37
|
-
|
|
38
|
-
</html>
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: 'Using YAML frontmatter'
|
|
3
|
-
layout: '../layouts/Base.astro'
|
|
4
|
-
illThrowIfIDontExist: "Oh no, that's scary!"
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
{frontmatter.illThrowIfIDontExist}
|
|
8
|
-
|
|
9
|
-
> Note: newline intentionally missing from the end of this file.
|
|
10
|
-
> Useful since that can be the source of bugs in our compile step.
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from 'astro/config';
|
|
2
|
-
import mdx from '@astrojs/mdx';
|
|
3
|
-
import { rehypeReadingTime, remarkDescription, remarkTitle } from './src/markdown-plugins.mjs';
|
|
4
|
-
|
|
5
|
-
// https://astro.build/config
|
|
6
|
-
export default defineConfig({
|
|
7
|
-
site: 'https://astro.build/',
|
|
8
|
-
integrations: [mdx({
|
|
9
|
-
remarkPlugins: [remarkTitle, remarkDescription],
|
|
10
|
-
rehypePlugins: [rehypeReadingTime],
|
|
11
|
-
})],
|
|
12
|
-
});
|