Fix: correctly transform import.meta.env.*
in MDX (#4858)
* fix: serialize route pattern for Netlify edge Co-authored-by: Jackie Macharia <jackiewmacharia> * fix: escape import.meta.env in MDX compiler output * test: env vars in mdx * chore: changeset * deps: estree-util-visit, @types/estree * feat: inject import.meta.env w/ recma * feat: pull importMetaEnv from vite + astro configs * test: `import.meta.env` in JSX * fix: lockfile * chore: update changeset * fix: remove stray stashed commit
This commit is contained in:
parent
b73ec14171
commit
58a2dca228
12 changed files with 454 additions and 233 deletions
5
.changeset/metal-hats-explain.md
Normal file
5
.changeset/metal-hats-explain.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'@astrojs/mdx': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Correctly parse import.meta.env in MDX files
|
|
@ -34,6 +34,7 @@
|
||||||
"@mdx-js/rollup": "^2.1.1",
|
"@mdx-js/rollup": "^2.1.1",
|
||||||
"acorn": "^8.8.0",
|
"acorn": "^8.8.0",
|
||||||
"es-module-lexer": "^0.10.5",
|
"es-module-lexer": "^0.10.5",
|
||||||
|
"estree-util-visit": "^1.2.0",
|
||||||
"github-slugger": "^1.4.0",
|
"github-slugger": "^1.4.0",
|
||||||
"gray-matter": "^4.0.3",
|
"gray-matter": "^4.0.3",
|
||||||
"kleur": "^4.1.4",
|
"kleur": "^4.1.4",
|
||||||
|
@ -47,6 +48,7 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/chai": "^4.3.1",
|
"@types/chai": "^4.3.1",
|
||||||
|
"@types/estree": "^1.0.0",
|
||||||
"@types/mocha": "^9.1.1",
|
"@types/mocha": "^9.1.1",
|
||||||
"@types/yargs-parser": "^21.0.0",
|
"@types/yargs-parser": "^21.0.0",
|
||||||
"astro": "workspace:*",
|
"astro": "workspace:*",
|
||||||
|
|
|
@ -1,103 +0,0 @@
|
||||||
import type { MarkdownAstroData } from 'astro';
|
|
||||||
import type { Data, VFile } from 'vfile';
|
|
||||||
import { jsToTreeNode } from './utils.js';
|
|
||||||
|
|
||||||
export function remarkInitializeAstroData() {
|
|
||||||
return function (tree: any, vfile: VFile) {
|
|
||||||
if (!vfile.data.astro) {
|
|
||||||
vfile.data.astro = { frontmatter: {} };
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const EXPORT_NAME = 'frontmatter';
|
|
||||||
|
|
||||||
export function rehypeApplyFrontmatterExport(pageFrontmatter: Record<string, any>) {
|
|
||||||
return function (tree: any, vfile: VFile) {
|
|
||||||
const { frontmatter: injectedFrontmatter } = safelyGetAstroData(vfile.data);
|
|
||||||
const frontmatter = { ...injectedFrontmatter, ...pageFrontmatter };
|
|
||||||
const exportNodes = [
|
|
||||||
jsToTreeNode(`export const ${EXPORT_NAME} = ${JSON.stringify(frontmatter)};`),
|
|
||||||
];
|
|
||||||
if (frontmatter.layout) {
|
|
||||||
// NOTE(bholmesdev) 08-22-2022
|
|
||||||
// Using an async layout import (i.e. `const Layout = (await import...)`)
|
|
||||||
// Preserves the dev server import cache when globbing a large set of MDX files
|
|
||||||
// Full explanation: 'https://github.com/withastro/astro/pull/4428'
|
|
||||||
exportNodes.unshift(
|
|
||||||
jsToTreeNode(
|
|
||||||
/** @see 'vite-plugin-markdown' for layout props reference */
|
|
||||||
`import { jsx as layoutJsx } from 'astro/jsx-runtime';
|
|
||||||
|
|
||||||
export default async function ({ children }) {
|
|
||||||
const Layout = (await import(${JSON.stringify(frontmatter.layout)})).default;
|
|
||||||
const { layout, ...content } = frontmatter;
|
|
||||||
content.file = file;
|
|
||||||
content.url = url;
|
|
||||||
content.astro = {};
|
|
||||||
Object.defineProperty(content.astro, 'headings', {
|
|
||||||
get() {
|
|
||||||
throw new Error('The "astro" property is no longer supported! To access "headings" from your layout, try using "Astro.props.headings."')
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Object.defineProperty(content.astro, 'html', {
|
|
||||||
get() {
|
|
||||||
throw new Error('The "astro" property is no longer supported! To access "html" from your layout, try using "Astro.props.compiledContent()."')
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Object.defineProperty(content.astro, 'source', {
|
|
||||||
get() {
|
|
||||||
throw new Error('The "astro" property is no longer supported! To access "source" from your layout, try using "Astro.props.rawContent()."')
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return layoutJsx(Layout, {
|
|
||||||
file,
|
|
||||||
url,
|
|
||||||
content,
|
|
||||||
frontmatter: content,
|
|
||||||
headings: getHeadings(),
|
|
||||||
'server:root': true,
|
|
||||||
children,
|
|
||||||
});
|
|
||||||
};`
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
tree.children = exportNodes.concat(tree.children);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copied from markdown utils
|
|
||||||
* @see "vite-plugin-utils"
|
|
||||||
*/
|
|
||||||
function isValidAstroData(obj: unknown): obj is MarkdownAstroData {
|
|
||||||
if (typeof obj === 'object' && obj !== null && obj.hasOwnProperty('frontmatter')) {
|
|
||||||
const { frontmatter } = obj as any;
|
|
||||||
try {
|
|
||||||
// ensure frontmatter is JSON-serializable
|
|
||||||
JSON.stringify(frontmatter);
|
|
||||||
} catch {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return typeof frontmatter === 'object' && frontmatter !== null;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copied from markdown utils
|
|
||||||
* @see "vite-plugin-utils"
|
|
||||||
*/
|
|
||||||
export function safelyGetAstroData(vfileData: Data): MarkdownAstroData {
|
|
||||||
const { astro } = vfileData;
|
|
||||||
|
|
||||||
if (!astro) return { frontmatter: {} };
|
|
||||||
if (!isValidAstroData(astro)) {
|
|
||||||
throw Error(
|
|
||||||
`[MDX] A remark or rehype plugin tried to add invalid frontmatter. Ensure "astro.frontmatter" is a JSON object!`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return astro;
|
|
||||||
}
|
|
|
@ -1,19 +1,19 @@
|
||||||
|
import type { AstroIntegration } from 'astro';
|
||||||
|
import type { Plugin as VitePlugin } from 'vite';
|
||||||
import { compile as mdxCompile } from '@mdx-js/mdx';
|
import { compile as mdxCompile } from '@mdx-js/mdx';
|
||||||
import mdxPlugin, { Options as MdxRollupPluginOptions } from '@mdx-js/rollup';
|
import mdxPlugin, { Options as MdxRollupPluginOptions } from '@mdx-js/rollup';
|
||||||
import type { AstroIntegration } from 'astro';
|
|
||||||
import { parse as parseESM } from 'es-module-lexer';
|
import { parse as parseESM } from 'es-module-lexer';
|
||||||
import { blue, bold } from 'kleur/colors';
|
import { blue, bold } from 'kleur/colors';
|
||||||
import { VFile } from 'vfile';
|
import { VFile } from 'vfile';
|
||||||
import type { Plugin as VitePlugin } from 'vite';
|
import fs from 'node:fs/promises';
|
||||||
import { rehypeApplyFrontmatterExport } from './astro-data-utils.js';
|
import { getFileInfo, handleExtendsNotSupported, parseFrontmatter } from './utils.js';
|
||||||
import type { MdxOptions } from './utils.js';
|
|
||||||
import {
|
import {
|
||||||
getFileInfo,
|
recmaInjectImportMetaEnvPlugin,
|
||||||
|
rehypeApplyFrontmatterExport,
|
||||||
getRehypePlugins,
|
getRehypePlugins,
|
||||||
getRemarkPlugins,
|
getRemarkPlugins,
|
||||||
handleExtendsNotSupported,
|
} from './plugins.js';
|
||||||
parseFrontmatter,
|
import { PluggableList } from '@mdx-js/mdx/lib/core.js';
|
||||||
} from './utils.js';
|
|
||||||
|
|
||||||
const RAW_CONTENT_ERROR =
|
const RAW_CONTENT_ERROR =
|
||||||
'MDX does not support rawContent()! If you need to read the Markdown contents to calculate values (ex. reading time), we suggest injecting frontmatter via remark plugins. Learn more on our docs: https://docs.astro.build/en/guides/integrations-guide/mdx/#inject-frontmatter-via-remark-or-rehype-plugins';
|
'MDX does not support rawContent()! If you need to read the Markdown contents to calculate values (ex. reading time), we suggest injecting frontmatter via remark plugins. Learn more on our docs: https://docs.astro.build/en/guides/integrations-guide/mdx/#inject-frontmatter-via-remark-or-rehype-plugins';
|
||||||
|
@ -21,6 +21,19 @@ const RAW_CONTENT_ERROR =
|
||||||
const COMPILED_CONTENT_ERROR =
|
const COMPILED_CONTENT_ERROR =
|
||||||
'MDX does not support compiledContent()! If you need to read the HTML contents to calculate values (ex. reading time), we suggest injecting frontmatter via rehype plugins. Learn more on our docs: https://docs.astro.build/en/guides/integrations-guide/mdx/#inject-frontmatter-via-remark-or-rehype-plugins';
|
'MDX does not support compiledContent()! If you need to read the HTML contents to calculate values (ex. reading time), we suggest injecting frontmatter via rehype plugins. Learn more on our docs: https://docs.astro.build/en/guides/integrations-guide/mdx/#inject-frontmatter-via-remark-or-rehype-plugins';
|
||||||
|
|
||||||
|
export type MdxOptions = {
|
||||||
|
remarkPlugins?: PluggableList;
|
||||||
|
rehypePlugins?: PluggableList;
|
||||||
|
/**
|
||||||
|
* Choose which remark and rehype plugins to inherit, if any.
|
||||||
|
*
|
||||||
|
* - "markdown" (default) - inherit your project’s markdown plugin config ([see Markdown docs](https://docs.astro.build/en/guides/markdown-content/#configuring-markdown))
|
||||||
|
* - "astroDefaults" - inherit Astro’s default plugins only ([see defaults](https://docs.astro.build/en/reference/configuration-reference/#markdownextenddefaultplugins))
|
||||||
|
* - false - do not inherit any plugins
|
||||||
|
*/
|
||||||
|
extendPlugins?: 'markdown' | 'astroDefaults' | false;
|
||||||
|
};
|
||||||
|
|
||||||
export default function mdx(mdxOptions: MdxOptions = {}): AstroIntegration {
|
export default function mdx(mdxOptions: MdxOptions = {}): AstroIntegration {
|
||||||
return {
|
return {
|
||||||
name: '@astrojs/mdx',
|
name: '@astrojs/mdx',
|
||||||
|
@ -58,17 +71,28 @@ export default function mdx(mdxOptions: MdxOptions = {}): AstroIntegration {
|
||||||
mdExtensions: [],
|
mdExtensions: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let importMetaEnv: Record<string, any> = {
|
||||||
|
SITE: config.site,
|
||||||
|
};
|
||||||
|
|
||||||
updateConfig({
|
updateConfig({
|
||||||
vite: {
|
vite: {
|
||||||
plugins: [
|
plugins: [
|
||||||
{
|
{
|
||||||
enforce: 'pre',
|
enforce: 'pre',
|
||||||
...mdxPlugin(mdxPluginOpts),
|
...mdxPlugin(mdxPluginOpts),
|
||||||
|
configResolved(resolved) {
|
||||||
|
importMetaEnv = { ...importMetaEnv, ...resolved.env };
|
||||||
|
},
|
||||||
// Override transform to alter code before MDX compilation
|
// Override transform to alter code before MDX compilation
|
||||||
// ex. inject layouts
|
// ex. inject layouts
|
||||||
async transform(code, id) {
|
async transform(_, id) {
|
||||||
if (!id.endsWith('mdx')) return;
|
if (!id.endsWith('mdx')) return;
|
||||||
|
|
||||||
|
// Read code from file manually to prevent Vite from parsing `import.meta.env` expressions
|
||||||
|
const { fileId } = getFileInfo(id, config);
|
||||||
|
const code = await fs.readFile(fileId, 'utf-8');
|
||||||
|
|
||||||
const { data: frontmatter, content: pageContent } = parseFrontmatter(code, id);
|
const { data: frontmatter, content: pageContent } = parseFrontmatter(code, id);
|
||||||
const compiled = await mdxCompile(new VFile({ value: pageContent, path: id }), {
|
const compiled = await mdxCompile(new VFile({ value: pageContent, path: id }), {
|
||||||
...mdxPluginOpts,
|
...mdxPluginOpts,
|
||||||
|
@ -76,10 +100,11 @@ export default function mdx(mdxOptions: MdxOptions = {}): AstroIntegration {
|
||||||
...(mdxPluginOpts.rehypePlugins ?? []),
|
...(mdxPluginOpts.rehypePlugins ?? []),
|
||||||
() => rehypeApplyFrontmatterExport(frontmatter),
|
() => rehypeApplyFrontmatterExport(frontmatter),
|
||||||
],
|
],
|
||||||
|
recmaPlugins: [() => recmaInjectImportMetaEnvPlugin({ importMetaEnv })],
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
code: String(compiled.value),
|
code: escapeViteEnvReferences(String(compiled.value)),
|
||||||
map: compiled.map,
|
map: compiled.map,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -123,7 +148,7 @@ export default function mdx(mdxOptions: MdxOptions = {}): AstroIntegration {
|
||||||
import.meta.hot.decline();
|
import.meta.hot.decline();
|
||||||
}`;
|
}`;
|
||||||
}
|
}
|
||||||
return code;
|
return escapeViteEnvReferences(code);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
] as VitePlugin[],
|
] as VitePlugin[],
|
||||||
|
@ -133,3 +158,10 @@ export default function mdx(mdxOptions: MdxOptions = {}): AstroIntegration {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Converts the first dot in `import.meta.env` to its Unicode escape sequence,
|
||||||
|
// which prevents Vite from replacing strings like `import.meta.env.SITE`
|
||||||
|
// in our JS representation of loaded Markdown files
|
||||||
|
function escapeViteEnvReferences(code: string) {
|
||||||
|
return code.replace(/import\.meta\.env/g, 'import\\u002Emeta.env');
|
||||||
|
}
|
||||||
|
|
273
packages/integrations/mdx/src/plugins.ts
Normal file
273
packages/integrations/mdx/src/plugins.ts
Normal file
|
@ -0,0 +1,273 @@
|
||||||
|
import type { MemberExpression, Literal } from 'estree';
|
||||||
|
import type { MarkdownAstroData, AstroConfig } from 'astro';
|
||||||
|
import type { Data, VFile } from 'vfile';
|
||||||
|
import { visit as estreeVisit } from 'estree-util-visit';
|
||||||
|
import { jsToTreeNode } from './utils.js';
|
||||||
|
import { nodeTypes } from '@mdx-js/mdx';
|
||||||
|
import type { PluggableList } from '@mdx-js/mdx/lib/core.js';
|
||||||
|
import type { Options as MdxRollupPluginOptions } from '@mdx-js/rollup';
|
||||||
|
import { bold, yellow } from 'kleur/colors';
|
||||||
|
import rehypeRaw from 'rehype-raw';
|
||||||
|
import remarkGfm from 'remark-gfm';
|
||||||
|
import remarkSmartypants from 'remark-smartypants';
|
||||||
|
import rehypeCollectHeadings from './rehype-collect-headings.js';
|
||||||
|
import remarkPrism from './remark-prism.js';
|
||||||
|
import remarkShiki from './remark-shiki.js';
|
||||||
|
import { MdxOptions } from './index.js';
|
||||||
|
|
||||||
|
export function recmaInjectImportMetaEnvPlugin({
|
||||||
|
importMetaEnv,
|
||||||
|
}: {
|
||||||
|
importMetaEnv: Record<string, any>;
|
||||||
|
}) {
|
||||||
|
return (tree: any) => {
|
||||||
|
estreeVisit(tree, (node) => {
|
||||||
|
if (node.type === 'MemberExpression') {
|
||||||
|
// attempt to get "import.meta.env" variable name
|
||||||
|
const envVarName = getImportMetaEnvVariableName(node as MemberExpression);
|
||||||
|
if (typeof envVarName === 'string') {
|
||||||
|
// clear object keys to replace with envVarLiteral
|
||||||
|
for (const key in node) {
|
||||||
|
delete (node as any)[key];
|
||||||
|
}
|
||||||
|
const envVarLiteral: Literal = {
|
||||||
|
type: 'Literal',
|
||||||
|
value: importMetaEnv[envVarName],
|
||||||
|
raw: JSON.stringify(importMetaEnv[envVarName]),
|
||||||
|
};
|
||||||
|
Object.assign(node, envVarLiteral);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function remarkInitializeAstroData() {
|
||||||
|
return function (tree: any, vfile: VFile) {
|
||||||
|
if (!vfile.data.astro) {
|
||||||
|
vfile.data.astro = { frontmatter: {} };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const EXPORT_NAME = 'frontmatter';
|
||||||
|
|
||||||
|
export function rehypeApplyFrontmatterExport(pageFrontmatter: Record<string, any>) {
|
||||||
|
return function (tree: any, vfile: VFile) {
|
||||||
|
const { frontmatter: injectedFrontmatter } = safelyGetAstroData(vfile.data);
|
||||||
|
const frontmatter = { ...injectedFrontmatter, ...pageFrontmatter };
|
||||||
|
const exportNodes = [
|
||||||
|
jsToTreeNode(`export const ${EXPORT_NAME} = ${JSON.stringify(frontmatter)};`),
|
||||||
|
];
|
||||||
|
if (frontmatter.layout) {
|
||||||
|
// NOTE(bholmesdev) 08-22-2022
|
||||||
|
// Using an async layout import (i.e. `const Layout = (await import...)`)
|
||||||
|
// Preserves the dev server import cache when globbing a large set of MDX files
|
||||||
|
// Full explanation: 'https://github.com/withastro/astro/pull/4428'
|
||||||
|
exportNodes.unshift(
|
||||||
|
jsToTreeNode(
|
||||||
|
/** @see 'vite-plugin-markdown' for layout props reference */
|
||||||
|
`import { jsx as layoutJsx } from 'astro/jsx-runtime';
|
||||||
|
|
||||||
|
export default async function ({ children }) {
|
||||||
|
const Layout = (await import(${JSON.stringify(frontmatter.layout)})).default;
|
||||||
|
const { layout, ...content } = frontmatter;
|
||||||
|
content.file = file;
|
||||||
|
content.url = url;
|
||||||
|
content.astro = {};
|
||||||
|
Object.defineProperty(content.astro, 'headings', {
|
||||||
|
get() {
|
||||||
|
throw new Error('The "astro" property is no longer supported! To access "headings" from your layout, try using "Astro.props.headings."')
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Object.defineProperty(content.astro, 'html', {
|
||||||
|
get() {
|
||||||
|
throw new Error('The "astro" property is no longer supported! To access "html" from your layout, try using "Astro.props.compiledContent()."')
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Object.defineProperty(content.astro, 'source', {
|
||||||
|
get() {
|
||||||
|
throw new Error('The "astro" property is no longer supported! To access "source" from your layout, try using "Astro.props.rawContent()."')
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return layoutJsx(Layout, {
|
||||||
|
file,
|
||||||
|
url,
|
||||||
|
content,
|
||||||
|
frontmatter: content,
|
||||||
|
headings: getHeadings(),
|
||||||
|
'server:root': true,
|
||||||
|
children,
|
||||||
|
});
|
||||||
|
};`
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
tree.children = exportNodes.concat(tree.children);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const DEFAULT_REMARK_PLUGINS: PluggableList = [remarkGfm, remarkSmartypants];
|
||||||
|
const DEFAULT_REHYPE_PLUGINS: PluggableList = [];
|
||||||
|
|
||||||
|
export async function getRemarkPlugins(
|
||||||
|
mdxOptions: MdxOptions,
|
||||||
|
config: AstroConfig
|
||||||
|
): Promise<MdxRollupPluginOptions['remarkPlugins']> {
|
||||||
|
let remarkPlugins: PluggableList = [
|
||||||
|
// Set "vfile.data.astro" for plugins to inject frontmatter
|
||||||
|
remarkInitializeAstroData,
|
||||||
|
];
|
||||||
|
switch (mdxOptions.extendPlugins) {
|
||||||
|
case false:
|
||||||
|
break;
|
||||||
|
case 'astroDefaults':
|
||||||
|
remarkPlugins = [...remarkPlugins, ...DEFAULT_REMARK_PLUGINS];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
remarkPlugins = [
|
||||||
|
...remarkPlugins,
|
||||||
|
...(markdownShouldExtendDefaultPlugins(config) ? DEFAULT_REMARK_PLUGINS : []),
|
||||||
|
...ignoreStringPlugins(config.markdown.remarkPlugins ?? []),
|
||||||
|
];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (config.markdown.syntaxHighlight === 'shiki') {
|
||||||
|
remarkPlugins.push([await remarkShiki(config.markdown.shikiConfig)]);
|
||||||
|
}
|
||||||
|
if (config.markdown.syntaxHighlight === 'prism') {
|
||||||
|
remarkPlugins.push(remarkPrism);
|
||||||
|
}
|
||||||
|
|
||||||
|
remarkPlugins = [...remarkPlugins, ...(mdxOptions.remarkPlugins ?? [])];
|
||||||
|
return remarkPlugins;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getRehypePlugins(
|
||||||
|
mdxOptions: MdxOptions,
|
||||||
|
config: AstroConfig
|
||||||
|
): MdxRollupPluginOptions['rehypePlugins'] {
|
||||||
|
let rehypePlugins: PluggableList = [
|
||||||
|
// getHeadings() is guaranteed by TS, so we can't allow user to override
|
||||||
|
rehypeCollectHeadings,
|
||||||
|
// rehypeRaw allows custom syntax highlighters to work without added config
|
||||||
|
[rehypeRaw, { passThrough: nodeTypes }] as any,
|
||||||
|
];
|
||||||
|
switch (mdxOptions.extendPlugins) {
|
||||||
|
case false:
|
||||||
|
break;
|
||||||
|
case 'astroDefaults':
|
||||||
|
rehypePlugins = [...rehypePlugins, ...DEFAULT_REHYPE_PLUGINS];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
rehypePlugins = [
|
||||||
|
...rehypePlugins,
|
||||||
|
...(markdownShouldExtendDefaultPlugins(config) ? DEFAULT_REHYPE_PLUGINS : []),
|
||||||
|
...ignoreStringPlugins(config.markdown.rehypePlugins ?? []),
|
||||||
|
];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
rehypePlugins = [...rehypePlugins, ...(mdxOptions.rehypePlugins ?? [])];
|
||||||
|
return rehypePlugins;
|
||||||
|
}
|
||||||
|
|
||||||
|
function markdownShouldExtendDefaultPlugins(config: AstroConfig): boolean {
|
||||||
|
return (
|
||||||
|
config.markdown.extendDefaultPlugins ||
|
||||||
|
(config.markdown.remarkPlugins.length === 0 && config.markdown.rehypePlugins.length === 0)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ignoreStringPlugins(plugins: any[]) {
|
||||||
|
let validPlugins: PluggableList = [];
|
||||||
|
let hasInvalidPlugin = false;
|
||||||
|
for (const plugin of plugins) {
|
||||||
|
if (typeof plugin === 'string') {
|
||||||
|
console.warn(yellow(`[MDX] ${bold(plugin)} not applied.`));
|
||||||
|
hasInvalidPlugin = true;
|
||||||
|
} else if (Array.isArray(plugin) && typeof plugin[0] === 'string') {
|
||||||
|
console.warn(yellow(`[MDX] ${bold(plugin[0])} not applied.`));
|
||||||
|
hasInvalidPlugin = true;
|
||||||
|
} else {
|
||||||
|
validPlugins.push(plugin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hasInvalidPlugin) {
|
||||||
|
console.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copied from markdown utils
|
||||||
|
* @see "vite-plugin-utils"
|
||||||
|
*/
|
||||||
|
function isValidAstroData(obj: unknown): obj is MarkdownAstroData {
|
||||||
|
if (typeof obj === 'object' && obj !== null && obj.hasOwnProperty('frontmatter')) {
|
||||||
|
const { frontmatter } = obj as any;
|
||||||
|
try {
|
||||||
|
// ensure frontmatter is JSON-serializable
|
||||||
|
JSON.stringify(frontmatter);
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return typeof frontmatter === 'object' && frontmatter !== null;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copied from markdown utils
|
||||||
|
* @see "vite-plugin-utils"
|
||||||
|
*/
|
||||||
|
function safelyGetAstroData(vfileData: Data): MarkdownAstroData {
|
||||||
|
const { astro } = vfileData;
|
||||||
|
|
||||||
|
if (!astro) return { frontmatter: {} };
|
||||||
|
if (!isValidAstroData(astro)) {
|
||||||
|
throw Error(
|
||||||
|
`[MDX] A remark or rehype plugin tried to add invalid frontmatter. Ensure "astro.frontmatter" is a JSON object!`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return astro;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if estree entry is "import.meta.env.VARIABLE"
|
||||||
|
* If it is, return the variable name (i.e. "VARIABLE")
|
||||||
|
*/
|
||||||
|
function getImportMetaEnvVariableName(node: MemberExpression): string | Error {
|
||||||
|
try {
|
||||||
|
// check for ".[ANYTHING]"
|
||||||
|
if (node.object.type !== 'MemberExpression' || node.property.type !== 'Identifier')
|
||||||
|
return new Error();
|
||||||
|
|
||||||
|
const nestedExpression = node.object;
|
||||||
|
// check for ".env"
|
||||||
|
if (nestedExpression.property.type !== 'Identifier' || nestedExpression.property.name !== 'env')
|
||||||
|
return new Error();
|
||||||
|
|
||||||
|
const envExpression = nestedExpression.object;
|
||||||
|
// check for ".meta"
|
||||||
|
if (
|
||||||
|
envExpression.type !== 'MetaProperty' ||
|
||||||
|
envExpression.property.type !== 'Identifier' ||
|
||||||
|
envExpression.property.name !== 'meta'
|
||||||
|
)
|
||||||
|
return new Error();
|
||||||
|
|
||||||
|
// check for "import"
|
||||||
|
if (envExpression.meta.name !== 'import') return new Error();
|
||||||
|
|
||||||
|
return node.property.name;
|
||||||
|
} catch (e) {
|
||||||
|
if (e instanceof Error) {
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
return new Error('Unknown parsing error');
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,32 +1,8 @@
|
||||||
import { nodeTypes } from '@mdx-js/mdx';
|
|
||||||
import type { PluggableList } from '@mdx-js/mdx/lib/core.js';
|
|
||||||
import type { Options as MdxRollupPluginOptions } from '@mdx-js/rollup';
|
|
||||||
import type { Options as AcornOpts } from 'acorn';
|
import type { Options as AcornOpts } from 'acorn';
|
||||||
import { parse } from 'acorn';
|
import { parse } from 'acorn';
|
||||||
import type { AstroConfig, SSRError } from 'astro';
|
import type { AstroConfig, SSRError } from 'astro';
|
||||||
import matter from 'gray-matter';
|
import matter from 'gray-matter';
|
||||||
import { bold, yellow } from 'kleur/colors';
|
|
||||||
import type { MdxjsEsm } from 'mdast-util-mdx';
|
import type { MdxjsEsm } from 'mdast-util-mdx';
|
||||||
import rehypeRaw from 'rehype-raw';
|
|
||||||
import remarkGfm from 'remark-gfm';
|
|
||||||
import remarkSmartypants from 'remark-smartypants';
|
|
||||||
import { remarkInitializeAstroData } from './astro-data-utils.js';
|
|
||||||
import rehypeCollectHeadings from './rehype-collect-headings.js';
|
|
||||||
import remarkPrism from './remark-prism.js';
|
|
||||||
import remarkShiki from './remark-shiki.js';
|
|
||||||
|
|
||||||
export type MdxOptions = {
|
|
||||||
remarkPlugins?: PluggableList;
|
|
||||||
rehypePlugins?: PluggableList;
|
|
||||||
/**
|
|
||||||
* Choose which remark and rehype plugins to inherit, if any.
|
|
||||||
*
|
|
||||||
* - "markdown" (default) - inherit your project’s markdown plugin config ([see Markdown docs](https://docs.astro.build/en/guides/markdown-content/#configuring-markdown))
|
|
||||||
* - "astroDefaults" - inherit Astro’s default plugins only ([see defaults](https://docs.astro.build/en/reference/configuration-reference/#markdownextenddefaultplugins))
|
|
||||||
* - false - do not inherit any plugins
|
|
||||||
*/
|
|
||||||
extendPlugins?: 'markdown' | 'astroDefaults' | false;
|
|
||||||
};
|
|
||||||
|
|
||||||
function appendForwardSlash(path: string) {
|
function appendForwardSlash(path: string) {
|
||||||
return path.endsWith('/') ? path : path + '/';
|
return path.endsWith('/') ? path : path + '/';
|
||||||
|
@ -37,9 +13,6 @@ interface FileInfo {
|
||||||
fileUrl: string;
|
fileUrl: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const DEFAULT_REMARK_PLUGINS: PluggableList = [remarkGfm, remarkSmartypants];
|
|
||||||
const DEFAULT_REHYPE_PLUGINS: PluggableList = [];
|
|
||||||
|
|
||||||
/** @see 'vite-plugin-utils' for source */
|
/** @see 'vite-plugin-utils' for source */
|
||||||
export function getFileInfo(id: string, config: AstroConfig): FileInfo {
|
export function getFileInfo(id: string, config: AstroConfig): FileInfo {
|
||||||
const sitePathname = appendForwardSlash(
|
const sitePathname = appendForwardSlash(
|
||||||
|
@ -110,97 +83,6 @@ export function jsToTreeNode(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getRemarkPlugins(
|
|
||||||
mdxOptions: MdxOptions,
|
|
||||||
config: AstroConfig
|
|
||||||
): Promise<MdxRollupPluginOptions['remarkPlugins']> {
|
|
||||||
let remarkPlugins: PluggableList = [
|
|
||||||
// Set "vfile.data.astro" for plugins to inject frontmatter
|
|
||||||
remarkInitializeAstroData,
|
|
||||||
];
|
|
||||||
switch (mdxOptions.extendPlugins) {
|
|
||||||
case false:
|
|
||||||
break;
|
|
||||||
case 'astroDefaults':
|
|
||||||
remarkPlugins = [...remarkPlugins, ...DEFAULT_REMARK_PLUGINS];
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
remarkPlugins = [
|
|
||||||
...remarkPlugins,
|
|
||||||
...(markdownShouldExtendDefaultPlugins(config) ? DEFAULT_REMARK_PLUGINS : []),
|
|
||||||
...ignoreStringPlugins(config.markdown.remarkPlugins ?? []),
|
|
||||||
];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (config.markdown.syntaxHighlight === 'shiki') {
|
|
||||||
remarkPlugins.push([await remarkShiki(config.markdown.shikiConfig)]);
|
|
||||||
}
|
|
||||||
if (config.markdown.syntaxHighlight === 'prism') {
|
|
||||||
remarkPlugins.push(remarkPrism);
|
|
||||||
}
|
|
||||||
|
|
||||||
remarkPlugins = [...remarkPlugins, ...(mdxOptions.remarkPlugins ?? [])];
|
|
||||||
return remarkPlugins;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getRehypePlugins(
|
|
||||||
mdxOptions: MdxOptions,
|
|
||||||
config: AstroConfig
|
|
||||||
): MdxRollupPluginOptions['rehypePlugins'] {
|
|
||||||
let rehypePlugins: PluggableList = [
|
|
||||||
// getHeadings() is guaranteed by TS, so we can't allow user to override
|
|
||||||
rehypeCollectHeadings,
|
|
||||||
// rehypeRaw allows custom syntax highlighters to work without added config
|
|
||||||
[rehypeRaw, { passThrough: nodeTypes }] as any,
|
|
||||||
];
|
|
||||||
switch (mdxOptions.extendPlugins) {
|
|
||||||
case false:
|
|
||||||
break;
|
|
||||||
case 'astroDefaults':
|
|
||||||
rehypePlugins = [...rehypePlugins, ...DEFAULT_REHYPE_PLUGINS];
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
rehypePlugins = [
|
|
||||||
...rehypePlugins,
|
|
||||||
...(markdownShouldExtendDefaultPlugins(config) ? DEFAULT_REHYPE_PLUGINS : []),
|
|
||||||
...ignoreStringPlugins(config.markdown.rehypePlugins ?? []),
|
|
||||||
];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
rehypePlugins = [...rehypePlugins, ...(mdxOptions.rehypePlugins ?? [])];
|
|
||||||
return rehypePlugins;
|
|
||||||
}
|
|
||||||
|
|
||||||
function markdownShouldExtendDefaultPlugins(config: AstroConfig): boolean {
|
|
||||||
return (
|
|
||||||
config.markdown.extendDefaultPlugins ||
|
|
||||||
(config.markdown.remarkPlugins.length === 0 && config.markdown.rehypePlugins.length === 0)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function ignoreStringPlugins(plugins: any[]) {
|
|
||||||
let validPlugins: PluggableList = [];
|
|
||||||
let hasInvalidPlugin = false;
|
|
||||||
for (const plugin of plugins) {
|
|
||||||
if (typeof plugin === 'string') {
|
|
||||||
console.warn(yellow(`[MDX] ${bold(plugin)} not applied.`));
|
|
||||||
hasInvalidPlugin = true;
|
|
||||||
} else if (Array.isArray(plugin) && typeof plugin[0] === 'string') {
|
|
||||||
console.warn(yellow(`[MDX] ${bold(plugin[0])} not applied.`));
|
|
||||||
hasInvalidPlugin = true;
|
|
||||||
} else {
|
|
||||||
validPlugins.push(plugin);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (hasInvalidPlugin) {
|
|
||||||
console.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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: remove for 1.0
|
// TODO: remove for 1.0
|
||||||
export function handleExtendsNotSupported(pluginConfig: any) {
|
export function handleExtendsNotSupported(pluginConfig: any) {
|
||||||
if (
|
if (
|
||||||
|
|
9
packages/integrations/mdx/test/fixtures/mdx-vite-env-vars/astro.config.mjs
vendored
Normal file
9
packages/integrations/mdx/test/fixtures/mdx-vite-env-vars/astro.config.mjs
vendored
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
import mdx from '@astrojs/mdx';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
site: 'https://mdx-is-neat.com/',
|
||||||
|
markdown: {
|
||||||
|
syntaxHighlight: false,
|
||||||
|
},
|
||||||
|
integrations: [mdx()],
|
||||||
|
}
|
7
packages/integrations/mdx/test/fixtures/mdx-vite-env-vars/package.json
vendored
Normal file
7
packages/integrations/mdx/test/fixtures/mdx-vite-env-vars/package.json
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"name": "@test/mdx-env-variables",
|
||||||
|
"dependencies": {
|
||||||
|
"astro": "workspace:*",
|
||||||
|
"@astrojs/mdx": "workspace:*"
|
||||||
|
}
|
||||||
|
}
|
7
packages/integrations/mdx/test/fixtures/mdx-vite-env-vars/src/pages/frontmatter.json.js
vendored
Normal file
7
packages/integrations/mdx/test/fixtures/mdx-vite-env-vars/src/pages/frontmatter.json.js
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
import { frontmatter } from './vite-env-vars.mdx';
|
||||||
|
|
||||||
|
export function get() {
|
||||||
|
return {
|
||||||
|
body: JSON.stringify(frontmatter),
|
||||||
|
}
|
||||||
|
}
|
38
packages/integrations/mdx/test/fixtures/mdx-vite-env-vars/src/pages/vite-env-vars.mdx
vendored
Normal file
38
packages/integrations/mdx/test/fixtures/mdx-vite-env-vars/src/pages/vite-env-vars.mdx
vendored
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
---
|
||||||
|
title: Let's talk about my import.meta.env.SITE
|
||||||
|
---
|
||||||
|
|
||||||
|
export const modeWorks =
|
||||||
|
import.meta.env.MODE === 'production' ? 'MODE works' : 'MODE does not work!';
|
||||||
|
|
||||||
|
# About my import.meta.env.SITE
|
||||||
|
|
||||||
|
My `import.meta.env.SITE` is so cool, I can put env variables in code!
|
||||||
|
|
||||||
|
```js
|
||||||
|
const site = import.meta.env.SITE;
|
||||||
|
```
|
||||||
|
|
||||||
|
## But I can use import.meta.env properly too
|
||||||
|
|
||||||
|
<div data-env-site>
|
||||||
|
|
||||||
|
I can compute my site, for example: {new URL('/blog/cool-post', import.meta.env.SITE)}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div data-env-variable-exports>
|
||||||
|
|
||||||
|
I can also use `import.meta.env` in variable exports: {modeWorks}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
I can also use vars as HTML attributes:
|
||||||
|
|
||||||
|
<div
|
||||||
|
data-env-dump
|
||||||
|
data-env-prod={import.meta.env.PROD}
|
||||||
|
data-env-dev={import.meta.env.DEV}
|
||||||
|
data-env-base-url={import.meta.env.BASE_URL}
|
||||||
|
data-env-mode={import.meta.env.MODE}
|
||||||
|
></div>
|
58
packages/integrations/mdx/test/mdx-vite-env-vars.test.js
Normal file
58
packages/integrations/mdx/test/mdx-vite-env-vars.test.js
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
import { expect } from 'chai';
|
||||||
|
import { parseHTML } from 'linkedom';
|
||||||
|
import { loadFixture } from '../../../astro/test/test-utils.js';
|
||||||
|
|
||||||
|
describe('MDX - Vite env vars', () => {
|
||||||
|
let fixture;
|
||||||
|
before(async () => {
|
||||||
|
fixture = await loadFixture({
|
||||||
|
root: new URL('./fixtures/mdx-vite-env-vars/', import.meta.url),
|
||||||
|
});
|
||||||
|
await fixture.build();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Avoids transforming `import.meta.env` outside JSX expressions', async () => {
|
||||||
|
const html = await fixture.readFile('/vite-env-vars/index.html');
|
||||||
|
const { document } = parseHTML(html);
|
||||||
|
|
||||||
|
expect(document.querySelector('h1')?.innerHTML).to.contain('import.meta.env.SITE');
|
||||||
|
expect(document.querySelector('code')?.innerHTML).to.contain('import.meta.env.SITE');
|
||||||
|
expect(document.querySelector('pre')?.innerHTML).to.contain('import.meta.env.SITE');
|
||||||
|
});
|
||||||
|
it('Allows referencing `import.meta.env` in frontmatter', async () => {
|
||||||
|
const { title = '' } = JSON.parse(await fixture.readFile('/frontmatter.json'));
|
||||||
|
expect(title).to.contain('import.meta.env.SITE');
|
||||||
|
});
|
||||||
|
it('Transforms `import.meta.env` in {JSX expressions}', async () => {
|
||||||
|
const html = await fixture.readFile('/vite-env-vars/index.html');
|
||||||
|
const { document } = parseHTML(html);
|
||||||
|
|
||||||
|
expect(document.querySelector('[data-env-site]')?.innerHTML).to.contain(
|
||||||
|
'https://mdx-is-neat.com/blog/cool-post',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('Transforms `import.meta.env` in variable exports', async () => {
|
||||||
|
const html = await fixture.readFile('/vite-env-vars/index.html');
|
||||||
|
const { document } = parseHTML(html);
|
||||||
|
|
||||||
|
expect(document.querySelector('[data-env-variable-exports]')?.innerHTML).to.contain(
|
||||||
|
'MODE works',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('Transforms `import.meta.env` in HTML attributes', async () => {
|
||||||
|
const html = await fixture.readFile('/vite-env-vars/index.html');
|
||||||
|
const { document } = parseHTML(html);
|
||||||
|
|
||||||
|
const dataAttrDump = document.querySelector('[data-env-dump]');
|
||||||
|
expect(dataAttrDump).to.not.be.null;
|
||||||
|
|
||||||
|
expect(dataAttrDump.getAttribute('data-env-prod')).to.not.be.null;
|
||||||
|
expect(dataAttrDump.getAttribute('data-env-dev')).to.be.null;
|
||||||
|
expect(dataAttrDump.getAttribute('data-env-base-url')).to.equal(
|
||||||
|
'/',
|
||||||
|
);
|
||||||
|
expect(dataAttrDump.getAttribute('data-env-mode')).to.equal(
|
||||||
|
'production',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
|
@ -2440,6 +2440,7 @@ importers:
|
||||||
'@mdx-js/mdx': ^2.1.2
|
'@mdx-js/mdx': ^2.1.2
|
||||||
'@mdx-js/rollup': ^2.1.1
|
'@mdx-js/rollup': ^2.1.1
|
||||||
'@types/chai': ^4.3.1
|
'@types/chai': ^4.3.1
|
||||||
|
'@types/estree': ^1.0.0
|
||||||
'@types/mocha': ^9.1.1
|
'@types/mocha': ^9.1.1
|
||||||
'@types/yargs-parser': ^21.0.0
|
'@types/yargs-parser': ^21.0.0
|
||||||
acorn: ^8.8.0
|
acorn: ^8.8.0
|
||||||
|
@ -2447,6 +2448,7 @@ importers:
|
||||||
astro-scripts: workspace:*
|
astro-scripts: workspace:*
|
||||||
chai: ^4.3.6
|
chai: ^4.3.6
|
||||||
es-module-lexer: ^0.10.5
|
es-module-lexer: ^0.10.5
|
||||||
|
estree-util-visit: ^1.2.0
|
||||||
github-slugger: ^1.4.0
|
github-slugger: ^1.4.0
|
||||||
gray-matter: ^4.0.3
|
gray-matter: ^4.0.3
|
||||||
kleur: ^4.1.4
|
kleur: ^4.1.4
|
||||||
|
@ -2469,6 +2471,7 @@ importers:
|
||||||
'@mdx-js/rollup': 2.1.3
|
'@mdx-js/rollup': 2.1.3
|
||||||
acorn: 8.8.0
|
acorn: 8.8.0
|
||||||
es-module-lexer: 0.10.5
|
es-module-lexer: 0.10.5
|
||||||
|
estree-util-visit: 1.2.0
|
||||||
github-slugger: 1.4.0
|
github-slugger: 1.4.0
|
||||||
gray-matter: 4.0.3
|
gray-matter: 4.0.3
|
||||||
kleur: 4.1.5
|
kleur: 4.1.5
|
||||||
|
@ -2481,6 +2484,7 @@ importers:
|
||||||
vfile: 5.3.5
|
vfile: 5.3.5
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@types/chai': 4.3.3
|
'@types/chai': 4.3.3
|
||||||
|
'@types/estree': 1.0.0
|
||||||
'@types/mocha': 9.1.1
|
'@types/mocha': 9.1.1
|
||||||
'@types/yargs-parser': 21.0.0
|
'@types/yargs-parser': 21.0.0
|
||||||
astro: link:../../astro
|
astro: link:../../astro
|
||||||
|
@ -2535,6 +2539,14 @@ importers:
|
||||||
'@astrojs/react': link:../../../../react
|
'@astrojs/react': link:../../../../react
|
||||||
astro: link:../../../../../astro
|
astro: link:../../../../../astro
|
||||||
|
|
||||||
|
packages/integrations/mdx/test/fixtures/mdx-vite-env-vars:
|
||||||
|
specifiers:
|
||||||
|
'@astrojs/mdx': workspace:*
|
||||||
|
astro: workspace:*
|
||||||
|
dependencies:
|
||||||
|
'@astrojs/mdx': link:../../..
|
||||||
|
astro: link:../../../../../astro
|
||||||
|
|
||||||
packages/integrations/netlify:
|
packages/integrations/netlify:
|
||||||
specifiers:
|
specifiers:
|
||||||
'@astrojs/webapi': ^1.0.0
|
'@astrojs/webapi': ^1.0.0
|
||||||
|
@ -9062,7 +9074,6 @@ packages:
|
||||||
|
|
||||||
/@types/estree/1.0.0:
|
/@types/estree/1.0.0:
|
||||||
resolution: {integrity: sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==}
|
resolution: {integrity: sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==}
|
||||||
dev: false
|
|
||||||
|
|
||||||
/@types/extend/3.0.1:
|
/@types/extend/3.0.1:
|
||||||
resolution: {integrity: sha512-R1g/VyKFFI2HLC1QGAeTtCBWCo6n75l41OnsVYNbmKG+kempOESaodf6BeJyUM3Q0rKa/NQcTHbB2+66lNnxLw==}
|
resolution: {integrity: sha512-R1g/VyKFFI2HLC1QGAeTtCBWCo6n75l41OnsVYNbmKG+kempOESaodf6BeJyUM3Q0rKa/NQcTHbB2+66lNnxLw==}
|
||||||
|
|
Loading…
Reference in a new issue