@astrojs/markdoc 0.2.1 → 0.2.2
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/components/Renderer.astro +2 -1
- package/components/TreeNode.ts +98 -12
- package/dist/index.js +49 -9
- package/dist/nodes/heading.js +1 -1
- package/package.json +3 -3
|
@@ -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,7 +2,16 @@ 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
|
+
} from 'astro/runtime/server/index.js';
|
|
6
15
|
|
|
7
16
|
export type TreeNode =
|
|
8
17
|
| {
|
|
@@ -12,6 +21,9 @@ export type TreeNode =
|
|
|
12
21
|
| {
|
|
13
22
|
type: 'component';
|
|
14
23
|
component: AstroInstance['default'];
|
|
24
|
+
collectedLinks?: string[];
|
|
25
|
+
collectedStyles?: string[];
|
|
26
|
+
collectedScripts?: string[];
|
|
15
27
|
props: Record<string, any>;
|
|
16
28
|
children: TreeNode[];
|
|
17
29
|
}
|
|
@@ -32,20 +44,67 @@ export const ComponentNode = createComponent({
|
|
|
32
44
|
)}`,
|
|
33
45
|
};
|
|
34
46
|
if (treeNode.type === 'component') {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
treeNode.
|
|
40
|
-
|
|
47
|
+
let styles = '',
|
|
48
|
+
links = '',
|
|
49
|
+
scripts = '';
|
|
50
|
+
if (Array.isArray(treeNode.collectedStyles)) {
|
|
51
|
+
styles = treeNode.collectedStyles
|
|
52
|
+
.map((style: any) =>
|
|
53
|
+
renderUniqueStylesheet({
|
|
54
|
+
type: 'inline',
|
|
55
|
+
content: style,
|
|
56
|
+
})
|
|
57
|
+
)
|
|
58
|
+
.join('');
|
|
59
|
+
}
|
|
60
|
+
if (Array.isArray(treeNode.collectedLinks)) {
|
|
61
|
+
links = treeNode.collectedLinks
|
|
62
|
+
.map((link: any) => {
|
|
63
|
+
return renderUniqueStylesheet(result, {
|
|
64
|
+
href: link[0] === '/' ? link : '/' + link,
|
|
65
|
+
});
|
|
66
|
+
})
|
|
67
|
+
.join('');
|
|
68
|
+
}
|
|
69
|
+
if (Array.isArray(treeNode.collectedScripts)) {
|
|
70
|
+
scripts = treeNode.collectedScripts
|
|
71
|
+
.map((script: any) => renderScriptElement(script))
|
|
72
|
+
.join('');
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const head = unescapeHTML(styles + links + scripts);
|
|
76
|
+
|
|
77
|
+
let headAndContent = createHeadAndContent(
|
|
78
|
+
head,
|
|
79
|
+
renderTemplate`${renderComponent(
|
|
80
|
+
result,
|
|
81
|
+
treeNode.component.name,
|
|
82
|
+
treeNode.component,
|
|
83
|
+
treeNode.props,
|
|
84
|
+
slots
|
|
85
|
+
)}`
|
|
41
86
|
);
|
|
87
|
+
|
|
88
|
+
// Let the runtime know that this component is being used.
|
|
89
|
+
result.propagators.set(
|
|
90
|
+
{},
|
|
91
|
+
{
|
|
92
|
+
init() {
|
|
93
|
+
return headAndContent;
|
|
94
|
+
},
|
|
95
|
+
}
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
return headAndContent;
|
|
42
99
|
}
|
|
43
100
|
return renderComponent(result, treeNode.tag, treeNode.tag, treeNode.attributes, slots);
|
|
44
101
|
},
|
|
45
|
-
propagation: '
|
|
102
|
+
propagation: 'self',
|
|
46
103
|
});
|
|
47
104
|
|
|
48
|
-
export function createTreeNode(
|
|
105
|
+
export async function createTreeNode(
|
|
106
|
+
node: RenderableTreeNode | RenderableTreeNode[]
|
|
107
|
+
): Promise<TreeNode> {
|
|
49
108
|
if (typeof node === 'string' || typeof node === 'number') {
|
|
50
109
|
return { type: 'text', content: String(node) };
|
|
51
110
|
} else if (Array.isArray(node)) {
|
|
@@ -53,16 +112,17 @@ export function createTreeNode(node: RenderableTreeNode | RenderableTreeNode[]):
|
|
|
53
112
|
type: 'component',
|
|
54
113
|
component: Fragment,
|
|
55
114
|
props: {},
|
|
56
|
-
children: node.map((child) => createTreeNode(child)),
|
|
115
|
+
children: await Promise.all(node.map((child) => createTreeNode(child))),
|
|
57
116
|
};
|
|
58
117
|
} else if (node === null || typeof node !== 'object' || !Markdoc.Tag.isTag(node)) {
|
|
59
118
|
return { type: 'text', content: '' };
|
|
60
119
|
}
|
|
61
120
|
|
|
121
|
+
const children = await Promise.all(node.children.map((child) => createTreeNode(child)));
|
|
122
|
+
|
|
62
123
|
if (typeof node.name === 'function') {
|
|
63
124
|
const component = node.name;
|
|
64
125
|
const props = node.attributes;
|
|
65
|
-
const children = node.children.map((child) => createTreeNode(child));
|
|
66
126
|
|
|
67
127
|
return {
|
|
68
128
|
type: 'component',
|
|
@@ -70,12 +130,38 @@ export function createTreeNode(node: RenderableTreeNode | RenderableTreeNode[]):
|
|
|
70
130
|
props,
|
|
71
131
|
children,
|
|
72
132
|
};
|
|
133
|
+
} else if (isPropagatedAssetsModule(node.name)) {
|
|
134
|
+
const { collectedStyles, collectedLinks, collectedScripts } = node.name;
|
|
135
|
+
const component = (await node.name.getMod())?.default ?? Fragment;
|
|
136
|
+
const props = node.attributes;
|
|
137
|
+
|
|
138
|
+
return {
|
|
139
|
+
type: 'component',
|
|
140
|
+
component,
|
|
141
|
+
collectedStyles,
|
|
142
|
+
collectedLinks,
|
|
143
|
+
collectedScripts,
|
|
144
|
+
props,
|
|
145
|
+
children,
|
|
146
|
+
};
|
|
73
147
|
} else {
|
|
74
148
|
return {
|
|
75
149
|
type: 'element',
|
|
76
150
|
tag: node.name,
|
|
77
151
|
attributes: node.attributes,
|
|
78
|
-
children
|
|
152
|
+
children,
|
|
79
153
|
};
|
|
80
154
|
}
|
|
81
155
|
}
|
|
156
|
+
|
|
157
|
+
type PropagatedAssetsModule = {
|
|
158
|
+
__astroPropagation: true;
|
|
159
|
+
getMod: () => Promise<AstroInstance['default']>;
|
|
160
|
+
collectedStyles: string[];
|
|
161
|
+
collectedLinks: string[];
|
|
162
|
+
collectedScripts: string[];
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
function isPropagatedAssetsModule(module: any): module is PropagatedAssetsModule {
|
|
166
|
+
return typeof module === 'object' && module != null && '__astroPropagation' in module;
|
|
167
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -20,7 +20,11 @@ function markdocIntegration(legacyConfig) {
|
|
|
20
20
|
name: "@astrojs/markdoc",
|
|
21
21
|
hooks: {
|
|
22
22
|
"astro:config:setup": async (params) => {
|
|
23
|
-
const {
|
|
23
|
+
const {
|
|
24
|
+
config: astroConfig,
|
|
25
|
+
updateConfig,
|
|
26
|
+
addContentEntryType
|
|
27
|
+
} = params;
|
|
24
28
|
markdocConfigResult = await loadMarkdocConfig(astroConfig);
|
|
25
29
|
const userMarkdocConfig = (markdocConfigResult == null ? void 0 : markdocConfigResult.config) ?? {};
|
|
26
30
|
function getEntryInfo({ fileUrl, contents }) {
|
|
@@ -35,6 +39,9 @@ function markdocIntegration(legacyConfig) {
|
|
|
35
39
|
addContentEntryType({
|
|
36
40
|
extensions: [".mdoc"],
|
|
37
41
|
getEntryInfo,
|
|
42
|
+
// Markdoc handles script / style propagation
|
|
43
|
+
// for Astro components internally
|
|
44
|
+
handlePropagation: false,
|
|
38
45
|
async getRenderModule({ entry, viteId }) {
|
|
39
46
|
const ast = Markdoc.parse(entry.body);
|
|
40
47
|
const pluginContext = this;
|
|
@@ -69,7 +76,10 @@ function markdocIntegration(legacyConfig) {
|
|
|
69
76
|
filePath: entry._internal.filePath
|
|
70
77
|
});
|
|
71
78
|
}
|
|
72
|
-
const res = `import {
|
|
79
|
+
const res = `import {
|
|
80
|
+
createComponent,
|
|
81
|
+
renderComponent,
|
|
82
|
+
} from 'astro/runtime/server/index.js';
|
|
73
83
|
import { Renderer } from '@astrojs/markdoc/components';
|
|
74
84
|
import { collectHeadings, setupConfig, Markdoc } from '@astrojs/markdoc/runtime';
|
|
75
85
|
import * as entry from ${JSON.stringify(viteId + "?astroContentCollectionEntry")};
|
|
@@ -94,14 +104,24 @@ export function getHeadings() {
|
|
|
94
104
|
const content = Markdoc.transform(ast, config);
|
|
95
105
|
return collectHeadings(Array.isArray(content) ? content : content.children);
|
|
96
106
|
}
|
|
97
|
-
export async function Content (props) {
|
|
98
|
-
const config = setupConfig({
|
|
99
|
-
...userConfig,
|
|
100
|
-
variables: { ...userConfig.variables, ...props },
|
|
101
|
-
}, entry);
|
|
102
107
|
|
|
103
|
-
|
|
104
|
-
|
|
108
|
+
export const Content = createComponent({
|
|
109
|
+
factory(result, props) {
|
|
110
|
+
const config = setupConfig({
|
|
111
|
+
...userConfig,
|
|
112
|
+
variables: { ...userConfig.variables, ...props },
|
|
113
|
+
}, entry);
|
|
114
|
+
|
|
115
|
+
return renderComponent(
|
|
116
|
+
result,
|
|
117
|
+
Renderer.name,
|
|
118
|
+
Renderer,
|
|
119
|
+
{ stringifiedAst, config },
|
|
120
|
+
{}
|
|
121
|
+
);
|
|
122
|
+
},
|
|
123
|
+
propagation: 'self',
|
|
124
|
+
});`;
|
|
105
125
|
return { code: res };
|
|
106
126
|
},
|
|
107
127
|
contentModuleTypes: await fs.promises.readFile(
|
|
@@ -109,6 +129,26 @@ export async function Content (props) {
|
|
|
109
129
|
"utf-8"
|
|
110
130
|
)
|
|
111
131
|
});
|
|
132
|
+
updateConfig({
|
|
133
|
+
vite: {
|
|
134
|
+
plugins: [
|
|
135
|
+
{
|
|
136
|
+
name: "@astrojs/markdoc:astro-propagated-assets",
|
|
137
|
+
enforce: "pre",
|
|
138
|
+
// Astro component styles and scripts should only be injected
|
|
139
|
+
// When a given Markdoc file actually uses that component.
|
|
140
|
+
// Add the `astroPropagatedAssets` flag to inject only when rendered.
|
|
141
|
+
resolveId(id, importer) {
|
|
142
|
+
if (importer === (markdocConfigResult == null ? void 0 : markdocConfigResult.fileUrl.pathname) && id.endsWith(".astro")) {
|
|
143
|
+
return this.resolve(id + "?astroPropagatedAssets", importer, {
|
|
144
|
+
skipSelf: true
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
]
|
|
150
|
+
}
|
|
151
|
+
});
|
|
112
152
|
},
|
|
113
153
|
"astro:server:setup": async ({ server }) => {
|
|
114
154
|
server.watcher.on("all", (event, entry) => {
|
package/dist/nodes/heading.js
CHANGED
|
@@ -27,7 +27,7 @@ const heading = {
|
|
|
27
27
|
// For components, pass down `level` as a prop,
|
|
28
28
|
// alongside `__collectHeading` for our `headings` collector.
|
|
29
29
|
// Avoid accidentally rendering `level` as an HTML attribute otherwise!
|
|
30
|
-
typeof render === "
|
|
30
|
+
typeof render === "string" ? { ...attributes, id: slug } : { ...attributes, id: slug, __collectHeading: true, level }
|
|
31
31
|
);
|
|
32
32
|
return new Markdoc.Tag(render, tagProps, children);
|
|
33
33
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astrojs/markdoc",
|
|
3
3
|
"description": "Add support for Markdoc pages in your Astro site",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.2",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
7
7
|
"author": "withastro",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"zod": "^3.17.3"
|
|
41
41
|
},
|
|
42
42
|
"peerDependencies": {
|
|
43
|
-
"astro": "^2.5.
|
|
43
|
+
"astro": "^2.5.3"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@astrojs/markdown-remark": "^2.2.1",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"mocha": "^9.2.2",
|
|
54
54
|
"rollup": "^3.20.1",
|
|
55
55
|
"vite": "^4.3.1",
|
|
56
|
-
"astro": "2.5.
|
|
56
|
+
"astro": "2.5.3",
|
|
57
57
|
"astro-scripts": "0.0.14"
|
|
58
58
|
},
|
|
59
59
|
"engines": {
|