@astrojs/markdoc 0.2.3 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +119 -29
- package/components/Renderer.astro +2 -1
- package/components/TreeNode.ts +104 -14
- package/dist/config.d.ts +6 -1
- package/dist/config.js +2 -2
- package/dist/extensions/prism.d.ts +2 -0
- package/dist/extensions/prism.js +21 -0
- package/dist/extensions/shiki.d.ts +3 -0
- package/dist/extensions/shiki.js +100 -0
- package/dist/heading-ids.d.ts +9 -0
- package/dist/{nodes/heading.js → heading-ids.js} +10 -4
- package/dist/index.js +106 -21
- package/dist/runtime.d.ts +7 -4
- package/dist/runtime.js +21 -8
- package/dist/utils.d.ts +14 -0
- package/dist/utils.js +20 -0
- package/package.json +9 -5
- package/dist/nodes/heading.d.ts +0 -10
- package/dist/nodes/index.d.ts +0 -4
- package/dist/nodes/index.js +0 -7
package/README.md
CHANGED
|
@@ -97,13 +97,9 @@ const { Content } = await entry.render();
|
|
|
97
97
|
|
|
98
98
|
`@astrojs/markdoc` offers configuration options to use all of Markdoc's features and connect UI components to your content.
|
|
99
99
|
|
|
100
|
-
###
|
|
100
|
+
### Use Astro components as Markdoc tags
|
|
101
101
|
|
|
102
|
-
You can
|
|
103
|
-
|
|
104
|
-
#### Render Markdoc tags as Astro components
|
|
105
|
-
|
|
106
|
-
You may configure [Markdoc tags][markdoc-tags] that map to components. You can configure a new tag by creating a `markdoc.config.mjs|ts` file at the root of your project and configuring the `tag` attribute.
|
|
102
|
+
You can configure [Markdoc tags][markdoc-tags] that map to `.astro` components. You can add a new tag by creating a `markdoc.config.mjs|ts` file at the root of your project and configuring the `tag` attribute.
|
|
107
103
|
|
|
108
104
|
This example renders an `Aside` component, and allows a `type` prop to be passed as a string:
|
|
109
105
|
|
|
@@ -141,9 +137,11 @@ Use tags like this fancy "aside" to add some *flair* to your docs.
|
|
|
141
137
|
{% /aside %}
|
|
142
138
|
```
|
|
143
139
|
|
|
144
|
-
|
|
140
|
+
### Custom headings
|
|
141
|
+
|
|
142
|
+
`@astrojs/markdoc` automatically adds anchor links to your headings, and [generates a list of `headings` via the content collections API](https://docs.astro.build/en/guides/content-collections/#rendering-content-to-html). To further customize how headings are rendered, you can apply an Astro component [as a Markdoc node][markdoc-nodes].
|
|
145
143
|
|
|
146
|
-
|
|
144
|
+
This example renders a `Heading.astro` component using the `render` property:
|
|
147
145
|
|
|
148
146
|
```js
|
|
149
147
|
// markdoc.config.mjs
|
|
@@ -154,26 +152,115 @@ export default defineMarkdocConfig({
|
|
|
154
152
|
nodes: {
|
|
155
153
|
heading: {
|
|
156
154
|
render: Heading,
|
|
155
|
+
// Preserve default anchor link generation
|
|
157
156
|
...nodes.heading,
|
|
158
157
|
},
|
|
159
158
|
},
|
|
160
159
|
})
|
|
161
160
|
```
|
|
162
161
|
|
|
163
|
-
All Markdown headings will render the `Heading.astro` component and pass `attributes` as component props
|
|
162
|
+
All Markdown headings will render the `Heading.astro` component and pass the following `attributes` as component props:
|
|
164
163
|
|
|
165
164
|
- `level: number` The heading level 1 - 6
|
|
166
165
|
- `id: string` An `id` generated from the heading's text contents. This corresponds to the `slug` generated by the [content `render()` function](https://docs.astro.build/en/guides/content-collections/#rendering-content-to-html).
|
|
167
166
|
|
|
168
167
|
For example, the heading `### Level 3 heading!` will pass `level: 3` and `id: 'level-3-heading'` as component props.
|
|
169
168
|
|
|
169
|
+
### Syntax highlighting
|
|
170
|
+
|
|
171
|
+
`@astrojs/markdoc` provides [Shiki](https://github.com/shikijs/shiki) and [Prism](https://github.com/PrismJS) extensions to highlight your code blocks.
|
|
172
|
+
|
|
173
|
+
#### Shiki
|
|
174
|
+
|
|
175
|
+
Apply the `shiki()` extension to your Markdoc config using the `extends` property. You can optionally pass a shiki configuration object:
|
|
176
|
+
|
|
177
|
+
```js
|
|
178
|
+
// markdoc.config.mjs
|
|
179
|
+
import { defineMarkdocConfig } from '@astrojs/markdoc/config';
|
|
180
|
+
import shiki from '@astrojs/markdoc/shiki';
|
|
181
|
+
|
|
182
|
+
export default defineMarkdocConfig({
|
|
183
|
+
extends: [
|
|
184
|
+
shiki({
|
|
185
|
+
// Choose from Shiki's built-in themes (or add your own)
|
|
186
|
+
// Default: 'github-dark'
|
|
187
|
+
// https://github.com/shikijs/shiki/blob/main/docs/themes.md
|
|
188
|
+
theme: 'dracula',
|
|
189
|
+
// Enable word wrap to prevent horizontal scrolling
|
|
190
|
+
// Default: false
|
|
191
|
+
wrap: true,
|
|
192
|
+
// Pass custom languages
|
|
193
|
+
// Note: Shiki has countless langs built-in, including `.astro`!
|
|
194
|
+
// https://github.com/shikijs/shiki/blob/main/docs/languages.md
|
|
195
|
+
langs: [],
|
|
196
|
+
})
|
|
197
|
+
],
|
|
198
|
+
})
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
#### Prism
|
|
202
|
+
|
|
203
|
+
Apply the `prism()` extension to your Markdoc config using the `extends` property.
|
|
204
|
+
|
|
205
|
+
```js
|
|
206
|
+
// markdoc.config.mjs
|
|
207
|
+
import { defineMarkdocConfig } from '@astrojs/markdoc/config';
|
|
208
|
+
import prism from '@astrojs/markdoc/prism';
|
|
209
|
+
|
|
210
|
+
export default defineMarkdocConfig({
|
|
211
|
+
extends: [prism()],
|
|
212
|
+
})
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
📚 To learn about configuring Prism stylesheets, [see our syntax highlighting guide](https://docs.astro.build/en/guides/markdown-content/#prism-configuration).
|
|
216
|
+
|
|
217
|
+
### Set the root HTML element
|
|
218
|
+
|
|
219
|
+
Markdoc wraps documents with an `<article>` tag by default. This can be changed from the `document` Markdoc node. This accepts an HTML element name or `null` if you prefer to remove the wrapper element:
|
|
220
|
+
|
|
221
|
+
```js
|
|
222
|
+
// markdoc.config.mjs
|
|
223
|
+
import { defineMarkdocConfig, nodes } from '@astrojs/markdoc/config';
|
|
224
|
+
|
|
225
|
+
export default defineMarkdocConfig({
|
|
226
|
+
nodes: {
|
|
227
|
+
document: {
|
|
228
|
+
render: null, // default 'article'
|
|
229
|
+
...nodes.document, // Apply defaults for other options
|
|
230
|
+
},
|
|
231
|
+
},
|
|
232
|
+
})
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### Custom Markdoc nodes / elements
|
|
236
|
+
|
|
237
|
+
You may want to render standard Markdown elements, such as paragraphs and bolded text, as Astro components. For this, you can configure a [Markdoc node][markdoc-nodes]. If a given node receives attributes, they will be available as component props.
|
|
238
|
+
|
|
239
|
+
This example renders blockquotes with a custom `Quote.astro` component:
|
|
240
|
+
|
|
241
|
+
```js
|
|
242
|
+
// markdoc.config.mjs
|
|
243
|
+
import { defineMarkdocConfig, nodes } from '@astrojs/markdoc/config';
|
|
244
|
+
import Quote from './src/components/Quote.astro';
|
|
245
|
+
|
|
246
|
+
export default defineMarkdocConfig({
|
|
247
|
+
nodes: {
|
|
248
|
+
blockquote: {
|
|
249
|
+
render: Quote,
|
|
250
|
+
// Apply Markdoc's defaults for other options
|
|
251
|
+
...nodes.blockquote,
|
|
252
|
+
},
|
|
253
|
+
},
|
|
254
|
+
})
|
|
255
|
+
```
|
|
256
|
+
|
|
170
257
|
📚 [Find all of Markdoc's built-in nodes and node attributes on their documentation.](https://markdoc.dev/docs/nodes#built-in-nodes)
|
|
171
258
|
|
|
172
|
-
|
|
259
|
+
### Use client-side UI components
|
|
173
260
|
|
|
174
|
-
|
|
261
|
+
Tags and nodes are restricted to `.astro` files. To embed client-side UI components in Markdoc, [use a wrapper `.astro` component that renders a framework component](/en/core-concepts/framework-components/#nesting-framework-components) with your desired `client:` directive.
|
|
175
262
|
|
|
176
|
-
This example wraps a `Aside.tsx` component with a `ClientAside.astro`
|
|
263
|
+
This example wraps a React `Aside.tsx` component with a `ClientAside.astro` component:
|
|
177
264
|
|
|
178
265
|
```astro
|
|
179
266
|
---
|
|
@@ -184,17 +271,17 @@ import Aside from './Aside';
|
|
|
184
271
|
<Aside {...Astro.props} client:load />
|
|
185
272
|
```
|
|
186
273
|
|
|
187
|
-
This component can be passed to the `render` prop for any [tag][markdoc-tags] or [node][markdoc-nodes] in your config:
|
|
274
|
+
This Astro component can now be passed to the `render` prop for any [tag][markdoc-tags] or [node][markdoc-nodes] in your config:
|
|
188
275
|
|
|
189
276
|
```js
|
|
190
277
|
// markdoc.config.mjs
|
|
191
278
|
import { defineMarkdocConfig } from '@astrojs/markdoc/config';
|
|
192
|
-
import
|
|
279
|
+
import ClientAside from './src/components/ClientAside.astro';
|
|
193
280
|
|
|
194
281
|
export default defineMarkdocConfig({
|
|
195
282
|
tags: {
|
|
196
283
|
aside: {
|
|
197
|
-
render:
|
|
284
|
+
render: ClientAside,
|
|
198
285
|
attributes: {
|
|
199
286
|
type: { type: String },
|
|
200
287
|
}
|
|
@@ -203,20 +290,6 @@ export default defineMarkdocConfig({
|
|
|
203
290
|
})
|
|
204
291
|
```
|
|
205
292
|
|
|
206
|
-
### Access frontmatter and content collection information from your templates
|
|
207
|
-
|
|
208
|
-
You can access content collection information from your Markdoc templates using the `$entry` variable. This includes the entry `slug`, `collection` name, and frontmatter `data` parsed by your content collection schema (if any). This example renders the `title` frontmatter property as a heading:
|
|
209
|
-
|
|
210
|
-
```md
|
|
211
|
-
---
|
|
212
|
-
title: Welcome to Markdoc 👋
|
|
213
|
-
---
|
|
214
|
-
|
|
215
|
-
# {% $entry.data.title %}
|
|
216
|
-
```
|
|
217
|
-
|
|
218
|
-
The `$entry` object matches [the `CollectionEntry` type](https://docs.astro.build/en/reference/api-reference/#collection-entry-type), excluding the `.render()` property.
|
|
219
|
-
|
|
220
293
|
### Markdoc config
|
|
221
294
|
|
|
222
295
|
The `markdoc.config.mjs|ts` file accepts [all Markdoc configuration options](https://markdoc.dev/docs/config), including [tags](https://markdoc.dev/docs/tags) and [functions](https://markdoc.dev/docs/functions).
|
|
@@ -292,6 +365,23 @@ export default defineMarkdocConfig({
|
|
|
292
365
|
})
|
|
293
366
|
```
|
|
294
367
|
|
|
368
|
+
### Access frontmatter from your Markdoc content
|
|
369
|
+
|
|
370
|
+
To access frontmatter, you can pass the entry `data` property [as a variable](#pass-markdoc-variables) where you render your content:
|
|
371
|
+
|
|
372
|
+
```astro
|
|
373
|
+
---
|
|
374
|
+
import { getEntry } from 'astro:content';
|
|
375
|
+
|
|
376
|
+
const entry = await getEntry('docs', 'why-markdoc');
|
|
377
|
+
const { Content } = await entry.render();
|
|
378
|
+
---
|
|
379
|
+
|
|
380
|
+
<Content frontmatter={entry.data} />
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
This can now be accessed as `$frontmatter` in your Markdoc.
|
|
384
|
+
|
|
295
385
|
## Examples
|
|
296
386
|
|
|
297
387
|
* The [Astro Markdoc starter template](https://github.com/withastro/astro/tree/latest/examples/with-markdoc) shows how to use Markdoc files in your Astro project.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
+
//! astro-head-inject
|
|
2
3
|
import type { Config } from '@markdoc/markdoc';
|
|
3
4
|
import Markdoc from '@markdoc/markdoc';
|
|
4
5
|
import { ComponentNode, createTreeNode } from './TreeNode.js';
|
|
@@ -14,4 +15,4 @@ const ast = Markdoc.Ast.fromJSON(stringifiedAst);
|
|
|
14
15
|
const content = Markdoc.transform(ast, config);
|
|
15
16
|
---
|
|
16
17
|
|
|
17
|
-
<ComponentNode treeNode={createTreeNode(content)} />
|
|
18
|
+
<ComponentNode treeNode={await createTreeNode(content)} />
|
package/components/TreeNode.ts
CHANGED
|
@@ -2,16 +2,30 @@ import type { AstroInstance } from 'astro';
|
|
|
2
2
|
import { Fragment } from 'astro/jsx-runtime';
|
|
3
3
|
import type { RenderableTreeNode } from '@markdoc/markdoc';
|
|
4
4
|
import Markdoc from '@markdoc/markdoc';
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
createComponent,
|
|
7
|
+
renderComponent,
|
|
8
|
+
render,
|
|
9
|
+
renderScriptElement,
|
|
10
|
+
renderUniqueStylesheet,
|
|
11
|
+
createHeadAndContent,
|
|
12
|
+
unescapeHTML,
|
|
13
|
+
renderTemplate,
|
|
14
|
+
HTMLString,
|
|
15
|
+
isHTMLString,
|
|
16
|
+
} from 'astro/runtime/server/index.js';
|
|
6
17
|
|
|
7
18
|
export type TreeNode =
|
|
8
19
|
| {
|
|
9
20
|
type: 'text';
|
|
10
|
-
content: string;
|
|
21
|
+
content: string | HTMLString;
|
|
11
22
|
}
|
|
12
23
|
| {
|
|
13
24
|
type: 'component';
|
|
14
25
|
component: AstroInstance['default'];
|
|
26
|
+
collectedLinks?: string[];
|
|
27
|
+
collectedStyles?: string[];
|
|
28
|
+
collectedScripts?: string[];
|
|
15
29
|
props: Record<string, any>;
|
|
16
30
|
children: TreeNode[];
|
|
17
31
|
}
|
|
@@ -25,6 +39,7 @@ export type TreeNode =
|
|
|
25
39
|
export const ComponentNode = createComponent({
|
|
26
40
|
factory(result: any, { treeNode }: { treeNode: TreeNode }) {
|
|
27
41
|
if (treeNode.type === 'text') return render`${treeNode.content}`;
|
|
42
|
+
|
|
28
43
|
const slots = {
|
|
29
44
|
default: () =>
|
|
30
45
|
render`${treeNode.children.map((child) =>
|
|
@@ -32,37 +47,86 @@ export const ComponentNode = createComponent({
|
|
|
32
47
|
)}`,
|
|
33
48
|
};
|
|
34
49
|
if (treeNode.type === 'component') {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
treeNode.
|
|
40
|
-
|
|
50
|
+
let styles = '',
|
|
51
|
+
links = '',
|
|
52
|
+
scripts = '';
|
|
53
|
+
if (Array.isArray(treeNode.collectedStyles)) {
|
|
54
|
+
styles = treeNode.collectedStyles
|
|
55
|
+
.map((style: any) =>
|
|
56
|
+
renderUniqueStylesheet(result, {
|
|
57
|
+
type: 'inline',
|
|
58
|
+
content: style,
|
|
59
|
+
})
|
|
60
|
+
)
|
|
61
|
+
.join('');
|
|
62
|
+
}
|
|
63
|
+
if (Array.isArray(treeNode.collectedLinks)) {
|
|
64
|
+
links = treeNode.collectedLinks
|
|
65
|
+
.map((link: any) => {
|
|
66
|
+
return renderUniqueStylesheet(result, {
|
|
67
|
+
type: 'external',
|
|
68
|
+
src: link[0] === '/' ? link : '/' + link,
|
|
69
|
+
});
|
|
70
|
+
})
|
|
71
|
+
.join('');
|
|
72
|
+
}
|
|
73
|
+
if (Array.isArray(treeNode.collectedScripts)) {
|
|
74
|
+
scripts = treeNode.collectedScripts
|
|
75
|
+
.map((script: any) => renderScriptElement(script))
|
|
76
|
+
.join('');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const head = unescapeHTML(styles + links + scripts);
|
|
80
|
+
|
|
81
|
+
let headAndContent = createHeadAndContent(
|
|
82
|
+
head,
|
|
83
|
+
renderTemplate`${renderComponent(
|
|
84
|
+
result,
|
|
85
|
+
treeNode.component.name,
|
|
86
|
+
treeNode.component,
|
|
87
|
+
treeNode.props,
|
|
88
|
+
slots
|
|
89
|
+
)}`
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
// Let the runtime know that this component is being used.
|
|
93
|
+
result.propagators.set(
|
|
94
|
+
{},
|
|
95
|
+
{
|
|
96
|
+
init() {
|
|
97
|
+
return headAndContent;
|
|
98
|
+
},
|
|
99
|
+
}
|
|
41
100
|
);
|
|
101
|
+
|
|
102
|
+
return headAndContent;
|
|
42
103
|
}
|
|
43
104
|
return renderComponent(result, treeNode.tag, treeNode.tag, treeNode.attributes, slots);
|
|
44
105
|
},
|
|
45
|
-
propagation: '
|
|
106
|
+
propagation: 'self',
|
|
46
107
|
});
|
|
47
108
|
|
|
48
|
-
export function createTreeNode(node: RenderableTreeNode | RenderableTreeNode[]): TreeNode {
|
|
49
|
-
if (
|
|
109
|
+
export async function createTreeNode(node: RenderableTreeNode | RenderableTreeNode[]): TreeNode {
|
|
110
|
+
if (isHTMLString(node)) {
|
|
111
|
+
return { type: 'text', content: node as HTMLString };
|
|
112
|
+
} else if (typeof node === 'string' || typeof node === 'number') {
|
|
50
113
|
return { type: 'text', content: String(node) };
|
|
51
114
|
} else if (Array.isArray(node)) {
|
|
52
115
|
return {
|
|
53
116
|
type: 'component',
|
|
54
117
|
component: Fragment,
|
|
55
118
|
props: {},
|
|
56
|
-
children: node.map((child) => createTreeNode(child)),
|
|
119
|
+
children: await Promise.all(node.map((child) => createTreeNode(child))),
|
|
57
120
|
};
|
|
58
121
|
} else if (node === null || typeof node !== 'object' || !Markdoc.Tag.isTag(node)) {
|
|
59
122
|
return { type: 'text', content: '' };
|
|
60
123
|
}
|
|
61
124
|
|
|
125
|
+
const children = await Promise.all(node.children.map((child) => createTreeNode(child)));
|
|
126
|
+
|
|
62
127
|
if (typeof node.name === 'function') {
|
|
63
128
|
const component = node.name;
|
|
64
129
|
const props = node.attributes;
|
|
65
|
-
const children = node.children.map((child) => createTreeNode(child));
|
|
66
130
|
|
|
67
131
|
return {
|
|
68
132
|
type: 'component',
|
|
@@ -70,12 +134,38 @@ export function createTreeNode(node: RenderableTreeNode | RenderableTreeNode[]):
|
|
|
70
134
|
props,
|
|
71
135
|
children,
|
|
72
136
|
};
|
|
137
|
+
} else if (isPropagatedAssetsModule(node.name)) {
|
|
138
|
+
const { collectedStyles, collectedLinks, collectedScripts } = node.name;
|
|
139
|
+
const component = (await node.name.getMod())?.default ?? Fragment;
|
|
140
|
+
const props = node.attributes;
|
|
141
|
+
|
|
142
|
+
return {
|
|
143
|
+
type: 'component',
|
|
144
|
+
component,
|
|
145
|
+
collectedStyles,
|
|
146
|
+
collectedLinks,
|
|
147
|
+
collectedScripts,
|
|
148
|
+
props,
|
|
149
|
+
children,
|
|
150
|
+
};
|
|
73
151
|
} else {
|
|
74
152
|
return {
|
|
75
153
|
type: 'element',
|
|
76
154
|
tag: node.name,
|
|
77
155
|
attributes: node.attributes,
|
|
78
|
-
children
|
|
156
|
+
children,
|
|
79
157
|
};
|
|
80
158
|
}
|
|
81
159
|
}
|
|
160
|
+
|
|
161
|
+
type PropagatedAssetsModule = {
|
|
162
|
+
__astroPropagation: true;
|
|
163
|
+
getMod: () => Promise<AstroInstance['default']>;
|
|
164
|
+
collectedStyles: string[];
|
|
165
|
+
collectedLinks: string[];
|
|
166
|
+
collectedScripts: string[];
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
function isPropagatedAssetsModule(module: any): module is PropagatedAssetsModule {
|
|
170
|
+
return typeof module === 'object' && module != null && '__astroPropagation' in module;
|
|
171
|
+
}
|
package/dist/config.d.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import type { ConfigType as MarkdocConfig } from '@markdoc/markdoc';
|
|
2
2
|
import _Markdoc from '@markdoc/markdoc';
|
|
3
|
+
export type AstroMarkdocConfig<C extends Record<string, any> = Record<string, any>> = MarkdocConfig & {
|
|
4
|
+
ctx?: C;
|
|
5
|
+
extends?: ResolvedAstroMarkdocConfig[];
|
|
6
|
+
};
|
|
7
|
+
export type ResolvedAstroMarkdocConfig = Omit<AstroMarkdocConfig, 'extends'>;
|
|
3
8
|
export declare const Markdoc: typeof _Markdoc;
|
|
4
9
|
export declare const nodes: {
|
|
5
10
|
heading: import("@markdoc/markdoc").Schema;
|
|
@@ -37,4 +42,4 @@ export declare const nodes: {
|
|
|
37
42
|
error: {};
|
|
38
43
|
node: {};
|
|
39
44
|
};
|
|
40
|
-
export declare function defineMarkdocConfig(config:
|
|
45
|
+
export declare function defineMarkdocConfig(config: AstroMarkdocConfig): AstroMarkdocConfig;
|
package/dist/config.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import _Markdoc from "@markdoc/markdoc";
|
|
2
|
-
import {
|
|
2
|
+
import { heading } from "./heading-ids.js";
|
|
3
3
|
const Markdoc = _Markdoc;
|
|
4
|
-
const nodes = { ...Markdoc.nodes,
|
|
4
|
+
const nodes = { ...Markdoc.nodes, heading };
|
|
5
5
|
function defineMarkdocConfig(config) {
|
|
6
6
|
return config;
|
|
7
7
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { unescapeHTML } from "astro/runtime/server/index.js";
|
|
2
|
+
import { runHighlighterWithAstro } from "@astrojs/prism/dist/highlighter";
|
|
3
|
+
import { Markdoc } from "../config.js";
|
|
4
|
+
function prism() {
|
|
5
|
+
return {
|
|
6
|
+
nodes: {
|
|
7
|
+
fence: {
|
|
8
|
+
attributes: Markdoc.nodes.fence.attributes,
|
|
9
|
+
transform({ attributes: { language, content } }) {
|
|
10
|
+
const { html, classLanguage } = runHighlighterWithAstro(language, content);
|
|
11
|
+
return unescapeHTML(
|
|
12
|
+
`<pre class="${classLanguage}"><code class="${classLanguage}">${html}</code></pre>`
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export {
|
|
20
|
+
prism as default
|
|
21
|
+
};
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { unescapeHTML } from "astro/runtime/server/index.js";
|
|
2
|
+
import Markdoc from "@markdoc/markdoc";
|
|
3
|
+
import { getHighlighter } from "shiki";
|
|
4
|
+
const compatThemes = {
|
|
5
|
+
"material-darker": "material-theme-darker",
|
|
6
|
+
"material-default": "material-theme",
|
|
7
|
+
"material-lighter": "material-theme-lighter",
|
|
8
|
+
"material-ocean": "material-theme-ocean",
|
|
9
|
+
"material-palenight": "material-theme-palenight"
|
|
10
|
+
};
|
|
11
|
+
const normalizeTheme = (theme) => {
|
|
12
|
+
if (typeof theme === "string") {
|
|
13
|
+
return compatThemes[theme] || theme;
|
|
14
|
+
} else if (compatThemes[theme.name]) {
|
|
15
|
+
return { ...theme, name: compatThemes[theme.name] };
|
|
16
|
+
} else {
|
|
17
|
+
return theme;
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
const ASTRO_COLOR_REPLACEMENTS = {
|
|
21
|
+
"#000001": "var(--astro-code-color-text)",
|
|
22
|
+
"#000002": "var(--astro-code-color-background)",
|
|
23
|
+
"#000004": "var(--astro-code-token-constant)",
|
|
24
|
+
"#000005": "var(--astro-code-token-string)",
|
|
25
|
+
"#000006": "var(--astro-code-token-comment)",
|
|
26
|
+
"#000007": "var(--astro-code-token-keyword)",
|
|
27
|
+
"#000008": "var(--astro-code-token-parameter)",
|
|
28
|
+
"#000009": "var(--astro-code-token-function)",
|
|
29
|
+
"#000010": "var(--astro-code-token-string-expression)",
|
|
30
|
+
"#000011": "var(--astro-code-token-punctuation)",
|
|
31
|
+
"#000012": "var(--astro-code-token-link)"
|
|
32
|
+
};
|
|
33
|
+
const PRE_SELECTOR = /<pre class="(.*?)shiki(.*?)"/;
|
|
34
|
+
const LINE_SELECTOR = /<span class="line"><span style="(.*?)">([\+|\-])/g;
|
|
35
|
+
const INLINE_STYLE_SELECTOR = /style="(.*?)"/;
|
|
36
|
+
const highlighterCache = /* @__PURE__ */ new Map();
|
|
37
|
+
async function shiki({
|
|
38
|
+
langs = [],
|
|
39
|
+
theme = "github-dark",
|
|
40
|
+
wrap = false
|
|
41
|
+
} = {}) {
|
|
42
|
+
theme = normalizeTheme(theme);
|
|
43
|
+
const cacheID = typeof theme === "string" ? theme : theme.name;
|
|
44
|
+
if (!highlighterCache.has(cacheID)) {
|
|
45
|
+
highlighterCache.set(
|
|
46
|
+
cacheID,
|
|
47
|
+
await getHighlighter({ theme }).then((hl) => {
|
|
48
|
+
hl.setColorReplacements(ASTRO_COLOR_REPLACEMENTS);
|
|
49
|
+
return hl;
|
|
50
|
+
})
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
const highlighter = highlighterCache.get(cacheID);
|
|
54
|
+
for (const lang of langs) {
|
|
55
|
+
await highlighter.loadLanguage(lang);
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
nodes: {
|
|
59
|
+
fence: {
|
|
60
|
+
attributes: Markdoc.nodes.fence.attributes,
|
|
61
|
+
transform({ attributes }) {
|
|
62
|
+
let lang;
|
|
63
|
+
if (typeof attributes.language === "string") {
|
|
64
|
+
const langExists = highlighter.getLoadedLanguages().includes(attributes.language);
|
|
65
|
+
if (langExists) {
|
|
66
|
+
lang = attributes.language;
|
|
67
|
+
} else {
|
|
68
|
+
console.warn(
|
|
69
|
+
`[Shiki highlighter] The language "${attributes.language}" doesn't exist, falling back to plaintext.`
|
|
70
|
+
);
|
|
71
|
+
lang = "plaintext";
|
|
72
|
+
}
|
|
73
|
+
} else {
|
|
74
|
+
lang = "plaintext";
|
|
75
|
+
}
|
|
76
|
+
let html = highlighter.codeToHtml(attributes.content, { lang });
|
|
77
|
+
html = html.replace(PRE_SELECTOR, `<pre class="$1astro-code$2"`);
|
|
78
|
+
if (attributes.language === "diff") {
|
|
79
|
+
html = html.replace(
|
|
80
|
+
LINE_SELECTOR,
|
|
81
|
+
'<span class="line"><span style="$1"><span style="user-select: none;">$2</span>'
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
if (wrap === false) {
|
|
85
|
+
html = html.replace(INLINE_STYLE_SELECTOR, 'style="$1; overflow-x: auto;"');
|
|
86
|
+
} else if (wrap === true) {
|
|
87
|
+
html = html.replace(
|
|
88
|
+
INLINE_STYLE_SELECTOR,
|
|
89
|
+
'style="$1; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;"'
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
return unescapeHTML(html);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
export {
|
|
99
|
+
shiki as default
|
|
100
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type Schema } from '@markdoc/markdoc';
|
|
2
|
+
import Slugger from 'github-slugger';
|
|
3
|
+
import type { AstroMarkdocConfig } from './config.js';
|
|
4
|
+
type HeadingIdConfig = AstroMarkdocConfig<{
|
|
5
|
+
headingSlugger: Slugger;
|
|
6
|
+
}>;
|
|
7
|
+
export declare const heading: Schema;
|
|
8
|
+
export declare function setupHeadingConfig(): HeadingIdConfig;
|
|
9
|
+
export {};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import Markdoc from "@markdoc/markdoc";
|
|
2
2
|
import Slugger from "github-slugger";
|
|
3
|
-
import { getTextContent } from "
|
|
3
|
+
import { getTextContent } from "./runtime.js";
|
|
4
|
+
import { MarkdocError } from "./utils.js";
|
|
4
5
|
function getSlug(attributes, children, headingSlugger) {
|
|
5
6
|
if (attributes.id && typeof attributes.id === "string") {
|
|
6
7
|
return attributes.id;
|
|
@@ -18,16 +19,21 @@ const heading = {
|
|
|
18
19
|
level: { type: Number, required: true, default: 1 }
|
|
19
20
|
},
|
|
20
21
|
transform(node, config) {
|
|
21
|
-
var _a, _b;
|
|
22
|
+
var _a, _b, _c;
|
|
22
23
|
const { level, ...attributes } = node.transformAttributes(config);
|
|
23
24
|
const children = node.transformChildren(config);
|
|
25
|
+
if (!((_a = config.ctx) == null ? void 0 : _a.headingSlugger)) {
|
|
26
|
+
throw new MarkdocError({
|
|
27
|
+
message: "Unexpected problem adding heading IDs to Markdoc file. Did you modify the `ctx.headingSlugger` property in your Markdoc config?"
|
|
28
|
+
});
|
|
29
|
+
}
|
|
24
30
|
const slug = getSlug(attributes, children, config.ctx.headingSlugger);
|
|
25
|
-
const render = ((
|
|
31
|
+
const render = ((_c = (_b = config.nodes) == null ? void 0 : _b.heading) == null ? void 0 : _c.render) ?? `h${level}`;
|
|
26
32
|
const tagProps = (
|
|
27
33
|
// For components, pass down `level` as a prop,
|
|
28
34
|
// alongside `__collectHeading` for our `headings` collector.
|
|
29
35
|
// Avoid accidentally rendering `level` as an HTML attribute otherwise!
|
|
30
|
-
typeof render === "
|
|
36
|
+
typeof render === "string" ? { ...attributes, id: slug } : { ...attributes, id: slug, __collectHeading: true, level }
|
|
31
37
|
);
|
|
32
38
|
return new Markdoc.Tag(render, tagProps, children);
|
|
33
39
|
}
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,26 @@
|
|
|
1
1
|
import Markdoc from "@markdoc/markdoc";
|
|
2
2
|
import fs from "node:fs";
|
|
3
3
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
createNameHash,
|
|
6
|
+
hasContentFlag,
|
|
7
|
+
isValidUrl,
|
|
8
|
+
MarkdocError,
|
|
9
|
+
parseFrontmatter,
|
|
10
|
+
prependForwardSlash,
|
|
11
|
+
PROPAGATED_ASSET_FLAG
|
|
12
|
+
} from "./utils.js";
|
|
5
13
|
import { emitESMImage } from "astro/assets";
|
|
6
14
|
import { bold, red, yellow } from "kleur/colors";
|
|
15
|
+
import path from "node:path";
|
|
16
|
+
import { normalizePath } from "vite";
|
|
7
17
|
import { loadMarkdocConfig } from "./load-config.js";
|
|
8
18
|
import { setupConfig } from "./runtime.js";
|
|
19
|
+
const markdocTokenizer = new Markdoc.Tokenizer({
|
|
20
|
+
// Strip <!-- comments --> from rendered output
|
|
21
|
+
// Without this, they're rendered as strings!
|
|
22
|
+
allowComments: true
|
|
23
|
+
});
|
|
9
24
|
function markdocIntegration(legacyConfig) {
|
|
10
25
|
if (legacyConfig) {
|
|
11
26
|
console.log(
|
|
@@ -16,12 +31,20 @@ function markdocIntegration(legacyConfig) {
|
|
|
16
31
|
process.exit(0);
|
|
17
32
|
}
|
|
18
33
|
let markdocConfigResult;
|
|
34
|
+
let markdocConfigResultId = "";
|
|
19
35
|
return {
|
|
20
36
|
name: "@astrojs/markdoc",
|
|
21
37
|
hooks: {
|
|
22
38
|
"astro:config:setup": async (params) => {
|
|
23
|
-
const {
|
|
39
|
+
const {
|
|
40
|
+
config: astroConfig,
|
|
41
|
+
updateConfig,
|
|
42
|
+
addContentEntryType
|
|
43
|
+
} = params;
|
|
24
44
|
markdocConfigResult = await loadMarkdocConfig(astroConfig);
|
|
45
|
+
if (markdocConfigResult) {
|
|
46
|
+
markdocConfigResultId = normalizePath(fileURLToPath(markdocConfigResult.fileUrl));
|
|
47
|
+
}
|
|
25
48
|
const userMarkdocConfig = (markdocConfigResult == null ? void 0 : markdocConfigResult.config) ?? {};
|
|
26
49
|
function getEntryInfo({ fileUrl, contents }) {
|
|
27
50
|
const parsed = parseFrontmatter(contents, fileURLToPath(fileUrl));
|
|
@@ -35,10 +58,16 @@ function markdocIntegration(legacyConfig) {
|
|
|
35
58
|
addContentEntryType({
|
|
36
59
|
extensions: [".mdoc"],
|
|
37
60
|
getEntryInfo,
|
|
38
|
-
|
|
39
|
-
|
|
61
|
+
// Markdoc handles script / style propagation
|
|
62
|
+
// for Astro components internally
|
|
63
|
+
handlePropagation: false,
|
|
64
|
+
async getRenderModule({ contents, fileUrl, viteId }) {
|
|
65
|
+
const entry = getEntryInfo({ contents, fileUrl });
|
|
66
|
+
const tokens = markdocTokenizer.tokenize(entry.body);
|
|
67
|
+
const ast = Markdoc.parse(tokens);
|
|
40
68
|
const pluginContext = this;
|
|
41
|
-
const markdocConfig = setupConfig(userMarkdocConfig
|
|
69
|
+
const markdocConfig = await setupConfig(userMarkdocConfig);
|
|
70
|
+
const filePath = fileURLToPath(fileUrl);
|
|
42
71
|
const validationErrors = Markdoc.validate(ast, markdocConfig).filter((e) => {
|
|
43
72
|
return (
|
|
44
73
|
// Ignore `variable-undefined` errors.
|
|
@@ -48,10 +77,11 @@ function markdocIntegration(legacyConfig) {
|
|
|
48
77
|
);
|
|
49
78
|
});
|
|
50
79
|
if (validationErrors.length) {
|
|
51
|
-
const frontmatterBlockOffset = entry.
|
|
80
|
+
const frontmatterBlockOffset = entry.rawData.split("\n").length + 2;
|
|
81
|
+
const rootRelativePath = path.relative(fileURLToPath(astroConfig.root), filePath);
|
|
52
82
|
throw new MarkdocError({
|
|
53
83
|
message: [
|
|
54
|
-
`**${String(
|
|
84
|
+
`**${String(rootRelativePath)}** contains invalid content:`,
|
|
55
85
|
...validationErrors.map((e) => `- ${e.error.message}`)
|
|
56
86
|
].join("\n"),
|
|
57
87
|
location: {
|
|
@@ -66,15 +96,17 @@ function markdocIntegration(legacyConfig) {
|
|
|
66
96
|
await emitOptimizedImages(ast.children, {
|
|
67
97
|
astroConfig,
|
|
68
98
|
pluginContext,
|
|
69
|
-
filePath
|
|
99
|
+
filePath
|
|
70
100
|
});
|
|
71
101
|
}
|
|
72
|
-
const res = `import {
|
|
102
|
+
const res = `import {
|
|
103
|
+
createComponent,
|
|
104
|
+
renderComponent,
|
|
105
|
+
} from 'astro/runtime/server/index.js';
|
|
73
106
|
import { Renderer } from '@astrojs/markdoc/components';
|
|
74
|
-
import { collectHeadings, setupConfig, Markdoc } from '@astrojs/markdoc/runtime';
|
|
75
|
-
import * as entry from ${JSON.stringify(viteId + "?astroContentCollectionEntry")};
|
|
107
|
+
import { collectHeadings, setupConfig, setupConfigSync, Markdoc } from '@astrojs/markdoc/runtime';
|
|
76
108
|
${markdocConfigResult ? `import _userConfig from ${JSON.stringify(
|
|
77
|
-
|
|
109
|
+
markdocConfigResultId
|
|
78
110
|
)};
|
|
79
111
|
const userConfig = _userConfig ?? {};` : "const userConfig = {};"}${astroConfig.experimental.assets ? `
|
|
80
112
|
import { experimentalAssetsConfig } from '@astrojs/markdoc/experimental-assets-config';
|
|
@@ -89,19 +121,29 @@ export function getHeadings() {
|
|
|
89
121
|
instead of the Content component. Would remove double-transform and unlock variable resolution in heading slugs. */
|
|
90
122
|
""}
|
|
91
123
|
const headingConfig = userConfig.nodes?.heading;
|
|
92
|
-
const config =
|
|
124
|
+
const config = setupConfigSync(headingConfig ? { nodes: { heading: headingConfig } } : {});
|
|
93
125
|
const ast = Markdoc.Ast.fromJSON(stringifiedAst);
|
|
94
126
|
const content = Markdoc.transform(ast, config);
|
|
95
127
|
return collectHeadings(Array.isArray(content) ? content : content.children);
|
|
96
128
|
}
|
|
97
|
-
export async function Content (props) {
|
|
98
|
-
const config = setupConfig({
|
|
99
|
-
...userConfig,
|
|
100
|
-
variables: { ...userConfig.variables, ...props },
|
|
101
|
-
}, entry);
|
|
102
129
|
|
|
103
|
-
|
|
104
|
-
|
|
130
|
+
export const Content = createComponent({
|
|
131
|
+
async factory(result, props) {
|
|
132
|
+
const config = await setupConfig({
|
|
133
|
+
...userConfig,
|
|
134
|
+
variables: { ...userConfig.variables, ...props },
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
return renderComponent(
|
|
138
|
+
result,
|
|
139
|
+
Renderer.name,
|
|
140
|
+
Renderer,
|
|
141
|
+
{ stringifiedAst, config },
|
|
142
|
+
{}
|
|
143
|
+
);
|
|
144
|
+
},
|
|
145
|
+
propagation: 'self',
|
|
146
|
+
});`;
|
|
105
147
|
return { code: res };
|
|
106
148
|
},
|
|
107
149
|
contentModuleTypes: await fs.promises.readFile(
|
|
@@ -109,10 +151,53 @@ export async function Content (props) {
|
|
|
109
151
|
"utf-8"
|
|
110
152
|
)
|
|
111
153
|
});
|
|
154
|
+
let rollupOptions = {};
|
|
155
|
+
if (markdocConfigResult) {
|
|
156
|
+
rollupOptions = {
|
|
157
|
+
output: {
|
|
158
|
+
// Split Astro components from your `markdoc.config`
|
|
159
|
+
// to only inject component styles and scripts at runtime.
|
|
160
|
+
manualChunks(id, { getModuleInfo }) {
|
|
161
|
+
var _a, _b;
|
|
162
|
+
if (markdocConfigResult && hasContentFlag(id, PROPAGATED_ASSET_FLAG) && ((_b = (_a = getModuleInfo(id)) == null ? void 0 : _a.importers) == null ? void 0 : _b.includes(markdocConfigResultId))) {
|
|
163
|
+
return createNameHash(id, [id]);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
updateConfig({
|
|
170
|
+
vite: {
|
|
171
|
+
vite: {
|
|
172
|
+
ssr: {
|
|
173
|
+
external: ["@astrojs/markdoc/prism", "@astrojs/markdoc/shiki"]
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
build: {
|
|
177
|
+
rollupOptions
|
|
178
|
+
},
|
|
179
|
+
plugins: [
|
|
180
|
+
{
|
|
181
|
+
name: "@astrojs/markdoc:astro-propagated-assets",
|
|
182
|
+
enforce: "pre",
|
|
183
|
+
// Astro component styles and scripts should only be injected
|
|
184
|
+
// When a given Markdoc file actually uses that component.
|
|
185
|
+
// Add the `astroPropagatedAssets` flag to inject only when rendered.
|
|
186
|
+
resolveId(id, importer) {
|
|
187
|
+
if (importer === markdocConfigResultId && id.endsWith(".astro")) {
|
|
188
|
+
return this.resolve(id + "?astroPropagatedAssets", importer, {
|
|
189
|
+
skipSelf: true
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
]
|
|
195
|
+
}
|
|
196
|
+
});
|
|
112
197
|
},
|
|
113
198
|
"astro:server:setup": async ({ server }) => {
|
|
114
199
|
server.watcher.on("all", (event, entry) => {
|
|
115
|
-
if (pathToFileURL(entry).pathname ===
|
|
200
|
+
if (prependForwardSlash(pathToFileURL(entry).pathname) === markdocConfigResultId) {
|
|
116
201
|
console.log(
|
|
117
202
|
yellow(
|
|
118
203
|
`${bold("[Markdoc]")} Restart the dev server for config changes to take effect.`
|
package/dist/runtime.d.ts
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import type { MarkdownHeading } from '@astrojs/markdown-remark';
|
|
2
|
-
import { type
|
|
3
|
-
import type {
|
|
2
|
+
import { type RenderableTreeNode } from '@markdoc/markdoc';
|
|
3
|
+
import type { AstroMarkdocConfig } from './config.js';
|
|
4
4
|
/** Used to call `Markdoc.transform()` and `Markdoc.Ast` in runtime modules */
|
|
5
5
|
export { default as Markdoc } from '@markdoc/markdoc';
|
|
6
6
|
/**
|
|
7
7
|
* Merge user config with default config and set up context (ex. heading ID slugger)
|
|
8
|
-
* Called on each file's individual transform
|
|
8
|
+
* Called on each file's individual transform.
|
|
9
|
+
* TODO: virtual module to merge configs per-build instead of per-file?
|
|
9
10
|
*/
|
|
10
|
-
export declare function setupConfig(userConfig:
|
|
11
|
+
export declare function setupConfig(userConfig: AstroMarkdocConfig): Promise<Omit<AstroMarkdocConfig, 'extends'>>;
|
|
12
|
+
/** Used for synchronous `getHeadings()` function */
|
|
13
|
+
export declare function setupConfigSync(userConfig: AstroMarkdocConfig): Omit<AstroMarkdocConfig, 'extends'>;
|
|
11
14
|
/**
|
|
12
15
|
* Get text content as a string from a Markdoc transform AST
|
|
13
16
|
*/
|
package/dist/runtime.js
CHANGED
|
@@ -1,18 +1,30 @@
|
|
|
1
1
|
import Markdoc from "@markdoc/markdoc";
|
|
2
|
-
import { setupHeadingConfig } from "./
|
|
2
|
+
import { setupHeadingConfig } from "./heading-ids.js";
|
|
3
3
|
import { default as default2 } from "@markdoc/markdoc";
|
|
4
|
-
function setupConfig(userConfig
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
async function setupConfig(userConfig) {
|
|
5
|
+
let defaultConfig = setupHeadingConfig();
|
|
6
|
+
if (userConfig.extends) {
|
|
7
|
+
for (let extension of userConfig.extends) {
|
|
8
|
+
if (extension instanceof Promise) {
|
|
9
|
+
extension = await extension;
|
|
10
|
+
}
|
|
11
|
+
defaultConfig = mergeConfig(defaultConfig, extension);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
return mergeConfig(defaultConfig, userConfig);
|
|
15
|
+
}
|
|
16
|
+
function setupConfigSync(userConfig) {
|
|
17
|
+
const defaultConfig = setupHeadingConfig();
|
|
10
18
|
return mergeConfig(defaultConfig, userConfig);
|
|
11
19
|
}
|
|
12
20
|
function mergeConfig(configA, configB) {
|
|
13
21
|
return {
|
|
14
22
|
...configA,
|
|
15
23
|
...configB,
|
|
24
|
+
ctx: {
|
|
25
|
+
...configA.ctx,
|
|
26
|
+
...configB.ctx
|
|
27
|
+
},
|
|
16
28
|
tags: {
|
|
17
29
|
...configA.tags,
|
|
18
30
|
...configB.tags
|
|
@@ -73,5 +85,6 @@ export {
|
|
|
73
85
|
default2 as Markdoc,
|
|
74
86
|
collectHeadings,
|
|
75
87
|
getTextContent,
|
|
76
|
-
setupConfig
|
|
88
|
+
setupConfig,
|
|
89
|
+
setupConfigSync
|
|
77
90
|
};
|
package/dist/utils.d.ts
CHANGED
|
@@ -37,4 +37,18 @@ interface ErrorProperties {
|
|
|
37
37
|
*/
|
|
38
38
|
export declare function prependForwardSlash(str: string): string;
|
|
39
39
|
export declare function isValidUrl(str: string): boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Identifies Astro components with propagated assets
|
|
42
|
+
* @see 'packages/astro/src/content/consts.ts'
|
|
43
|
+
*/
|
|
44
|
+
export declare const PROPAGATED_ASSET_FLAG = "astroPropagatedAssets";
|
|
45
|
+
/**
|
|
46
|
+
* @see 'packages/astro/src/content/utils.ts'
|
|
47
|
+
*/
|
|
48
|
+
export declare function hasContentFlag(viteId: string, flag: string): boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Create build hash for manual Rollup chunks.
|
|
51
|
+
* @see 'packages/astro/src/core/build/plugins/plugin-css.ts'
|
|
52
|
+
*/
|
|
53
|
+
export declare function createNameHash(baseId: string, hashIds: string[]): string;
|
|
40
54
|
export {};
|
package/dist/utils.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import matter from "gray-matter";
|
|
2
|
+
import crypto from "node:crypto";
|
|
3
|
+
import path from "node:path";
|
|
2
4
|
function parseFrontmatter(fileContents, filePath) {
|
|
3
5
|
try {
|
|
4
6
|
matter.clearCache();
|
|
@@ -52,8 +54,26 @@ function isValidUrl(str) {
|
|
|
52
54
|
return false;
|
|
53
55
|
}
|
|
54
56
|
}
|
|
57
|
+
const PROPAGATED_ASSET_FLAG = "astroPropagatedAssets";
|
|
58
|
+
function hasContentFlag(viteId, flag) {
|
|
59
|
+
const flags = new URLSearchParams(viteId.split("?")[1] ?? "");
|
|
60
|
+
return flags.has(flag);
|
|
61
|
+
}
|
|
62
|
+
function createNameHash(baseId, hashIds) {
|
|
63
|
+
const baseName = baseId ? path.parse(baseId).name : "index";
|
|
64
|
+
const hash = crypto.createHash("sha256");
|
|
65
|
+
for (const id of hashIds) {
|
|
66
|
+
hash.update(id, "utf-8");
|
|
67
|
+
}
|
|
68
|
+
const h = hash.digest("hex").slice(0, 8);
|
|
69
|
+
const proposedName = baseName + "." + h;
|
|
70
|
+
return proposedName;
|
|
71
|
+
}
|
|
55
72
|
export {
|
|
56
73
|
MarkdocError,
|
|
74
|
+
PROPAGATED_ASSET_FLAG,
|
|
75
|
+
createNameHash,
|
|
76
|
+
hasContentFlag,
|
|
57
77
|
isValidUrl,
|
|
58
78
|
parseFrontmatter,
|
|
59
79
|
prependForwardSlash
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astrojs/markdoc",
|
|
3
|
-
"description": "Add support for Markdoc
|
|
4
|
-
"version": "0.
|
|
3
|
+
"description": "Add support for Markdoc in your Astro site",
|
|
4
|
+
"version": "0.3.1",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
7
7
|
"author": "withastro",
|
|
@@ -19,6 +19,8 @@
|
|
|
19
19
|
"bugs": "https://github.com/withastro/astro/issues",
|
|
20
20
|
"homepage": "https://docs.astro.build/en/guides/integrations-guide/markdoc/",
|
|
21
21
|
"exports": {
|
|
22
|
+
"./prism": "./dist/extensions/prism.js",
|
|
23
|
+
"./shiki": "./dist/extensions/shiki.js",
|
|
22
24
|
".": "./dist/index.js",
|
|
23
25
|
"./components": "./components/index.ts",
|
|
24
26
|
"./runtime": "./dist/runtime.js",
|
|
@@ -32,7 +34,9 @@
|
|
|
32
34
|
"template"
|
|
33
35
|
],
|
|
34
36
|
"dependencies": {
|
|
35
|
-
"
|
|
37
|
+
"shiki": "^0.14.1",
|
|
38
|
+
"@astrojs/prism": "^2.1.2",
|
|
39
|
+
"@markdoc/markdoc": "^0.3.0",
|
|
36
40
|
"esbuild": "^0.17.12",
|
|
37
41
|
"github-slugger": "^2.0.0",
|
|
38
42
|
"gray-matter": "^4.0.3",
|
|
@@ -40,7 +44,7 @@
|
|
|
40
44
|
"zod": "^3.17.3"
|
|
41
45
|
},
|
|
42
46
|
"peerDependencies": {
|
|
43
|
-
"astro": "^2.5.
|
|
47
|
+
"astro": "^2.5.7"
|
|
44
48
|
},
|
|
45
49
|
"devDependencies": {
|
|
46
50
|
"@astrojs/markdown-remark": "^2.2.1",
|
|
@@ -53,7 +57,7 @@
|
|
|
53
57
|
"mocha": "^9.2.2",
|
|
54
58
|
"rollup": "^3.20.1",
|
|
55
59
|
"vite": "^4.3.1",
|
|
56
|
-
"astro": "2.5.
|
|
60
|
+
"astro": "2.5.7",
|
|
57
61
|
"astro-scripts": "0.0.14"
|
|
58
62
|
},
|
|
59
63
|
"engines": {
|
package/dist/nodes/heading.d.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { type ConfigType, type Schema } from '@markdoc/markdoc';
|
|
2
|
-
import Slugger from 'github-slugger';
|
|
3
|
-
type ConfigTypeWithCtx = ConfigType & {
|
|
4
|
-
ctx: {
|
|
5
|
-
headingSlugger: Slugger;
|
|
6
|
-
};
|
|
7
|
-
};
|
|
8
|
-
export declare const heading: Schema;
|
|
9
|
-
export declare function setupHeadingConfig(): ConfigTypeWithCtx;
|
|
10
|
-
export {};
|
package/dist/nodes/index.d.ts
DELETED