@astrojs/markdoc 0.1.2 → 0.1.3
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/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +9 -0
- package/README.md +6 -8
- package/dist/config.d.ts +1 -0
- package/dist/config.js +2 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +38 -13
- package/dist/load-config.d.ts +5 -12
- package/package.json +3 -3
- package/src/config.ts +1 -0
- package/src/index.ts +42 -18
- package/src/load-config.ts +8 -1
package/.turbo/turbo-build.log
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# @astrojs/markdoc
|
|
2
2
|
|
|
3
|
+
## 0.1.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#7045](https://github.com/withastro/astro/pull/7045) [`3a9f72c7f`](https://github.com/withastro/astro/commit/3a9f72c7f30ed173438fd0a222a094e5997b917d) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Improve Markdoc validation errors with full message and file preview.
|
|
8
|
+
|
|
9
|
+
- Updated dependencies [[`48395c815`](https://github.com/withastro/astro/commit/48395c81522f7527126699c4f185f7b4488a4b9a), [`630f8c8ef`](https://github.com/withastro/astro/commit/630f8c8ef68fedfa393899c13a072e50145895e8)]:
|
|
10
|
+
- astro@2.4.4
|
|
11
|
+
|
|
3
12
|
## 0.1.2
|
|
4
13
|
|
|
5
14
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -143,28 +143,26 @@ Use tags like this fancy "aside" to add some *flair* to your docs.
|
|
|
143
143
|
|
|
144
144
|
#### Render Markdoc nodes / HTML elements as Astro components
|
|
145
145
|
|
|
146
|
-
You may also want to map standard HTML elements like headings and paragraphs to components. For this, you can configure a custom [Markdoc node][markdoc-nodes]. This example overrides Markdoc's `heading` node to render a `Heading` component,
|
|
146
|
+
You may also want to map standard HTML elements like headings and paragraphs to components. For this, you can configure a custom [Markdoc node][markdoc-nodes]. This example overrides Markdoc's `heading` node to render a `Heading` component, and passes through [Markdoc's default attributes for headings](https://markdoc.dev/docs/nodes#built-in-nodes).
|
|
147
147
|
|
|
148
148
|
```js
|
|
149
149
|
// markdoc.config.mjs
|
|
150
|
-
import { defineMarkdocConfig } from '@astrojs/markdoc/config';
|
|
150
|
+
import { defineMarkdocConfig, Markdoc } from '@astrojs/markdoc/config';
|
|
151
151
|
import Heading from './src/components/Heading.astro';
|
|
152
152
|
|
|
153
153
|
export default defineMarkdocConfig({
|
|
154
154
|
nodes: {
|
|
155
155
|
heading: {
|
|
156
156
|
render: Heading,
|
|
157
|
-
attributes:
|
|
158
|
-
// Pass the attributes from Markdoc's default heading node
|
|
159
|
-
// as component props.
|
|
160
|
-
level: { type: String },
|
|
161
|
-
}
|
|
157
|
+
attributes: Markdoc.nodes.heading.attributes,
|
|
162
158
|
},
|
|
163
159
|
},
|
|
164
160
|
})
|
|
165
161
|
```
|
|
166
162
|
|
|
167
|
-
Now, all Markdown headings will render with the `Heading.astro` component
|
|
163
|
+
Now, all Markdown headings will render with the `Heading.astro` component, and pass these `attributes` as component props. For headings, Markdoc provides a `level` attribute containing the numeric heading level.
|
|
164
|
+
|
|
165
|
+
This example uses a level 3 heading, automatically passing `level: 3` as the component prop:
|
|
168
166
|
|
|
169
167
|
```md
|
|
170
168
|
### I'm a level 3 heading!
|
package/dist/config.d.ts
CHANGED
package/dist/config.js
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { AstroIntegration } from 'astro';
|
|
2
|
-
export default function markdocIntegration(legacyConfig
|
|
2
|
+
export default function markdocIntegration(legacyConfig?: any): AstroIntegration;
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import Markdoc from "@markdoc/markdoc";
|
|
2
2
|
import fs from "node:fs";
|
|
3
|
-
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
4
4
|
import { isValidUrl, MarkdocError, parseFrontmatter, prependForwardSlash } from "./utils.js";
|
|
5
5
|
import { emitESMImage } from "astro/assets";
|
|
6
|
-
import { bold, red } from "kleur/colors";
|
|
6
|
+
import { bold, red, yellow } from "kleur/colors";
|
|
7
7
|
import { applyDefaultConfig } from "./default-config.js";
|
|
8
8
|
import { loadMarkdocConfig } from "./load-config.js";
|
|
9
9
|
function markdocIntegration(legacyConfig) {
|
|
@@ -15,13 +15,14 @@ function markdocIntegration(legacyConfig) {
|
|
|
15
15
|
);
|
|
16
16
|
process.exit(0);
|
|
17
17
|
}
|
|
18
|
+
let markdocConfigResult;
|
|
18
19
|
return {
|
|
19
20
|
name: "@astrojs/markdoc",
|
|
20
21
|
hooks: {
|
|
21
22
|
"astro:config:setup": async (params) => {
|
|
22
23
|
const { config: astroConfig, addContentEntryType } = params;
|
|
23
|
-
|
|
24
|
-
const userMarkdocConfig = (
|
|
24
|
+
markdocConfigResult = await loadMarkdocConfig(astroConfig);
|
|
25
|
+
const userMarkdocConfig = (markdocConfigResult == null ? void 0 : markdocConfigResult.config) ?? {};
|
|
25
26
|
function getEntryInfo({ fileUrl, contents }) {
|
|
26
27
|
const parsed = parseFrontmatter(contents, fileURLToPath(fileUrl));
|
|
27
28
|
return {
|
|
@@ -39,14 +40,26 @@ function markdocIntegration(legacyConfig) {
|
|
|
39
40
|
const pluginContext = this;
|
|
40
41
|
const markdocConfig = applyDefaultConfig(userMarkdocConfig, { entry });
|
|
41
42
|
const validationErrors = Markdoc.validate(ast, markdocConfig).filter((e) => {
|
|
42
|
-
return
|
|
43
|
+
return (
|
|
44
|
+
// Ignore `variable-undefined` errors.
|
|
45
|
+
// Variables can be configured at runtime,
|
|
46
|
+
// so we cannot validate them at build time.
|
|
47
|
+
e.error.id !== "variable-undefined" && (e.error.level === "error" || e.error.level === "critical")
|
|
48
|
+
);
|
|
43
49
|
});
|
|
44
50
|
if (validationErrors.length) {
|
|
51
|
+
const frontmatterBlockOffset = entry._internal.rawData.split("\n").length + 2;
|
|
45
52
|
throw new MarkdocError({
|
|
46
53
|
message: [
|
|
47
|
-
`**${String(entry.collection)} \u2192 ${String(entry.id)}**
|
|
48
|
-
...validationErrors.map((e) => e.error.
|
|
49
|
-
].join("\n")
|
|
54
|
+
`**${String(entry.collection)} \u2192 ${String(entry.id)}** contains invalid content:`,
|
|
55
|
+
...validationErrors.map((e) => `- ${e.error.message}`)
|
|
56
|
+
].join("\n"),
|
|
57
|
+
location: {
|
|
58
|
+
// Error overlay does not support multi-line or ranges.
|
|
59
|
+
// Just point to the first line.
|
|
60
|
+
line: frontmatterBlockOffset + validationErrors[0].lines[0],
|
|
61
|
+
file: viteId
|
|
62
|
+
}
|
|
50
63
|
});
|
|
51
64
|
}
|
|
52
65
|
if (astroConfig.experimental.assets) {
|
|
@@ -56,29 +69,41 @@ function markdocIntegration(legacyConfig) {
|
|
|
56
69
|
filePath: entry._internal.filePath
|
|
57
70
|
});
|
|
58
71
|
}
|
|
59
|
-
|
|
72
|
+
return {
|
|
60
73
|
code: `import { jsx as h } from 'astro/jsx-runtime';
|
|
61
74
|
import { applyDefaultConfig } from '@astrojs/markdoc/default-config';
|
|
62
75
|
import { Renderer } from '@astrojs/markdoc/components';
|
|
63
|
-
import * as entry from ${JSON.stringify(viteId + "?astroContent")};${
|
|
64
|
-
import userConfig from ${JSON.stringify(
|
|
76
|
+
import * as entry from ${JSON.stringify(viteId + "?astroContent")};${markdocConfigResult ? `
|
|
77
|
+
import userConfig from ${JSON.stringify(
|
|
78
|
+
markdocConfigResult.fileUrl.pathname
|
|
79
|
+
)};` : ""}${astroConfig.experimental.assets ? `
|
|
65
80
|
import { experimentalAssetsConfig } from '@astrojs/markdoc/experimental-assets-config';` : ""}
|
|
66
81
|
const stringifiedAst = ${JSON.stringify(
|
|
67
82
|
/* Double stringify to encode *as* stringified JSON */
|
|
68
83
|
JSON.stringify(ast)
|
|
69
84
|
)};
|
|
70
85
|
export async function Content (props) {
|
|
71
|
-
const config = applyDefaultConfig(${
|
|
86
|
+
const config = applyDefaultConfig(${markdocConfigResult ? "{ ...userConfig, variables: { ...userConfig.variables, ...props } }" : "{ variables: props }"}, { entry });${astroConfig.experimental.assets ? `
|
|
72
87
|
config.nodes = { ...experimentalAssetsConfig.nodes, ...config.nodes };` : ""}
|
|
73
88
|
return h(Renderer, { stringifiedAst, config }); };`
|
|
74
89
|
};
|
|
75
|
-
return code;
|
|
76
90
|
},
|
|
77
91
|
contentModuleTypes: await fs.promises.readFile(
|
|
78
92
|
new URL("../template/content-module-types.d.ts", import.meta.url),
|
|
79
93
|
"utf-8"
|
|
80
94
|
)
|
|
81
95
|
});
|
|
96
|
+
},
|
|
97
|
+
"astro:server:setup": async ({ server }) => {
|
|
98
|
+
server.watcher.on("all", (event, entry) => {
|
|
99
|
+
if (pathToFileURL(entry).pathname === (markdocConfigResult == null ? void 0 : markdocConfigResult.fileUrl.pathname)) {
|
|
100
|
+
console.log(
|
|
101
|
+
yellow(
|
|
102
|
+
`${bold("[Markdoc]")} Restart the dev server for config changes to take effect.`
|
|
103
|
+
)
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
});
|
|
82
107
|
}
|
|
83
108
|
}
|
|
84
109
|
};
|
package/dist/load-config.d.ts
CHANGED
|
@@ -1,14 +1,7 @@
|
|
|
1
|
+
import type { Config as MarkdocConfig } from '@markdoc/markdoc';
|
|
1
2
|
import type { AstroConfig } from 'astro';
|
|
2
|
-
export
|
|
3
|
-
config:
|
|
4
|
-
nodes: Partial<Record<import("@markdoc/markdoc").NodeType, import("@markdoc/markdoc").Schema<Readonly<Partial<any>>, string>>>;
|
|
5
|
-
tags: Record<string, import("@markdoc/markdoc").Schema<Readonly<Partial<any>>, string>>;
|
|
6
|
-
variables: Record<string, any>;
|
|
7
|
-
functions: Record<string, import("@markdoc/markdoc").ConfigFunction>;
|
|
8
|
-
partials: Record<string, any>;
|
|
9
|
-
validation?: {
|
|
10
|
-
validateFunctions?: boolean | undefined;
|
|
11
|
-
} | undefined;
|
|
12
|
-
}>>;
|
|
3
|
+
export type MarkdocConfigResult = {
|
|
4
|
+
config: MarkdocConfig;
|
|
13
5
|
fileUrl: URL;
|
|
14
|
-
}
|
|
6
|
+
};
|
|
7
|
+
export declare function loadMarkdocConfig(astroConfig: Pick<AstroConfig, 'root'>): Promise<MarkdocConfigResult | undefined>;
|
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.1.
|
|
4
|
+
"version": "0.1.3",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
7
7
|
"author": "withastro",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"zod": "^3.17.3"
|
|
35
35
|
},
|
|
36
36
|
"peerDependencies": {
|
|
37
|
-
"astro": "^2.4.
|
|
37
|
+
"astro": "^2.4.4"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@types/chai": "^4.3.1",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"mocha": "^9.2.2",
|
|
47
47
|
"rollup": "^3.20.1",
|
|
48
48
|
"vite": "^4.3.1",
|
|
49
|
-
"astro": "2.4.
|
|
49
|
+
"astro": "2.4.4",
|
|
50
50
|
"astro-scripts": "0.0.14"
|
|
51
51
|
},
|
|
52
52
|
"engines": {
|
package/src/config.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
1
2
|
import type { Node } from '@markdoc/markdoc';
|
|
2
3
|
import Markdoc from '@markdoc/markdoc';
|
|
3
4
|
import type { AstroConfig, AstroIntegration, ContentEntryType, HookParameters } from 'astro';
|
|
4
5
|
import fs from 'node:fs';
|
|
5
|
-
import { fileURLToPath } from 'node:url';
|
|
6
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
6
7
|
import { isValidUrl, MarkdocError, parseFrontmatter, prependForwardSlash } from './utils.js';
|
|
7
8
|
// @ts-expect-error Cannot find module 'astro/assets' or its corresponding type declarations.
|
|
8
9
|
import { emitESMImage } from 'astro/assets';
|
|
9
|
-
import { bold, red } from 'kleur/colors';
|
|
10
|
+
import { bold, red, yellow } from 'kleur/colors';
|
|
10
11
|
import type * as rollup from 'rollup';
|
|
11
12
|
import { applyDefaultConfig } from './default-config.js';
|
|
12
|
-
import { loadMarkdocConfig } from './load-config.js';
|
|
13
|
+
import { loadMarkdocConfig, type MarkdocConfigResult } from './load-config.js';
|
|
13
14
|
|
|
14
15
|
type SetupHookParams = HookParameters<'astro:config:setup'> & {
|
|
15
16
|
// `contentEntryType` is not a public API
|
|
@@ -17,9 +18,8 @@ type SetupHookParams = HookParameters<'astro:config:setup'> & {
|
|
|
17
18
|
addContentEntryType: (contentEntryType: ContentEntryType) => void;
|
|
18
19
|
};
|
|
19
20
|
|
|
20
|
-
export default function markdocIntegration(legacyConfig
|
|
21
|
+
export default function markdocIntegration(legacyConfig?: any): AstroIntegration {
|
|
21
22
|
if (legacyConfig) {
|
|
22
|
-
// eslint-disable-next-line no-console
|
|
23
23
|
console.log(
|
|
24
24
|
`${red(
|
|
25
25
|
bold('[Markdoc]')
|
|
@@ -27,14 +27,15 @@ export default function markdocIntegration(legacyConfig: any): AstroIntegration
|
|
|
27
27
|
);
|
|
28
28
|
process.exit(0);
|
|
29
29
|
}
|
|
30
|
+
let markdocConfigResult: MarkdocConfigResult | undefined;
|
|
30
31
|
return {
|
|
31
32
|
name: '@astrojs/markdoc',
|
|
32
33
|
hooks: {
|
|
33
34
|
'astro:config:setup': async (params) => {
|
|
34
35
|
const { config: astroConfig, addContentEntryType } = params as SetupHookParams;
|
|
35
36
|
|
|
36
|
-
|
|
37
|
-
const userMarkdocConfig =
|
|
37
|
+
markdocConfigResult = await loadMarkdocConfig(astroConfig);
|
|
38
|
+
const userMarkdocConfig = markdocConfigResult?.config ?? {};
|
|
38
39
|
|
|
39
40
|
function getEntryInfo({ fileUrl, contents }: { fileUrl: URL; contents: string }) {
|
|
40
41
|
const parsed = parseFrontmatter(contents, fileURLToPath(fileUrl));
|
|
@@ -54,17 +55,28 @@ export default function markdocIntegration(legacyConfig: any): AstroIntegration
|
|
|
54
55
|
const markdocConfig = applyDefaultConfig(userMarkdocConfig, { entry });
|
|
55
56
|
|
|
56
57
|
const validationErrors = Markdoc.validate(ast, markdocConfig).filter((e) => {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
return (
|
|
59
|
+
// Ignore `variable-undefined` errors.
|
|
60
|
+
// Variables can be configured at runtime,
|
|
61
|
+
// so we cannot validate them at build time.
|
|
62
|
+
e.error.id !== 'variable-undefined' &&
|
|
63
|
+
(e.error.level === 'error' || e.error.level === 'critical')
|
|
64
|
+
);
|
|
61
65
|
});
|
|
62
66
|
if (validationErrors.length) {
|
|
67
|
+
// Heuristic: take number of newlines for `rawData` and add 2 for the `---` fences
|
|
68
|
+
const frontmatterBlockOffset = entry._internal.rawData.split('\n').length + 2;
|
|
63
69
|
throw new MarkdocError({
|
|
64
70
|
message: [
|
|
65
|
-
`**${String(entry.collection)} → ${String(entry.id)}**
|
|
66
|
-
...validationErrors.map((e) => e.error.
|
|
71
|
+
`**${String(entry.collection)} → ${String(entry.id)}** contains invalid content:`,
|
|
72
|
+
...validationErrors.map((e) => `- ${e.error.message}`),
|
|
67
73
|
].join('\n'),
|
|
74
|
+
location: {
|
|
75
|
+
// Error overlay does not support multi-line or ranges.
|
|
76
|
+
// Just point to the first line.
|
|
77
|
+
line: frontmatterBlockOffset + validationErrors[0].lines[0],
|
|
78
|
+
file: viteId,
|
|
79
|
+
},
|
|
68
80
|
});
|
|
69
81
|
}
|
|
70
82
|
|
|
@@ -76,13 +88,15 @@ export default function markdocIntegration(legacyConfig: any): AstroIntegration
|
|
|
76
88
|
});
|
|
77
89
|
}
|
|
78
90
|
|
|
79
|
-
|
|
91
|
+
return {
|
|
80
92
|
code: `import { jsx as h } from 'astro/jsx-runtime';
|
|
81
93
|
import { applyDefaultConfig } from '@astrojs/markdoc/default-config';
|
|
82
94
|
import { Renderer } from '@astrojs/markdoc/components';
|
|
83
95
|
import * as entry from ${JSON.stringify(viteId + '?astroContent')};${
|
|
84
|
-
|
|
85
|
-
? `\nimport userConfig from ${JSON.stringify(
|
|
96
|
+
markdocConfigResult
|
|
97
|
+
? `\nimport userConfig from ${JSON.stringify(
|
|
98
|
+
markdocConfigResult.fileUrl.pathname
|
|
99
|
+
)};`
|
|
86
100
|
: ''
|
|
87
101
|
}${
|
|
88
102
|
astroConfig.experimental.assets
|
|
@@ -94,7 +108,7 @@ const stringifiedAst = ${JSON.stringify(
|
|
|
94
108
|
)};
|
|
95
109
|
export async function Content (props) {
|
|
96
110
|
const config = applyDefaultConfig(${
|
|
97
|
-
|
|
111
|
+
markdocConfigResult
|
|
98
112
|
? '{ ...userConfig, variables: { ...userConfig.variables, ...props } }'
|
|
99
113
|
: '{ variables: props }'
|
|
100
114
|
}, { entry });${
|
|
@@ -104,7 +118,6 @@ export async function Content (props) {
|
|
|
104
118
|
}
|
|
105
119
|
return h(Renderer, { stringifiedAst, config }); };`,
|
|
106
120
|
};
|
|
107
|
-
return code;
|
|
108
121
|
},
|
|
109
122
|
contentModuleTypes: await fs.promises.readFile(
|
|
110
123
|
new URL('../template/content-module-types.d.ts', import.meta.url),
|
|
@@ -112,6 +125,17 @@ export async function Content (props) {
|
|
|
112
125
|
),
|
|
113
126
|
});
|
|
114
127
|
},
|
|
128
|
+
'astro:server:setup': async ({ server }) => {
|
|
129
|
+
server.watcher.on('all', (event, entry) => {
|
|
130
|
+
if (pathToFileURL(entry).pathname === markdocConfigResult?.fileUrl.pathname) {
|
|
131
|
+
console.log(
|
|
132
|
+
yellow(
|
|
133
|
+
`${bold('[Markdoc]')} Restart the dev server for config changes to take effect.`
|
|
134
|
+
)
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
},
|
|
115
139
|
},
|
|
116
140
|
};
|
|
117
141
|
}
|
package/src/load-config.ts
CHANGED
|
@@ -11,7 +11,14 @@ const SUPPORTED_MARKDOC_CONFIG_FILES = [
|
|
|
11
11
|
'markdoc.config.ts',
|
|
12
12
|
];
|
|
13
13
|
|
|
14
|
-
export
|
|
14
|
+
export type MarkdocConfigResult = {
|
|
15
|
+
config: MarkdocConfig;
|
|
16
|
+
fileUrl: URL;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export async function loadMarkdocConfig(
|
|
20
|
+
astroConfig: Pick<AstroConfig, 'root'>
|
|
21
|
+
): Promise<MarkdocConfigResult | undefined> {
|
|
15
22
|
let markdocConfigUrl: URL | undefined;
|
|
16
23
|
for (const filename of SUPPORTED_MARKDOC_CONFIG_FILES) {
|
|
17
24
|
const filePath = new URL(filename, astroConfig.root);
|