Compare commits

...

3 commits

Author SHA1 Message Date
Nate Moore
2d4d6cbe7b chore: move jsx-runtime to astro 2022-06-17 12:44:22 -05:00
Nate Moore
6faef606d7 feat: first pass at MDX support 2022-06-17 10:25:11 -05:00
Nate Moore
dbe8d7e89d wip: add @astrojs/jsx package 2022-06-16 21:12:40 -05:00
56 changed files with 1170 additions and 26 deletions

19
examples/jsx/.gitignore vendored Normal file
View file

@ -0,0 +1,19 @@
# build output
dist/
# dependencies
node_modules/
# logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# environment variables
.env
.env.production
# macOS-specific files
.DS_Store

2
examples/jsx/.npmrc Normal file
View file

@ -0,0 +1,2 @@
# Expose Astro dependencies for `pnpm` users
shamefully-hoist=true

View file

@ -0,0 +1,6 @@
{
"startCommand": "npm start",
"env": {
"ENABLE_CJS_IMPORTS": true
}
}

4
examples/jsx/.vscode/extensions.json vendored Normal file
View file

@ -0,0 +1,4 @@
{
"recommendations": ["astro-build.astro-vscode"],
"unwantedRecommendations": []
}

11
examples/jsx/.vscode/launch.json vendored Normal file
View file

@ -0,0 +1,11 @@
{
"version": "0.2.0",
"configurations": [
{
"command": "./node_modules/.bin/astro dev",
"name": "Development server",
"request": "launch",
"type": "node-terminal"
}
]
}

43
examples/jsx/README.md Normal file
View file

