Compare commits
7 commits
main
...
content-pe
Author | SHA1 | Date | |
---|---|---|---|
|
add212f9f2 | ||
|
3c6c841a65 | ||
|
36154b1170 | ||
|
c1ca780e20 | ||
|
fd432e6752 | ||
|
e9ee166964 | ||
|
da1895fbdb |
83 changed files with 2576 additions and 107 deletions
7
.changeset/breezy-cats-grab.md
Normal file
7
.changeset/breezy-cats-grab.md
Normal file
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
'astro': patch
|
||||
'@astrojs/markdoc': patch
|
||||
'@astrojs/mdx': patch
|
||||
---
|
||||
|
||||
Introduce the (experimental) `@astrojs/markdoc` integration. This unlocks Markdoc inside your Content Collections, and brings support for Astro and UI components in your content. This also improves internals to make Content Collections extensible to more file types in the future.
|
21
examples/with-markdoc/.gitignore
vendored
Normal file
21
examples/with-markdoc/.gitignore
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
# build output
|
||||
dist/
|
||||
# generated types
|
||||
.astro/
|
||||
|
||||
# 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
|
4
examples/with-markdoc/.vscode/extensions.json
vendored
Normal file
4
examples/with-markdoc/.vscode/extensions.json
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"recommendations": ["astro-build.astro-vscode"],
|
||||
"unwantedRecommendations": []
|
||||
}
|
11
examples/with-markdoc/.vscode/launch.json
vendored
Normal file
11
examples/with-markdoc/.vscode/launch.json
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"command": "./node_modules/.bin/astro dev",
|
||||
"name": "Development server",
|
||||
"request": "launch",
|
||||
"type": "node-terminal"
|
||||
}
|
||||
]
|
||||
}
|
50
examples/with-markdoc/README.md
Normal file
50
examples/with-markdoc/README.md
Normal file
|
@ -0,0 +1,50 @@
|
|||
# Astro Example: Markdoc (experimental)
|
||||
|
||||
This starter showcases the experimental Markdoc integration.
|
||||
|
||||
```
|
||||
npm create astro@latest -- --template with-markdoc
|
||||
```
|
||||
|
||||
[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/withastro/astro/tree/latest/examples/with-markdoc)
|
||||
[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/withastro/astro/tree/latest/examples/with-markdoc)
|
||||
|
||||
> 🧑🚀 **Seasoned astronaut?** Delete this file. Have fun!
|
||||
|
||||
## 🚀 Project Structure
|
||||
|
||||
Inside of your Astro project, you'll see the following folders and files:
|
||||
|
||||
```
|
||||
/
|
||||
├── public/
|
||||
├── src/
|
||||
│ └── content/docs/
|
||||
│ └── intro.mdoc
|
||||
│ └── components/
|
||||
│ └── DocsContent.astro
|
||||
│ └── pages/
|
||||
│ └── index.astro
|
||||
└── package.json
|
||||
```
|
||||
|
||||
Markdoc can be used in content collections with the `.mdoc` extension. See `content/docs/` for an example.
|
||||
|
||||
You can also apply Astro components and server-rendered UI components (React, Vue, Svelte, etc) to your Markdoc files. See `src/content/DocsContent.astro` for an example configuration.
|
||||
|
||||
## 🧞 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 |
|
||||
| `npm run astro ...` | Run CLI commands like `astro add`, `astro check` |
|
||||
| `npm run astro --help` | Get help using the Astro CLI |
|
||||
|
||||
## 👀 Want to learn more?
|
||||
|
||||
Feel free to check [our documentation](https://docs.astro.build) or jump into our [Discord server](https://astro.build/chat).
|
7
examples/with-markdoc/astro.config.mjs
Normal file
7
examples/with-markdoc/astro.config.mjs
Normal file
|
@ -0,0 +1,7 @@
|
|||
import { defineConfig } from 'astro/config';
|
||||
import markdoc from '@astrojs/markdoc';
|
||||
|
||||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
integrations: [markdoc()],
|
||||
});
|
17
examples/with-markdoc/package.json
Normal file
17
examples/with-markdoc/package.json
Normal file
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"name": "@example/with-markdoc",
|
||||
"type": "module",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "astro dev",
|
||||
"start": "astro dev",
|
||||
"build": "astro build",
|
||||
"preview": "astro preview",
|
||||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"@astrojs/markdoc": "^0.0.0",
|
||||
"astro": "^2.0.6"
|
||||
}
|
||||
}
|
13
examples/with-markdoc/public/favicon.svg
Normal file
13
examples/with-markdoc/public/favicon.svg
Normal file
|
@ -0,0 +1,13 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 36 36">
|
||||
<path fill="#000" d="M22.25 4h-8.5a1 1 0 0 0-.96.73l-5.54 19.4a.5.5 0 0 0 .62.62l5.05-1.44a2 2 0 0 0 1.38-1.4l3.22-11.66a.5.5 0 0 1 .96 0l3.22 11.67a2 2 0 0 0 1.38 1.39l5.05 1.44a.5.5 0 0 0 .62-.62l-5.54-19.4a1 1 0 0 0-.96-.73Z"/>
|
||||
<path fill="url(#gradient)" d="M18 28a7.63 7.63 0 0 1-5-2c-1.4 2.1-.35 4.35.6 5.55.14.17.41.07.47-.15.44-1.8 2.93-1.22 2.93.6 0 2.28.87 3.4 1.72 3.81.34.16.59-.2.49-.56-.31-1.05-.29-2.46 1.29-3.25 3-1.5 3.17-4.83 2.5-6-.67.67-2.6 2-5 2Z"/>
|
||||
<defs>
|
||||
<linearGradient id="gradient" x1="16" x2="16" y1="32" y2="24" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#000"/>
|
||||
<stop offset="1" stop-color="#000" stop-opacity="0"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<style>
|
||||
@media (prefers-color-scheme:dark){:root{filter:invert(100%)}}
|
||||
</style>
|
||||
</svg>
|
After Width: | Height: | Size: 873 B |
11
examples/with-markdoc/sandbox.config.json
Normal file
11
examples/with-markdoc/sandbox.config.json
Normal file
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"infiniteLoopProtection": true,
|
||||
"hardReloadOnChange": false,
|
||||
"view": "browser",
|
||||
"template": "node",
|
||||
"container": {
|
||||
"port": 3000,
|
||||
"startScript": "start",
|
||||
"node": "14"
|
||||
}
|
||||
}
|
116
examples/with-markdoc/src/components/Aside.astro
Normal file
116
examples/with-markdoc/src/components/Aside.astro
Normal file
|
@ -0,0 +1,116 @@
|
|||
---
|
||||
// Inspired by the `Aside` component from docs.astro.build
|
||||
// https://github.com/withastro/docs/blob/main/src/components/Aside.astro
|
||||
|
||||
export interface Props {
|
||||
type?: 'note' | 'tip' | 'caution' | 'danger';
|
||||
title?: string;
|
||||
}
|
||||
|
||||
const labelByType = {
|
||||
note: 'Note',
|
||||
tip: 'Tip',
|
||||
caution: 'Caution',
|
||||
danger: 'Danger',
|
||||
};
|
||||
const { type = 'note' } = Astro.props as Props;
|
||||
const title = Astro.props.title ?? labelByType[type] ?? '';
|
||||
|
||||
// SVG icon paths based on GitHub Octicons
|
||||
const icons: Record<NonNullable<Props['type']>, { viewBox: string; d: string }> = {
|
||||
note: {
|
||||
viewBox: '0 0 18 18',
|
||||
d: 'M0 3.75C0 2.784.784 2 1.75 2h12.5c.966 0 1.75.784 1.75 1.75v8.5A1.75 1.75 0 0114.25 14H1.75A1.75 1.75 0 010 12.25v-8.5zm1.75-.25a.25.25 0 00-.25.25v8.5c0 .138.112.25.25.25h12.5a.25.25 0 00.25-.25v-8.5a.25.25 0 00-.25-.25H1.75zM3.5 6.25a.75.75 0 01.75-.75h7a.75.75 0 010 1.5h-7a.75.75 0 01-.75-.75zm.75 2.25a.75.75 0 000 1.5h4a.75.75 0 000-1.5h-4z',
|
||||
},
|
||||
tip: {
|
||||
viewBox: '0 0 18 18',
|
||||
d: 'M14 0a8.8 8.8 0 0 0-6 2.6l-.5.4-.9 1H3.3a1.8 1.8 0 0 0-1.5.8L.1 7.6a.8.8 0 0 0 .4 1.1l3.1 1 .2.1 2.4 2.4.1.2 1 3a.8.8 0 0 0 1 .5l2.9-1.7a1.8 1.8 0 0 0 .8-1.5V9.5l1-1 .4-.4A8.8 8.8 0 0 0 16 2v-.1A1.8 1.8 0 0 0 14.2 0h-.1zm-3.5 10.6-.3.2L8 12.3l.5 1.8 2-1.2a.3.3 0 0 0 .1-.2v-2zM3.7 8.1l1.5-2.3.2-.3h-2a.3.3 0 0 0-.3.1l-1.2 2 1.8.5zm5.2-4.5a7.3 7.3 0 0 1 5.2-2.1h.1a.3.3 0 0 1 .3.3v.1a7.3 7.3 0 0 1-2.1 5.2l-.5.4a15.2 15.2 0 0 1-2.5 2L7.1 11 5 9l1.5-2.3a15.3 15.3 0 0 1 2-2.5l.4-.5zM12 5a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm-8.4 9.6a1.5 1.5 0 1 0-2.2-2.2 7 7 0 0 0-1.1 3 .2.2 0 0 0 .3.3c.6 0 2.2-.4 3-1.1z',
|
||||
},
|
||||
caution: {
|
||||
viewBox: '-1 1 18 18',
|
||||
d: 'M8.9 1.5C8.7 1.2 8.4 1 8 1s-.7.2-.9.5l-7 12a1 1 0 0 0 0 1c.2.3.6.5 1 .5H15c.4 0 .7-.2.9-.5a1 1 0 0 0 0-1l-7-12zM9 13H7v-2h2v2zm0-3H7V6h2v4z',
|
||||
},
|
||||
danger: {
|
||||
viewBox: '0 1 14 17',
|
||||
d: 'M5 .3c.9 2.2.5 3.4-.5 4.3C3.5 5.6 2 6.5 1 8c-1.5 2-1.7 6.5 3.5 7.7-2.2-1.2-2.6-4.5-.3-6.6-.6 2 .6 3.3 2 2.8 1.4-.4 2.3.6 2.2 1.7 0 .8-.3 1.4-1 1.8A5.6 5.6 0 0 0 12 10c0-2.9-2.5-3.3-1.3-5.7-1.5.2-2 1.2-1.8 2.8 0 1-1 1.8-2 1.3-.6-.4-.6-1.2 0-1.8C8.2 5.3 8.7 2.5 5 .3z',
|
||||
},
|
||||
};
|
||||
const { viewBox, d } = icons[type];
|
||||
---
|
||||
|
||||
<aside class={`content ${type}`} aria-label={title}>
|
||||
<p class="title" aria-hidden="true">
|
||||
<span class="icon">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox={viewBox} width={16} height={16}>
|
||||
<path fill-rule="evenodd" d={d}></path>
|
||||
</svg>
|
||||
</span>
|
||||
{title}
|
||||
</p>
|
||||
<section>
|
||||
<slot />
|
||||
</section>
|
||||
</aside>
|
||||
|
||||
<style>
|
||||
aside {
|
||||
--color-base-purple: 269, 79%;
|
||||
--color-base-teal: 180, 80%;
|
||||
--color-base-red: 351, 100%;
|
||||
--color-base-yellow: 41, 100%;
|
||||
|
||||
--aside-color-base: var(--color-base-purple);
|
||||
--aside-color-lightness: 54%;
|
||||
--aside-accent-color: hsl(var(--aside-color-base), var(--aside-color-lightness));
|
||||
--aside-text-lightness: 20%;
|
||||
--aside-text-accent-color: hsl(var(--aside-color-base), var(--aside-text-lightness));
|
||||
|
||||
border-inline-start: 4px solid var(--aside-accent-color);
|
||||
padding: 1rem;
|
||||
background-color: hsla(var(--aside-color-base), var(--aside-color-lightness), 0.1);
|
||||
/* Indicates the aside boundaries for forced colors users, transparent is changed to a solid color */
|
||||
outline: 1px solid transparent;
|
||||
}
|
||||
|
||||
.title {
|
||||
line-height: 1;
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: 0.9rem;
|
||||
letter-spacing: 0.05em;
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
color: var(--aside-text-accent-color);
|
||||
}
|
||||
|
||||
.icon svg {
|
||||
width: 1.5em;
|
||||
height: 1.5em;
|
||||
vertical-align: middle;
|
||||
fill: currentcolor;
|
||||
}
|
||||
|
||||
aside :global(a),
|
||||
aside :global(a > code:not([class*='language'])) {
|
||||
color: var(--aside-text-accent-color);
|
||||
}
|
||||
|
||||
aside :global(pre) {
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.tip {
|
||||
--aside-color-lightness: 42%;
|
||||
--aside-color-base: var(--color-base-teal);
|
||||
}
|
||||
|
||||
.caution {
|
||||
--aside-color-lightness: 59%;
|
||||
--aside-color-base: var(--color-base-yellow);
|
||||
}
|
||||
|
||||
.danger {
|
||||
--aside-color-lightness: 54%;
|
||||
--aside-color-base: var(--color-base-red);
|
||||
}
|
||||
</style>
|
43
examples/with-markdoc/src/components/DocsContent.astro
Normal file
43
examples/with-markdoc/src/components/DocsContent.astro
Normal file
|
@ -0,0 +1,43 @@
|
|||
---
|
||||
import Aside from './Aside.astro';
|
||||
import type { CollectionEntry } from 'astro:content';
|
||||
|
||||
type Props = {
|
||||
entry: CollectionEntry<'docs'>;
|
||||
};
|
||||
|
||||
const { entry } = Astro.props;
|
||||
const { Content } = await entry.render();
|
||||
---
|
||||
|
||||
<Content
|
||||
config={{
|
||||
// Accepts all Markdoc configuration options
|
||||
// See https://markdoc.dev/docs/config#full-example
|
||||
tags: {
|
||||
aside: {
|
||||
render: 'Aside',
|
||||
attributes: {
|
||||
type: { type: String },
|
||||
title: { type: String },
|
||||
},
|
||||
},
|
||||
},
|
||||
}}
|
||||
components={{
|
||||
// Pass a mapping from the component name
|
||||
// To an Astro or UI component import
|
||||
Aside,
|
||||
}}
|
||||
/>
|
||||
|
||||
<style is:global>
|
||||
table {
|
||||
margin-block: 2rem;
|
||||
margin-inline: auto;
|
||||
}
|
||||
table td {
|
||||
padding-block: 0.3rem;
|
||||
padding-inline: 0.5rem;
|
||||
}
|
||||
</style>
|
9
examples/with-markdoc/src/content/config.ts
Normal file
9
examples/with-markdoc/src/content/config.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
import { defineCollection, z } from 'astro:content';
|
||||
|
||||
const docs = defineCollection({
|
||||
schema: z.object({
|
||||
title: z.string(),
|
||||
}),
|
||||
});
|
||||
|
||||
export const collections = { docs };
|
39
examples/with-markdoc/src/content/docs/intro.mdoc
Normal file
39
examples/with-markdoc/src/content/docs/intro.mdoc
Normal file
|
@ -0,0 +1,39 @@
|
|||
---
|
||||
title: Welcome to Markdoc 👋
|
||||
---
|
||||
|
||||
This simple starter showcases Markdoc with Content Collections. All Markdoc features are supported, including this nifty built-in `{% table %}` tag:
|
||||
|
||||
{% table %}
|
||||
* Feature
|
||||
* Supported
|
||||
---
|
||||
* `.mdoc` in Content Collections
|
||||
* ✅
|
||||
---
|
||||
* Markdoc transform configuration
|
||||
* ✅
|
||||
---
|
||||
* Astro components
|
||||
* ✅
|
||||
{% /table %}
|
||||
|
||||
{% aside title="Code Challenge" type="tip" %}
|
||||
|
||||
Reveal the secret message below by adding `revealSecret: true` to your list of Markdoc variables.
|
||||
|
||||
_Hint: Try [adding a `variables` object](https://markdoc.dev/docs/variables#global-variables) to the `config` property under `src/components/DocsContent.astro`._
|
||||
|
||||
{% if $revealSecret %}
|
||||
|
||||
Maybe the real secret was the Rick Rolls we shared along the way.
|
||||
|
||||
![Rick Astley dancing](https://media.tenor.com/x8v1oNUOmg4AAAAM/rickroll-roll.gif)
|
||||
|
||||
{% /if %}
|
||||
|
||||
{% /aside %}
|
||||
|
||||
Check out [the `@astrojs/markdoc` integration][astro-markdoc] for complete documentation and usage examples.
|
||||
|
||||
[astro-markdoc]: https://docs.astro.build/en/guides/integrations-guide/markdoc/
|
2
examples/with-markdoc/src/env.d.ts
vendored
Normal file
2
examples/with-markdoc/src/env.d.ts
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
/// <reference path="../.astro/types.d.ts" />
|
||||
/// <reference types="astro/client" />
|
35
examples/with-markdoc/src/layouts/Layout.astro
Normal file
35
examples/with-markdoc/src/layouts/Layout.astro
Normal file
|
@ -0,0 +1,35 @@
|
|||
---
|
||||
export interface Props {
|
||||
title: string;
|
||||
}
|
||||
|
||||
const { title } = Astro.props;
|
||||
---
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
<meta name="generator" content={Astro.generator} />
|
||||
<title>{title}</title>
|
||||
</head>
|
||||
<body>
|
||||
<slot />
|
||||
</body>
|
||||
</html>
|
||||
<style is:global>
|
||||
html {
|
||||
font-family: system-ui, sans-serif;
|
||||
background-color: #f6f6f6;
|
||||
}
|
||||
code {
|
||||
font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono,
|
||||
Bitstream Vera Sans Mono, Courier New, monospace;
|
||||
}
|
||||
main {
|
||||
margin: auto;
|
||||
max-width: 60ch;
|
||||
}
|
||||
</style>
|
18
examples/with-markdoc/src/pages/index.astro
Normal file
18
examples/with-markdoc/src/pages/index.astro
Normal file
|
@ -0,0 +1,18 @@
|
|||
---
|
||||
import { getEntryBySlug } from 'astro:content';
|
||||
import DocsContent from '../components/DocsContent.astro';
|
||||
import Layout from '../layouts/Layout.astro';
|
||||
|
||||
const intro = await getEntryBySlug('docs', 'intro');
|
||||
---
|
||||
|
||||
<Layout title={intro.data.title}>
|
||||
<main>
|
||||
<h1>{intro.data.title}</h1>
|
||||
<!-- `DocsContent` is a thin wrapper around -->
|
||||
<!-- the `Content` component provided by Content Collections, -->
|
||||
<!-- with added Markdoc configuration and component mapping. -->
|
||||
<!-- This allows you to share config wherever you render your Markdoc files. -->
|
||||
<DocsContent entry={intro} />
|
||||
</main>
|
||||
</Layout>
|
6
examples/with-markdoc/tsconfig.json
Normal file
6
examples/with-markdoc/tsconfig.json
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"extends": "astro/tsconfigs/base",
|
||||
"compilerOptions": {
|
||||
"strictNullChecks": true
|
||||
}
|
||||
}
|
2
packages/astro/performance/.gitignore
vendored
Normal file
2
packages/astro/performance/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
.astro/
|
||||
**/src/content/generated/
|
17
packages/astro/performance/fixtures/md/package.json
Normal file
17
packages/astro/performance/fixtures/md/package.json
Normal file
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"name": "@performance/md",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "astro build --perf"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "unlicensed",
|
||||
"dependencies": {
|
||||
"@performance/utils": "^0.0.0",
|
||||
"astro": "^2.0.12"
|
||||
}
|
||||
}
|
2
packages/astro/performance/fixtures/md/src/env.d.ts
vendored
Normal file
2
packages/astro/performance/fixtures/md/src/env.d.ts
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
/// <reference path="../.astro/types.d.ts" />
|
||||
/// <reference types="astro/client" />
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
import { getCollection } from 'astro:content';
|
||||
import { RenderContent } from '@performance/utils';
|
||||
|
||||
const posts = await getCollection('generated');
|
||||
---
|
||||
|
||||
<RenderContent {posts} />
|
|
@ -0,0 +1,7 @@
|
|||
import { defineConfig } from 'astro/config';
|
||||
import markdoc from "@astrojs/markdoc";
|
||||
|
||||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
integrations: [markdoc()]
|
||||
});
|
18
packages/astro/performance/fixtures/mdoc/package.json
Normal file
18
packages/astro/performance/fixtures/mdoc/package.json
Normal file
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"name": "@performance/mdoc",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "astro build --perf"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "unlicensed",
|
||||
"dependencies": {
|
||||
"@performance/utils": "^0.0.0",
|
||||
"astro": "^2.0.12",
|
||||
"@astrojs/markdoc": "^0.0.0"
|
||||
}
|
||||
}
|
2
packages/astro/performance/fixtures/mdoc/src/env.d.ts
vendored
Normal file
2
packages/astro/performance/fixtures/mdoc/src/env.d.ts
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
/// <reference path="../.astro/types.d.ts" />
|
||||
/// <reference types="astro/client" />
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
import { getCollection } from 'astro:content';
|
||||
import { RenderContent } from '@performance/utils';
|
||||
|
||||
const posts = await getCollection('generated');
|
||||
---
|
||||
|
||||
<RenderContent {posts} />
|
7
packages/astro/performance/fixtures/mdx/astro.config.mjs
Normal file
7
packages/astro/performance/fixtures/mdx/astro.config.mjs
Normal file
|
@ -0,0 +1,7 @@
|
|||
import { defineConfig } from 'astro/config';
|
||||
import mdx from "@astrojs/mdx";
|
||||
|
||||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
integrations: [mdx()]
|
||||
});
|
18
packages/astro/performance/fixtures/mdx/package.json
Normal file
18
packages/astro/performance/fixtures/mdx/package.json
Normal file
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"name": "@performance/mdx",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "astro build --perf"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "unlicensed",
|
||||
"dependencies": {
|
||||
"@astrojs/mdx": "^0.16.2",
|
||||
"@performance/utils": "^0.0.0",
|
||||
"astro": "^2.0.12"
|
||||
}
|
||||
}
|
2
packages/astro/performance/fixtures/mdx/src/env.d.ts
vendored
Normal file
2
packages/astro/performance/fixtures/mdx/src/env.d.ts
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
/// <reference path="../.astro/types.d.ts" />
|
||||
/// <reference types="astro/client" />
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
import { getCollection } from 'astro:content';
|
||||
import { RenderContent } from '@performance/utils';
|
||||
|
||||
const posts = await getCollection('generated');
|
||||
---
|
||||
|
||||
<RenderContent {posts} />
|
|
@ -0,0 +1,31 @@
|
|||
---
|
||||
type Props = {
|
||||
posts: any[];
|
||||
}
|
||||
|
||||
const { posts } = Astro.props;
|
||||
---
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Md render test</title>
|
||||
</head>
|
||||
<body>
|
||||
{
|
||||
posts.map(async (entry) => {
|
||||
const { Content } = await entry.render();
|
||||
return (
|
||||
<div>
|
||||
<h1>{entry.data.title}</h1>
|
||||
<p>{entry.data.description}</p>
|
||||
<Content />
|
||||
</div>
|
||||
);
|
||||
})
|
||||
}
|
||||
</body>
|
||||
</html>
|
2
packages/astro/performance/fixtures/utils/index.ts
Normal file
2
packages/astro/performance/fixtures/utils/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
// @ts-ignore
|
||||
export { default as RenderContent } from './RenderContent.astro';
|
17
packages/astro/performance/fixtures/utils/package.json
Normal file
17
packages/astro/performance/fixtures/utils/package.json
Normal file
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"name": "@performance/utils",
|
||||
"version": "0.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "unlicensed",
|
||||
"devDependencies": {
|
||||
"astro": "^2.0.12"
|
||||
},
|
||||
"exports": {
|
||||
".": "./index.ts"
|
||||
}
|
||||
}
|
18
packages/astro/performance/package.json
Normal file
18
packages/astro/performance/package.json
Normal file
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"name": "@test/performance",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"write": "run-p write:*",
|
||||
"write:md": "node scripts/write-posts.mjs fixtures/md/src/content/generated 1000 md",
|
||||
"write:mdx": "node scripts/write-posts.mjs fixtures/mdx/src/content/generated 1000 mdx",
|
||||
"write:mdoc": "node scripts/write-posts.mjs fixtures/mdoc/src/content/generated 1000 mdoc"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"npm-run-all": "^4.1.5"
|
||||
}
|
||||
}
|
74
packages/astro/performance/scripts/write-posts.mjs
Normal file
74
packages/astro/performance/scripts/write-posts.mjs
Normal file
|
@ -0,0 +1,74 @@
|
|||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
const NUM_POSTS = 10;
|
||||
const POSTS_DIR = './src/content/posts.generated';
|
||||
const EXT = '.md';
|
||||
|
||||
(async function writePosts() {
|
||||
const postsDir = process.argv[2] ?? POSTS_DIR;
|
||||
const numPosts = Number(process.argv[3]) ?? NUM_POSTS;
|
||||
const ext = process.argv[4] ?? EXT;
|
||||
if (fs.existsSync(postsDir)) {
|
||||
const files = await fs.promises.readdir(postsDir);
|
||||
await Promise.all(files.map((file) => fs.promises.unlink(path.join(postsDir, file))));
|
||||
} else {
|
||||
await fs.promises.mkdir(postsDir, { recursive: true });
|
||||
}
|
||||
|
||||
await Promise.all(
|
||||
Array.from(Array(numPosts).keys()).map((idx) => {
|
||||
return fs.promises.writeFile(
|
||||
`${postsDir}/post-${idx}${ext.startsWith('.') ? ext : `.${ext}`}`,
|
||||
toMdContents(idx)
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
console.log(`${numPosts} posts written 🚀`);
|
||||
})();
|
||||
|
||||
const toMdContents = (idx) => `---
|
||||
title: Example ${idx}
|
||||
---
|
||||
|
||||
# Post ${idx}
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur interdum quam vitae est dapibus auctor. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Vivamus id purus vel ante interdum eleifend non sed magna. Nullam aliquet metus eget nunc pretium, ac malesuada elit ultricies. Quisque fermentum tellus sed risus tristique tincidunt. Interdum et malesuada fames ac ante ipsum primis in faucibus. Maecenas eleifend odio sed tortor rhoncus venenatis. Maecenas dignissim convallis sem et sagittis. Aliquam facilisis auctor consectetur. Morbi vulputate fermentum lobortis. Aenean luctus risus erat, sit amet imperdiet lectus tempor et.
|
||||
|
||||
Aliquam erat volutpat. Vivamus sodales auctor hendrerit. Proin sollicitudin, neque id volutpat ultrices, urna tellus maximus quam, at placerat diam quam a nisl. In commodo, nibh quis rhoncus lacinia, felis nisi egestas tortor, dictum mollis magna massa at tortor. Cras tempus eleifend turpis, nec suscipit velit egestas a. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Suspendisse nec nulla accumsan, sollicitudin dolor non, varius ipsum. Sed vel congue felis, sit amet bibendum neque. Pellentesque ut diam mollis augue auctor venenatis. Sed vitae aliquet lacus. Proin rutrum eget urna in vehicula. Vestibulum malesuada quis velit ac imperdiet. Donec interdum posuere nisl in auctor. Integer auctor pretium posuere.
|
||||
|
||||
Aenean tincidunt vitae augue id lacinia. Fusce a lorem accumsan, luctus magna non, fermentum arcu. Quisque mattis nibh ut ultrices vehicula. Fusce at porta mauris, eu sollicitudin augue. Curabitur tempor ante vulputate posuere interdum. Nam volutpat odio in blandit dapibus. Aliquam sit amet rutrum tortor.
|
||||
|
||||
Nulla eu odio nisl. Quisque malesuada arcu quis velit fermentum condimentum. Suspendisse potenti. Nullam non egestas sem. Sed et mi pharetra, ornare nunc ultricies, cursus est. Cras dignissim nisl eleifend nisl condimentum placerat. Vivamus tristique mattis vestibulum.
|
||||
|
||||
Maecenas at convallis dui. Pellentesque ac convallis libero. Mauris elementum arcu in quam pulvinar, a tincidunt dolor volutpat. Donec posuere eros ac nunc aliquam, non iaculis purus faucibus. Maecenas non lacus eu elit hendrerit fringilla eget vitae justo. Donec non lorem eu libero placerat volutpat. Vivamus euismod tristique lacus quis tincidunt.
|
||||
|
||||
Morbi a ligula eu odio dictum pharetra. Vestibulum a leo sit amet urna sodales facilisis posuere pretium lorem. Duis consectetur elementum sodales. Ut id libero quis dui laoreet faucibus eget ac felis. Suspendisse eu augue facilisis, consequat ex at, malesuada justo. Fusce tempor convallis orci a tristique. Pellentesque dapibus magna in sapien congue pharetra. Suspendisse potenti. Fusce in tortor justo. In hac habitasse platea dictumst. Pellentesque ligula odio, auctor vel consectetur quis, egestas a lectus. Sed arcu sapien, venenatis vitae nunc vitae, feugiat consequat elit.
|
||||
|
||||
Fusce bibendum odio tellus, ac consequat magna fringilla nec. Donec sed purus at magna pulvinar iaculis ac at nulla. Cras placerat, velit quis suscipit malesuada, eros dui ultrices sapien, sodales imperdiet enim ipsum vitae nisi. Mauris malesuada pretium nibh et luctus. Suspendisse potenti. In ante nibh, euismod at diam in, dapibus facilisis nunc. Suspendisse eleifend mollis dolor sit amet tristique. Nulla mattis tempor urna, nec pellentesque ante feugiat ut. Curabitur eleifend purus sed justo facilisis lacinia. Etiam maximus magna rhoncus quam tincidunt sollicitudin. Proin rhoncus metus lacus, non euismod mi gravida ac. Nam ac ipsum nec ante ultrices tempus ac mollis erat. Quisque ac tortor dolor. Integer eros mi, porttitor at rutrum ut, cursus sit amet ex. Pellentesque sed tortor vitae lorem malesuada gravida. Pellentesque bibendum ex nunc, non cursus lorem viverra gravida.
|
||||
|
||||
Integer lobortis erat quis dolor maximus porta. Sed ipsum est, maximus sit amet hendrerit ac, euismod quis nisi. Sed tincidunt, nisi sit amet varius tempus, turpis nisi sodales ante, sed ultricies urna neque vel purus. Maecenas sed laoreet tortor. Pellentesque enim massa, cursus in mauris vitae, facilisis egestas nisi. Mauris non ultrices purus, nec cursus diam. Proin eget ullamcorper augue. Pellentesque vehicula, sem vel dapibus tempus, neque tortor euismod libero, sed euismod diam enim id sapien. Sed mauris tellus, pretium eu ornare vitae, rhoncus at quam. Donec luctus mollis justo id rutrum. Aenean efficitur arcu nisi, non dignissim massa auctor et. In egestas lobortis nisi ac pharetra. Nam ultricies ipsum ut dui porta, sed commodo arcu vestibulum. Sed in felis molestie ante sodales auctor.
|
||||
|
||||
Praesent ac augue dui. Sed venenatis sit amet quam non rutrum. Vestibulum vitae tempor mi. Cras id luctus sapien, consectetur euismod magna. Nunc quis pellentesque sem, ut suscipit justo. Aliquam dignissim risus ante, vitae luctus enim vestibulum id. In hac habitasse platea dictumst. Nam rhoncus ante sed commodo porta. Ut lectus eros, porta sit amet velit vitae, elementum dignissim nulla. Cras nec scelerisque nulla. Quisque in diam eleifend, congue nulla eu, vestibulum magna. Sed vel purus elementum, mattis nunc id, mollis arcu. Pellentesque in pellentesque ipsum, non condimentum augue. Aenean tincidunt dui ut purus aliquet pretium. Integer vitae velit aliquet, tincidunt urna sed, bibendum lorem. Vivamus sit amet sapien ut sapien rhoncus fringilla vel a mi.
|
||||
|
||||
Praesent dignissim, arcu vel sollicitudin dictum, augue velit pretium ante, sit amet egestas velit lectus et tortor. In egestas ullamcorper risus, non vestibulum diam ultricies eu. Praesent a ex ac nisi consequat rhoncus. Fusce feugiat feugiat libero, vel lobortis mauris faucibus elementum. Mauris vitae luctus sapien. Etiam id pretium metus, in lacinia eros. Morbi et dictum risus. Morbi fringilla lorem ut elit fringilla blandit.
|
||||
|
||||
Nullam eu nibh ipsum. Curabitur aliquet varius ante, a pretium mauris dictum in. Integer nibh arcu, tristique ac sagittis nec, maximus et ligula. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin blandit nec mi vel hendrerit. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Morbi consequat blandit orci, sed placerat sem fermentum sit amet. Quisque eu iaculis nisl. Suspendisse quam mauris, semper vel eleifend vitae, mollis in arcu.
|
||||
|
||||
Aenean porttitor blandit orci id bibendum. Nunc sit amet ligula bibendum, congue urna fringilla, dictum purus. Pellentesque blandit, nibh id laoreet placerat, mauris dui semper mi, id tincidunt metus massa nec nisi. Suspendisse potenti. Phasellus ut risus velit. Curabitur porttitor metus nunc, in malesuada justo gravida sit amet. Cras auctor justo magna, ut eleifend turpis dictum id. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Pellentesque ut augue ac velit imperdiet suscipit non at massa.
|
||||
|
||||
Suspendisse euismod ornare quam id varius. Etiam ac velit id quam accumsan imperdiet sit amet eu nibh. Ut nec massa ultricies enim iaculis feugiat. Phasellus vehicula massa id ligula dapibus, sit amet viverra justo volutpat. Sed nunc est, efficitur et purus id, lacinia pellentesque metus. Pellentesque mi quam, maximus a blandit nec, mollis eget leo. Nulla sit amet elementum augue. Aenean id luctus nisl. Etiam non ante id augue dignissim suscipit in id quam. Quisque non consequat diam, eget condimentum turpis. Donec fringilla metus eget condimentum congue. Pellentesque aliquet blandit posuere. In bibendum ultrices ex a ornare. Donec quis efficitur metus. In commodo sollicitudin turpis et efficitur. Ut ac viverra nunc, sit amet varius sapien.
|
||||
|
||||
In sit amet felis et diam vehicula placerat. Nullam finibus lorem libero, et pretium eros consectetur euismod. In fringilla semper diam et hendrerit. Phasellus id erat at justo imperdiet aliquet. Donec dignissim auctor nunc, et ultrices ex rutrum nec. Aliquam ut cursus leo. Suspendisse semper velit ac lorem aliquet fermentum. Suspendisse congue mi et ultrices bibendum. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec ac neque et enim facilisis posuere volutpat a augue. Vivamus feugiat fermentum rhoncus.
|
||||
|
||||
Proin ultricies turpis non mauris finibus elementum. Cras scelerisque pretium justo non efficitur. Curabitur at risus ut velit ullamcorper fringilla congue in nulla. Nunc laoreet lacinia purus at lobortis. Sed vulputate ex non cursus accumsan. Morbi risus elit, porttitor ac hendrerit sed, commodo suscipit nisi. Vivamus vestibulum ex sapien, sagittis blandit velit fermentum et.
|
||||
|
||||
Suspendisse ut ullamcorper ex, a hendrerit elit. Vivamus gravida tempor efficitur. Ut lobortis neque a mollis efficitur. Donec sit amet arcu quis massa fringilla consequat. Duis vitae nisl laoreet, suscipit tellus nec, malesuada sem. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Phasellus in sollicitudin nisi. Fusce id sapien ac nunc sagittis lobortis tempor auctor eros. Nunc lacinia enim vitae massa lacinia, suscipit facilisis turpis tempus. Integer nec mollis ex. Pellentesque magna nisl, dignissim in mi quis, malesuada elementum nibh. Duis consectetur erat quis interdum ornare. Phasellus lorem felis, aliquam a nunc at, luctus faucibus odio. In hac habitasse platea dictumst.
|
||||
|
||||
Vestibulum sit amet lorem arcu. Integer sed nisl ut turpis dapibus mollis sit amet sed turpis. Donec massa dolor, blandit at lacinia eu, ultricies eu turpis. Sed mollis non diam non consectetur. Morbi suscipit metus at orci sagittis ultricies. Mauris pulvinar maximus ex vitae convallis. Ut imperdiet vehicula mi ut imperdiet. Aliquam et dui at turpis volutpat condimentum. Morbi laoreet scelerisque leo, non tristique ante convallis vulputate. Nam et lorem enim. Cras cursus sodales nisi, nec facilisis felis feugiat sit amet. Aenean consequat pellentesque magna id venenatis. Nunc sed quam consequat, vestibulum diam nec, dignissim justo. Duis vulputate nibh sit amet tortor lobortis iaculis. Curabitur pellentesque dui sapien, nec varius libero hendrerit vel.
|
||||
|
||||
Curabitur quis mi ac massa hendrerit ornare id eget velit. Nulla dui lacus, hendrerit et fringilla sed, eleifend ut erat. Nunc ut fringilla ex, sit amet fringilla libero. Maecenas non ullamcorper orci. Duis posuere erat et urna rhoncus iaculis. Proin pellentesque porttitor nulla, non blandit ante semper vitae. Phasellus ut augue venenatis, tempus purus eu, efficitur massa. Etiam vel egestas tellus, ac pharetra lectus. Aliquam non commodo turpis. Quisque pharetra nunc et mauris bibendum, id vestibulum tellus fringilla. Nullam enim massa, porta id nisi at, accumsan sollicitudin elit. Morbi auctor lectus vitae orci cursus, et hendrerit odio accumsan. Pellentesque quis libero auctor, tempor dolor tempor, finibus arcu. Aliquam non cursus ex. Aliquam quis lacus ut purus pellentesque ultrices in a augue.
|
||||
|
||||
Morbi nunc diam, egestas sed condimentum a, interdum suscipit ligula. Morbi interdum dignissim imperdiet. Interdum et malesuada fames ac ante ipsum primis in faucibus. Mauris egestas, nulla nec feugiat porttitor, ex magna sodales nisl, ac volutpat tortor mauris vitae nibh. Cras cursus dignissim pretium. Nunc faucibus dui at lectus pellentesque vehicula. Maecenas tincidunt, libero quis hendrerit aliquet, tortor leo iaculis enim, sit amet ullamcorper tellus risus a orci. Donec dignissim metus in nulla eleifend molestie. Nunc at turpis et sem laoreet rutrum. Nulla facilisi. Sed luctus nisi sed egestas cursus.
|
||||
`;
|
|
@ -977,12 +977,28 @@ export interface AstroConfig extends z.output<typeof AstroConfigSchema> {
|
|||
integrations: AstroIntegration[];
|
||||
}
|
||||
|
||||
export interface ContentEntryType {
|
||||
extensions: string[];
|
||||
getEntryInfo(params: { fileUrl: URL; contents: string }): Promise<{
|
||||
data: Record<string, unknown>;
|
||||
/**
|
||||
* Used for error hints to point to correct line and location
|
||||
* Should be the untouched data as read from the file,
|
||||
* including newlines
|
||||
*/
|
||||
rawData: string;
|
||||
body: string;
|
||||
slug: string;
|
||||
}>;
|
||||
contentModuleTypes?: string;
|
||||
}
|
||||
|
||||
export interface AstroSettings {
|
||||
config: AstroConfig;
|
||||
|
||||
adapter: AstroAdapter | undefined;
|
||||
injectedRoutes: InjectedRoute[];
|
||||
pageExtensions: string[];
|
||||
contentEntryTypes: ContentEntryType[];
|
||||
renderers: AstroRenderer[];
|
||||
scripts: {
|
||||
stage: InjectedScriptStage;
|
||||
|
@ -992,6 +1008,7 @@ export interface AstroSettings {
|
|||
tsConfigPath: string | undefined;
|
||||
watchFiles: string[];
|
||||
forceDisableTelemetry: boolean;
|
||||
performanceRun?: boolean;
|
||||
}
|
||||
|
||||
export type AsyncRendererComponentFn<U> = (
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
export const contentFileExts = ['.md', '.mdx'];
|
||||
export const PROPAGATED_ASSET_FLAG = 'astroPropagatedAssets';
|
||||
export const CONTENT_FLAG = 'astroContent';
|
||||
export const VIRTUAL_MODULE_ID = 'astro:content';
|
||||
|
|
|
@ -184,7 +184,7 @@ async function render({
|
|||
|
||||
return {
|
||||
Content,
|
||||
headings: mod.getHeadings(),
|
||||
remarkPluginFrontmatter: mod.frontmatter,
|
||||
headings: mod.getHeadings?.() ?? [],
|
||||
remarkPluginFrontmatter: mod.frontmatter ?? {},
|
||||
};
|
||||
}
|
||||
|
|
20
packages/astro/src/content/template/types.d.ts
vendored
20
packages/astro/src/content/template/types.d.ts
vendored
|
@ -1,7 +1,17 @@
|
|||
declare module 'astro:content' {
|
||||
interface Render {
|
||||
'.md': Promise<{
|
||||
Content: import('astro').MarkdownInstance<{}>['Content'];
|
||||
headings: import('astro').MarkdownHeading[];
|
||||
remarkPluginFrontmatter: Record<string, any>;
|
||||
}>;
|
||||
}
|
||||
}
|
||||
|
||||
declare module 'astro:content' {
|
||||
export { z } from 'astro/zod';
|
||||
export type CollectionEntry<C extends keyof typeof entryMap> =
|
||||
(typeof entryMap)[C][keyof (typeof entryMap)[C]] & Render;
|
||||
(typeof entryMap)[C][keyof (typeof entryMap)[C]];
|
||||
|
||||
type BaseSchemaWithoutEffects =
|
||||
| import('astro/zod').AnyZodObject
|
||||
|
@ -57,14 +67,6 @@ declare module 'astro:content' {
|
|||
Required<ContentConfig['collections'][C]>['schema']
|
||||
>;
|
||||
|
||||
type Render = {
|
||||
render(): Promise<{
|
||||
Content: import('astro').MarkdownInstance<{}>['Content'];
|
||||
headings: import('astro').MarkdownHeading[];
|
||||
remarkPluginFrontmatter: Record<string, any>;
|
||||
}>;
|
||||
};
|
||||
|
||||
const entryMap: {
|
||||
// @@ENTRY_MAP@@
|
||||
};
|
||||
|
|
|
@ -4,7 +4,7 @@ import type fsMod from 'node:fs';
|
|||
import * as path from 'node:path';
|
||||
import { fileURLToPath, pathToFileURL } from 'node:url';
|
||||
import { normalizePath, ViteDevServer } from 'vite';
|
||||
import type { AstroSettings } from '../@types/astro.js';
|
||||
import type { AstroSettings, ContentEntryType } from '../@types/astro.js';
|
||||
import { AstroError, AstroErrorData } from '../core/errors/index.js';
|
||||
import { info, LogOptions, warn } from '../core/logger/core.js';
|
||||
import { isRelativePath } from '../core/path.js';
|
||||
|
@ -14,6 +14,7 @@ import {
|
|||
ContentObservable,
|
||||
ContentPaths,
|
||||
EntryInfo,
|
||||
getContentEntryExts,
|
||||
getContentPaths,
|
||||
getEntryInfo,
|
||||
getEntrySlug,
|
||||
|
@ -52,11 +53,12 @@ export async function createContentTypesGenerator({
|
|||
}: CreateContentGeneratorParams) {
|
||||
const contentTypes: ContentTypes = {};
|
||||
const contentPaths = getContentPaths(settings.config, fs);
|
||||
const contentEntryExts = getContentEntryExts(settings);
|
||||
|
||||
let events: Promise<{ shouldGenerateTypes: boolean; error?: Error }>[] = [];
|
||||
let debounceTimeout: NodeJS.Timeout | undefined;
|
||||
|
||||
const contentTypesBase = await fs.promises.readFile(contentPaths.typesTemplate, 'utf-8');
|
||||
const typeTemplateContent = await fs.promises.readFile(contentPaths.typesTemplate, 'utf-8');
|
||||
|
||||
async function init(): Promise<
|
||||
{ typesGenerated: true } | { typesGenerated: false; reason: 'no-content-dir' }
|
||||
|
@ -112,7 +114,7 @@ export async function createContentTypesGenerator({
|
|||
}
|
||||
return { shouldGenerateTypes: true };
|
||||
}
|
||||
const fileType = getEntryType(fileURLToPath(event.entry), contentPaths);
|
||||
const fileType = getEntryType(fileURLToPath(event.entry), contentPaths, contentEntryExts);
|
||||
if (fileType === 'ignored') {
|
||||
return { shouldGenerateTypes: false };
|
||||
}
|
||||
|
@ -243,8 +245,9 @@ export async function createContentTypesGenerator({
|
|||
fs,
|
||||
contentTypes,
|
||||
contentPaths,
|
||||
contentTypesBase,
|
||||
typeTemplateContent,
|
||||
contentConfig: observable.status === 'loaded' ? observable.config : undefined,
|
||||
contentEntryTypes: settings.contentEntryTypes,
|
||||
});
|
||||
if (observable.status === 'loaded' && ['info', 'warn'].includes(logLevel)) {
|
||||
warnNonexistentCollections({
|
||||
|
@ -282,7 +285,7 @@ async function parseSlug({
|
|||
// on dev server startup or production build init.
|
||||
const rawContents = await fs.promises.readFile(event.entry, 'utf-8');
|
||||
const { data: frontmatter } = parseFrontmatter(rawContents, fileURLToPath(event.entry));
|
||||
return getEntrySlug({ ...entryInfo, data: frontmatter });
|
||||
return getEntrySlug({ ...entryInfo, unvalidatedSlug: frontmatter.slug });
|
||||
}
|
||||
|
||||
function setEntry(
|
||||
|
@ -302,13 +305,15 @@ async function writeContentFiles({
|
|||
fs,
|
||||
contentPaths,
|
||||
contentTypes,
|
||||
contentTypesBase,
|
||||
typeTemplateContent,
|
||||
contentEntryTypes,
|
||||
contentConfig,
|
||||
}: {
|
||||
fs: typeof fsMod;
|
||||
contentPaths: ContentPaths;
|
||||
contentTypes: ContentTypes;
|
||||
contentTypesBase: string;
|
||||
typeTemplateContent: string;
|
||||
contentEntryTypes: ContentEntryType[];
|
||||
contentConfig?: ContentConfig;
|
||||
}) {
|
||||
let contentTypesStr = '';
|
||||
|
@ -320,8 +325,11 @@ async function writeContentFiles({
|
|||
for (const entryKey of entryKeys) {
|
||||
const entryMetadata = contentTypes[collectionKey][entryKey];
|
||||
const dataType = collectionConfig?.schema ? `InferEntrySchema<${collectionKey}>` : 'any';
|
||||
const renderType = `{ render(): Render[${JSON.stringify(
|
||||
path.extname(JSON.parse(entryKey))
|
||||
)}] }`;
|
||||
const slugType = JSON.stringify(entryMetadata.slug);
|
||||
contentTypesStr += `${entryKey}: {\n id: ${entryKey},\n slug: ${slugType},\n body: string,\n collection: ${collectionKey},\n data: ${dataType}\n},\n`;
|
||||
contentTypesStr += `${entryKey}: {\n id: ${entryKey},\n slug: ${slugType},\n body: string,\n collection: ${collectionKey},\n data: ${dataType}\n} & ${renderType},\n`;
|
||||
}
|
||||
contentTypesStr += `},\n`;
|
||||
}
|
||||
|
@ -341,13 +349,21 @@ async function writeContentFiles({
|
|||
configPathRelativeToCacheDir = configPathRelativeToCacheDir.replace(/\.ts$/, '');
|
||||
}
|
||||
|
||||
contentTypesBase = contentTypesBase.replace('// @@ENTRY_MAP@@', contentTypesStr);
|
||||
contentTypesBase = contentTypesBase.replace(
|
||||
for (const contentEntryType of contentEntryTypes) {
|
||||
if (contentEntryType.contentModuleTypes) {
|
||||
typeTemplateContent = contentEntryType.contentModuleTypes + '\n' + typeTemplateContent;
|
||||
}
|
||||
}
|
||||
typeTemplateContent = typeTemplateContent.replace('// @@ENTRY_MAP@@', contentTypesStr);
|
||||
typeTemplateContent = typeTemplateContent.replace(
|
||||
"'@@CONTENT_CONFIG_TYPE@@'",
|
||||
contentConfig ? `typeof import(${JSON.stringify(configPathRelativeToCacheDir)})` : 'never'
|
||||
);
|
||||
|
||||
await fs.promises.writeFile(new URL(CONTENT_TYPES_FILE, contentPaths.cacheDir), contentTypesBase);
|
||||
await fs.promises.writeFile(
|
||||
new URL(CONTENT_TYPES_FILE, contentPaths.cacheDir),
|
||||
typeTemplateContent
|
||||
);
|
||||
}
|
||||
|
||||
function warnNonexistentCollections({
|
||||
|
|
|
@ -7,7 +7,7 @@ import { ErrorPayload as ViteErrorPayload, normalizePath, ViteDevServer } from '
|
|||
import { z } from 'zod';
|
||||
import { AstroConfig, AstroSettings } from '../@types/astro.js';
|
||||
import { AstroError, AstroErrorData } from '../core/errors/index.js';
|
||||
import { contentFileExts, CONTENT_TYPES_FILE } from './consts.js';
|
||||
import { CONTENT_TYPES_FILE } from './consts.js';
|
||||
|
||||
export const collectionConfigParser = z.object({
|
||||
schema: z.any().optional(),
|
||||
|
@ -29,14 +29,7 @@ export const contentConfigParser = z.object({
|
|||
export type CollectionConfig = z.infer<typeof collectionConfigParser>;
|
||||
export type ContentConfig = z.infer<typeof contentConfigParser>;
|
||||
|
||||
type Entry = {
|
||||
id: string;
|
||||
collection: string;
|
||||
slug: string;
|
||||
data: any;
|
||||
body: string;
|
||||
_internal: { rawData: string; filePath: string };
|
||||
};
|
||||
type EntryInternal = { rawData: string; filePath: string };
|
||||
|
||||
export type EntryInfo = {
|
||||
id: string;
|
||||
|
@ -53,10 +46,10 @@ export function getEntrySlug({
|
|||
id,
|
||||
collection,
|
||||
slug,
|
||||
data: unparsedData,
|
||||
}: Pick<Entry, 'id' | 'collection' | 'slug' | 'data'>) {
|
||||
unvalidatedSlug,
|
||||
}: EntryInfo & { unvalidatedSlug?: unknown }) {
|
||||
try {
|
||||
return z.string().default(slug).parse(unparsedData.slug);
|
||||
return z.string().default(slug).parse(unvalidatedSlug);
|
||||
} catch {
|
||||
throw new AstroError({
|
||||
...AstroErrorData.InvalidContentEntrySlugError,
|
||||
|
@ -65,9 +58,12 @@ export function getEntrySlug({
|
|||
}
|
||||
}
|
||||
|
||||
export async function getEntryData(entry: Entry, collectionConfig: CollectionConfig) {
|
||||
export async function getEntryData(
|
||||
entry: EntryInfo & { unvalidatedData: Record<string, unknown>; _internal: EntryInternal },
|
||||
collectionConfig: CollectionConfig
|
||||
) {
|
||||
// Remove reserved `slug` field before parsing data
|
||||
let { slug, ...data } = entry.data;
|
||||
let { slug, ...data } = entry.unvalidatedData;
|
||||
if (collectionConfig.schema) {
|
||||
// TODO: remove for 2.0 stable release
|
||||
if (
|
||||
|
@ -94,7 +90,9 @@ export async function getEntryData(entry: Entry, collectionConfig: CollectionCon
|
|||
});
|
||||
}
|
||||
// Use `safeParseAsync` to allow async transforms
|
||||
const parsed = await collectionConfig.schema.safeParseAsync(entry.data, { errorMap });
|
||||
const parsed = await collectionConfig.schema.safeParseAsync(entry.unvalidatedData, {
|
||||
errorMap,
|
||||
});
|
||||
if (parsed.success) {
|
||||
data = parsed.data;
|
||||
} else {
|
||||
|
@ -120,6 +118,10 @@ export async function getEntryData(entry: Entry, collectionConfig: CollectionCon
|
|||
return data;
|
||||
}
|
||||
|
||||
export function getContentEntryExts(settings: Pick<AstroSettings, 'contentEntryTypes'>) {
|
||||
return settings.contentEntryTypes.map((t) => t.extensions).flat();
|
||||
}
|
||||
|
||||
export class NoCollectionError extends Error {}
|
||||
|
||||
export function getEntryInfo(
|
||||
|
@ -160,14 +162,15 @@ export function getEntryInfo({
|
|||
|
||||
export function getEntryType(
|
||||
entryPath: string,
|
||||
paths: Pick<ContentPaths, 'config'>
|
||||
paths: Pick<ContentPaths, 'config'>,
|
||||
contentFileExts: string[]
|
||||
): 'content' | 'config' | 'ignored' | 'unsupported' {
|
||||
const { ext, base } = path.parse(entryPath);
|
||||
const fileUrl = pathToFileURL(entryPath);
|
||||
|
||||
if (hasUnderscoreInPath(fileUrl) || isOnIgnoreList(base)) {
|
||||
return 'ignored';
|
||||
} else if ((contentFileExts as readonly string[]).includes(ext)) {
|
||||
} else if (contentFileExts.includes(ext)) {
|
||||
return 'content';
|
||||
} else if (fileUrl.href === paths.config.url.href) {
|
||||
return 'config';
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import npath from 'node:path';
|
||||
import { pathToFileURL } from 'url';
|
||||
import type { Plugin } from 'vite';
|
||||
import { AstroSettings } from '../@types/astro.js';
|
||||
import { moduleIsTopLevelPage, walkParentInfos } from '../core/build/graph.js';
|
||||
import { BuildInternals, getPageDataByViteID } from '../core/build/internal.js';
|
||||
import { AstroBuildPlugin } from '../core/build/plugin.js';
|
||||
|
@ -11,23 +12,30 @@ import { prependForwardSlash } from '../core/path.js';
|
|||
import { getStylesForURL } from '../core/render/dev/css.js';
|
||||
import { getScriptsForURL } from '../core/render/dev/scripts.js';
|
||||
import {
|
||||
contentFileExts,
|
||||
LINKS_PLACEHOLDER,
|
||||
PROPAGATED_ASSET_FLAG,
|
||||
SCRIPTS_PLACEHOLDER,
|
||||
STYLES_PLACEHOLDER,
|
||||
} from './consts.js';
|
||||
import { getContentEntryExts } from './utils.js';
|
||||
|
||||
function isPropagatedAsset(viteId: string): boolean {
|
||||
function isPropagatedAsset(viteId: string, contentEntryExts: string[]): boolean {
|
||||
const url = new URL(viteId, 'file://');
|
||||
return (
|
||||
url.searchParams.has(PROPAGATED_ASSET_FLAG) &&
|
||||
contentFileExts.some((ext) => url.pathname.endsWith(ext))
|
||||
contentEntryExts.some((ext) => url.pathname.endsWith(ext))
|
||||
);
|
||||
}
|
||||
|
||||
export function astroContentAssetPropagationPlugin({ mode }: { mode: string }): Plugin {
|
||||
export function astroContentAssetPropagationPlugin({
|
||||
mode,
|
||||
settings,
|
||||
}: {
|
||||
mode: string;
|
||||
settings: AstroSettings;
|
||||
}): Plugin {
|
||||
let devModuleLoader: ModuleLoader;
|
||||
const contentEntryExts = getContentEntryExts(settings);
|
||||
return {
|
||||
name: 'astro:content-asset-propagation',
|
||||
enforce: 'pre',
|
||||
|
@ -37,7 +45,7 @@ export function astroContentAssetPropagationPlugin({ mode }: { mode: string }):
|
|||
}
|
||||
},
|
||||
load(id) {
|
||||
if (isPropagatedAsset(id)) {
|
||||
if (isPropagatedAsset(id, contentEntryExts)) {
|
||||
const basePath = id.split('?')[0];
|
||||
const code = `
|
||||
export async function getMod() {
|
||||
|
@ -52,7 +60,7 @@ export function astroContentAssetPropagationPlugin({ mode }: { mode: string }):
|
|||
},
|
||||
async transform(code, id, options) {
|
||||
if (!options?.ssr) return;
|
||||
if (devModuleLoader && isPropagatedAsset(id)) {
|
||||
if (devModuleLoader && isPropagatedAsset(id, contentEntryExts)) {
|
||||
const basePath = id.split('?')[0];
|
||||
if (!devModuleLoader.getModuleById(basePath)?.ssrModule) {
|
||||
await devModuleLoader.import(basePath);
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
import * as devalue from 'devalue';
|
||||
import type fsMod from 'node:fs';
|
||||
import { extname } from 'node:path';
|
||||
import { pathToFileURL } from 'url';
|
||||
import type { Plugin } from 'vite';
|
||||
import { AstroSettings } from '../@types/astro.js';
|
||||
import { AstroSettings, ContentEntryType } from '../@types/astro.js';
|
||||
import { AstroErrorData } from '../core/errors/errors-data.js';
|
||||
import { AstroError } from '../core/errors/errors.js';
|
||||
import { escapeViteEnvReferences, getFileInfo } from '../vite-plugin-utils/index.js';
|
||||
import { contentFileExts, CONTENT_FLAG } from './consts.js';
|
||||
import { CONTENT_FLAG } from './consts.js';
|
||||
import {
|
||||
ContentConfig,
|
||||
getContentEntryExts,
|
||||
getContentPaths,
|
||||
getEntryData,
|
||||
getEntryInfo,
|
||||
|
@ -18,9 +20,9 @@ import {
|
|||
parseFrontmatter,
|
||||
} from './utils.js';
|
||||
|
||||
function isContentFlagImport(viteId: string) {
|
||||
const { pathname, searchParams } = new URL(viteId, 'file://');
|
||||
return searchParams.has(CONTENT_FLAG) && contentFileExts.some((ext) => pathname.endsWith(ext));
|
||||
function isContentFlagImport(viteId: string, contentEntryExts: string[]) {
|
||||
const { searchParams, pathname } = new URL(viteId, 'file://');
|
||||
return searchParams.has(CONTENT_FLAG) && contentEntryExts.some((ext) => pathname.endsWith(ext));
|
||||
}
|
||||
|
||||
export function astroContentImportPlugin({
|
||||
|
@ -31,12 +33,20 @@ export function astroContentImportPlugin({
|
|||
settings: AstroSettings;
|
||||
}): Plugin {
|
||||
const contentPaths = getContentPaths(settings.config, fs);
|
||||
const contentEntryExts = getContentEntryExts(settings);
|
||||
|
||||
const contentEntryExtToParser: Map<string, ContentEntryType> = new Map();
|
||||
for (const entryType of settings.contentEntryTypes) {
|
||||
for (const ext of entryType.extensions) {
|
||||
contentEntryExtToParser.set(ext, entryType);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
name: 'astro:content-imports',
|
||||
async load(id) {
|
||||
const { fileId } = getFileInfo(id, settings.config);
|
||||
if (isContentFlagImport(id)) {
|
||||
if (isContentFlagImport(id, contentEntryExts)) {
|
||||
const observable = globalContentConfigObserver.get();
|
||||
|
||||
// Content config should be loaded before this plugin is used
|
||||
|
@ -69,37 +79,48 @@ export function astroContentImportPlugin({
|
|||
});
|
||||
}
|
||||
const rawContents = await fs.promises.readFile(fileId, 'utf-8');
|
||||
const {
|
||||
content: body,
|
||||
data: unparsedData,
|
||||
matter: rawData = '',
|
||||
} = parseFrontmatter(rawContents, fileId);
|
||||
const entryInfo = getEntryInfo({
|
||||
const fileExt = extname(fileId);
|
||||
if (!contentEntryExtToParser.has(fileExt)) {
|
||||
throw new AstroError({
|
||||
...AstroErrorData.UnknownContentCollectionError,
|
||||
message: `No parser found for content entry ${JSON.stringify(
|
||||
fileId
|
||||
)}. Did you apply an integration for this file type?`,
|
||||
});
|
||||
}
|
||||
const contentEntryParser = contentEntryExtToParser.get(fileExt)!;
|
||||
const info = await contentEntryParser.getEntryInfo({
|
||||
fileUrl: pathToFileURL(fileId),
|
||||
contents: rawContents,
|
||||
});
|
||||
const generatedInfo = getEntryInfo({
|
||||
entry: pathToFileURL(fileId),
|
||||
contentDir: contentPaths.contentDir,
|
||||
});
|
||||
if (entryInfo instanceof Error) return;
|
||||
if (generatedInfo instanceof Error) return;
|
||||
|
||||
const _internal = { filePath: fileId, rawData };
|
||||
const partialEntry = { data: unparsedData, body, _internal, ...entryInfo };
|
||||
const _internal = { filePath: fileId, rawData: info.rawData };
|
||||
// TODO: move slug calculation to the start of the build
|
||||
// to generate a performant lookup map for `getEntryBySlug`
|
||||
const slug = getEntrySlug(partialEntry);
|
||||
const slug = getEntrySlug({ ...generatedInfo, unvalidatedSlug: info.slug });
|
||||
|
||||
const collectionConfig = contentConfig?.collections[entryInfo.collection];
|
||||
const collectionConfig = contentConfig?.collections[generatedInfo.collection];
|
||||
const data = collectionConfig
|
||||
? await getEntryData(partialEntry, collectionConfig)
|
||||
: unparsedData;
|
||||
? await getEntryData(
|
||||
{ ...generatedInfo, _internal, unvalidatedData: info.data },
|
||||
collectionConfig
|
||||
)
|
||||
: info.data;
|
||||
|
||||
const code = escapeViteEnvReferences(`
|
||||
export const id = ${JSON.stringify(entryInfo.id)};
|
||||
export const collection = ${JSON.stringify(entryInfo.collection)};
|
||||
export const id = ${JSON.stringify(generatedInfo.id)};
|
||||
export const collection = ${JSON.stringify(generatedInfo.collection)};
|
||||
export const slug = ${JSON.stringify(slug)};
|
||||
export const body = ${JSON.stringify(body)};
|
||||
export const body = ${JSON.stringify(info.body)};
|
||||
export const data = ${devalue.uneval(data) /* TODO: reuse astro props serializer */};
|
||||
export const _internal = {
|
||||
filePath: ${JSON.stringify(fileId)},
|
||||
rawData: ${JSON.stringify(rawData)},
|
||||
filePath: ${JSON.stringify(_internal.filePath)},
|
||||
rawData: ${JSON.stringify(_internal.rawData)},
|
||||
};
|
||||
`);
|
||||
return { code };
|
||||
|
@ -109,11 +130,11 @@ export const _internal = {
|
|||
viteServer.watcher.on('all', async (event, entry) => {
|
||||
if (
|
||||
['add', 'unlink', 'change'].includes(event) &&
|
||||
getEntryType(entry, contentPaths) === 'config'
|
||||
getEntryType(entry, contentPaths, contentEntryExts) === 'config'
|
||||
) {
|
||||
// Content modules depend on config, so we need to invalidate them.
|
||||
for (const modUrl of viteServer.moduleGraph.urlToModuleMap.keys()) {
|
||||
if (isContentFlagImport(modUrl)) {
|
||||
if (isContentFlagImport(modUrl, contentEntryExts)) {
|
||||
const mod = await viteServer.moduleGraph.getModuleByUrl(modUrl);
|
||||
if (mod) {
|
||||
viteServer.moduleGraph.invalidateModule(mod);
|
||||
|
@ -124,7 +145,7 @@ export const _internal = {
|
|||
});
|
||||
},
|
||||
async transform(code, id) {
|
||||
if (isContentFlagImport(id)) {
|
||||
if (isContentFlagImport(id, contentEntryExts)) {
|
||||
// Escape before Rollup internal transform.
|
||||
// Base on MUCH trial-and-error, inspired by MDX integration 2-step transform.
|
||||
return { code: escapeViteEnvReferences(code) };
|
||||
|
|
|
@ -4,8 +4,8 @@ import type { Plugin } from 'vite';
|
|||
import { normalizePath } from 'vite';
|
||||
import type { AstroSettings } from '../@types/astro.js';
|
||||
import { appendForwardSlash, prependForwardSlash } from '../core/path.js';
|
||||
import { contentFileExts, VIRTUAL_MODULE_ID } from './consts.js';
|
||||
import { getContentPaths } from './utils.js';
|
||||
import { VIRTUAL_MODULE_ID } from './consts.js';
|
||||
import { getContentEntryExts, getContentPaths } from './utils.js';
|
||||
|
||||
interface AstroContentVirtualModPluginParams {
|
||||
settings: AstroSettings;
|
||||
|
@ -22,7 +22,14 @@ export function astroContentVirtualModPlugin({
|
|||
)
|
||||
)
|
||||
);
|
||||
const entryGlob = `${relContentDir}**/*{${contentFileExts.join(',')}}`;
|
||||
const contentEntryExts = getContentEntryExts(settings);
|
||||
|
||||
const extGlob =
|
||||
contentEntryExts.length === 1
|
||||
? // Wrapping {...} breaks when there is only one extension
|
||||
contentEntryExts[0]
|
||||
: `{${contentEntryExts.join(',')}}`;
|
||||
const entryGlob = `${relContentDir}**/*${extGlob}`;
|
||||
const virtualModContents = fsMod
|
||||
.readFileSync(contentPaths.virtualModTemplate, 'utf-8')
|
||||
.replace('@@CONTENT_DIR@@', relContentDir)
|
||||
|
|
|
@ -350,6 +350,7 @@ async function generatePath(
|
|||
markdown: {
|
||||
...settings.config.markdown,
|
||||
contentDir: getContentPaths(settings.config).contentDir,
|
||||
performanceRun: settings.performanceRun,
|
||||
},
|
||||
mode: opts.mode,
|
||||
renderers,
|
||||
|
|
|
@ -215,6 +215,7 @@ function buildManifest(
|
|||
markdown: {
|
||||
...settings.config.markdown,
|
||||
contentDir: getContentPaths(settings.config).contentDir,
|
||||
performanceRun: settings.performanceRun,
|
||||
},
|
||||
pageMap: null as any,
|
||||
propagation: Array.from(internals.propagation),
|
||||
|
|
|
@ -5,6 +5,7 @@ import { fileURLToPath, pathToFileURL } from 'url';
|
|||
import jsxRenderer from '../../jsx/renderer.js';
|
||||
import { createDefaultDevConfig } from './config.js';
|
||||
import { loadTSConfig } from './tsconfig.js';
|
||||
import { markdownContentEntryType } from '../../vite-plugin-markdown/content-entry-type.js';
|
||||
|
||||
export function createBaseSettings(config: AstroConfig): AstroSettings {
|
||||
return {
|
||||
|
@ -15,6 +16,7 @@ export function createBaseSettings(config: AstroConfig): AstroSettings {
|
|||
adapter: undefined,
|
||||
injectedRoutes: [],
|
||||
pageExtensions: ['.astro', '.html', ...SUPPORTED_MARKDOWN_FILE_EXTENSIONS],
|
||||
contentEntryTypes: [markdownContentEntryType],
|
||||
renderers: [jsxRenderer],
|
||||
scripts: [],
|
||||
watchFiles: [],
|
||||
|
@ -23,6 +25,9 @@ export function createBaseSettings(config: AstroConfig): AstroSettings {
|
|||
}
|
||||
|
||||
export function createSettings(config: AstroConfig, cwd?: string): AstroSettings {
|
||||
// TODO: hoisted to flags handler
|
||||
const performanceRun = process.argv.some((arg) => arg === '--perf');
|
||||
|
||||
const tsconfig = loadTSConfig(cwd);
|
||||
const settings = createBaseSettings(config);
|
||||
|
||||
|
@ -35,6 +40,7 @@ export function createSettings(config: AstroConfig, cwd?: string): AstroSettings
|
|||
settings.tsConfig = tsconfig?.config;
|
||||
settings.tsConfigPath = tsconfig?.path;
|
||||
settings.watchFiles = watchFiles;
|
||||
settings.performanceRun = performanceRun;
|
||||
return settings;
|
||||
}
|
||||
|
||||
|
|
|
@ -112,7 +112,7 @@ export async function createVite(
|
|||
astroInjectEnvTsPlugin({ settings, logging, fs }),
|
||||
astroContentVirtualModPlugin({ settings }),
|
||||
astroContentImportPlugin({ fs, settings }),
|
||||
astroContentAssetPropagationPlugin({ mode }),
|
||||
astroContentAssetPropagationPlugin({ mode, settings }),
|
||||
],
|
||||
publicDir: fileURLToPath(settings.config.publicDir),
|
||||
root: fileURLToPath(settings.config.root),
|
||||
|
|
|
@ -25,6 +25,7 @@ export function createDevelopmentEnvironment(
|
|||
markdown: {
|
||||
...settings.config.markdown,
|
||||
contentDir: getContentPaths(settings.config).contentDir,
|
||||
performanceRun: settings.performanceRun,
|
||||
},
|
||||
mode,
|
||||
// This will be overridden in the dev server
|
||||
|
|
|
@ -8,6 +8,7 @@ import {
|
|||
AstroRenderer,
|
||||
AstroSettings,
|
||||
BuildConfig,
|
||||
ContentEntryType,
|
||||
HookParameters,
|
||||
RouteData,
|
||||
} from '../@types/astro.js';
|
||||
|
@ -100,11 +101,22 @@ export async function runHookConfigSetup({
|
|||
const exts = (input.flat(Infinity) as string[]).map((ext) => `.${ext.replace(/^\./, '')}`);
|
||||
updatedSettings.pageExtensions.push(...exts);
|
||||
}
|
||||
|
||||
// Semi-private `addContentEntryType` hook
|
||||
function addContentEntryType(contentEntryType: ContentEntryType) {
|
||||
updatedSettings.contentEntryTypes.push(contentEntryType);
|
||||
}
|
||||
|
||||
Object.defineProperty(hooks, 'addPageExtension', {
|
||||
value: addPageExtension,
|
||||
writable: false,
|
||||
enumerable: false,
|
||||
});
|
||||
Object.defineProperty(hooks, 'addContentEntryType', {
|
||||
value: addContentEntryType,
|
||||
writable: false,
|
||||
enumerable: false,
|
||||
});
|
||||
await withTakingALongTimeMsg({
|
||||
name: integration.name,
|
||||
hookResult: integration.hooks['astro:config:setup'](hooks),
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
import { fileURLToPath } from 'node:url';
|
||||
import { ContentEntryType } from '../@types/astro.js';
|
||||
import { parseFrontmatter } from '../content/utils.js';
|
||||
|
||||
export const markdownContentEntryType: ContentEntryType = {
|
||||
extensions: ['.md'],
|
||||
async getEntryInfo({ fileUrl, contents }: { fileUrl: URL; contents: string }) {
|
||||
const parsed = parseFrontmatter(contents, fileURLToPath(fileUrl));
|
||||
return {
|
||||
data: parsed.data,
|
||||
body: parsed.content,
|
||||
slug: parsed.data.slug,
|
||||
rawData: parsed.matter,
|
||||
};
|
||||
},
|
||||
};
|
|
@ -72,6 +72,7 @@ export default function markdown({ settings, logging }: AstroPluginOptions): Plu
|
|||
...settings.config.markdown,
|
||||
fileURL: new URL(`file://${fileId}`),
|
||||
contentDir: getContentPaths(settings.config).contentDir,
|
||||
performanceRun: settings.performanceRun,
|
||||
frontmatter: raw.data,
|
||||
});
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"astro": "workspace:*",
|
||||
"@astrojs/mdx": "workspace:*"
|
||||
"astro": "workspace:*"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@ import { getEntryType } from '../../../dist/content/utils.js';
|
|||
import { expect } from 'chai';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const contentFileExts = ['.md', '.mdx'];
|
||||
|
||||
describe('Content Collections - getEntryType', () => {
|
||||
const contentDir = new URL('src/content/', import.meta.url);
|
||||
const contentPaths = {
|
||||
|
@ -14,7 +16,7 @@ describe('Content Collections - getEntryType', () => {
|
|||
it('Returns "content" for Markdown files', () => {
|
||||
for (const entryPath of ['blog/first-post.md', 'blog/first-post.mdx']) {
|
||||
const entry = fileURLToPath(new URL(entryPath, contentDir));
|
||||
const type = getEntryType(entry, contentPaths);
|
||||
const type = getEntryType(entry, contentPaths, contentFileExts);
|
||||
expect(type).to.equal('content');
|
||||
}
|
||||
});
|
||||
|
@ -22,44 +24,44 @@ describe('Content Collections - getEntryType', () => {
|
|||
it('Returns "content" for Markdown files in nested directories', () => {
|
||||
for (const entryPath of ['blog/2021/01/01/index.md', 'blog/2021/01/01/index.mdx']) {
|
||||
const entry = fileURLToPath(new URL(entryPath, contentDir));
|
||||
const type = getEntryType(entry, contentPaths);
|
||||
const type = getEntryType(entry, contentPaths, contentFileExts);
|
||||
expect(type).to.equal('content');
|
||||
}
|
||||
});
|
||||
|
||||
it('Returns "config" for config files', () => {
|
||||
const entry = fileURLToPath(contentPaths.config.url);
|
||||
const type = getEntryType(entry, contentPaths);
|
||||
const type = getEntryType(entry, contentPaths, contentFileExts);
|
||||
expect(type).to.equal('config');
|
||||
});
|
||||
|
||||
it('Returns "unsupported" for non-Markdown files', () => {
|
||||
const entry = fileURLToPath(new URL('blog/robots.txt', contentDir));
|
||||
const type = getEntryType(entry, contentPaths);
|
||||
const type = getEntryType(entry, contentPaths, contentFileExts);
|
||||
expect(type).to.equal('unsupported');
|
||||
});
|
||||
|
||||
it('Returns "ignored" for .DS_Store', () => {
|
||||
const entry = fileURLToPath(new URL('blog/.DS_Store', contentDir));
|
||||
const type = getEntryType(entry, contentPaths);
|
||||
const type = getEntryType(entry, contentPaths, contentFileExts);
|
||||
expect(type).to.equal('ignored');
|
||||
});
|
||||
|
||||
it('Returns "ignored" for unsupported files using an underscore', () => {
|
||||
const entry = fileURLToPath(new URL('blog/_draft-robots.txt', contentDir));
|
||||
const type = getEntryType(entry, contentPaths);
|
||||
const type = getEntryType(entry, contentPaths, contentFileExts);
|
||||
expect(type).to.equal('ignored');
|
||||
});
|
||||
|
||||
it('Returns "ignored" when using underscore on file name', () => {
|
||||
const entry = fileURLToPath(new URL('blog/_first-post.md', contentDir));
|
||||
const type = getEntryType(entry, contentPaths);
|
||||
const type = getEntryType(entry, contentPaths, contentFileExts);
|
||||
expect(type).to.equal('ignored');
|
||||
});
|
||||
|
||||
it('Returns "ignored" when using underscore on directory name', () => {
|
||||
const entry = fileURLToPath(new URL('blog/_draft/first-post.md', contentDir));
|
||||
const type = getEntryType(entry, contentPaths);
|
||||
const type = getEntryType(entry, contentPaths, contentFileExts);
|
||||
expect(type).to.equal('ignored');
|
||||
});
|
||||
});
|
||||
|
|
614
packages/integrations/markdoc/CHANGELOG.md
Normal file
614
packages/integrations/markdoc/CHANGELOG.md
Normal file
|
@ -0,0 +1,614 @@
|
|||
# @astrojs/mdx
|
||||
|
||||
## 0.16.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#6050](https://github.com/withastro/astro/pull/6050) [`2ab32b59e`](https://github.com/withastro/astro/commit/2ab32b59ef0a28d34757f2c2adb9cf2baa86855e) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Fix: load syntax highlighters after MDX remark plugins. This keeps MDX consistent with Astro's markdown behavior.
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#6062](https://github.com/withastro/astro/pull/6062) [`c6cf847bd`](https://github.com/withastro/astro/commit/c6cf847bd0b6bef3c51a5710fba5ca43b11e46f9) Thanks [@delucis](https://github.com/delucis)! - Update MDX README
|
||||
|
||||
## 0.15.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#5478](https://github.com/withastro/astro/pull/5478) [`1c7eef308`](https://github.com/withastro/astro/commit/1c7eef308e808aa5ed4662b53e67ec8d1b814d1f) Thanks [@nemo0](https://github.com/nemo0)! - Update READMEs for consistency
|
||||
|
||||
## 0.15.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#5978](https://github.com/withastro/astro/pull/5978) [`7abb1e905`](https://github.com/withastro/astro/commit/7abb1e9056c4b4fd0abfced347df32a41cdfbf28) Thanks [@HiDeoo](https://github.com/HiDeoo)! - Fix MDX heading IDs generation when using a frontmatter reference
|
||||
|
||||
- Updated dependencies [[`7abb1e905`](https://github.com/withastro/astro/commit/7abb1e9056c4b4fd0abfced347df32a41cdfbf28)]:
|
||||
- @astrojs/markdown-remark@2.0.1
|
||||
|
||||
## 0.15.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#5684](https://github.com/withastro/astro/pull/5684) [`a9c292026`](https://github.com/withastro/astro/commit/a9c2920264e36cc5dc05f4adc1912187979edb0d) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Refine Markdown and MDX configuration options for ease-of-use. & [#5769](https://github.com/withastro/astro/pull/5769) [`93e633922`](https://github.com/withastro/astro/commit/93e633922c2e449df3bb2357b3683af1d3c0e07b) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Introduce a `smartypants` flag to opt-out of Astro's default SmartyPants plugin.
|
||||
|
||||
- **Markdown**
|
||||
|
||||
- **Replace the `extendDefaultPlugins` option** with a `gfm` boolean and a `smartypants` boolean. These are enabled by default, and can be disabled to remove GitHub-Flavored Markdown and SmartyPants.
|
||||
|
||||
- Ensure GitHub-Flavored Markdown and SmartyPants are applied whether or not custom `remarkPlugins` or `rehypePlugins` are configured. If you want to apply custom plugins _and_ remove Astro's default plugins, manually set `gfm: false` and `smartypants: false` in your config.
|
||||
|
||||
- **Migrate `extendDefaultPlugins` to `gfm` and `smartypants`**
|
||||
|
||||
You may have disabled Astro's built-in plugins (GitHub-Flavored Markdown and Smartypants) with the `extendDefaultPlugins` option. This has now been split into 2 flags to disable each plugin individually:
|
||||
|
||||
- `markdown.gfm` to disable GitHub-Flavored Markdown
|
||||
- `markdown.smartypants` to disable SmartyPants
|
||||
|
||||
```diff
|
||||
// astro.config.mjs
|
||||
import { defineConfig } from 'astro/config';
|
||||
|
||||
export default defineConfig({
|
||||
markdown: {
|
||||
- extendDefaultPlugins: false,
|
||||
+ smartypants: false,
|
||||
+ gfm: false,
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
Additionally, applying remark and rehype plugins **no longer disables** `gfm` and `smartypants`. You will need to opt-out manually by setting `gfm` and `smartypants` to `false`.
|
||||
|
||||
- **MDX**
|
||||
|
||||
- Support _all_ Markdown configuration options (except `drafts`) from your MDX integration config. This includes `syntaxHighlighting` and `shikiConfig` options to further customize the MDX renderer.
|
||||
|
||||
- Simplify `extendPlugins` to an `extendMarkdownConfig` option. MDX options will default to their equivalent in your Markdown config. By setting `extendMarkdownConfig` to false, you can "eject" to set your own syntax highlighting, plugins, and more.
|
||||
|
||||
- **Migrate MDX's `extendPlugins` to `extendMarkdownConfig`**
|
||||
|
||||
You may have used the `extendPlugins` option to manage plugin defaults in MDX. This has been replaced by 3 flags:
|
||||
|
||||
- `extendMarkdownConfig` (`true` by default) to toggle Markdown config inheritance. This replaces the `extendPlugins: 'markdown'` option.
|
||||
- `gfm` (`true` by default) and `smartypants` (`true` by default) to toggle GitHub-Flavored Markdown and SmartyPants in MDX. This replaces the `extendPlugins: 'defaults'` option.
|
||||
|
||||
- [#5687](https://github.com/withastro/astro/pull/5687) [`e2019be6f`](https://github.com/withastro/astro/commit/e2019be6ffa46fa33d92cfd346f9ecbe51bb7144) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Give remark and rehype plugins access to user frontmatter via frontmatter injection. This means `data.astro.frontmatter` is now the _complete_ Markdown or MDX document's frontmatter, rather than an empty object.
|
||||
|
||||
This allows plugin authors to modify existing frontmatter, or compute new properties based on other properties. For example, say you want to compute a full image URL based on an `imageSrc` slug in your document frontmatter:
|
||||
|
||||
```ts
|
||||
export function remarkInjectSocialImagePlugin() {
|
||||
return function (tree, file) {
|
||||
const { frontmatter } = file.data.astro;
|
||||
frontmatter.socialImageSrc = new URL(frontmatter.imageSrc, 'https://my-blog.com/').pathname;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
When using Content Collections, you can access this modified frontmatter using the `remarkPluginFrontmatter` property returned when rendering an entry.
|
||||
|
||||
**Migration instructions**
|
||||
|
||||
Plugin authors should now **check for user frontmatter when applying defaults.**
|
||||
|
||||
For example, say a remark plugin wants to apply a default `title` if none is present. Add a conditional to check if the property is present, and update if none exists:
|
||||
|
||||
```diff
|
||||
export function remarkInjectTitlePlugin() {
|
||||
return function (tree, file) {
|
||||
const { frontmatter } = file.data.astro;
|
||||
+ if (!frontmatter.title) {
|
||||
frontmatter.title = 'Default title';
|
||||
+ }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This differs from previous behavior, where a Markdown file's frontmatter would _always_ override frontmatter injected via remark or reype.
|
||||
|
||||
- [#5891](https://github.com/withastro/astro/pull/5891) [`05caf445d`](https://github.com/withastro/astro/commit/05caf445d4d2728f1010aeb2179a9e756c2fd17d) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Remove deprecated Markdown APIs from Astro v0.X. This includes `getHeaders()`, the `.astro` property for layouts, and the `rawContent()` and `compiledContent()` error messages for MDX.
|
||||
|
||||
- [#5782](https://github.com/withastro/astro/pull/5782) [`1f92d64ea`](https://github.com/withastro/astro/commit/1f92d64ea35c03fec43aff64eaf704dc5a9eb30a) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Remove support for Node 14. Minimum supported Node version is now >=16.12.0
|
||||
|
||||
- [#5825](https://github.com/withastro/astro/pull/5825) [`52209ca2a`](https://github.com/withastro/astro/commit/52209ca2ad72a30854947dcb3a90ab4db0ac0a6f) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Baseline the experimental `contentCollections` flag. You're free to remove this from your astro config!
|
||||
|
||||
```diff
|
||||
import { defineConfig } from 'astro/config';
|
||||
|
||||
export default defineConfig({
|
||||
- experimental: { contentCollections: true }
|
||||
})
|
||||
```
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#5837](https://github.com/withastro/astro/pull/5837) [`12f65a4d5`](https://github.com/withastro/astro/commit/12f65a4d55e3fd2993c2f67b18794dd536280c69) Thanks [@giuseppelt](https://github.com/giuseppelt)! - fix shiki css class replace logic
|
||||
|
||||
- [#5741](https://github.com/withastro/astro/pull/5741) [`000d3e694`](https://github.com/withastro/astro/commit/000d3e6940839c2aebba1984e6fb3b133cec6749) Thanks [@delucis](https://github.com/delucis)! - Fix broken links in README
|
||||
|
||||
- Updated dependencies [[`93e633922`](https://github.com/withastro/astro/commit/93e633922c2e449df3bb2357b3683af1d3c0e07b), [`e2019be6f`](https://github.com/withastro/astro/commit/e2019be6ffa46fa33d92cfd346f9ecbe51bb7144), [`1f92d64ea`](https://github.com/withastro/astro/commit/1f92d64ea35c03fec43aff64eaf704dc5a9eb30a), [`12f65a4d5`](https://github.com/withastro/astro/commit/12f65a4d55e3fd2993c2f67b18794dd536280c69), [`16107b6a1`](https://github.com/withastro/astro/commit/16107b6a10514ef1b563e585ec9add4b14f42b94), [`a9c292026`](https://github.com/withastro/astro/commit/a9c2920264e36cc5dc05f4adc1912187979edb0d), [`52209ca2a`](https://github.com/withastro/astro/commit/52209ca2ad72a30854947dcb3a90ab4db0ac0a6f), [`7572f7402`](https://github.com/withastro/astro/commit/7572f7402238da37de748be58d678fedaf863b53)]:
|
||||
- @astrojs/markdown-remark@2.0.0
|
||||
- @astrojs/prism@2.0.0
|
||||
|
||||
## 1.0.0-beta.2
|
||||
|
||||
<details>
|
||||
<summary>See changes in 1.0.0-beta.2</summary>
|
||||
|
||||
### Major Changes
|
||||
|
||||
- [#5825](https://github.com/withastro/astro/pull/5825) [`52209ca2a`](https://github.com/withastro/astro/commit/52209ca2ad72a30854947dcb3a90ab4db0ac0a6f) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Baseline the experimental `contentCollections` flag. You're free to remove this from your astro config!
|
||||
|
||||
```diff
|
||||
import { defineConfig } from 'astro/config';
|
||||
|
||||
export default defineConfig({
|
||||
- experimental: { contentCollections: true }
|
||||
})
|
||||
```
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#5782](https://github.com/withastro/astro/pull/5782) [`1f92d64ea`](https://github.com/withastro/astro/commit/1f92d64ea35c03fec43aff64eaf704dc5a9eb30a) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Remove support for Node 14. Minimum supported Node version is now >=16.12.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#5837](https://github.com/withastro/astro/pull/5837) [`12f65a4d5`](https://github.com/withastro/astro/commit/12f65a4d55e3fd2993c2f67b18794dd536280c69) Thanks [@giuseppelt](https://github.com/giuseppelt)! - fix shiki css class replace logic
|
||||
|
||||
- Updated dependencies [[`1f92d64ea`](https://github.com/withastro/astro/commit/1f92d64ea35c03fec43aff64eaf704dc5a9eb30a), [`12f65a4d5`](https://github.com/withastro/astro/commit/12f65a4d55e3fd2993c2f67b18794dd536280c69), [`16107b6a1`](https://github.com/withastro/astro/commit/16107b6a10514ef1b563e585ec9add4b14f42b94), [`52209ca2a`](https://github.com/withastro/astro/commit/52209ca2ad72a30854947dcb3a90ab4db0ac0a6f), [`7572f7402`](https://github.com/withastro/astro/commit/7572f7402238da37de748be58d678fedaf863b53)]:
|
||||
- @astrojs/prism@2.0.0-beta.0
|
||||
- @astrojs/markdown-remark@2.0.0-beta.2
|
||||
|
||||
</details>
|
||||
|
||||
## 0.15.0-beta.1
|
||||
|
||||
<details>
|
||||
<summary>See changes in 0.15.0-beta.1</summary>
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#5769](https://github.com/withastro/astro/pull/5769) [`93e633922`](https://github.com/withastro/astro/commit/93e633922c2e449df3bb2357b3683af1d3c0e07b) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Introduce a `smartypants` flag to opt-out of Astro's default SmartyPants plugin.
|
||||
|
||||
```js
|
||||
{
|
||||
markdown: {
|
||||
smartypants: false,
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Migration
|
||||
|
||||
You may have disabled Astro's built-in plugins (GitHub-Flavored Markdown and Smartypants) with the `extendDefaultPlugins` option. This has now been split into 2 flags to disable each plugin individually:
|
||||
|
||||
- `markdown.gfm` to disable GitHub-Flavored Markdown
|
||||
- `markdown.smartypants` to disable SmartyPants
|
||||
|
||||
```diff
|
||||
// astro.config.mjs
|
||||
import { defineConfig } from 'astro/config';
|
||||
|
||||
export default defineConfig({
|
||||
markdown: {
|
||||
- extendDefaultPlugins: false,
|
||||
+ smartypants: false,
|
||||
+ gfm: false,
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#5741](https://github.com/withastro/astro/pull/5741) [`000d3e694`](https://github.com/withastro/astro/commit/000d3e6940839c2aebba1984e6fb3b133cec6749) Thanks [@delucis](https://github.com/delucis)! - Fix broken links in README
|
||||
|
||||
- Updated dependencies [[`93e633922`](https://github.com/withastro/astro/commit/93e633922c2e449df3bb2357b3683af1d3c0e07b)]:
|
||||
- @astrojs/markdown-remark@2.0.0-beta.1
|
||||
|
||||
</details>
|
||||
|
||||
## 0.15.0-beta.0
|
||||
|
||||
<details>
|
||||
<summary>See changes in 0.15.0-beta.0</summary>
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#5687](https://github.com/withastro/astro/pull/5687) [`e2019be6f`](https://github.com/withastro/astro/commit/e2019be6ffa46fa33d92cfd346f9ecbe51bb7144) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Give remark and rehype plugins access to user frontmatter via frontmatter injection. This means `data.astro.frontmatter` is now the _complete_ Markdown or MDX document's frontmatter, rather than an empty object.
|
||||
|
||||
This allows plugin authors to modify existing frontmatter, or compute new properties based on other properties. For example, say you want to compute a full image URL based on an `imageSrc` slug in your document frontmatter:
|
||||
|
||||
```ts
|
||||
export function remarkInjectSocialImagePlugin() {
|
||||
return function (tree, file) {
|
||||
const { frontmatter } = file.data.astro;
|
||||
frontmatter.socialImageSrc = new URL(frontmatter.imageSrc, 'https://my-blog.com/').pathname;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
#### Content Collections - new `remarkPluginFrontmatter` property
|
||||
|
||||
We have changed _inject_ frontmatter to _modify_ frontmatter in our docs to improve discoverability. This is based on support forum feedback, where "injection" is rarely the term used.
|
||||
|
||||
To reflect this, the `injectedFrontmatter` property has been renamed to `remarkPluginFrontmatter`. This should clarify this plugin is still separate from the `data` export Content Collections expose today.
|
||||
|
||||
#### Migration instructions
|
||||
|
||||
Plugin authors should now **check for user frontmatter when applying defaults.**
|
||||
|
||||
For example, say a remark plugin wants to apply a default `title` if none is present. Add a conditional to check if the property is present, and update if none exists:
|
||||
|
||||
```diff
|
||||
export function remarkInjectTitlePlugin() {
|
||||
return function (tree, file) {
|
||||
const { frontmatter } = file.data.astro;
|
||||
+ if (!frontmatter.title) {
|
||||
frontmatter.title = 'Default title';
|
||||
+ }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This differs from previous behavior, where a Markdown file's frontmatter would _always_ override frontmatter injected via remark or reype.
|
||||
|
||||
- [#5684](https://github.com/withastro/astro/pull/5684) [`a9c292026`](https://github.com/withastro/astro/commit/a9c2920264e36cc5dc05f4adc1912187979edb0d) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Refine Markdown and MDX configuration options for ease-of-use.
|
||||
|
||||
#### Markdown
|
||||
|
||||
- **Remove `remark-smartypants`** from Astro's default Markdown plugins.
|
||||
- **Replace the `extendDefaultPlugins` option** with a simplified `gfm` boolean. This is enabled by default, and can be disabled to remove GitHub-Flavored Markdown.
|
||||
- Ensure GitHub-Flavored Markdown is applied whether or not custom `remarkPlugins` or `rehypePlugins` are configured. If you want to apply custom plugins _and_ remove GFM, manually set `gfm: false` in your config.
|
||||
|
||||
#### MDX
|
||||
|
||||
- Support _all_ Markdown configuration options (except `drafts`) from your MDX integration config. This includes `syntaxHighlighting` and `shikiConfig` options to further customize the MDX renderer.
|
||||
- Simplify `extendDefaults` to an `extendMarkdownConfig` option. MDX options will default to their equivalent in your Markdown config. By setting `extendMarkdownConfig` to false, you can "eject" to set your own syntax highlighting, plugins, and more.
|
||||
|
||||
#### Migration
|
||||
|
||||
To preserve your existing Markdown and MDX setup, you may need some configuration changes:
|
||||
|
||||
##### Smartypants manual installation
|
||||
|
||||
[Smartypants](https://github.com/silvenon/remark-smartypants) has been removed from Astro's default setup. If you rely on this plugin, [install `remark-smartypants`](https://github.com/silvenon/remark-smartypants#installing) and apply to your `astro.config.*`:
|
||||
|
||||
```diff
|
||||
// astro.config.mjs
|
||||
import { defineConfig } from 'astro/config';
|
||||
+ import smartypants from 'remark-smartypants';
|
||||
|
||||
export default defineConfig({
|
||||
markdown: {
|
||||
+ remarkPlugins: [smartypants],
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
##### Migrate `extendDefaultPlugins` to `gfm`
|
||||
|
||||
You may have disabled Astro's built-in plugins (GitHub-Flavored Markdown and Smartypants) with the `extendDefaultPlugins` option. Since Smartypants has been removed, this has been renamed to `gfm`.
|
||||
|
||||
```diff
|
||||
// astro.config.mjs
|
||||
import { defineConfig } from 'astro/config';
|
||||
|
||||
export default defineConfig({
|
||||
markdown: {
|
||||
- extendDefaultPlugins: false,
|
||||
+ gfm: false,
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
Additionally, applying remark and rehype plugins **no longer disables** `gfm`. You will need to opt-out manually by setting `gfm` to `false`.
|
||||
|
||||
##### Migrate MDX's `extendPlugins` to `extendMarkdownConfig`
|
||||
|
||||
You may have used the `extendPlugins` option to manage plugin defaults in MDX. This has been replaced by 2 flags:
|
||||
|
||||
- `extendMarkdownConfig` (`true` by default) to toggle Markdown config inheritance. This replaces the `extendPlugins: 'markdown'` option.
|
||||
- `gfm` (`true` by default) to toggle GitHub-Flavored Markdown in MDX. This replaces the `extendPlugins: 'defaults'` option.
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`e2019be6f`](https://github.com/withastro/astro/commit/e2019be6ffa46fa33d92cfd346f9ecbe51bb7144), [`a9c292026`](https://github.com/withastro/astro/commit/a9c2920264e36cc5dc05f4adc1912187979edb0d)]:
|
||||
- @astrojs/markdown-remark@2.0.0-beta.0
|
||||
|
||||
</details>
|
||||
|
||||
## 0.14.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#5654](https://github.com/withastro/astro/pull/5654) [`2c65b433b`](https://github.com/withastro/astro/commit/2c65b433bf840a1bb93b0a1947df5949e33512ff) Thanks [@delucis](https://github.com/delucis)! - Run heading ID injection after user plugins
|
||||
|
||||
⚠️ BREAKING CHANGE ⚠️
|
||||
|
||||
If you are using a rehype plugin that depends on heading IDs injected by Astro, the IDs will no longer be available when your plugin runs by default.
|
||||
|
||||
To inject IDs before your plugins run, import and add the `rehypeHeadingIds` plugin to your `rehypePlugins` config:
|
||||
|
||||
```diff
|
||||
// astro.config.mjs
|
||||
+ import { rehypeHeadingIds } from '@astrojs/markdown-remark';
|
||||
import mdx from '@astrojs/mdx';
|
||||
|
||||
export default {
|
||||
integrations: [mdx()],
|
||||
markdown: {
|
||||
rehypePlugins: [
|
||||
+ rehypeHeadingIds,
|
||||
otherPluginThatReliesOnHeadingIDs,
|
||||
],
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#5667](https://github.com/withastro/astro/pull/5667) [`a5ba4af79`](https://github.com/withastro/astro/commit/a5ba4af79930145f4edf66d45cd40ddad045cc86) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Chore: remove verbose "Now interiting Markdown plugins..." logs
|
||||
|
||||
- [#5648](https://github.com/withastro/astro/pull/5648) [`853081d1c`](https://github.com/withastro/astro/commit/853081d1c857d8ad8a9634c37ed8fd123d32d241) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Prevent relative image paths in `src/content/`
|
||||
|
||||
- Updated dependencies [[`853081d1c`](https://github.com/withastro/astro/commit/853081d1c857d8ad8a9634c37ed8fd123d32d241), [`2c65b433b`](https://github.com/withastro/astro/commit/2c65b433bf840a1bb93b0a1947df5949e33512ff)]:
|
||||
- @astrojs/markdown-remark@1.2.0
|
||||
|
||||
## 0.13.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#5291](https://github.com/withastro/astro/pull/5291) [`5ec0f6ed5`](https://github.com/withastro/astro/commit/5ec0f6ed55b0a14a9663a90a03428345baf126bd) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Introduce Content Collections experimental API
|
||||
- Organize your Markdown and MDX content into easy-to-manage collections.
|
||||
- Add type safety to your frontmatter with schemas.
|
||||
- Generate landing pages, static routes, and SSR endpoints from your content using the collection query APIs.
|
||||
|
||||
## 0.12.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#5586](https://github.com/withastro/astro/pull/5586) [`f4ff69a3c`](https://github.com/withastro/astro/commit/f4ff69a3cd874c8804c6d01c7cbbaed8a8e90be7) Thanks [@delucis](https://github.com/delucis)! - Fix link in MDX integration README
|
||||
|
||||
- [#5570](https://github.com/withastro/astro/pull/5570) [`3f811eb68`](https://github.com/withastro/astro/commit/3f811eb682d55bd1f908f9b4bc3b795d2859d713) Thanks [@sarah11918](https://github.com/sarah11918)! - Revise README
|
||||
|
||||
## 0.12.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#5522](https://github.com/withastro/astro/pull/5522) [`efc4363e0`](https://github.com/withastro/astro/commit/efc4363e0baf7f92900e20af339811bb3df42b0e) Thanks [@delucis](https://github.com/delucis)! - Support use of `<Fragment>` in MDX files rendered with `<Content />` component
|
||||
|
||||
## 0.12.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#5427](https://github.com/withastro/astro/pull/5427) [`2a1c085b1`](https://github.com/withastro/astro/commit/2a1c085b199f24e34424ec8c19041c03602c53c5) Thanks [@backflip](https://github.com/backflip)! - Uses remark-rehype options from astro.config.mjs
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#5448](https://github.com/withastro/astro/pull/5448) [`ef2ffc7ae`](https://github.com/withastro/astro/commit/ef2ffc7ae9ff554860238ecd2fb3bf6d82b5801b) Thanks [@delucis](https://github.com/delucis)! - Fix broken link in README
|
||||
|
||||
## 0.11.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#5335](https://github.com/withastro/astro/pull/5335) [`dca762cf7`](https://github.com/withastro/astro/commit/dca762cf734a657d8f126fd6958892b6163a4f67) Thanks [@bluwy](https://github.com/bluwy)! - Preserve code element node `data.meta` in `properties.metastring` for rehype syntax highlighters, like `rehype-pretty-code``
|
||||
|
||||
## 0.11.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#5146](https://github.com/withastro/astro/pull/5146) [`308e565ad`](https://github.com/withastro/astro/commit/308e565ad39957e3353d72ca5d3bbce1a1b45008) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Support recmaPlugins config option
|
||||
|
||||
## 0.11.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#4953](https://github.com/withastro/astro/pull/4953) [`a59731995`](https://github.com/withastro/astro/commit/a59731995b93ae69c21dc3adc5c8b482b466d12e) Thanks [@bluwy](https://github.com/bluwy)! - Log markdown hints with console.info
|
||||
|
||||
## 0.11.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#4842](https://github.com/withastro/astro/pull/4842) [`812658ad2`](https://github.com/withastro/astro/commit/812658ad2ab3732a99e35c4fd903e302e723db46) Thanks [@bluwy](https://github.com/bluwy)! - Add missing dependencies, support strict dependency installation (e.g. pnpm)
|
||||
|
||||
## 0.11.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#4700](https://github.com/withastro/astro/pull/4700) [`e5f71142e`](https://github.com/withastro/astro/commit/e5f71142eb62bd72456e889dad5774347c3753f2) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Document MDXLayoutProps utility type
|
||||
|
||||
- [#4858](https://github.com/withastro/astro/pull/4858) [`58a2dca22`](https://github.com/withastro/astro/commit/58a2dca2286cb14f6211cf51267c02447e78433a) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Correctly parse import.meta.env in MDX files
|
||||
|
||||
## 0.11.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#4588](https://github.com/withastro/astro/pull/4588) [`db38f61b2`](https://github.com/withastro/astro/commit/db38f61b2b2dc55f03b28797d19b163b1940f1c8) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Fix: Add GFM and Smartypants to MDX by default
|
||||
|
||||
## 0.11.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#4504](https://github.com/withastro/astro/pull/4504) [`8f8dff4d3`](https://github.com/withastro/astro/commit/8f8dff4d339a3a12ee155d81a97132032ef3b622) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Introduce new `extendPlugins` configuration option. This defaults to inheriting all remark and rehype plugins from your `markdown` config, with options to use either Astro's defaults or no inheritance at all.
|
||||
|
||||
## 0.10.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#4519](https://github.com/withastro/astro/pull/4519) [`a2e8e76c3`](https://github.com/withastro/astro/commit/a2e8e76c303e8d6f39c24c122905a10f06907997) Thanks [@JuanM04](https://github.com/JuanM04)! - Upgraded Shiki to v0.11.1
|
||||
|
||||
- [#4530](https://github.com/withastro/astro/pull/4530) [`8504cd79b`](https://github.com/withastro/astro/commit/8504cd79b708e0d3bf1a2bb4ff9b86936bdd692b) Thanks [@kylebutts](https://github.com/kylebutts)! - Add custom components to README
|
||||
|
||||
## 0.10.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#4423](https://github.com/withastro/astro/pull/4423) [`d4cd7a59f`](https://github.com/withastro/astro/commit/d4cd7a59fd38d411c442a818cfaab40f74106628) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Update Markdown type signature to match new markdown plugin,and update top-level layout props for better alignment
|
||||
|
||||
## 0.10.2-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#4423](https://github.com/withastro/astro/pull/4423) [`d4cd7a59f`](https://github.com/withastro/astro/commit/d4cd7a59fd38d411c442a818cfaab40f74106628) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Update Markdown type signature to match new markdown plugin,and update top-level layout props for better alignment
|
||||
|
||||
## 0.10.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#4443](https://github.com/withastro/astro/pull/4443) [`adb207979`](https://github.com/withastro/astro/commit/adb20797962c280d4d38f335f577fd52a1b48d4b) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Fix MDX style imports when layout is not applied
|
||||
|
||||
* [#4428](https://github.com/withastro/astro/pull/4428) [`a2414bf59`](https://github.com/withastro/astro/commit/a2414bf59e2e2cd633aece68e724401c4ad281b9) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Fix dev server reload performance when globbing from an MDX layout
|
||||
|
||||
## 0.10.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#4292](https://github.com/withastro/astro/pull/4292) [`f1a52c18a`](https://github.com/withastro/astro/commit/f1a52c18afe66e6d310743ae6884be76f69be265) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Switch from Shiki Twoslash to Astro's Shiki Markdown highlighter
|
||||
|
||||
## 0.9.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#4268](https://github.com/withastro/astro/pull/4268) [`f7afdb889`](https://github.com/withastro/astro/commit/f7afdb889fe4e97177958c8ec92f80c5f6e5cb51) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Align MD with MDX on layout props and "glob" import results:
|
||||
- Add `Content` to MDX
|
||||
- Add `file` and `url` to MDX frontmatter (layout import only)
|
||||
- Update glob types to reflect differences (lack of `rawContent` and `compiledContent`)
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#4272](https://github.com/withastro/astro/pull/4272) [`24d2f7a6e`](https://github.com/withastro/astro/commit/24d2f7a6e6700c10c863f826f37bb653d70e3a83) Thanks [@natemoo-re](https://github.com/natemoo-re)! - Properly handle hydration for namespaced components
|
||||
|
||||
## 0.8.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#4248](https://github.com/withastro/astro/pull/4248) [`869d00935`](https://github.com/withastro/astro/commit/869d0093596b709cfcc1a1a95ee631b48d6d1c26) Thanks [@svemat01](https://github.com/svemat01)! - Load builtin rehype plugins before user plugins instead of after
|
||||
|
||||
* [#4255](https://github.com/withastro/astro/pull/4255) [`411612808`](https://github.com/withastro/astro/commit/4116128082121ee276d51cb245bf8095be4728a1) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Pass injected frontmatter from remark and rehype plugins to layouts
|
||||
|
||||
* Updated dependencies [[`1f0dd31d9`](https://github.com/withastro/astro/commit/1f0dd31d9239b5e3dca99c88d021e7a9a3e2054d)]:
|
||||
- @astrojs/prism@1.0.1
|
||||
|
||||
## 0.8.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#4237](https://github.com/withastro/astro/pull/4237) [`9d5ab5508`](https://github.com/withastro/astro/commit/9d5ab55086964fbede17da3d78c209c6d8d13711) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Update "Astro.props.content" -> "Astro.props.frontmatter" in README
|
||||
|
||||
## 0.8.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`04ad44563`](https://github.com/withastro/astro/commit/04ad445632c67bdd60c1704e1e0dcbcaa27b9308)]:
|
||||
- @astrojs/prism@1.0.0
|
||||
|
||||
## 0.8.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#4204](https://github.com/withastro/astro/pull/4204) [`4c2ca5352`](https://github.com/withastro/astro/commit/4c2ca5352d0c4119ed2a9e5e0b78ce71eb1b414a) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Remove `frontmatterOptions` from MDX config
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#4205](https://github.com/withastro/astro/pull/4205) [`6c9736cbc`](https://github.com/withastro/astro/commit/6c9736cbc90162f1de3ebccd7cfe98332749b639) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Add frontmatter injection instructions to README
|
||||
|
||||
## 0.7.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#4176](https://github.com/withastro/astro/pull/4176) [`2675b8633`](https://github.com/withastro/astro/commit/2675b8633c5d5c45b237ec87940d5eaf1bfb1b4b) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Support frontmatter injection for MD and MDX using remark and rehype plugins
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#4181](https://github.com/withastro/astro/pull/4181) [`77cede720`](https://github.com/withastro/astro/commit/77cede720b09bce34f29c3d2d8b505311ce876b1) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Make collect-headings rehype plugin non-overridable
|
||||
|
||||
* [#4174](https://github.com/withastro/astro/pull/4174) [`8eb3a8c6d`](https://github.com/withastro/astro/commit/8eb3a8c6d9554707963c3a3bc36ed8b68d3cf0fb) Thanks [@matthewp](https://github.com/matthewp)! - Allows using React with automatic imports alongside MDX
|
||||
|
||||
- [#4145](https://github.com/withastro/astro/pull/4145) [`c7efcf57e`](https://github.com/withastro/astro/commit/c7efcf57e00a0fcde3bc9f813e3cc59902bd484c) Thanks [@FredKSchott](https://github.com/FredKSchott)! - Fix a missing newline bug when `layout` was set.
|
||||
|
||||
## 0.6.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#4134](https://github.com/withastro/astro/pull/4134) [`2968ba2b6`](https://github.com/withastro/astro/commit/2968ba2b6f00775b6e9872681b390cb466fdbfa2) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Add `headings` and `frontmatter` properties to layout props
|
||||
|
||||
## 0.5.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#4095](https://github.com/withastro/astro/pull/4095) [`40ef43a59`](https://github.com/withastro/astro/commit/40ef43a59b08a1a8fbcd9f4a53745a9636a4fbb9) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Add IDs to MDX headings and expose via getHeadings() export
|
||||
|
||||
* [#4114](https://github.com/withastro/astro/pull/4114) [`64432bcb8`](https://github.com/withastro/astro/commit/64432bcb873efd0e4297c00fc9583a1fe516dfe7) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Refactor `@astrojs/mdx` and `@astrojs/markdown-remark` to use `@astrojs/prism` instead of duplicating the code
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#4112](https://github.com/withastro/astro/pull/4112) [`e33fc9bc4`](https://github.com/withastro/astro/commit/e33fc9bc46ff0a30013deb6dc76e545e70cc3a3e) Thanks [@matthewp](https://github.com/matthewp)! - Fix MDX working with a ts config file
|
||||
|
||||
* [#4049](https://github.com/withastro/astro/pull/4049) [`b60cc0538`](https://github.com/withastro/astro/commit/b60cc0538bc5c68dd411117780d20d892530789d) Thanks [@natemoo-re](https://github.com/natemoo-re)! - Improve `injectScript` handling for non-Astro pages
|
||||
|
||||
* Updated dependencies [[`64432bcb8`](https://github.com/withastro/astro/commit/64432bcb873efd0e4297c00fc9583a1fe516dfe7)]:
|
||||
- @astrojs/prism@0.7.0
|
||||
|
||||
## 0.4.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#4088](https://github.com/withastro/astro/pull/4088) [`1743fe140`](https://github.com/withastro/astro/commit/1743fe140eb58d60e26cbd11a066bb60de046e0c) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Support "layout" frontmatter property
|
||||
|
||||
## 0.3.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#4076](https://github.com/withastro/astro/pull/4076) [`6120a71e5`](https://github.com/withastro/astro/commit/6120a71e5425ad55a17ddac800d64a3f50273bce) Thanks [@matthewp](https://github.com/matthewp)! - Ensure file and url are always present in MDX for Astro.glob
|
||||
|
||||
## 0.3.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#3977](https://github.com/withastro/astro/pull/3977) [`19433eb4a`](https://github.com/withastro/astro/commit/19433eb4a4441522f68492ca914ad2ab4f061343) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Add remarkPlugins and rehypePlugins to config, with the same default plugins as our standard Markdown parser
|
||||
|
||||
* [#4002](https://github.com/withastro/astro/pull/4002) [`3b8a74452`](https://github.com/withastro/astro/commit/3b8a7445247221100462ba035f6778b43ea180e7) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Support Prism and Shiki syntax highlighting based on project config
|
||||
|
||||
- [#3995](https://github.com/withastro/astro/pull/3995) [`b2b367c96`](https://github.com/withastro/astro/commit/b2b367c969493aaf21c974064beb241d05228066) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Support YAML frontmatter in MDX files
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#4050](https://github.com/withastro/astro/pull/4050) [`9ab66c4ba`](https://github.com/withastro/astro/commit/9ab66c4ba9bf2250990114c76b792f26d0694365) Thanks [@FredKSchott](https://github.com/FredKSchott)! - Add support for injected "page-ssr" scripts
|
||||
|
||||
* [#3981](https://github.com/withastro/astro/pull/3981) [`61fec6304`](https://github.com/withastro/astro/commit/61fec63044e1585348e8405bee6fdf4dec635efa) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Include page url in MDX glob result
|
||||
|
||||
## 0.2.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#3937](https://github.com/withastro/astro/pull/3937) [`31f9c0bf0`](https://github.com/withastro/astro/commit/31f9c0bf029ffa4b470e620f2c32e1370643e81e) Thanks [@delucis](https://github.com/delucis)! - Roll back supported Node engines
|
||||
|
||||
## 0.2.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#3914](https://github.com/withastro/astro/pull/3914) [`b48767985`](https://github.com/withastro/astro/commit/b48767985359bd359df8071324952ea5f2bc0d86) Thanks [@ran-dall](https://github.com/ran-dall)! - Rollback supported `node@16` version. Minimum versions are now `node@14.20.0` or `node@16.14.0`.
|
||||
|
||||
## 0.1.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#3885](https://github.com/withastro/astro/pull/3885) [`bf5d1cc1e`](https://github.com/withastro/astro/commit/bf5d1cc1e71da38a14658c615e9481f2145cc6e7) Thanks [@delucis](https://github.com/delucis)! - Integration README fixes
|
||||
|
||||
## 0.1.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#3871](https://github.com/withastro/astro/pull/3871) [`1cc5b7890`](https://github.com/withastro/astro/commit/1cc5b78905633608e5b07ad291f916f54e67feb1) Thanks [@natemoo-re](https://github.com/natemoo-re)! - Update supported `node` versions. Minimum versions are now `node@14.20.0` or `node@16.16.0`.
|
||||
|
||||
## 0.0.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#3854](https://github.com/withastro/astro/pull/3854) [`b012ee55`](https://github.com/withastro/astro/commit/b012ee55b107dea0730286263b27d83e530fad5d) Thanks [@bholmesdev](https://github.com/bholmesdev)! - [astro add] Support adapters and third party packages
|
||||
|
||||
## 0.0.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#3706](https://github.com/withastro/astro/pull/3706) [`032ad1c0`](https://github.com/withastro/astro/commit/032ad1c047a62dd663067cc562537d16f2872aa7) Thanks [@natemoo-re](https://github.com/natemoo-re)! - Initial release! 🎉
|
160
packages/integrations/markdoc/README.md
Normal file
160
packages/integrations/markdoc/README.md
Normal file
|
@ -0,0 +1,160 @@
|
|||
# @astrojs/markdoc (experimental) 📝
|
||||
|
||||
This **[Astro integration][astro-integration]** enables the usage of [Markdoc](https://markdoc.dev/) to create components, pages, and content collection entries.
|
||||
|
||||
- <strong>[Why Markdoc?](#why-markdoc)</strong>
|
||||
- <strong>[Installation](#installation)</strong>
|
||||
- <strong>[Usage](#usage)</strong>
|
||||
- <strong>[Configuration](#configuration)</strong>
|
||||
- <strong>[Examples](#examples)</strong>
|
||||
- <strong>[Troubleshooting](#troubleshooting)</strong>
|
||||
- <strong>[Contributing](#contributing)</strong>
|
||||
- <strong>[Changelog](#changelog)</strong>
|
||||
|
||||
## Why Markdoc?
|
||||
|
||||
Markdoc allows you to enhance your Markdown with [UI components][astro-ui-frameworks]. If you have existing content authored in Markdoc, this integration allows you to bring those files to your Astro project using content collections.
|
||||
|
||||
## Installation
|
||||
|
||||
### Quick Install
|
||||
|
||||
The `astro add` command-line tool automates the installation for you. Run one of the following commands in a new terminal window. (If you aren't sure which package manager you're using, run the first command.) Then, follow the prompts, and type "y" in the terminal (meaning "yes") for each one.
|
||||
|
||||
```sh
|
||||
# Using NPM
|
||||
npx astro add markdoc
|
||||
# Using Yarn
|
||||
yarn astro add markdoc
|
||||
# Using PNPM
|
||||
pnpm astro add markdoc
|
||||
```
|
||||
|
||||
If you run into any issues, [feel free to report them to us on GitHub](https://github.com/withastro/astro/issues) and try the manual installation steps below.
|
||||
|
||||
### Manual Install
|
||||
|
||||
First, install the `@astrojs/markdoc` package using your package manager. If you're using npm or aren't sure, run this in the terminal:
|
||||
|
||||
```sh
|
||||
npm install @astrojs/markdoc
|
||||
```
|
||||
|
||||
Then, apply this integration to your `astro.config.*` file using the `integrations` property:
|
||||
|
||||
__`astro.config.mjs`__
|
||||
|
||||
```js ins={2} "markdoc()"
|
||||
import { defineConfig } from 'astro/config';
|
||||
import markdoc from '@astrojs/markdoc';
|
||||
|
||||
export default defineConfig({
|
||||
// ...
|
||||
integrations: [markdoc()],
|
||||
});
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
Markdoc files can be used within content collections. Add entries to any content collection using the `.mdoc` extension:
|
||||
|
||||
```sh
|
||||
src/content/docs/
|
||||
why-markdoc.mdoc
|
||||
quick-start.mdoc
|
||||
```
|
||||
|
||||
Then, query for these files using the [Content Collection APIs](https://docs.astro.build/en/guides/content-collections/#querying-collections):
|
||||
|
||||
```astro
|
||||
---
|
||||
import { getEntryBySlug } from 'astro:content';
|
||||
|
||||
const entry = await getEntryBySlug('docs', 'why-markdoc');
|
||||
const { Content } = await entry.render();
|
||||
---
|
||||
|
||||
<!--Access frontmatter properties with `data`-->
|
||||
<h1>{entry.data.title}</h1>
|
||||
<!--Render Markdoc contents with the Content component-->
|
||||
<Content />
|
||||
```
|
||||
|
||||
📚 See the [Astro Content Collection docs][astro-content-collections] for more information.
|
||||
|
||||
## Configuration
|
||||
|
||||
You can configure how your Markdoc content is rendered using props via the `Content` component. This component is returned by [a content collection `render()` result](https://docs.astro.build/en/guides/content-collections/#rendering-content-to-html).
|
||||
|
||||
### `config` prop
|
||||
|
||||
The `config` prop accepts all [Markdoc configuration options](https://markdoc.dev/docs/config#full-example), including tags and variables.
|
||||
|
||||
This example defines a `version` variable to use within a `why-markdoc.mdoc` entry:
|
||||
|
||||
```astro
|
||||
---
|
||||
import { getEntryBySlug } from 'astro:content';
|
||||
|
||||
const entry = await getEntryBySlug('docs', 'why-markdoc');
|
||||
const { Content } = await entry.render();
|
||||
---
|
||||
|
||||
<Content
|
||||
config={{
|
||||
variables: {
|
||||
version: '0.0.1',
|
||||
}
|
||||
}}
|
||||
/>
|
||||
```
|
||||
|
||||
### `components` prop
|
||||
|
||||
The `components` prop defines mappings from an HTML element name to an Astro or UI framework component (React, Vue, Svelte, etc).
|
||||
|
||||
:::note
|
||||
`components` does not support the `client:` directive for hydrating components. To embed client-side components, create a wrapper `.astro` file to import your component and apply a `client:` directive manually.
|
||||
:::
|
||||
|
||||
This example renders all `h1` headings using a `Title` component:
|
||||
|
||||
```astro
|
||||
---
|
||||
import { getEntryBySlug } from 'astro:content';
|
||||
import Title from '../components/Title.astro';
|
||||
|
||||
const entry = await getEntryBySlug('docs', 'why-markdoc');
|
||||
const { Content } = await entry.render();
|
||||
---
|
||||
|
||||
<Content
|
||||
components={{
|
||||
h1: Title,
|
||||
}}
|
||||
/>
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
* The [Astro Markdoc starter template](https://github.com/withastro/astro/tree/latest/examples/with-mdx) shows how to use Markdoc files in your Astro project.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
For help, check out the `#support` channel on [Discord](https://astro.build/chat). Our friendly Support Squad members are here to help!
|
||||
|
||||
You can also check our [Astro Integration Documentation][astro-integration] for more on integrations.
|
||||
|
||||
## Contributing
|
||||
|
||||
This package is maintained by Astro's Core team. You're welcome to submit an issue or PR!
|
||||
|
||||
## Changelog
|
||||
|
||||
See [CHANGELOG.md](https://github.com/withastro/astro/tree/main/packages/integrations/markdoc/CHANGELOG.md) for a history of changes to this integration.
|
||||
|
||||
[astro-integration]: https://docs.astro.build/en/guides/integrations-guide/
|
||||
|
||||
[astro-ui-frameworks]: https://docs.astro.build/en/core-concepts/framework-components/#using-framework-components
|
||||
|
||||
[astro-content-collections]: https://docs.astro.build/en/guides/content-collections/
|
30
packages/integrations/markdoc/components/RenderNode.astro
Normal file
30
packages/integrations/markdoc/components/RenderNode.astro
Normal file
|
@ -0,0 +1,30 @@
|
|||
---
|
||||
import stringifyAttributes from 'stringify-attributes';
|
||||
import type { AstroNode } from './astroNode';
|
||||
|
||||
type Props = {
|
||||
node: AstroNode;
|
||||
};
|
||||
|
||||
const Node = (Astro.props as Props).node;
|
||||
---
|
||||
|
||||
{
|
||||
typeof Node === 'string' ? (
|
||||
<Fragment set:text={Node} />
|
||||
) : 'component' in Node ? (
|
||||
<Node.component {...Node.props}>
|
||||
{Node.children.map((child) => (
|
||||
<Astro.self node={child} />
|
||||
))}
|
||||
</Node.component>
|
||||
) : (
|
||||
<Fragment>
|
||||
<Fragment set:html={`<${Node.tag} ${stringifyAttributes(Node.attributes)}>`} />
|
||||
{Node.children.map((child) => (
|
||||
<Astro.self node={child} />
|
||||
))}
|
||||
<Fragment set:html={`</${Node.tag}>`} />
|
||||
</Fragment>
|
||||
)
|
||||
}
|
14
packages/integrations/markdoc/components/Renderer.astro
Normal file
14
packages/integrations/markdoc/components/Renderer.astro
Normal file
|
@ -0,0 +1,14 @@
|
|||
---
|
||||
import type { RenderableTreeNode } from '@markdoc/markdoc';
|
||||
import { ComponentRenderer, createAstroNode } from './astroNode';
|
||||
import RenderNode from './RenderNode.astro';
|
||||
|
||||
type Props = {
|
||||
content: RenderableTreeNode;
|
||||
components: Record<string, ComponentRenderer>;
|
||||
};
|
||||
|
||||
const { content, components } = Astro.props as Props;
|
||||
---
|
||||
|
||||
<RenderNode node={createAstroNode(content, components)} />
|
63
packages/integrations/markdoc/components/astroNode.ts
Normal file
63
packages/integrations/markdoc/components/astroNode.ts
Normal file
|
@ -0,0 +1,63 @@
|
|||
import type { ComponentInstance } from 'astro';
|
||||
import type { RenderableTreeNode, Tag } from '@markdoc/markdoc';
|
||||
import Markdoc from '@markdoc/markdoc';
|
||||
|
||||
export type ComponentRenderer =
|
||||
| ComponentInstance['default']
|
||||
| {
|
||||
component: ComponentInstance['default'];
|
||||
props?(params: { attributes: Record<string, any>; getTreeNode(): Tag }): Record<string, any>;
|
||||
};
|
||||
|
||||
export type AstroNode =
|
||||
| string
|
||||
| {
|
||||
component: ComponentInstance['default'];
|
||||
props: Record<string, any>;
|
||||
children: AstroNode[];
|
||||
}
|
||||
| {
|
||||
tag: string;
|
||||
attributes: Record<string, any>;
|
||||
children: AstroNode[];
|
||||
};
|
||||
|
||||
export function createAstroNode(
|
||||
node: RenderableTreeNode,
|
||||
components: Record<string, ComponentRenderer> = {}
|
||||
): AstroNode {
|
||||
if (typeof node === 'string' || typeof node === 'number') {
|
||||
return String(node);
|
||||
} else if (node === null || typeof node !== 'object' || !Markdoc.Tag.isTag(node)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (node.name in components) {
|
||||
const componentRenderer = components[node.name];
|
||||
const component =
|
||||
'component' in componentRenderer ? componentRenderer.component : componentRenderer;
|
||||
const props =
|
||||
'props' in componentRenderer && typeof componentRenderer.props === 'function'
|
||||
? componentRenderer.props({
|
||||
attributes: node.attributes,
|
||||
getTreeNode() {
|
||||
return node;
|
||||
},
|
||||
})
|
||||
: node.attributes;
|
||||
|
||||
const children = node.children.map((child) => createAstroNode(child, components));
|
||||
|
||||
return {
|
||||
component,
|
||||
props,
|
||||
children,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
tag: node.name,
|
||||
attributes: node.attributes,
|
||||
children: node.children.map((child) => createAstroNode(child, components)),
|
||||
};
|
||||
}
|
||||
}
|
2
packages/integrations/markdoc/components/index.ts
Normal file
2
packages/integrations/markdoc/components/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
// @ts-ignore
|
||||
export { default as Renderer } from './Renderer.astro';
|
53
packages/integrations/markdoc/package.json
Normal file
53
packages/integrations/markdoc/package.json
Normal file
|
@ -0,0 +1,53 @@
|
|||
{
|
||||
"name": "@astrojs/markdoc",
|
||||
"description": "Use Markdoc within Astro",
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"types": "./dist/index.d.ts",
|
||||
"author": "withastro",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/withastro/astro.git",
|
||||
"directory": "packages/integrations/markdoc"
|
||||
},
|
||||
"keywords": [
|
||||
"astro-integration",
|
||||
"astro-component",
|
||||
"markdoc"
|
||||
],
|
||||
"bugs": "https://github.com/withastro/astro/issues",
|
||||
"homepage": "https://docs.astro.build/en/guides/integrations-guide/markdoc/",
|
||||
"exports": {
|
||||
".": "./dist/index.js",
|
||||
"./components": "./components/index.ts",
|
||||
"./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\"",
|
||||
"test": "mocha --exit --timeout 20000",
|
||||
"test:match": "mocha --timeout 20000 -g"
|
||||
},
|
||||
"dependencies": {
|
||||
"@markdoc/markdoc": "^0.2.2",
|
||||
"gray-matter": "^4.0.3",
|
||||
"stringify-attributes": "^3.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/chai": "^4.3.1",
|
||||
"@types/html-escaper": "^3.0.0",
|
||||
"@types/mocha": "^9.1.1",
|
||||
"astro": "workspace:*",
|
||||
"astro-scripts": "workspace:*",
|
||||
"chai": "^4.3.6",
|
||||
"devalue": "^4.2.0",
|
||||
"linkedom": "^0.14.12",
|
||||
"mocha": "^9.2.2",
|
||||
"vite": "^4.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.12.0"
|
||||
}
|
||||
}
|
52
packages/integrations/markdoc/src/index.ts
Normal file
52
packages/integrations/markdoc/src/index.ts
Normal file
|
@ -0,0 +1,52 @@
|
|||
import type { AstroIntegration } from 'astro';
|
||||
import type { InlineConfig } from 'vite';
|
||||
import type { Config as _MarkdocConfig } from '@markdoc/markdoc';
|
||||
import _Markdoc from '@markdoc/markdoc';
|
||||
import { parseFrontmatter } from './utils.js';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import fs from 'node:fs';
|
||||
|
||||
export default function markdoc(): AstroIntegration {
|
||||
return {
|
||||
name: '@astrojs/markdoc',
|
||||
hooks: {
|
||||
'astro:config:setup': async ({ updateConfig, config, addContentEntryType, command }: any) => {
|
||||
const contentEntryType = {
|
||||
extensions: ['.mdoc'],
|
||||
async getEntryInfo({ fileUrl, contents }: { fileUrl: URL; contents: string }) {
|
||||
const parsed = parseFrontmatter(contents, fileURLToPath(fileUrl));
|
||||
return {
|
||||
data: parsed.data,
|
||||
body: parsed.content,
|
||||
slug: parsed.data.slug,
|
||||
rawData: parsed.matter,
|
||||
};
|
||||
},
|
||||
contentModuleTypes: await fs.promises.readFile(
|
||||
new URL('../template/content-module-types.d.ts', import.meta.url),
|
||||
'utf-8'
|
||||
),
|
||||
};
|
||||
addContentEntryType(contentEntryType);
|
||||
|
||||
const viteConfig: InlineConfig = {
|
||||
plugins: [
|
||||
{
|
||||
name: '@astrojs/markdoc',
|
||||
async transform(code, id) {
|
||||
if (!id.endsWith('.mdoc')) return;
|
||||
return `import { jsx as h } from 'astro/jsx-runtime';\nimport { Markdoc } from '@astrojs/markdoc';\nimport { Renderer } from '@astrojs/markdoc/components';\nexport const body = ${JSON.stringify(
|
||||
code
|
||||
)};\nexport function getParsed() { return Markdoc.parse(body); }\nexport function getTransformed(inlineConfig) { return Markdoc.transform(getParsed(), inlineConfig) }\nexport async function Content ({ config, components }) { return h(Renderer, { content: getTransformed(config), components }); }\nContent[Symbol.for('astro.needsHeadRendering')] = true;`;
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
updateConfig({ vite: viteConfig });
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export const Markdoc = _Markdoc;
|
||||
export type MarkdocConfig = _MarkdocConfig;
|
25
packages/integrations/markdoc/src/utils.ts
Normal file
25
packages/integrations/markdoc/src/utils.ts
Normal file
|
@ -0,0 +1,25 @@
|
|||
import matter from 'gray-matter';
|
||||
import type { ErrorPayload as ViteErrorPayload } from 'vite';
|
||||
|
||||
/**
|
||||
* Match YAML exception handling from Astro core errors
|
||||
* @see 'astro/src/core/errors.ts'
|
||||
*/
|
||||
export function parseFrontmatter(fileContents: string, filePath: string) {
|
||||
try {
|
||||
// `matter` is empty string on cache results
|
||||
// clear cache to prevent this
|
||||
(matter as any).clearCache();
|
||||
return matter(fileContents);
|
||||
} catch (e: any) {
|
||||
if (e.name === 'YAMLException') {
|
||||
const err: Error & ViteErrorPayload['err'] = e;
|
||||
err.id = filePath;
|
||||
err.loc = { file: e.id, line: e.mark.line + 1, column: e.mark.column };
|
||||
err.message = e.reason;
|
||||
throw err;
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
20
packages/integrations/markdoc/template/content-module-types.d.ts
vendored
Normal file
20
packages/integrations/markdoc/template/content-module-types.d.ts
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
declare module 'astro:content' {
|
||||
type ComponentRenderer =
|
||||
| import('astro').ComponentInstance['default']
|
||||
| {
|
||||
component: import('astro').ComponentInstance['default'];
|
||||
props?(params: {
|
||||
attributes: Record<string, any>;
|
||||
getTreeNode(): typeof import('@astrojs/markdoc').Markdoc.Tag;
|
||||
}): Record<string, any>;
|
||||
};
|
||||
|
||||
interface Render {
|
||||
'.mdoc': Promise<{
|
||||
Content(props: {
|
||||
config?: import('@astrojs/markdoc').MarkdocConfig;
|
||||
components?: Record<string, ComponentRenderer>;
|
||||
}): import('astro').MarkdownInstance<{}>['Content'];
|
||||
}>;
|
||||
}
|
||||
}
|
181
packages/integrations/markdoc/test/content-collections.test.js
Normal file
181
packages/integrations/markdoc/test/content-collections.test.js
Normal file
|
@ -0,0 +1,181 @@
|
|||
import { parseHTML } from 'linkedom';
|
||||
import { parse as parseDevalue } from 'devalue';
|
||||
import { expect } from 'chai';
|
||||
import { loadFixture, fixLineEndings } from '../../../astro/test/test-utils.js';
|
||||
|
||||
function formatPost(post) {
|
||||
return {
|
||||
...post,
|
||||
body: fixLineEndings(post.body),
|
||||
};
|
||||
}
|
||||
|
||||
describe('Markdoc - Content Collections', () => {
|
||||
let fixture;
|
||||
|
||||
before(async () => {
|
||||
fixture = await loadFixture({
|
||||
root: new URL('./fixtures/content-collections/', import.meta.url),
|
||||
});
|
||||
});
|
||||
|
||||
describe('dev', () => {
|
||||
let devServer;
|
||||
|
||||
before(async () => {
|
||||
devServer = await fixture.startDevServer();
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await devServer.stop();
|
||||
});
|
||||
|
||||
it('loads entry', async () => {
|
||||
const res = await fixture.fetch('/entry.json');
|
||||
const post = parseDevalue(await res.text());
|
||||
expect(formatPost(post)).to.deep.equal(simplePostEntry);
|
||||
});
|
||||
|
||||
it('loads collection', async () => {
|
||||
const res = await fixture.fetch('/collection.json');
|
||||
const posts = parseDevalue(await res.text());
|
||||
expect(posts).to.not.be.null;
|
||||
expect(posts.sort().map((post) => formatPost(post))).to.deep.equal([
|
||||
simplePostEntry,
|
||||
withComponentsEntry,
|
||||
withConfigEntry,
|
||||
]);
|
||||
});
|
||||
|
||||
it('renders content - simple', async () => {
|
||||
const res = await fixture.fetch('/content-simple');
|
||||
const html = await res.text();
|
||||
const { document } = parseHTML(html);
|
||||
const h2 = document.querySelector('h2');
|
||||
expect(h2.textContent).to.equal('Simple post');
|
||||
const p = document.querySelector('p');
|
||||
expect(p.textContent).to.equal('This is a simple Markdoc post.');
|
||||
});
|
||||
|
||||
it('renders content - with config', async () => {
|
||||
const res = await fixture.fetch('/content-with-config');
|
||||
const html = await res.text();
|
||||
const { document } = parseHTML(html);
|
||||
const h2 = document.querySelector('h2');
|
||||
expect(h2.textContent).to.equal('Post with config');
|
||||
const marquee = document.querySelector('marquee');
|
||||
expect(marquee).to.not.be.null;
|
||||
expect(marquee.textContent).to.equal('Im a marquee!');
|
||||
});
|
||||
|
||||
it('renders content - with components', async () => {
|
||||
const res = await fixture.fetch('/content-with-components');
|
||||
const html = await res.text();
|
||||
const { document } = parseHTML(html);
|
||||
const h2 = document.querySelector('h2');
|
||||
expect(h2.textContent).to.equal('Post with components');
|
||||
|
||||
// Renders custom shortcode component
|
||||
const marquee = document.querySelector('marquee');
|
||||
expect(marquee).to.not.be.null;
|
||||
expect(marquee.hasAttribute('data-custom-marquee')).to.equal(true);
|
||||
|
||||
// Renders Astro Code component
|
||||
const pre = document.querySelector('pre');
|
||||
expect(pre).to.not.be.null;
|
||||
expect(pre.className).to.equal('astro-code');
|
||||
});
|
||||
});
|
||||
|
||||
describe('build', () => {
|
||||
before(async () => {
|
||||
await fixture.build();
|
||||
});
|
||||
|
||||
it('loads entry', async () => {
|
||||
const res = await fixture.readFile('/entry.json');
|
||||
const post = parseDevalue(res);
|
||||
expect(formatPost(post)).to.deep.equal(simplePostEntry);
|
||||
});
|
||||
|
||||
it('loads collection', async () => {
|
||||
const res = await fixture.readFile('/collection.json');
|
||||
const posts = parseDevalue(res);
|
||||
expect(posts).to.not.be.null;
|
||||
expect(posts.sort().map((post) => formatPost(post))).to.deep.equal([
|
||||
simplePostEntry,
|
||||
withComponentsEntry,
|
||||
withConfigEntry,
|
||||
]);
|
||||
});
|
||||
|
||||
it('renders content - simple', async () => {
|
||||
const html = await fixture.readFile('/content-simple/index.html');
|
||||
const { document } = parseHTML(html);
|
||||
const h2 = document.querySelector('h2');
|
||||
expect(h2.textContent).to.equal('Simple post');
|
||||
const p = document.querySelector('p');
|
||||
expect(p.textContent).to.equal('This is a simple Markdoc post.');
|
||||
});
|
||||
|
||||
it('renders content - with config', async () => {
|
||||
const html = await fixture.readFile('/content-with-config/index.html');
|
||||
const { document } = parseHTML(html);
|
||||
const h2 = document.querySelector('h2');
|
||||
expect(h2.textContent).to.equal('Post with config');
|
||||
const marquee = document.querySelector('marquee');
|
||||
expect(marquee).to.not.be.null;
|
||||
expect(marquee.textContent).to.equal('Im a marquee!');
|
||||
});
|
||||
|
||||
it('renders content - with components', async () => {
|
||||
const html = await fixture.readFile('/content-with-components/index.html');
|
||||
const { document } = parseHTML(html);
|
||||
const h2 = document.querySelector('h2');
|
||||
expect(h2.textContent).to.equal('Post with components');
|
||||
|
||||
// Renders custom shortcode component
|
||||
const marquee = document.querySelector('marquee');
|
||||
expect(marquee).to.not.be.null;
|
||||
expect(marquee.hasAttribute('data-custom-marquee')).to.equal(true);
|
||||
|
||||
// Renders Astro Code component
|
||||
const pre = document.querySelector('pre');
|
||||
expect(pre).to.not.be.null;
|
||||
expect(pre.className).to.equal('astro-code');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const simplePostEntry = {
|
||||
id: 'simple.mdoc',
|
||||
slug: 'simple',
|
||||
collection: 'blog',
|
||||
data: {
|
||||
schemaWorks: true,
|
||||
title: 'Simple post',
|
||||
},
|
||||
body: '\n## Simple post\n\nThis is a simple Markdoc post.\n',
|
||||
};
|
||||
|
||||
const withComponentsEntry = {
|
||||
id: 'with-components.mdoc',
|
||||
slug: 'with-components',
|
||||
collection: 'blog',
|
||||
data: {
|
||||
schemaWorks: true,
|
||||
title: 'Post with components',
|
||||
},
|
||||
body: '\n## Post with components\n\nThis uses a custom marquee component with a shortcode:\n\n{% mq direction="right" %}\nI\'m a marquee too!\n{% /mq %}\n\nAnd a code component for code blocks:\n\n```js\nconst isRenderedWithShiki = true;\n```\n',
|
||||
};
|
||||
|
||||
const withConfigEntry = {
|
||||
id: 'with-config.mdoc',
|
||||
slug: 'with-config',
|
||||
collection: 'blog',
|
||||
data: {
|
||||
schemaWorks: true,
|
||||
title: 'Post with config',
|
||||
},
|
||||
body: '\n## Post with config\n\nThis uses a shortcode to render a marquee element,\nwith a variable to show and hide:\n\n{% if $showMarquee %}\n{% mq direction="down" %}\nIm a marquee!\n{% /mq %}\n{% /if %}\n',
|
||||
};
|
7
packages/integrations/markdoc/test/fixtures/content-collections/astro.config.mjs
vendored
Normal file
7
packages/integrations/markdoc/test/fixtures/content-collections/astro.config.mjs
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
import { defineConfig } from 'astro/config';
|
||||
import markdoc from '@astrojs/markdoc';
|
||||
|
||||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
integrations: [markdoc()],
|
||||
});
|
13
packages/integrations/markdoc/test/fixtures/content-collections/package.json
vendored
Normal file
13
packages/integrations/markdoc/test/fixtures/content-collections/package.json
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"name": "@test/markdoc-content-collections",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@astrojs/markdoc": "workspace:*",
|
||||
"@markdoc/markdoc": "^0.2.2",
|
||||
"astro": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"shiki": "^0.11.1"
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
<marquee data-custom-marquee {...Astro.props}><slot /></marquee>
|
7
packages/integrations/markdoc/test/fixtures/content-collections/src/content/blog/simple.mdoc
vendored
Normal file
7
packages/integrations/markdoc/test/fixtures/content-collections/src/content/blog/simple.mdoc
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
title: Simple post
|
||||
---
|
||||
|
||||
## Simple post
|
||||
|
||||
This is a simple Markdoc post.
|
|
@ -0,0 +1,17 @@
|
|||
---
|
||||
title: Post with components
|
||||
---
|
||||
|
||||
## Post with components
|
||||
|
||||
This uses a custom marquee component with a shortcode:
|
||||
|
||||
{% mq direction="right" %}
|
||||
I'm a marquee too!
|
||||
{% /mq %}
|
||||
|
||||
And a code component for code blocks:
|
||||
|
||||
```js
|
||||
const isRenderedWithShiki = true;
|
||||
```
|
|
@ -0,0 +1,14 @@
|
|||
---
|
||||
title: Post with config
|
||||
---
|
||||
|
||||
## Post with config
|
||||
|
||||
This uses a shortcode to render a marquee element,
|
||||
with a variable to show and hide:
|
||||
|
||||
{% if $showMarquee %}
|
||||
{% mq direction="down" %}
|
||||
Im a marquee!
|
||||
{% /mq %}
|
||||
{% /if %}
|
12
packages/integrations/markdoc/test/fixtures/content-collections/src/content/config.ts
vendored
Normal file
12
packages/integrations/markdoc/test/fixtures/content-collections/src/content/config.ts
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
import { defineCollection, z } from 'astro:content';
|
||||
|
||||
const blog = defineCollection({
|
||||
schema: z.object({
|
||||
title: z.string(),
|
||||
}).transform(data => ({
|
||||
...data,
|
||||
schemaWorks: true,
|
||||
}))
|
||||
});
|
||||
|
||||
export const collections = { blog };
|
10
packages/integrations/markdoc/test/fixtures/content-collections/src/pages/collection.json.js
vendored
Normal file
10
packages/integrations/markdoc/test/fixtures/content-collections/src/pages/collection.json.js
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
import { getCollection } from 'astro:content';
|
||||
import { stringify } from 'devalue';
|
||||
import { stripAllRenderFn } from '../../utils.js';
|
||||
|
||||
export async function get() {
|
||||
const posts = await getCollection('blog');
|
||||
return {
|
||||
body: stringify(stripAllRenderFn(posts))
|
||||
};
|
||||
}
|
18
packages/integrations/markdoc/test/fixtures/content-collections/src/pages/content-simple.astro
vendored
Normal file
18
packages/integrations/markdoc/test/fixtures/content-collections/src/pages/content-simple.astro
vendored
Normal file
|
@ -0,0 +1,18 @@
|
|||
---
|
||||
import { getEntryBySlug } from "astro:content";
|
||||
const post = await getEntryBySlug('blog', 'simple');
|
||||
const { Content } = await post.render();
|
||||
---
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Content - Simple</title>
|
||||
</head>
|
||||
<body>
|
||||
<Content />
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,50 @@
|
|||
---
|
||||
import { getEntryBySlug } from "astro:content";
|
||||
import { Code } from 'astro/components';
|
||||
import CustomMarquee from '../components/CustomMarquee.astro';
|
||||
import Markdoc from '@markdoc/markdoc';
|
||||
|
||||
const post = await getEntryBySlug('blog', 'with-components');
|
||||
const { Content } = await post.render();
|
||||
---
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Content - with components</title>
|
||||
</head>
|
||||
<body>
|
||||
<Content
|
||||
config={{
|
||||
tags: {
|
||||
mq: {
|
||||
render: 'marquee',
|
||||
attributes: {
|
||||
direction: {
|
||||
type: String,
|
||||
default: 'left',
|
||||
matches: ['left', 'right', 'up', 'down'],
|
||||
errorLevel: 'critical',
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}}
|
||||
components={{
|
||||
marquee: CustomMarquee,
|
||||
pre: {
|
||||
component: Code,
|
||||
props({ attributes, getTreeNode }) {
|
||||
return {
|
||||
lang: attributes['data-language'],
|
||||
code: Markdoc.renderers.html(getTreeNode().children),
|
||||
};
|
||||
},
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,38 @@
|
|||
---
|
||||
import { getEntryBySlug } from "astro:content";
|
||||
|
||||
const post = await getEntryBySlug('blog', 'with-config');
|
||||
const { Content } = await post.render();
|
||||
---
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Content - with config</title>
|
||||
</head>
|
||||
<body>
|
||||
<Content
|
||||
config={{
|
||||
variables: {
|
||||
showMarquee: true,
|
||||
},
|
||||
tags: {
|
||||
mq: {
|
||||
render: 'marquee',
|
||||
attributes: {
|
||||
direction: {
|
||||
type: String,
|
||||
default: 'left',
|
||||
matches: ['left', 'right', 'up', 'down'],
|
||||
errorLevel: 'critical',
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</body>
|
||||
</html>
|
10
packages/integrations/markdoc/test/fixtures/content-collections/src/pages/entry.json.js
vendored
Normal file
10
packages/integrations/markdoc/test/fixtures/content-collections/src/pages/entry.json.js
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
import { getEntryBySlug } from 'astro:content';
|
||||
import { stringify } from 'devalue';
|
||||
import { stripRenderFn } from '../../utils.js';
|
||||
|
||||
export async function get() {
|
||||
const post = await getEntryBySlug('blog', 'simple');
|
||||
return {
|
||||
body: stringify(stripRenderFn(post)),
|
||||
};
|
||||
}
|
8
packages/integrations/markdoc/test/fixtures/content-collections/utils.js
vendored
Normal file
8
packages/integrations/markdoc/test/fixtures/content-collections/utils.js
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
export function stripRenderFn(entryWithRender) {
|
||||
const { render, ...entry } = entryWithRender;
|
||||
return entry;
|
||||
}
|
||||
|
||||
export function stripAllRenderFn(collection = []) {
|
||||
return collection.map(stripRenderFn);
|
||||
}
|
10
packages/integrations/markdoc/tsconfig.json
Normal file
10
packages/integrations/markdoc/tsconfig.json
Normal file
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"extends": "../../../tsconfig.base.json",
|
||||
"include": ["src"],
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"module": "ES2020",
|
||||
"outDir": "./dist",
|
||||
"target": "ES2020"
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ import mdxPlugin, { Options as MdxRollupPluginOptions } from '@mdx-js/rollup';
|
|||
import type { AstroIntegration } from 'astro';
|
||||
import { parse as parseESM } from 'es-module-lexer';
|
||||
import fs from 'node:fs/promises';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import type { Options as RemarkRehypeOptions } from 'remark-rehype';
|
||||
import { VFile } from 'vfile';
|
||||
import type { Plugin as VitePlugin } from 'vite';
|
||||
|
@ -26,8 +27,32 @@ export default function mdx(partialMdxOptions: Partial<MdxOptions> = {}): AstroI
|
|||
return {
|
||||
name: '@astrojs/mdx',
|
||||
hooks: {
|
||||
'astro:config:setup': async ({ updateConfig, config, addPageExtension, command }: any) => {
|
||||
'astro:config:setup': async ({
|
||||
updateConfig,
|
||||
config,
|
||||
addPageExtension,
|
||||
addContentEntryType,
|
||||
command,
|
||||
}: any) => {
|
||||
const contentEntryType = {
|
||||
extensions: ['.mdx'],
|
||||
async getEntryInfo({ fileUrl, contents }: { fileUrl: URL; contents: string }) {
|
||||
const parsed = parseFrontmatter(contents, fileURLToPath(fileUrl));
|
||||
return {
|
||||
data: parsed.data,
|
||||
body: parsed.content,
|
||||
slug: parsed.data.slug,
|
||||
rawData: parsed.matter,
|
||||
};
|
||||
},
|
||||
contentModuleTypes: await fs.readFile(
|
||||
new URL('../template/content-module-types.d.ts', import.meta.url),
|
||||
'utf-8'
|
||||
),
|
||||
};
|
||||
|
||||
addPageExtension('.mdx');
|
||||
addContentEntryType(contentEntryType);
|
||||
|
||||
const extendMarkdownConfig =
|
||||
partialMdxOptions.extendMarkdownConfig ?? defaultOptions.extendMarkdownConfig;
|
||||
|
|
9
packages/integrations/mdx/template/content-module-types.d.ts
vendored
Normal file
9
packages/integrations/mdx/template/content-module-types.d.ts
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
declare module 'astro:content' {
|
||||
interface Render {
|
||||
'.mdx': Promise<{
|
||||
Content: import('astro').MarkdownInstance<{}>['Content'];
|
||||
headings: import('astro').MarkdownHeading[];
|
||||
remarkPluginFrontmatter: Record<string, any>;
|
||||
}>;
|
||||
}
|
||||
}
|
|
@ -55,6 +55,7 @@ export async function renderMarkdown(
|
|||
smartypants = markdownConfigDefaults.smartypants,
|
||||
contentDir,
|
||||
frontmatter: userFrontmatter = {},
|
||||
performanceRun = false,
|
||||
} = opts;
|
||||
const input = new VFile({ value: content, path: fileURL });
|
||||
const scopedClassName = opts.$?.scopedClassName;
|
||||
|
@ -64,8 +65,10 @@ export async function renderMarkdown(
|
|||
.use(toRemarkInitializeAstroData({ userFrontmatter }))
|
||||
.use([]);
|
||||
|
||||
if (gfm) {
|
||||
parser.use(remarkGfm);
|
||||
if (!performanceRun) {
|
||||
if (gfm) {
|
||||
parser.use(remarkGfm);
|
||||
}
|
||||
}
|
||||
|
||||
if (smartypants) {
|
||||
|
@ -79,18 +82,20 @@ export async function renderMarkdown(
|
|||
parser.use([[plugin, pluginOpts]]);
|
||||
});
|
||||
|
||||
if (scopedClassName) {
|
||||
parser.use([scopedStyles(scopedClassName)]);
|
||||
}
|
||||
if (!performanceRun) {
|
||||
if (scopedClassName) {
|
||||
parser.use([scopedStyles(scopedClassName)]);
|
||||
}
|
||||
|
||||
if (syntaxHighlight === 'shiki') {
|
||||
parser.use([await remarkShiki(shikiConfig, scopedClassName)]);
|
||||
} else if (syntaxHighlight === 'prism') {
|
||||
parser.use([remarkPrism(scopedClassName)]);
|
||||
}
|
||||
if (syntaxHighlight === 'shiki') {
|
||||
parser.use([await remarkShiki(shikiConfig, scopedClassName)]);
|
||||
} else if (syntaxHighlight === 'prism') {
|
||||
parser.use([remarkPrism(scopedClassName)]);
|
||||
}
|
||||
|
||||
// Apply later in case user plugins resolve relative image paths
|
||||
parser.use([toRemarkContentRelImageError({ contentDir })]);
|
||||
// Apply later in case user plugins resolve relative image paths
|
||||
parser.use([toRemarkContentRelImageError({ contentDir })]);
|
||||
}
|
||||
|
||||
parser.use([
|
||||
[
|
||||
|
@ -107,7 +112,11 @@ export async function renderMarkdown(
|
|||
parser.use([[plugin, pluginOpts]]);
|
||||
});
|
||||
|
||||
parser.use([rehypeHeadingIds, rehypeRaw]).use(rehypeStringify, { allowDangerousHtml: true });
|
||||
if (!performanceRun) {
|
||||
parser.use([rehypeHeadingIds]);
|
||||
}
|
||||
|
||||
parser.use([rehypeRaw]).use(rehypeStringify, { allowDangerousHtml: true });
|
||||
|
||||
let vfile: MarkdownVFile;
|
||||
try {
|
||||
|
|
|
@ -62,6 +62,8 @@ export interface MarkdownRenderingOptions extends AstroMarkdownOptions {
|
|||
contentDir: URL;
|
||||
/** Used for frontmatter injection plugins */
|
||||
frontmatter?: Record<string, any>;
|
||||
/** @internal Used for performance testing */
|
||||
performanceRun?: boolean;
|
||||
}
|
||||
|
||||
export interface MarkdownHeading {
|
||||
|
|
243
pnpm-lock.yaml
243
pnpm-lock.yaml
|
@ -285,6 +285,14 @@ importers:
|
|||
unocss: 0.15.6
|
||||
vite-imagetools: 4.0.18
|
||||
|
||||
examples/with-markdoc:
|
||||
specifiers:
|
||||
'@astrojs/markdoc': ^0.0.0
|
||||
astro: ^2.0.6
|
||||
dependencies:
|
||||
'@astrojs/markdoc': link:../../packages/integrations/markdoc
|
||||
astro: link:../../packages/astro
|
||||
|
||||
examples/with-markdown-plugins:
|
||||
specifiers:
|
||||
'@astrojs/markdown-remark': ^2.0.1
|
||||
|
@ -1098,6 +1106,46 @@ importers:
|
|||
astro: link:../../..
|
||||
vue: 3.2.47
|
||||
|
||||
packages/astro/performance:
|
||||
specifiers:
|
||||
npm-run-all: ^4.1.5
|
||||
devDependencies:
|
||||
npm-run-all: 4.1.5
|
||||
|
||||
packages/astro/performance/fixtures/md:
|
||||
specifiers:
|
||||
'@performance/utils': ^0.0.0
|
||||
astro: ^2.0.12
|
||||
dependencies:
|
||||
'@performance/utils': link:../utils
|
||||
astro: link:../../..
|
||||
|
||||
packages/astro/performance/fixtures/mdoc:
|
||||
specifiers:
|
||||
'@astrojs/markdoc': ^0.0.0
|
||||
'@performance/utils': ^0.0.0
|
||||
astro: ^2.0.12
|
||||
dependencies:
|
||||
'@astrojs/markdoc': link:../../../../integrations/markdoc
|
||||
'@performance/utils': link:../utils
|
||||
astro: link:../../..
|
||||
|
||||
packages/astro/performance/fixtures/mdx:
|
||||
specifiers:
|
||||
'@astrojs/mdx': ^0.16.2
|
||||
'@performance/utils': ^0.0.0
|
||||
astro: ^2.0.12
|
||||
dependencies:
|
||||
'@astrojs/mdx': link:../../../../integrations/mdx
|
||||
'@performance/utils': link:../utils
|
||||
astro: link:../../..
|
||||
|
||||
packages/astro/performance/fixtures/utils:
|
||||
specifiers:
|
||||
astro: ^2.0.12
|
||||
devDependencies:
|
||||
astro: link:../../..
|
||||
|
||||
packages/astro/test/benchmark/simple:
|
||||
specifiers:
|
||||
'@astrojs/node': workspace:*
|
||||
|
@ -1690,10 +1738,8 @@ importers:
|
|||
|
||||
packages/astro/test/fixtures/content-collections-with-config-mjs:
|
||||
specifiers:
|
||||
'@astrojs/mdx': workspace:*
|
||||
astro: workspace:*
|
||||
dependencies:
|
||||
'@astrojs/mdx': link:../../../../integrations/mdx
|
||||
astro: link:../../..
|
||||
|
||||
packages/astro/test/fixtures/content-ssr-integration:
|
||||
|
@ -2884,6 +2930,50 @@ importers:
|
|||
mocha: 9.2.2
|
||||
sass: 1.58.0
|
||||
|
||||
packages/integrations/markdoc:
|
||||
specifiers:
|
||||
'@markdoc/markdoc': ^0.2.2
|
||||
'@types/chai': ^4.3.1
|
||||
'@types/html-escaper': ^3.0.0
|
||||
'@types/mocha': ^9.1.1
|
||||
astro: workspace:*
|
||||
astro-scripts: workspace:*
|
||||
chai: ^4.3.6
|
||||
devalue: ^4.2.0
|
||||
gray-matter: ^4.0.3
|
||||
linkedom: ^0.14.12
|
||||
mocha: ^9.2.2
|
||||
stringify-attributes: ^3.0.0
|
||||
vite: ^4.0.3
|
||||
dependencies:
|
||||
'@markdoc/markdoc': 0.2.2
|
||||
gray-matter: 4.0.3
|
||||
stringify-attributes: 3.0.0
|
||||
devDependencies:
|
||||
'@types/chai': 4.3.4
|
||||
'@types/html-escaper': 3.0.0
|
||||
'@types/mocha': 9.1.1
|
||||
astro: link:../../astro
|
||||
astro-scripts: link:../../../scripts
|
||||
chai: 4.3.7
|
||||
devalue: 4.2.3
|
||||
linkedom: 0.14.21
|
||||
mocha: 9.2.2
|
||||
vite: 4.1.1
|
||||
|
||||
packages/integrations/markdoc/test/fixtures/content-collections:
|
||||
specifiers:
|
||||
'@astrojs/markdoc': workspace:*
|
||||
'@markdoc/markdoc': ^0.2.2
|
||||
astro: workspace:*
|
||||
shiki: ^0.11.1
|
||||
dependencies:
|
||||
'@astrojs/markdoc': link:../../..
|
||||
'@markdoc/markdoc': 0.2.2
|
||||
astro: link:../../../../../astro
|
||||
devDependencies:
|
||||
shiki: 0.11.1
|
||||
|
||||
packages/integrations/mdx:
|
||||
specifiers:
|
||||
'@astrojs/markdown-remark': ^2.0.1
|
||||
|
@ -6412,6 +6502,21 @@ packages:
|
|||
- supports-color
|
||||
dev: false
|
||||
|
||||
/@markdoc/markdoc/0.2.2:
|
||||
resolution: {integrity: sha512-0TiD9jmA5h5znN4lxo7HECAu3WieU5g5vUsfByeucrdR/x88hEilpt16EydFyJwJddQ/3w5HQgW7Ovy62r4cyw==}
|
||||
engines: {node: '>=14.7.0'}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
react: '*'
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
react:
|
||||
optional: true
|
||||
optionalDependencies:
|
||||
'@types/markdown-it': 12.2.3
|
||||
dev: false
|
||||
|
||||
/@mdx-js/mdx/2.3.0:
|
||||
resolution: {integrity: sha512-jLuwRlz8DQfQNiUCJR50Y09CGPq3fLtmtUQfVrj79E0JWu3dvsVcxVIcfhR5h0iXu+/z++zDrYeiJqifRynJkA==}
|
||||
dependencies:
|
||||
|
@ -7216,11 +7321,30 @@ packages:
|
|||
/@types/json5/0.0.30:
|
||||
resolution: {integrity: sha512-sqm9g7mHlPY/43fcSNrCYfOeX9zkTTK+euO5E6+CVijSMm5tTjkVdwdqRkY3ljjIAf8679vps5jKUoJBCLsMDA==}
|
||||
|
||||
/@types/linkify-it/3.0.2:
|
||||
resolution: {integrity: sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA==}
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@types/markdown-it/12.2.3:
|
||||
resolution: {integrity: sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==}
|
||||
requiresBuild: true
|
||||
dependencies:
|
||||
'@types/linkify-it': 3.0.2
|
||||
'@types/mdurl': 1.0.2
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@types/mdast/3.0.10:
|
||||
resolution: {integrity: sha512-W864tg/Osz1+9f4lrGTZpCSO5/z4608eUp19tbozkq2HJK6i3z1kT0H9tlADXuYIb1YYOBByU4Jsqkk75q48qA==}
|
||||
dependencies:
|
||||
'@types/unist': 2.0.6
|
||||
|
||||
/@types/mdurl/1.0.2:
|
||||
resolution: {integrity: sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==}
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@types/mdx/2.0.3:
|
||||
resolution: {integrity: sha512-IgHxcT3RC8LzFLhKwP3gbMPeaK7BM9eBH46OdapPA7yvuIUJ8H6zHZV53J8hGZcTSnt95jANt+rTBNUUc22ACQ==}
|
||||
dev: false
|
||||
|
@ -8697,7 +8821,7 @@ packages:
|
|||
dev: false
|
||||
|
||||
/concat-map/0.0.1:
|
||||
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
|
||||
resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=}
|
||||
|
||||
/concurrently/7.6.0:
|
||||
resolution: {integrity: sha512-BKtRgvcJGeZ4XttiDiNcFiRlxoAeZOseqUvyYRUp/Vtd+9p1ULmeoSqGsDA+2ivdeDFpqrJvGvmI+StKfKl5hw==}
|
||||
|
@ -8766,6 +8890,17 @@ packages:
|
|||
which: 1.3.1
|
||||
dev: true
|
||||
|
||||
/cross-spawn/6.0.5:
|
||||
resolution: {integrity: sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==}
|
||||
engines: {node: '>=4.8'}
|
||||
dependencies:
|
||||
nice-try: 1.0.5
|
||||
path-key: 2.0.1
|
||||
semver: 5.7.1
|
||||
shebang-command: 1.2.0
|
||||
which: 1.3.1
|
||||
dev: true
|
||||
|
||||
/cross-spawn/7.0.3:
|
||||
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
|
||||
engines: {node: '>= 8'}
|
||||
|
@ -9080,7 +9215,6 @@ packages:
|
|||
|
||||
/devalue/4.2.3:
|
||||
resolution: {integrity: sha512-JG6Q248aN0pgFL57e3zqTVeFraBe+5W2ugvv1mLXsJP6YYIYJhRZhAl7QP8haJrqob6X10F9NEkuCvNILZTPeQ==}
|
||||
dev: false
|
||||
|
||||
/didyoumean/1.2.2:
|
||||
resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==}
|
||||
|
@ -9566,6 +9700,11 @@ packages:
|
|||
resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
/escape-goat/3.0.0:
|
||||
resolution: {integrity: sha512-w3PwNZJwRxlp47QGzhuEBldEqVHHhh8/tIPcl6ecf2Bou99cdAt0knihBV0Ecc7CGxYduXVBDheH1K2oADRlvw==}
|
||||
engines: {node: '>=10'}
|
||||
dev: false
|
||||
|
||||
/escape-html/1.0.3:
|
||||
resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==}
|
||||
dev: false
|
||||
|
@ -11078,6 +11217,10 @@ packages:
|
|||
hasBin: true
|
||||
dev: false
|
||||
|
||||
/json-parse-better-errors/1.0.2:
|
||||
resolution: {integrity: sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==}
|
||||
dev: true
|
||||
|
||||
/json-parse-even-better-errors/2.3.1:
|
||||
resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==}
|
||||
dev: true
|
||||
|
@ -11219,6 +11362,16 @@ packages:
|
|||
resolution: {integrity: sha512-XXXAk5sbvtjjwbie3XG+6HppgTm1HTGL/Uk9z9NkJH53o7puZLur434heHzAjkS60hZB3vT4ls25zl5rMiX4EA==}
|
||||
dev: false
|
||||
|
||||
/load-json-file/4.0.0:
|
||||
resolution: {integrity: sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==}
|
||||
engines: {node: '>=4'}
|
||||
dependencies:
|
||||
graceful-fs: 4.2.10
|
||||
parse-json: 4.0.0
|
||||
pify: 3.0.0
|
||||
strip-bom: 3.0.0
|
||||
dev: true
|
||||
|
||||
/load-yaml-file/0.2.0:
|
||||
resolution: {integrity: sha512-OfCBkGEw4nN6JLtgRidPX6QxjBQGQf72q3si2uvqyFEMbycSFFHwAZeXx6cJgFM9wmLrf9zBwCP3Ivqa+LLZPw==}
|
||||
engines: {node: '>=6'}
|
||||
|
@ -11600,6 +11753,11 @@ packages:
|
|||
fs-monkey: 1.0.3
|
||||
dev: true
|
||||
|
||||
/memorystream/0.3.1:
|
||||
resolution: {integrity: sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==}
|
||||
engines: {node: '>= 0.10.0'}
|
||||
dev: true
|
||||
|
||||
/meow/6.1.1:
|
||||
resolution: {integrity: sha512-3YffViIt2QWgTy6Pale5QpopX/IvU3LPL03jOTqp6pGj3VjesdO/U8CuHMKpnQr4shCNCM5fd5XFFvIIl6JBHg==}
|
||||
engines: {node: '>=8'}
|
||||
|
@ -12193,6 +12351,10 @@ packages:
|
|||
engines: {node: '>= 0.4.0'}
|
||||
dev: true
|
||||
|
||||
/nice-try/1.0.5:
|
||||
resolution: {integrity: sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==}
|
||||
dev: true
|
||||
|
||||
/nlcst-to-string/3.1.1:
|
||||
resolution: {integrity: sha512-63mVyqaqt0cmn2VcI2aH6kxe1rLAmSROqHMA0i4qqg1tidkfExgpb0FGMikMCn86mw5dFtBtEANfmSSK7TjNHw==}
|
||||
dependencies:
|
||||
|
@ -12301,6 +12463,22 @@ packages:
|
|||
resolution: {integrity: sha512-5PDmaAsVfnWUgTUbJ3ERwn7u79Z0dYxN9ErxCpVJJqe2RK0PJ3z+iFUxuqjwtlDDegXvtWoxD/3Fzxox7tFGWA==}
|
||||
dev: false
|
||||
|
||||
/npm-run-all/4.1.5:
|
||||
resolution: {integrity: sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==}
|
||||
engines: {node: '>= 4'}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
ansi-styles: 3.2.1
|
||||
chalk: 2.4.2
|
||||
cross-spawn: 6.0.5
|
||||
memorystream: 0.3.1
|
||||
minimatch: 3.1.2
|
||||
pidtree: 0.3.1
|
||||
read-pkg: 3.0.0
|
||||
shell-quote: 1.8.0
|
||||
string.prototype.padend: 3.1.4
|
||||
dev: true
|
||||
|
||||
/npm-run-path/4.0.1:
|
||||
resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==}
|
||||
engines: {node: '>=8'}
|
||||
|
@ -12560,6 +12738,14 @@ packages:
|
|||
is-decimal: 2.0.1
|
||||
is-hexadecimal: 2.0.1
|
||||
|
||||
/parse-json/4.0.0:
|
||||
resolution: {integrity: sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==}
|
||||
engines: {node: '>=4'}
|
||||
dependencies:
|
||||
error-ex: 1.3.2
|
||||
json-parse-better-errors: 1.0.2
|
||||
dev: true
|
||||
|
||||
/parse-json/5.2.0:
|
||||
resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
|
||||
engines: {node: '>=8'}
|
||||
|
@ -12631,6 +12817,11 @@ packages:
|
|||
resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
/path-key/2.0.1:
|
||||
resolution: {integrity: sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==}
|
||||
engines: {node: '>=4'}
|
||||
dev: true
|
||||
|
||||
/path-key/3.1.1:
|
||||
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
|
||||
engines: {node: '>=8'}
|
||||
|
@ -12645,6 +12836,13 @@ packages:
|
|||
/path-to-regexp/6.2.1:
|
||||
resolution: {integrity: sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==}
|
||||
|
||||
/path-type/3.0.0:
|
||||
resolution: {integrity: sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==}
|
||||
engines: {node: '>=4'}
|
||||
dependencies:
|
||||
pify: 3.0.0
|
||||
dev: true
|
||||
|
||||
/path-type/4.0.0:
|
||||
resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
|
||||
engines: {node: '>=8'}
|
||||
|
@ -12675,10 +12873,21 @@ packages:
|
|||
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
|
||||
engines: {node: '>=8.6'}
|
||||
|
||||
/pidtree/0.3.1:
|
||||
resolution: {integrity: sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==}
|
||||
engines: {node: '>=0.10'}
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/pify/2.3.0:
|
||||
resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
/pify/3.0.0:
|
||||
resolution: {integrity: sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==}
|
||||
engines: {node: '>=4'}
|
||||
dev: true
|
||||
|
||||
/pify/4.0.1:
|
||||
resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==}
|
||||
engines: {node: '>=6'}
|
||||
|
@ -13339,6 +13548,15 @@ packages:
|
|||
type-fest: 0.8.1
|
||||
dev: true
|
||||
|
||||
/read-pkg/3.0.0:
|
||||
resolution: {integrity: sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==}
|
||||
engines: {node: '>=4'}
|
||||
dependencies:
|
||||
load-json-file: 4.0.0
|
||||
normalize-package-data: 2.5.0
|
||||
path-type: 3.0.0
|
||||
dev: true
|
||||
|
||||
/read-pkg/5.2.0:
|
||||
resolution: {integrity: sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==}
|
||||
engines: {node: '>=8'}
|
||||
|
@ -13950,7 +14168,6 @@ packages:
|
|||
|
||||
/shell-quote/1.8.0:
|
||||
resolution: {integrity: sha512-QHsz8GgQIGKlRi24yFc6a6lN69Idnx634w49ay6+jA5yFh7a1UY+4Rp6HPx/L/1zcEDPEij8cIsiqR6bQsE5VQ==}
|
||||
dev: false
|
||||
|
||||
/shiki-twoslash/3.1.0:
|
||||
resolution: {integrity: sha512-uDqrTutOIZzyHbo103GsK7Vvc10saK1XCCivnOQ1NHJzgp3FBilEpftGeVzVSMOJs+JyhI7whkvhXV7kXQ5zCg==}
|
||||
|
@ -14215,6 +14432,15 @@ packages:
|
|||
side-channel: 1.0.4
|
||||
dev: false
|
||||
|
||||
/string.prototype.padend/3.1.4:
|
||||
resolution: {integrity: sha512-67otBXoksdjsnXXRUq+KMVTdlVRZ2af422Y0aTyTjVaoQkGr3mxl2Bc5emi7dOQ3OGVVQQskmLEWwFXwommpNw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
dependencies:
|
||||
call-bind: 1.0.2
|
||||
define-properties: 1.1.4
|
||||
es-abstract: 1.21.1
|
||||
dev: true
|
||||
|
||||
/string.prototype.trimend/1.0.6:
|
||||
resolution: {integrity: sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==}
|
||||
dependencies:
|
||||
|
@ -14238,6 +14464,13 @@ packages:
|
|||
dependencies:
|
||||
safe-buffer: 5.2.1
|
||||
|
||||
/stringify-attributes/3.0.0:
|
||||
resolution: {integrity: sha512-tJKiThlLfog6ljT7ZTihlMh0iAtjKlu/ss9DMmBE5oOosbMqOMcuxc7zDfxP2lGzSb2Bwvbd3gQTqTSCmXyySw==}
|
||||
engines: {node: '>=12'}
|
||||
dependencies:
|
||||
escape-goat: 3.0.0
|
||||
dev: false
|
||||
|
||||
/stringify-entities/4.0.3:
|
||||
resolution: {integrity: sha512-BP9nNHMhhfcMbiuQKCqMjhDP5yBCAxsPu4pHFFzJ6Alo9dZgY4VLDPutXqIjpRiMoKdp7Av85Gr73Q5uH9k7+g==}
|
||||
dependencies:
|
||||
|
|
Loading…
Reference in a new issue