summaryrefslogtreecommitdiff
path: root/packages/integrations/mdx/src/utils.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/integrations/mdx/src/utils.ts')
-rw-r--r--packages/integrations/mdx/src/utils.ts108
1 files changed, 108 insertions, 0 deletions
diff --git a/packages/integrations/mdx/src/utils.ts b/packages/integrations/mdx/src/utils.ts
new file mode 100644
index 000000000..7dcd4a14c
--- /dev/null
+++ b/packages/integrations/mdx/src/utils.ts
@@ -0,0 +1,108 @@
+import { parseFrontmatter } from '@astrojs/markdown-remark';
+import type { Options as AcornOpts } from 'acorn';
+import { parse } from 'acorn';
+import type { AstroConfig, AstroIntegrationLogger, SSRError } from 'astro';
+import { bold } from 'kleur/colors';
+import type { MdxjsEsm } from 'mdast-util-mdx';
+import type { PluggableList } from 'unified';
+
+function appendForwardSlash(path: string) {
+ return path.endsWith('/') ? path : path + '/';
+}
+
+export interface FileInfo {
+ fileId: string;
+ fileUrl: string;
+}
+
+/** @see 'vite-plugin-utils' for source */
+export function getFileInfo(id: string, config: AstroConfig): FileInfo {
+ const sitePathname = appendForwardSlash(
+ config.site ? new URL(config.base, config.site).pathname : config.base,
+ );
+
+ // Try to grab the file's actual URL
+ let url: URL | undefined = undefined;
+ try {
+ url = new URL(`file://${id}`);
+ } catch {}
+
+ const fileId = id.split('?')[0];
+ let fileUrl: string;
+ const isPage = fileId.includes('/pages/');
+ if (isPage) {
+ fileUrl = fileId.replace(/^.*?\/pages\//, sitePathname).replace(/(?:\/index)?\.mdx$/, '');
+ } else if (url?.pathname.startsWith(config.root.pathname)) {
+ fileUrl = url.pathname.slice(config.root.pathname.length);
+ } else {
+ fileUrl = fileId;
+ }
+
+ if (fileUrl && config.trailingSlash === 'always') {
+ fileUrl = appendForwardSlash(fileUrl);
+ }
+ return { fileId, fileUrl };
+}
+
+/**
+ * Match YAML exception handling from Astro core errors
+ * @see 'astro/src/core/errors.ts'
+ */
+export function safeParseFrontmatter(code: string, id: string) {
+ try {
+ return parseFrontmatter(code, { frontmatter: 'empty-with-spaces' });
+ } catch (e: any) {
+ if (e.name === 'YAMLException') {
+ const err: SSRError = e;
+ err.id = id;
+ err.loc = { file: e.id, line: e.mark.line + 1, column: e.mark.column };
+ err.message = e.reason;
+ throw err;
+ } else {
+ throw e;
+ }
+ }
+}
+
+export function jsToTreeNode(
+ jsString: string,
+ acornOpts: AcornOpts = {
+ ecmaVersion: 'latest',
+ sourceType: 'module',
+ },
+): MdxjsEsm {
+ return {
+ type: 'mdxjsEsm',
+ value: '',
+ data: {
+ // @ts-expect-error `parse` return types is incompatible but it should work in runtime
+ estree: {
+ ...parse(jsString, acornOpts),
+ type: 'Program',
+ sourceType: 'module',
+ },
+ },
+ };
+}
+
+export function ignoreStringPlugins(plugins: any[], logger: AstroIntegrationLogger): PluggableList {
+ let validPlugins: PluggableList = [];
+ let hasInvalidPlugin = false;
+ for (const plugin of plugins) {
+ if (typeof plugin === 'string') {
+ logger.warn(`${bold(plugin)} not applied.`);
+ hasInvalidPlugin = true;
+ } else if (Array.isArray(plugin) && typeof plugin[0] === 'string') {
+ logger.warn(`${bold(plugin[0])} not applied.`);
+ hasInvalidPlugin = true;
+ } else {
+ validPlugins.push(plugin);
+ }
+ }
+ if (hasInvalidPlugin) {
+ logger.warn(
+ `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`,
+ );
+ }
+ return validPlugins;
+}