@ -0,0 +1,43 @@
# Astro Starter Kit: Minimal
```
npm init astro -- --template minimal
```
[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/withastro/astro/tree/latest/examples/minimal)
> 🧑‍🚀 **Seasoned astronaut?** Delete this file. Have fun!
## 🚀 Project Structure
Inside of your Astro project, you'll see the following folders and files:
```
/
├── public/
├── src/
│ └── pages/
│ └── index.astro
└── package.json
```
Astro looks for `.astro` or `.md` files in the `src/pages/` directory. Each page is exposed as a route based on its file name.
There's nothing special about `src/components/`, but that's where we like to put any Astro/React/Vue/Svelte/Preact components.
Any static assets, like images, can be placed in the `public/` directory.
## 🧞 Commands
All commands are run from the root of the project, from a terminal:
| Command | Action |
|:---------------- |:-------------------------------------------- |
| `npm install` | Installs dependencies |
| `npm run dev` | Starts local dev server at `localhost:3000` |
| `npm run build` | Build your production site to `./dist/` |
| `npm run preview` | Preview your build locally, before deploying |
## 👀 Want to learn more?
Feel free to check [our documentation](https://docs.astro.build) or jump into our [Discord server](https://astro.build/chat).

View file

@ -0,0 +1,11 @@
import { defineConfig } from 'astro/config';
import preact from '@astrojs/preact';
import jsx from '@astrojs/jsx';
// https://astro.build/config
export default defineConfig({
integrations: [
jsx(),
preact(),
]
});

19
examples/jsx/package.json Normal file
View file

@ -0,0 +1,19 @@
{
"name": "@example/jsx",
"version": "0.0.1",
"private": true,
"scripts": {
"dev": "astro dev",
"start": "astro dev",
"build": "astro build",
"preview": "astro preview"
},
"devDependencies": {
"@astrojs/jsx": "^0.0.1",
"@astrojs/preact": "^0.1.3",
"astro": "^1.0.0-beta.47"
},
"dependencies": {
"preact": "^10.8.1"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View file

@ -0,0 +1,11 @@
{
"infiniteLoopProtection": true,
"hardReloadOnChange": false,
"view": "browser",
"template": "node",
"container": {
"port": 3000,
"startScript": "start",
"node": "14"
}
}

View file

@ -0,0 +1,18 @@
import { useState } from 'preact/hooks';
export default function Counter({ children }) {
const [count, setCount] = useState(0);
const add = () => setCount((i) => i + 1);
const subtract = () => setCount((i) => i - 1);
return (
<>
<div class="counter">
<button onClick={subtract}>-</button>
<pre>{count}</pre>
<button onClick={add}>+</button>
</div>
<div class="counter-message">{children}</div>
</>
);
}

View file

@ -0,0 +1,3 @@
.title {
color: red;
}

View file

@ -0,0 +1,31 @@
import Counter from '../components/Counter';
const Component = () => {
return <div>It works!</div>
}
export default async function Home() {
return (
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>Astro</title>
</head>
<body>
<h1>Astro</h1>
{/* <Counter client:load>
<div>
<h1>Hello!</h1> */}
<Component client:idle />
{/* <Counter client:load>
<h2>AHHHHHHHHHH</h2>
</Counter>
</div>
</Counter> */}
</body>
</html>
)
}

View file

@ -0,0 +1,15 @@
{
"compilerOptions": {
// Enable top-level await, and other modern ESM features.
"target": "ESNext",
"module": "ESNext",
// Enable node-style module resolution, for things like npm package imports.
"moduleResolution": "node",
// Enable JSON imports.
"resolveJsonModule": true,
// Enable stricter transpilation for better output.
"isolatedModules": true,
// Add type definitions for our Vite runtime.
"types": ["vite/client"]
}
}

19
examples/mdx/.gitignore vendored Normal file
View file

@ -0,0 +1,19 @@
# build output
dist/
# dependencies
node_modules/
# logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# environment variables
.env
.env.production
# macOS-specific files
.DS_Store

2
examples/mdx/.npmrc Normal file
View file

@ -0,0 +1,2 @@
# Expose Astro dependencies for `pnpm` users
shamefully-hoist=true

View file

@ -0,0 +1,6 @@
{
"startCommand": "npm start",
"env": {
"ENABLE_CJS_IMPORTS": true
}
}

4
examples/mdx/.vscode/extensions.json vendored Normal file
View file

@ -0,0 +1,4 @@
{
"recommendations": ["astro-build.astro-vscode"],
"unwantedRecommendations": []
}

11
examples/mdx/.vscode/launch.json vendored Normal file
View file

@ -0,0 +1,11 @@
{
"version": "0.2.0",
"configurations": [
{
"command": "./node_modules/.bin/astro dev",
"name": "Development server",
"request": "launch",
"type": "node-terminal"
}
]
}

43
examples/mdx/README.md Normal file
View file

@ -0,0 +1,43 @@
# Astro Starter Kit: Minimal
```
npm init astro -- --template minimal
```
[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/withastro/astro/tree/latest/examples/minimal)
> 🧑‍🚀 **Seasoned astronaut?** Delete this file. Have fun!
## 🚀 Project Structure
Inside of your Astro project, you'll see the following folders and files:
```
/
├── public/
├── src/
│ └── pages/
│ └── index.astro
└── package.json
```
Astro looks for `.astro` or `.md` files in the `src/pages/` directory. Each page is exposed as a route based on its file name.
There's nothing special about `src/components/`, but that's where we like to put any Astro/React/Vue/Svelte/Preact components.
Any static assets, like images, can be placed in the `public/` directory.
## 🧞 Commands
All commands are run from the root of the project, from a terminal:
| Command | Action |
|:---------------- |:-------------------------------------------- |
| `npm install` | Installs dependencies |
| `npm run dev` | Starts local dev server at `localhost:3000` |
| `npm run build` | Build your production site to `./dist/` |
| `npm run preview` | Preview your build locally, before deploying |
## 👀 Want to learn more?
Feel free to check [our documentation](https://docs.astro.build) or jump into our [Discord server](https://astro.build/chat).

View file

@ -0,0 +1,11 @@
import { defineConfig } from 'astro/config';
import mdx from '@astrojs/mdx';
import preact from '@astrojs/preact';
// https://astro.build/config
export default defineConfig({
integrations: [
mdx(),
preact()
]
});

17
examples/mdx/package.json Normal file
View file

@ -0,0 +1,17 @@
{
"name": "@example/mdx",
"version": "0.0.1",
"private": true,
"scripts": {
"dev": "astro dev",
"start": "astro dev",
"build": "astro build",
"preview": "astro preview"
},
"devDependencies": {
"astro": "^1.0.0-beta.47",
"@astrojs/preact": "^0.1.3",
"@astrojs/jsx": "^0.0.1",
"@astrojs/mdx": "^0.0.1"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View file

@ -0,0 +1,11 @@
{
"infiniteLoopProtection": true,
"hardReloadOnChange": false,
"view": "browser",
"template": "node",
"container": {
"port": 3000,
"startScript": "start",
"node": "14"
}
}

View file

@ -0,0 +1,18 @@
import { useState } from 'preact/hooks';
export default function Counter({ children }) {
const [count, setCount] = useState(0);
const add = () => setCount((i) => i + 1);
const subtract = () => setCount((i) => i - 1);
return (
<>
<div class="counter">
<button onClick={subtract}>-</button>
<pre>{count}</pre>
<button onClick={add}>+</button>
</div>
<div class="counter-message">{children}</div>
</>
);
}

View file

@ -0,0 +1,7 @@
---
console.log(Astro.props);
---
<h1 style={{ color: 'red', border: '1px solid green', borderColor: 'orange' }}>
<slot />
</h1>

View file

@ -0,0 +1,13 @@
export default ({ children }) => (
<html>
<head>
<title>Hello world!</title>
</head>
<body>
<article style={{ maxWidth: '480px', margin: '0 auto' }}>
{children}
</article>
</body>
</html>
)

View file

@ -0,0 +1,28 @@
import Heading from '../components/MyHeading.astro'
export const authors = [
{name: 'Jane', email: 'hi@jane.com'},
{name: 'John', twitter: '@john2002'}
]
export const published = new Date('2022-02-01')
export const components = { h1: Heading }
# Hello world!
Text that is not a quote
> Text that is a quote
Use `git status` to list all new or modified files that haven't yet been committed.
Some basic Git commands are:
```
git status
git add
git commit
```
This site was built using [GitHub Pages](https://pages.github.com/).
Written by: {new Intl.ListFormat('en').format(authors.map(d => d.name))}.
Published on: {new Intl.DateTimeFormat('en', {dateStyle: 'long'}).format(published)}.

View file

@ -0,0 +1,15 @@
{
"compilerOptions": {
// Enable top-level await, and other modern ESM features.
"target": "ESNext",
"module": "ESNext",
// Enable node-style module resolution, for things like npm package imports.
"moduleResolution": "node",
// Enable JSON imports.
"resolveJsonModule": true,
// Enable stricter transpilation for better output.
"isolatedModules": true,
// Add type definitions for our Vite runtime.
"types": ["vite/client"]
}
}

View file

@ -50,6 +50,7 @@
"pnpm": {
"peerDependencyRules": {
"ignoreMissing": [
"rollup",
"@babel/core",
"@babel/plugin-transform-react-jsx",
"vite"

View file

@ -20,6 +20,9 @@
],
"app/*": [
"./dist/types/core/app/*"
],
"server": [
"./dist/types/runtime/server/index"
]
}
},
@ -27,8 +30,8 @@
".": "./astro.js",
"./env": "./env.d.ts",
"./astro-jsx": "./astro-jsx.d.ts",
"./jsx-runtime": "./dist/jsx-runtime/index.js",
"./config": "./config.mjs",
"./internal": "./internal.js",
"./app": "./dist/core/app/index.js",
"./app/node": "./dist/core/app/node.js",
"./client/*": "./dist/runtime/client/*",
@ -38,6 +41,7 @@
"./internal/*": "./dist/runtime/server/*",
"./package.json": "./package.json",
"./runtime/*": "./dist/runtime/*",
"./server": "./dist/runtime/server/index.js",
"./server/*": "./dist/runtime/server/*",
"./vite-plugin-astro": "./dist/vite-plugin-astro/index.js",
"./vite-plugin-astro/*": "./dist/vite-plugin-astro/*",

View file

@ -729,6 +729,7 @@ export interface AstroConfig extends z.output<typeof AstroConfigSchema> {
injectedRoutes: InjectedRoute[];
adapter: AstroAdapter | undefined;
renderers: AstroRenderer[];
pageExtensions: string[];
scripts: { stage: InjectedScriptStage; content: string }[];
};
}
@ -932,6 +933,7 @@ export interface AstroIntegration {
command: 'dev' | 'build';
updateConfig: (newConfig: Record<string, any>) => void;
addRenderer: (renderer: AstroRenderer) => void;
addPageExtensions: (extensions: string|string[]) => void;
injectScript: (stage: InjectedScriptStage, content: string) => void;
injectRoute: (injectRoute: InjectedRoute) => void;
// TODO: Add support for `injectElement()` for full HTML element injection, not just scripts.

View file

@ -338,7 +338,7 @@ export async function validateConfig(
// First-Pass Validation
const result = {
...(await AstroConfigRelativeSchema.parseAsync(userConfig)),
_ctx: { scripts: [], renderers: [], injectedRoutes: [], adapter: undefined },
_ctx: { pageExtensions: [], scripts: [], renderers: [], injectedRoutes: [], adapter: undefined },
};
// Final-Pass Validation (perform checks that require the full config object)
if (

View file

@ -124,9 +124,25 @@ export async function createVite(
let result = commonConfig;
result = vite.mergeConfig(result, astroConfig.vite || {});
result = vite.mergeConfig(result, commandConfig);
sortPlugins(result);
return result;
}
function getPluginName(plugin: vite.PluginOption) {
if (plugin && typeof plugin === 'object' && !Array.isArray(plugin)) {
return plugin.name;
}
}
function sortPlugins(result: ViteConfigWithSSR) {
// HACK: move mdxPlugin to top because it needs to run before internal JSX plugin
const jsxPluginIndex = result.plugins?.findIndex(plugin => getPluginName(plugin) === 'astro:jsx') ?? -1;
const mdxPluginIndex = result.plugins?.findIndex(plugin => getPluginName(plugin) === '@mdx-js/rollup') ?? -1;
const mdxPlugin = result.plugins?.[mdxPluginIndex];
result.plugins?.splice(mdxPluginIndex, 1);
result.plugins?.splice(jsxPluginIndex, 0, mdxPlugin);
}
// Scans `projectRoot` for third-party Astro packages that could export an `.astro` file
// `.astro` files need to be built by Vite, so these should use `noExternal`
async function getAstroPackages({ root }: AstroConfig): Promise<string[]> {

View file

@ -9,7 +9,7 @@ import type {
} from '../../@types/astro';
import type { LogOptions } from '../logger/core.js';
import { renderHead, renderPage } from '../../runtime/server/index.js';
import { renderHead, renderPage, renderComponent, replaceHeadInjection } from '../../runtime/server/index.js';
import { getParams } from '../routing/params.js';
import { createResult } from './result.js';
import { callGetStaticPaths, findPathItemByKey, RouteCache } from './route-cache.js';
@ -126,8 +126,6 @@ export async function render(
const Component = await mod.default;
if (!Component)
throw new Error(`Expected an exported Astro component but received typeof ${typeof Component}`);
if (!Component.isAstroComponentFactory)
throw new Error(`Unable to SSR non-Astro component (${route?.component})`);
const result = createResult({
links,
@ -146,7 +144,27 @@ export async function render(
ssr,
});
let page = await renderPage(result, Component, pageProps, null);
let page: Awaited<ReturnType<typeof renderPage>>;
if (!Component.isAstroComponentFactory) {
const props: Record<string, any> = { ...(pageProps ?? {}), 'server:root': true };
if (route?.component.endsWith('.mdx')) {
props['components'] = new Proxy({ ...((mod as any).components ?? {}) }, {
get(target, prop, receiver) {
if (!Reflect.has(target, prop)) return undefined;
const value = Reflect.get(target, prop, receiver);
return value;
}
});
}
const template = await renderComponent(result, Component.name, Component, props, null);
const html = await replaceHeadInjection(result, template);
page = {
type: 'html',
html: html.toString()
}
} else {
page = await renderPage(result, Component, pageProps, null);
}
if (page.type === 'response') {
return page;

View file

@ -93,6 +93,16 @@ export async function preload({
return [renderers, mod];
}
function isPage(filePath: URL, astroConfig: AstroConfig): boolean {
const relativeURL = filePath.toString().replace(astroConfig.srcDir.toString().slice(0, -1), '');
if (!relativeURL.startsWith('/pages/')) return false;
const ext = '.' + relativeURL.split('.').at(-1);
for (const _ext of astroConfig._ctx.pageExtensions) {
if (ext === _ext) return true;
}
return false;
}
/** use Vite to SSR */
export async function render(
renderers: SSRLoadedRenderer[],
@ -117,7 +127,7 @@ export async function render(
);
// Inject HMR scripts
if (mod.hasOwnProperty('$$metadata') && mode === 'development') {
if (isPage(filePath, astroConfig) && mode === 'development') {
scripts.add({
props: { type: 'module', src: '/@vite/client' },
children: '',

View file

@ -165,7 +165,7 @@ export function createRouteManifest(
): ManifestData {
const components: string[] = [];
const routes: RouteData[] = [];
const validPageExtensions: Set<string> = new Set(['.astro', '.md']);
const validPageExtensions: Set<string> = new Set(['.astro', '.md', ...config._ctx.pageExtensions]);
const validEndpointExtensions: Set<string> = new Set(['.js', '.ts']);
function walk(dir: string, parentSegments: RoutePart[][], parentParams: string[]) {

View file

@ -40,6 +40,10 @@ export async function runHookConfigSetup({
addRenderer(renderer: AstroRenderer) {
updatedConfig._ctx.renderers.push(renderer);
},
addPageExtensions: (exts: string|string[]) => {
const ext = Array.isArray(exts) ? exts : [exts];
updatedConfig._ctx.pageExtensions.push(...ext);
},
injectScript: (stage, content) => {
updatedConfig._ctx.scripts.push({ stage, content });
},

View file

@ -0,0 +1,20 @@
import { Fragment } from '../runtime/server/index.js';
const AstroJSX = Symbol('@astrojs/jsx');
function createVNode(type: any, props: Record<string, any>) {
const vnode = {
[AstroJSX]: true,
type,
props: props ?? {},
};
return vnode;
}
export {
AstroJSX,
createVNode as jsx,
createVNode as jsxs,
createVNode as jsxDEV,
Fragment
}

View file

@ -1,6 +1,18 @@
if (import.meta.hot) {
import.meta.hot.accept((mod) => mod);
const parser = new DOMParser();
function isPage(path: string) {
if (!path.includes('/pages/')) return false;
const parts = path.split('/pages/').slice(1);
let isPrivate = false;
for (const part of parts) {
if (part.startsWith('_')) {
isPrivate = true;
break;
}
}
return !isPrivate;
}
async function updatePage() {
const { default: diff } = await import('micromorph');
const html = await fetch(`${window.location}`).then((res) => res.text());
@ -35,11 +47,11 @@ if (import.meta.hot) {
});
}
async function updateAll(files: any[]) {
let hasAstroUpdate = false;
let hasPageUpdate = false;
let styles = [];
for (const file of files) {
if (file.acceptedPath.endsWith('.astro')) {
hasAstroUpdate = true;
if (isPage(file.acceptedPath)) {
hasPageUpdate = true;
continue;
}
if (file.acceptedPath.includes('svelte&type=style')) {
@ -72,7 +84,7 @@ if (import.meta.hot) {
updateStyle(id, content);
}
}
if (hasAstroUpdate) {
if (hasPageUpdate) {
return await updatePage();
}
}

View file

@ -11,6 +11,7 @@ import { serializeListValue } from './util.js';
const HydrationDirectives = ['load', 'idle', 'media', 'visible', 'only'];
interface ExtractedProps {
isPage: boolean,
hydration: {
directive: string;
value: string;
@ -24,10 +25,14 @@ interface ExtractedProps {
// Finds these special props and removes them from what gets passed into the component.
export function extractDirectives(inputProps: Record<string | number, any>): ExtractedProps {
let extracted: ExtractedProps = {
isPage: false,
hydration: null,
props: {},
};
for (const [key, value] of Object.entries(inputProps)) {
if (key.startsWith('server:')) {
extracted.isPage = true;
}
if (key.startsWith('client:')) {
if (!extracted.hydration) {
extracted.hydration = {

View file

@ -21,11 +21,11 @@ import { serializeProps } from './serialize.js';
import { shorthash } from './shorthash.js';
import { serializeListValue } from './util.js';
export { markHTMLString, markHTMLString as unescapeHTML } from './escape.js';
export { escapeHTML, markHTMLString, markHTMLString as unescapeHTML, HTMLString } from './escape.js';
export type { Metadata } from './metadata';
export { createMetadata } from './metadata.js';
const voidElementNames =
export const voidElementNames =
/^(area|base|br|col|command|embed|hr|img|input|keygen|link|meta|param|source|track|wbr)$/i;
const htmlBooleanAttributes =
/^(allowfullscreen|async|autofocus|autoplay|controls|default|defer|disabled|disablepictureinpicture|disableremoteplayback|formnovalidate|hidden|loop|nomodule|novalidate|open|playsinline|readonly|required|reversed|scoped|seamless|itemscope)$/i;
@ -40,7 +40,7 @@ const svgEnumAttributes = /^(autoReverse|externalResourcesRequired|focusable|pre
// INVESTIGATE: Can we have more specific types both for the argument and output?
// If these are intentional, add comments that these are intention and why.
// Or maybe type UserValue = any; ?
async function _render(child: any): Promise<any> {
export async function _render(child: any): Promise<any> {
child = await child;
if (child instanceof HTMLString) {
return child;
@ -181,7 +181,7 @@ export async function renderComponent(
const { renderers } = result._metadata;
const metadata: AstroComponentMetadata = { displayName };
const { hydration, props } = extractDirectives(_props);
const { hydration, isPage, props } = extractDirectives(_props);
let html = '';
let needsHydrationScript = hydration && determineIfNeedsHydrationScript(result);
let needsDirectiveScript =
@ -215,7 +215,7 @@ Did you mean to add ${formatList(probableRendererNames.map((r) => '`' + r + '`')
let error;
for (const r of renderers) {
try {
if (await r.ssr.check(Component, props, children)) {
if (await r.ssr.check.call({ result }, Component, props, children)) {
renderer = r;
break;
}
@ -281,7 +281,7 @@ Did you mean to enable ${formatList(probableRendererNames.map((r) => '`' + r + '
// We already know that renderer.ssr.check() has failed
// but this will throw a much more descriptive error!
renderer = matchingRenderers[0];
({ html } = await renderer.ssr.renderToStaticMarkup(Component, props, children, metadata));
({ html } = await renderer.ssr.renderToStaticMarkup.call({ result }, Component, props, children, metadata));
} else {
throw new Error(`Unable to render ${metadata.displayName}!
@ -300,7 +300,7 @@ If you're still stuck, please open an issue on GitHub or join us at https://astr
if (metadata.hydrate === 'only') {
html = await renderSlot(result, slots?.fallback);
} else {
({ html } = await renderer.ssr.renderToStaticMarkup(Component, props, children, metadata));
({ html } = await renderer.ssr.renderToStaticMarkup.call({ result }, Component, props, children, metadata));
}
}
@ -317,6 +317,9 @@ If you're still stuck, please open an issue on GitHub or join us at https://astr
}
if (!hydration) {
if (isPage) {
return html;
}
return markHTMLString(html.replace(/\<\/?astro-fragment\>/g, ''));
}
@ -407,6 +410,9 @@ const toAttributeString = (value: any, shouldEscape = true) =>
const STATIC_DIRECTIVES = new Set(['set:html', 'set:text']);
const kebab = (k: string) => k.toLowerCase() === k ? k : k.replace(/[A-Z]/g, match => `-${match.toLowerCase()}`);
const toStyleString = (obj: Record<string, any>) => Object.entries(obj).map(([k, v]) => `${kebab(k)}:${v}`).join(';')
// A helper used to turn expressions into attribute key/value
export function addAttribute(value: any, key: string, shouldEscape = true) {
if (value == null) {
@ -434,6 +440,10 @@ Make sure to use the static attribute syntax (\`${key}={value}\`) instead of the
return markHTMLString(` ${key.slice(0, -5)}="${toAttributeString(serializeListValue(value))}"`);
}
if (key === 'style' && typeof value === 'object') {
return markHTMLString(` ${key}="${toStyleString(value)}"`);
}
// Boolean values only need the key
if (value === true && (key.startsWith('data-') || htmlBooleanAttributes.test(key))) {
return markHTMLString(` ${key}`);
@ -454,7 +464,7 @@ function internalSpreadAttributes(values: Record<any, any>, shouldEscape = true)
// Adds support for `<Component {...value} />
export function spreadAttributes(
values: Record<any, any>,
name: string,
name?: string,
{ class: scopedClassName }: { class?: string } = {}
) {
let output = '';
@ -560,7 +570,7 @@ Update your code to remove this warning.`);
return handler.call(mod, proxy, request);
}
async function replaceHeadInjection(result: SSRResult, html: string): Promise<string> {
export async function replaceHeadInjection(result: SSRResult, html: string): Promise<string> {
let template = html;
// <!--astro:head--> injected by compiler
// Must be handled at the end of the rendering process

View file

@ -0,0 +1,41 @@
import { HTMLString, markHTMLString, escapeHTML, Fragment, renderComponent, spreadAttributes, voidElementNames } from './index.js';
import { jsx, AstroJSX } from '../../jsx-runtime/index.js';
export async function renderJSX(result: any, vnode: any): Promise<any> {
switch (true) {
case (vnode instanceof HTMLString): return vnode;
case (typeof vnode === 'string'): return markHTMLString(escapeHTML(vnode));
case (!vnode && vnode !== 0): return '';
case (vnode.type === Fragment): return renderJSX(result, vnode.props.children);
case (Array.isArray(vnode)): return markHTMLString((await Promise.all(vnode.map((v: any) => renderJSX(result, v)))).join(''));
}
if (vnode[AstroJSX]) {
if (!vnode.type && vnode.type !== 0) return '';
if (typeof vnode.type === 'string') {
return await renderElement(result, vnode.type, vnode.props ?? {});
}
if (typeof vnode.type === 'function') {
try {
const output = await vnode.type(vnode.props ?? {});
return await renderJSX(result, output);
} catch (e) {}
const { children = null, ...props } = vnode.props ?? {};
const slots: Record<string, any> = {}
if (children) {
slots.default = () => renderJSX(result, jsx(Fragment, { children }))
}
return markHTMLString(await renderComponent(result, vnode.type.name, vnode.type, props, slots));
}
}
// numbers, plain objects, etc
return markHTMLString(`${vnode}`);
}
async function renderElement(result: any, tag: string, { children, ...props }: Record<string, any>) {
return markHTMLString(`<${tag}${spreadAttributes(props)}${markHTMLString(
(children == null || children == '') && voidElementNames.test(tag)
? `/>`
: `>${children == null ? '' : await renderJSX(result, children)}${tag === 'head' ? '<!--astro:head-->' : ''}</${tag}>`
)}`);
}

View file

@ -12,11 +12,12 @@ import { error } from '../core/logger/core.js';
import { parseNpmName } from '../core/util.js';
const JSX_RENDERER_CACHE = new WeakMap<AstroConfig, Map<string, AstroRenderer>>();
const JSX_EXTENSIONS = new Set(['.jsx', '.tsx']);
const JSX_EXTENSIONS = new Set(['.jsx', '.tsx', '.mdx']);
const IMPORT_STATEMENTS: Record<string, string> = {
react: "import React from 'react'",
preact: "import { h } from 'preact'",
'solid-js': "import 'solid-js/web'",
astro: "import 'astro'",
};
// A code snippet to inject into JS files to prevent esbuild reference bugs.
@ -25,6 +26,7 @@ const IMPORT_STATEMENTS: Record<string, string> = {
const PREVENT_UNUSED_IMPORTS = ';;(React,Fragment,h);';
function getEsbuildLoader(fileExt: string): string {
if (fileExt === '.mdx') return 'jsx';
return fileExt.slice(1);
}
@ -165,16 +167,20 @@ export default function jsx({ config, logging }: AstroPluginJSXOptions): Plugin
// if no imports were found, look for @jsxImportSource comment
if (!importSource) {
const multiline = code.match(/\/\*\*[\S\s]*\*\//gm) || [];
const multiline = code.match(/\/\*\*?[\S\s]*\*\//gm) || [];
for (const comment of multiline) {
const [_, lib] = comment.match(/@jsxImportSource\s*(\S+)/) || [];
const [_, lib] = comment.slice(0, -2).match(/@jsxImportSource\s*(\S+)$/) || [];
if (lib) {
importSource = lib;
importSource = lib.trim();
break;
}
}
}
if (!importSource && jsxRenderers.has('astro')) {
importSource = 'astro';
}
// if JSX renderer found, then use that
if (importSource) {
const jsxRenderer = jsxRenderers.get(importSource);

View file

@ -0,0 +1,43 @@
{
"name": "@astrojs/jsx",
"description": "Use generic JSX components within Astro",
"version": "0.0.1",
"type": "module",
"types": "./dist/index.d.ts",
"author": "withastro",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/withastro/astro.git",
"directory": "packages/integrations/jsx"
},
"keywords": [
"astro-component",
"renderer",
"jsx"
],
"bugs": "https://github.com/withastro/astro/issues",
"homepage": "https://astro.build",
"exports": {
".": "./dist/index.js",
"./babel": "./dist/babel/index.js",
"./client.js": "./dist/client.js",
"./server.js": "./dist/server.js",
"./package.json": "./package.json"
},
"scripts": {
"build": "astro-scripts build \"src/**/*.ts\" && tsc",
"build:ci": "astro-scripts build \"src/**/*.ts\"",
"dev": "astro-scripts dev \"src/**/*.ts\""
},
"dependencies": {
"astro": "workspace:*",
"@babel/plugin-transform-react-jsx": "^7.17.3"
},
"devDependencies": {
"astro-scripts": "workspace:*"
},
"engines": {
"node": "^14.15.0 || >=16.0.0"
}
}

View file

@ -0,0 +1,119 @@
import * as t from "@babel/types";
import type { PluginObj } from '@babel/core';
function isComponent(tagName: string) {
return (
(tagName[0] && tagName[0].toLowerCase() !== tagName[0]) ||
tagName.includes(".") ||
/[^a-zA-Z]/.test(tagName[0])
);
}
function hasClientDirective(node: t.JSXElement) {
for (const attr of node.openingElement.attributes) {
if (attr.type === 'JSXAttribute' && attr.name.type === 'JSXNamespacedName') {
return attr.name.namespace.name === 'client'
}
}
return false;
}
function getTagName(tag: t.JSXElement) {
const jsxName = tag.openingElement.name;
return jsxElementNameToString(jsxName);
}
function jsxElementNameToString(node: t.JSXOpeningElement['name']): string {
if (t.isJSXMemberExpression(node)) {
return `${jsxElementNameToString(node.object)}.${node.property.name}`;
}
if (t.isJSXIdentifier(node) || t.isIdentifier(node)) {
return node.name;
}
return `${node.namespace.name}:${node.name.name}`;
}
function jsxAttributeToString(attr: t.JSXAttribute): string {
if (t.isJSXNamespacedName(attr.name)) {
return `${attr.name.namespace.name}:${attr.name.name.name}`
}
return `${attr.name.name}`;
}
function addClientMetadata(node: t.JSXElement, meta: { path: string, name: string }) {
const existingAttributes = node.openingElement.attributes.map(attr => t.isJSXAttribute(attr) ? jsxAttributeToString(attr) : null);
if (!existingAttributes.find(attr => attr === 'client:component-path')) {
const componentPath = t.jsxAttribute(
t.jsxNamespacedName(t.jsxIdentifier('client'), t.jsxIdentifier('component-path')),
!meta.path.startsWith('.') ? t.stringLiteral(meta.path) : t.jsxExpressionContainer(t.binaryExpression("+", t.stringLiteral('/@fs'), t.memberExpression(t.newExpression(t.identifier('URL'), [t.stringLiteral(meta.path), t.identifier('import.meta.url')]), t.identifier('pathname')))),
);
node.openingElement.attributes.push(componentPath);
}
if (!existingAttributes.find(attr => attr === 'client:component-export')) {
const componentExport = t.jsxAttribute(
t.jsxNamespacedName(t.jsxIdentifier('client'), t.jsxIdentifier('component-export')),
t.stringLiteral(meta.name),
);
node.openingElement.attributes.push(componentExport);
}
if (!existingAttributes.find(attr => attr === 'client:component-hydration')) {
const staticMarker = t.jsxAttribute(
t.jsxNamespacedName(t.jsxIdentifier('client'), t.jsxIdentifier('component-hydration')),
)
node.openingElement.attributes.push(staticMarker);
}
}
export default function astroJSX(): PluginObj {
return {
visitor: {
ImportDeclaration(path, state) {
const source = path.node.source.value;
if (source.startsWith('astro/jsx-runtime')) return;
const specs = path.node.specifiers.map(spec => {
if (t.isImportDefaultSpecifier(spec)) return { local: spec.local.name, imported: 'default' }
if (t.isImportNamespaceSpecifier(spec)) return { local: spec.local.name, imported: '*' }
if (t.isIdentifier(spec.imported)) return { local: spec.local.name, imported: spec.imported.name };
return { local: spec.local.name, imported: spec.imported.value };
});
const imports = state.get('imports') ?? new Map();
for (const spec of specs) {
if (imports.has(source)) {
const existing = imports.get(source);
existing.add(spec);
imports.set(source, existing)
} else {
imports.set(source, new Set([spec]))
}
}
state.set('imports', imports);
},
JSXIdentifier(path, state) {
const isAttr = path.findParent(n => t.isJSXAttribute(n));
if (isAttr) return;
const parent = path.findParent(n => t.isJSXElement(n))!;
const parentNode = parent.node as t.JSXElement;
const tagName = getTagName(parentNode);
if (!isComponent(tagName)) return;
if (!hasClientDirective(parentNode)) return;
for (const [source, specs] of state.get('imports')) {
for (const { imported } of specs) {
const reference = path.referencesImport(source, imported);
if (reference) {
path.setData('import', { name: imported, path: source });
break;
}
}
}
// TODO: map unmatched identifiers back to imports if possible
const meta = path.getData('import');
if (meta) {
addClientMetadata(parentNode, meta)
} else {
console.warn(getTagName(parentNode))
}
},
}
};
};

View file

@ -0,0 +1,5 @@
import { h, render } from 'preact';
export default (element) => (Component, props, children) => {
throw new Error("Unable to hydrate Astro JSX!");
}

View file

@ -0,0 +1,41 @@
import { AstroIntegration } from 'astro';
function getRenderer() {
return {
name: '@astrojs/jsx',
clientEntrypoint: '@astrojs/jsx/client.js',
serverEntrypoint: '@astrojs/jsx/server.js',
jsxImportSource: 'astro',
jsxTransformOptions: async () => {
const { default: { default: jsx } } = await import('@babel/plugin-transform-react-jsx');
const { default: astroJSX } = await import('./babel/index.js');
return {
plugins: [astroJSX(), jsx({ }, { throwIfNamespace: false, runtime: 'automatic', importSource: 'astro' })],
};
},
};
}
function getViteConfiguration() {
return {
optimizeDeps: {
include: ['@astrojs/jsx/client.js'],
exclude: ['@astrojs/jsx/server.js'],
},
};
}
export default function (): AstroIntegration {
return {
name: '@astrojs/jsx',
hooks: {
'astro:config:setup': ({ addRenderer, updateConfig, addPageExtensions }) => {
addRenderer(getRenderer());
addPageExtensions(['.jsx', '.tsx']);
updateConfig({
vite: getViteConfiguration(),
});
},
},
};
}

View file

@ -0,0 +1,24 @@
import { renderJSX } from 'astro/server/jsx.js';
import { AstroJSX, jsx } from 'astro/jsx-runtime';
export async function check(Component: any, props: any, children: any) {
if (typeof Component !== 'function') return false;
try {
const result = await Component({ ...props, children });
return result[AstroJSX];
} catch (e) {};
return false;
}
export async function renderToStaticMarkup(this: any, Component: any, props = {}, children = null) {
const { result } = this;
try {
const html = await renderJSX(result, jsx(Component, { children, ...props }));
return { html };
} catch (e) {}
}
export default {
check,
renderToStaticMarkup,
};

View file

@ -0,0 +1,10 @@
{
"extends": "../../../tsconfig.base.json",
"include": ["src"],
"compilerOptions": {
"allowJs": true,
"module": "ES2020",
"outDir": "./dist",
"target": "ES2020"
}
}

View file

@ -0,0 +1,43 @@
{
"name": "@astrojs/mdx",
"description": "Use MDX within Astro",
"version": "0.0.1",
"type": "module",
"types": "./dist/index.d.ts",
"author": "withastro",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/withastro/astro.git",
"directory": "packages/integrations/mdx"
},
"keywords": [
"astro-component",
"renderer",
"mdx"
],
"bugs": "https://github.com/withastro/astro/issues",
"homepage": "https://astro.build",
"exports": {
".": "./dist/index.js",
"./client.js": "./client.js",
"./server.js": "./server.js",
"./package.json": "./package.json"
},
"scripts": {
"build": "astro-scripts build \"src/**/*.ts\" && tsc",
"build:ci": "astro-scripts build \"src/**/*.ts\"",
"dev": "astro-scripts dev \"src/**/*.ts\""
},
"dependencies": {
"@astrojs/jsx": "^0.0.1",
"@mdx-js/rollup": "^2.1.1"
},
"devDependencies": {
"astro": "workspace:*",
"astro-scripts": "workspace:*"
},
"engines": {
"node": "^14.15.0 || >=16.0.0"
}
}

View file

@ -0,0 +1,41 @@
import type { AstroIntegration } from 'astro';
import jsx from '@astrojs/jsx';
import mdx from '@mdx-js/rollup';
export default function (): AstroIntegration {
return [
{
name: '@astrojs/mdx',
hooks: {
'astro:config:setup': ({ updateConfig, addPageExtensions }) => {
const mdxPlugin = mdx({
jsx: true,
'jsxImportSource': 'astro'
})
addPageExtensions(['.mdx']);
updateConfig({
vite: {
plugins: [
{
enforce: 'pre',
...mdxPlugin
},
{
name: '@astrojs/mdx',
transform(code, id) {
if (!id.endsWith('.mdx')) return;
return `${code}\nif (import.meta.hot) {
import.meta.hot.accept();
}`
}
}
]
}
})
}
}
},
jsx(),
];
}

View file

@ -20,6 +20,7 @@ function check(Component, props, children) {
return !/\<undefined\>/.test(html);
} catch (err) {
console.log(err);
return false;
}
}

View file

@ -20,6 +20,9 @@ function getRenderer() {
function getViteConfiguration() {
return {
resolve: {
dedupe: ['preact', 'preact/hooks', 'preact/jsx-runtime']
},
optimizeDeps: {
include: [
'@astrojs/preact/client.js',

View file

@ -1,5 +1,5 @@
export { pathToPosix } from './lib/utils';
export { AbortController, AbortSignal, alert, atob, Blob, btoa, ByteLengthQueuingStrategy, cancelAnimationFrame, cancelIdleCallback, CanvasRenderingContext2D, CharacterData, clearTimeout, Comment, CountQueuingStrategy, CSSStyleSheet, CustomElementRegistry, CustomEvent, Document, DocumentFragment, DOMException, Element, Event, EventTarget, fetch, File, FormData, Headers, HTMLBodyElement, HTMLCanvasElement, HTMLDivElement, HTMLDocument, HTMLElement, HTMLHeadElement, HTMLHtmlElement, HTMLImageElement, HTMLSpanElement, HTMLStyleElement, HTMLTemplateElement, HTMLUnknownElement, Image, ImageData, IntersectionObserver, MediaQueryList, MutationObserver, Node, NodeFilter, NodeIterator, OffscreenCanvas, ReadableByteStreamController, ReadableStream, ReadableStreamBYOBReader, ReadableStreamBYOBRequest, ReadableStreamDefaultController, ReadableStreamDefaultReader, Request, requestAnimationFrame, requestIdleCallback, ResizeObserver, Response, setTimeout, ShadowRoot, structuredClone, StyleSheet, Text, TransformStream, TreeWalker, URLPattern, Window, WritableStream, WritableStreamDefaultController, WritableStreamDefaultWriter } from './mod.js';
export { AbortController, AbortSignal, alert, atob, Blob, btoa, ByteLengthQueuingStrategy, cancelAnimationFrame, cancelIdleCallback, CanvasRenderingContext2D, CharacterData, clearTimeout, Comment, CountQueuingStrategy, CSSStyleSheet, CustomElementRegistry, CustomEvent, Document, DocumentFragment, DOMException, Element, Event, EventTarget, fetch, File, FormData, Headers, HTMLBodyElement, HTMLCanvasElement, HTMLDivElement, HTMLDocument, HTMLElement, HTMLHeadElement, HTMLHtmlElement, HTMLImageElement, HTMLSpanElement, HTMLStyleElement, HTMLTemplateElement, HTMLUnknownElement, Image, ImageData, IntersectionObserver, MediaQueryList, MutationObserver, Node, NodeFilter, NodeIterator, OffscreenCanvas, ReadableByteStreamController, ReadableStream, ReadableStreamBYOBReader, ReadableStreamBYOBRequest, ReadableStreamDefaultController, ReadableStreamDefaultReader, Request, requestAnimationFrame, requestIdleCallback, ResizeObserver, Response, setTimeout, ShadowRoot, structuredClone, StyleSheet, Text, TransformStream, TreeWalker, URLPattern, Window, WritableStream, WritableStreamDefaultController, WritableStreamDefaultWriter, } from './mod.js';
export declare const polyfill: {
(target: any, options?: PolyfillOptions): any;
internals(target: any, name: string): any;

View file

@ -278,6 +278,31 @@ importers:
astro: link:../../packages/astro
solid-js: 1.4.3
examples/jsx:
specifiers:
'@astrojs/jsx': ^0.0.1
'@astrojs/preact': ^0.1.3
astro: ^1.0.0-beta.47
preact: ^10.8.1
dependencies:
preact: 10.8.1
devDependencies:
'@astrojs/jsx': link:../../packages/integrations/jsx
'@astrojs/preact': link:../../packages/integrations/preact
astro: link:../../packages/astro
examples/mdx:
specifiers:
'@astrojs/jsx': ^0.0.1
'@astrojs/mdx': ^0.0.1
'@astrojs/preact': ^0.1.3
astro: ^1.0.0-beta.47
devDependencies:
'@astrojs/jsx': link:../../packages/integrations/jsx
'@astrojs/mdx': link:../../packages/integrations/mdx
'@astrojs/preact': link:../../packages/integrations/preact
astro: link:../../packages/astro
examples/minimal:
specifiers:
astro: ^1.0.0-beta.47
@ -1704,6 +1729,17 @@ importers:
'@astrojs/deno': link:../../..
astro: link:../../../../../astro
packages/integrations/jsx:
specifiers:
'@babel/plugin-transform-react-jsx': ^7.17.3
astro: workspace:*
astro-scripts: workspace:*
dependencies:
'@babel/plugin-transform-react-jsx': 7.17.12
astro: link:../../astro
devDependencies:
astro-scripts: link:../../../scripts
packages/integrations/lit:
specifiers:
'@lit-labs/ssr': ^2.2.0
@ -1719,6 +1755,19 @@ importers:
cheerio: 1.0.0-rc.11
sass: 1.52.2
packages/integrations/mdx:
specifiers:
'@astrojs/jsx': ^0.0.1
'@mdx-js/rollup': ^2.1.1
astro: workspace:*
astro-scripts: workspace:*
dependencies:
'@astrojs/jsx': link:../jsx
'@mdx-js/rollup': 2.1.1
devDependencies:
astro: link:../../astro
astro-scripts: link:../../../scripts
packages/integrations/netlify:
specifiers:
'@astrojs/webapi': ^0.12.0
@ -4173,6 +4222,46 @@ packages:
- supports-color
dev: false
/@mdx-js/mdx/2.1.1:
resolution: {integrity: sha512-SXC18cChut3F2zkVXwsb2no0fzTQ1z6swjK13XwFbF5QU/SFQM0orAItPypSdL3GvqYyzVJtz8UofzJhPEQtMw==}
dependencies:
'@types/estree-jsx': 0.0.1
'@types/mdx': 2.0.2
astring: 1.8.3
estree-util-build-jsx: 2.1.0
estree-util-is-identifier-name: 2.0.0
estree-walker: 3.0.1
hast-util-to-estree: 2.0.2
markdown-extensions: 1.1.1
periscopic: 3.0.4
remark-mdx: 2.1.1
remark-parse: 10.0.1
remark-rehype: 10.1.0
unified: 10.1.2
unist-util-position-from-estree: 1.1.1
unist-util-stringify-position: 3.0.2
unist-util-visit: 4.1.0
vfile: 5.3.2
transitivePeerDependencies:
- supports-color
dev: false
/@mdx-js/rollup/2.1.1:
resolution: {integrity: sha512-oOWCEpm91ewLeywxeyNmOeaORCosLAQ6O0t/4yvou33z64F14lCx3rIJUZb7K+ZIEp03q46t5mTj37ybBmI1sw==}
peerDependencies:
rollup: '>=2'
peerDependenciesMeta:
rollup:
optional: true
dependencies:
'@mdx-js/mdx': 2.1.1
'@rollup/pluginutils': 4.2.1
source-map: 0.7.4
vfile: 5.3.2
transitivePeerDependencies:
- supports-color
dev: false
/@nanostores/preact/0.1.3_xtkr2uyxt54wubcnyxiwramgs4:
resolution: {integrity: sha512-uiX1ned0LrzASot+sPUjyJzr8Js3pX075omazgsSdLf0zPp4ss8xwTiuNh5FSKigTSQEVqZFiS+W8CnHIrX62A==}
engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
@ -6417,6 +6506,9 @@ packages:
engines: {node: '>=8.0.0'}
peerDependencies:
rollup: ^1.20.0||^2.0.0
peerDependenciesMeta:
rollup:
optional: true
dependencies:
rollup: 2.75.6
slash: 3.0.0
@ -6434,6 +6526,8 @@ packages:
optional: true
'@types/babel__core':
optional: true
rollup:
optional: true
dependencies:
'@babel/core': 7.18.2
'@babel/helper-module-imports': 7.16.7
@ -6445,6 +6539,9 @@ packages:
resolution: {integrity: sha512-4pbcU4J/nS+zuHk+c+OL3WtmEQhqxlZ9uqfjQMQDOHOPld7PsCd8k5LWs8h5wjwJN7MgnAn768F2sDxEP4eNFQ==}
peerDependencies:
rollup: ^1.20.0 || ^2.0.0
peerDependenciesMeta:
rollup:
optional: true
dependencies:
'@rollup/pluginutils': 3.1.0_rollup@2.75.6
estree-walker: 2.0.2
@ -6457,6 +6554,9 @@ packages:
engines: {node: '>= 10.0.0'}
peerDependencies:
rollup: ^1.20.0||^2.0.0
peerDependenciesMeta:
rollup:
optional: true
dependencies:
'@rollup/pluginutils': 3.1.0_rollup@2.75.6
'@types/resolve': 1.17.1
@ -6472,6 +6572,9 @@ packages:
engines: {node: '>= 10.0.0'}
peerDependencies:
rollup: ^2.42.0
peerDependenciesMeta:
rollup:
optional: true
dependencies:
'@rollup/pluginutils': 3.1.0_rollup@2.75.6
'@types/resolve': 1.17.1
@ -6486,6 +6589,9 @@ packages:
resolution: {integrity: sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg==}
peerDependencies:
rollup: ^1.20.0 || ^2.0.0
peerDependenciesMeta:
rollup:
optional: true
dependencies:
'@rollup/pluginutils': 3.1.0_rollup@2.75.6
magic-string: 0.25.9
@ -6499,6 +6605,9 @@ packages:
rollup: ^2.14.0
tslib: '*'
typescript: '>=3.7.0'
peerDependenciesMeta:
rollup:
optional: true
dependencies:
'@rollup/pluginutils': 3.1.0_rollup@2.75.6
resolve: 1.22.0
@ -6512,6 +6621,9 @@ packages:
engines: {node: '>= 8.0.0'}
peerDependencies:
rollup: ^1.20.0||^2.0.0
peerDependenciesMeta:
rollup:
optional: true
dependencies:
'@types/estree': 0.0.39
estree-walker: 1.0.1
@ -6732,6 +6844,10 @@ packages:
resolution: {integrity: sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==}
dev: false
/@types/mdx/2.0.2:
resolution: {integrity: sha512-mJGfgj4aWpiKb8C0nnJJchs1sHBHn0HugkVfqqyQi7Wn6mBRksLeQsPOFvih/Pu8L1vlDzfe/LidhVHBeUk3aQ==}
dev: false
/@types/mime/1.3.2:
resolution: {integrity: sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==}
dev: true
@ -7501,6 +7617,11 @@ packages:
tslib: 2.4.0
dev: false
/astring/1.8.3:
resolution: {integrity: sha512-sRpyiNrx2dEYIMmUXprS8nlpRg2Drs8m9ElX9vVEXaCB4XEAJhKfs7IcX0IwShjuOAjLR6wzIrgoptz1n19i1A==}
hasBin: true
dev: false
/async/3.2.4:
resolution: {integrity: sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==}
dev: true
@ -8950,6 +9071,20 @@ packages:
engines: {node: '>=4.0'}
dev: true
/estree-util-attach-comments/2.0.1:
resolution: {integrity: sha512-1wTBNndwMIsnvnuxjFIaYQz0M7PsCvcgP0YD7/dU8xWh1FuHk+O6pYpT4sLa5THY/CywJvdIdgw4uhozujga/g==}
dependencies:
'@types/estree': 0.0.51
dev: false
/estree-util-build-jsx/2.1.0:
resolution: {integrity: sha512-gsBGfsY6LOJUIDwmMkTOcgCX+3r/LUjRBccgHMSW55PHjhZsV13RmPl/iwpAvW8KcQqoN9P0FEFWTSS2Zc5bGA==}
dependencies:
'@types/estree-jsx': 0.0.1
estree-util-is-identifier-name: 2.0.0
estree-walker: 3.0.1
dev: false
/estree-util-is-identifier-name/2.0.0:
resolution: {integrity: sha512-aXXZFVMnBBDRP81vS4YtAYJ0hUkgEsXea7lNKWCOeaAquGb1Jm2rcONPB5fpzwgbNxulTvrWuKnp9UElUGAKeQ==}
dev: false
@ -9601,6 +9736,27 @@ packages:
zwitch: 2.0.2
dev: false
/hast-util-to-estree/2.0.2:
resolution: {integrity: sha512-UQrZVeBj6A9od0lpFvqHKNSH9zvDrNoyWKbveu1a2oSCXEDUI+3bnd6BoiQLPnLrcXXn/jzJ6y9hmJTTlvf8lQ==}
dependencies:
'@types/estree-jsx': 0.0.1
'@types/hast': 2.3.4
'@types/unist': 2.0.6
comma-separated-tokens: 2.0.2
estree-util-attach-comments: 2.0.1
estree-util-is-identifier-name: 2.0.0
hast-util-whitespace: 2.0.0
mdast-util-mdx-expression: 1.2.0
mdast-util-mdxjs-esm: 1.2.0
property-information: 6.1.1
space-separated-tokens: 2.0.1
style-to-object: 0.3.0
unist-util-position: 4.0.3
zwitch: 2.0.2
transitivePeerDependencies:
- supports-color
dev: false
/hast-util-to-html/8.0.3:
resolution: {integrity: sha512-/D/E5ymdPYhHpPkuTHOUkSatxr4w1ZKrZsG0Zv/3C2SRVT0JFJG53VS45AMrBtYk0wp5A7ksEhiC8QaOZM95+A==}
dependencies:
@ -10026,6 +10182,12 @@ packages:
resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==}
dev: true
/is-reference/3.0.0:
resolution: {integrity: sha512-Eo1W3wUoHWoCoVM4GVl/a+K0IgiqE5aIo4kJABFyMum1ZORlPkC+UC357sSQUL5w5QCE5kCC9upl75b7+7CY/Q==}
dependencies:
'@types/estree': 0.0.51
dev: false
/is-regex/1.1.4:
resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==}
engines: {node: '>= 0.4'}
@ -10436,6 +10598,11 @@ packages:
engines: {node: '>=8'}
dev: true
/markdown-extensions/1.1.1:
resolution: {integrity: sha512-WWC0ZuMzCyDHYCasEGs4IPvLyTGftYwh6wIEOULOF0HXcqZlhwRzrK0w2VUlxWA98xnvb/jszw4ZSkJ6ADpM6Q==}
engines: {node: '>=0.10.0'}
dev: false
/markdown-table/3.0.2:
resolution: {integrity: sha512-y8j3a5/DkJCmS5x4dMCQL+OR0+2EAq3DOtio1COSHsmW2BGXnNCK3v12hJt1LrUz5iZH5g0LmuYOjDdI+czghA==}
dev: false
@ -10555,6 +10722,43 @@ packages:
vfile-message: 3.1.2
dev: false
/mdast-util-mdx-jsx/2.0.1:
resolution: {integrity: sha512-oPC7/smPBf7vxnvIYH5y3fPo2lw1rdrswFfSb4i0GTAXRUQv7JUU/t/hbp07dgGdUFTSDOHm5DNamhNg/s2Hrg==}
dependencies:
'@types/estree-jsx': 0.0.1
'@types/hast': 2.3.4
'@types/mdast': 3.0.10
ccount: 2.0.1
mdast-util-to-markdown: 1.3.0
parse-entities: 4.0.0
stringify-entities: 4.0.3
unist-util-remove-position: 4.0.1
unist-util-stringify-position: 3.0.2
vfile-message: 3.1.2
dev: false
/mdast-util-mdx/2.0.0:
resolution: {integrity: sha512-M09lW0CcBT1VrJUaF/PYxemxxHa7SLDHdSn94Q9FhxjCQfuW7nMAWKWimTmA3OyDMSTH981NN1csW1X+HPSluw==}
dependencies:
mdast-util-mdx-expression: 1.2.0
mdast-util-mdx-jsx: 2.0.1
mdast-util-mdxjs-esm: 1.2.0
transitivePeerDependencies:
- supports-color
dev: false
/mdast-util-mdxjs-esm/1.2.0:
resolution: {integrity: sha512-IPpX9GBzAIbIRCjbyeLDpMhACFb0wxTIujuR3YElB8LWbducUdMgRJuqs/Vg8xQ1bIAMm7lw8L+YNtua0xKXRw==}
dependencies:
'@types/estree-jsx': 0.0.1
'@types/hast': 2.3.4
'@types/mdast': 3.0.10
mdast-util-from-markdown: 1.2.0
mdast-util-to-markdown: 1.3.0
transitivePeerDependencies:
- supports-color
dev: false
/mdast-util-to-hast/12.1.1:
resolution: {integrity: sha512-qE09zD6ylVP14jV4mjLIhDBOrpFdShHZcEsYvvKGABlr9mGbV7mTlRWdoFxL/EYSTNDiC9GZXy7y8Shgb9Dtzw==}
dependencies:
@ -10720,12 +10924,52 @@ packages:
uvu: 0.5.3
dev: false
/micromark-extension-mdx-jsx/1.0.3:
resolution: {integrity: sha512-VfA369RdqUISF0qGgv2FfV7gGjHDfn9+Qfiv5hEwpyr1xscRj/CiVRkU7rywGFCO7JwJ5L0e7CJz60lY52+qOA==}
dependencies:
'@types/acorn': 4.0.6
estree-util-is-identifier-name: 2.0.0
micromark-factory-mdx-expression: 1.0.6
micromark-factory-space: 1.0.0
micromark-util-character: 1.1.0
micromark-util-symbol: 1.0.1
micromark-util-types: 1.0.2
uvu: 0.5.3
vfile-message: 3.1.2
dev: false
/micromark-extension-mdx-md/1.0.0:
resolution: {integrity: sha512-xaRAMoSkKdqZXDAoSgp20Azm0aRQKGOl0RrS81yGu8Hr/JhMsBmfs4wR7m9kgVUIO36cMUQjNyiyDKPrsv8gOw==}
dependencies:
micromark-util-types: 1.0.2
dev: false
/micromark-extension-mdxjs-esm/1.0.3:
resolution: {integrity: sha512-2N13ol4KMoxb85rdDwTAC6uzs8lMX0zeqpcyx7FhS7PxXomOnLactu8WI8iBNXW8AVyea3KIJd/1CKnUmwrK9A==}
dependencies:
micromark-core-commonmark: 1.0.6
micromark-util-character: 1.1.0
micromark-util-events-to-acorn: 1.1.0
micromark-util-symbol: 1.0.1
micromark-util-types: 1.0.2
unist-util-position-from-estree: 1.1.1
uvu: 0.5.3
vfile-message: 3.1.2
dev: false
/micromark-extension-mdxjs/1.0.0:
resolution: {integrity: sha512-TZZRZgeHvtgm+IhtgC2+uDMR7h8eTKF0QUX9YsgoL9+bADBpBY6SiLvWqnBlLbCEevITmTqmEuY3FoxMKVs1rQ==}
dependencies:
acorn: 8.7.1
acorn-jsx: 5.3.2_acorn@8.7.1
micromark-extension-mdx-expression: 1.0.3
micromark-extension-mdx-jsx: 1.0.3
micromark-extension-mdx-md: 1.0.0
micromark-extension-mdxjs-esm: 1.0.3
micromark-util-combine-extensions: 1.0.0
micromark-util-types: 1.0.2
dev: false
/micromark-factory-destination/1.0.0:
resolution: {integrity: sha512-eUBA7Rs1/xtTVun9TmV3gjfPz2wEwgK5R5xcbIM5ZYAtvGF6JkyaDsj0agx8urXnO31tEO6Ug83iVH3tdedLnw==}
dependencies:
@ -11631,6 +11875,13 @@ packages:
resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==}
dev: true
/periscopic/3.0.4:
resolution: {integrity: sha512-SFx68DxCv0Iyo6APZuw/AKewkkThGwssmU0QWtTlvov3VAtPX+QJ4CadwSaz8nrT5jPIuxdvJWB4PnD2KNDxQg==}
dependencies:
estree-walker: 3.0.1
is-reference: 3.0.0
dev: false
/picocolors/1.0.0:
resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
@ -11738,6 +11989,10 @@ packages:
/preact/10.7.3:
resolution: {integrity: sha512-giqJXP8VbtA1tyGa3f1n9wiN7PrHtONrDyE3T+ifjr/tTkg+2N4d/6sjC9WyJKv8wM7rOYDveqy5ZoFmYlwo4w==}
/preact/10.8.1:
resolution: {integrity: sha512-p5CKQ0MCEXTGKGOHiFaNE2V2nDq2hvDHykXvIlz+4lbfJ9umLZr8JS/fa1bXUwRcHXK+Ljk8zqmDhr25n0LtVg==}
dev: false
/prebuild-install/7.1.1:
resolution: {integrity: sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==}
engines: {node: '>=10'}
@ -12201,6 +12456,15 @@ packages:
- supports-color
dev: false
/remark-mdx/2.1.1:
resolution: {integrity: sha512-0wXdEITnFyjLquN3VvACNLzbGzWM5ujzTvfgOkONBZgSFJ7ezLLDaTWqf6H9eUgVITEP8asp6LJ0W/X090dXBg==}
dependencies:
mdast-util-mdx: 2.0.0
micromark-extension-mdxjs: 1.0.0
transitivePeerDependencies:
- supports-color
dev: false
/remark-parse/10.0.1:
resolution: {integrity: sha512-1fUyHr2jLsVOkhbvPRBJ5zTKZZyD6yZzYaWCS6BPBdQ8vEMBCH+9zNCDA6tET/zHCi/jLqjCWtlJZUPk+DbnFw==}
dependencies:
@ -12323,6 +12587,9 @@ packages:
resolution: {integrity: sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==}
peerDependencies:
rollup: ^2.0.0
peerDependenciesMeta:
rollup:
optional: true
dependencies:
'@babel/code-frame': 7.16.7
jest-worker: 26.6.2