@astrojs/markdoc 0.4.4 → 0.5.0

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 CHANGED
@@ -278,7 +278,7 @@ export default defineMarkdocConfig({
278
278
 
279
279
  ### Use client-side UI components
280
280
 
281
- 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.
281
+ 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](https://docs.astro.build/en/core-concepts/framework-components/#nesting-framework-components) with your desired `client:` directive.
282
282
 
283
283
  This example wraps a React `Aside.tsx` component with a `ClientAside.astro` component:
284
284
 
@@ -344,6 +344,36 @@ Now, you can call this function from any Markdoc content entry:
344
344
 
345
345
  📚 [See the Markdoc documentation](https://markdoc.dev/docs/functions#creating-a-custom-function) for more on using variables or functions in your content.
346
346
 
347
+ ### Markdoc Language Server
348
+
349
+ If you are using VS Code, there is an official [Markdoc language extension](https://marketplace.visualstudio.com/items?itemName=Stripe.markdoc-language-support) that includes syntax highlighting and autocomplete for configured tags. [See the language server on GitHub](https://github.com/markdoc/language-server.git) for more information.
350
+
351
+ To set up the extension, create a `markdoc.config.json` file into the project root with following content:
352
+
353
+ ```json
354
+ [
355
+ {
356
+ "id": "my-site",
357
+ "path": "src/content",
358
+ "schema": {
359
+ "path": "markdoc.config.mjs",
360
+ "type": "esm",
361
+ "property": "default",
362
+ "watch": true
363
+ }
364
+ }
365
+ ]
366
+ ```
367
+
368
+ The `schema` property contains all information to configure the language server for Astro content collections. It accepts following properties:
369
+
370
+ - `path`: The path to the configuration file.
371
+ - `type`: The type of module your configuration file uses (`esm` allows `import` syntax).
372
+ - `property`: The exported property name that contains the configuration object.
373
+ - `watch`: Tell the server to watch for changes in the configuration.
374
+
375
+ The top-level `path` property tells the server where content is located. Since Markdoc is specific to content collections, you can use `src/content`.
376
+
347
377
  ### Pass Markdoc variables
348
378
 
349
379
  You may need to pass [variables][markdoc-variables] to your content. This is useful when passing SSR parameters like A/B tests.
@@ -425,9 +455,7 @@ export default defineConfig({
425
455
  ```
426
456
 
427
457
  > **Warning**
428
- > When `allowHTML` is enabled, HTML markup inside Markdoc documents will be rendered as actual HTML elements (including `<script>`), making attack vectors like XSS possible.
429
- >
430
- > Ensure that any HTML markup comes from trusted sources.
458
+ > When `allowHTML` is enabled, HTML markup inside Markdoc documents will be rendered as actual HTML elements (including `<script>`), making attack vectors like XSS possible. Ensure that any HTML markup comes from trusted sources.
431
459
 
432
460
  ## Examples
433
461
 
@@ -1,13 +1,13 @@
1
1
  import Markdoc from "@markdoc/markdoc";
2
+ import { emitESMImage } from "astro/assets/utils";
2
3
  import matter from "gray-matter";
3
4
  import fs from "node:fs";
4
- import { fileURLToPath } from "node:url";
5
- import { MarkdocError, isComponentConfig, isValidUrl, prependForwardSlash } from "./utils.js";
6
- import { emitESMImage } from "astro/assets/utils";
7
5
  import path from "node:path";
6
+ import { fileURLToPath } from "node:url";
8
7
  import { htmlTokenTransform } from "./html/transform/html-token-transform.js";
9
8
  import { setupConfig } from "./runtime.js";
10
9
  import { getMarkdocTokenizer } from "./tokenizer.js";
10
+ import { MarkdocError, isComponentConfig, isValidUrl, prependForwardSlash } from "./utils.js";
11
11
  async function getContentEntryType({
12
12
  markdocConfigResult,
13
13
  astroConfig,
@@ -18,27 +18,26 @@ async function getContentEntryType({
18
18
  getEntryInfo,
19
19
  handlePropagation: true,
20
20
  async getRenderModule({ contents, fileUrl, viteId }) {
21
- var _a, _b;
22
21
  const entry = getEntryInfo({ contents, fileUrl });
23
22
  const tokenizer = getMarkdocTokenizer(options);
24
23
  let tokens = tokenizer.tokenize(entry.body);
25
- if (options == null ? void 0 : options.allowHTML) {
24
+ if (options?.allowHTML) {
26
25
  tokens = htmlTokenTransform(tokenizer, tokens);
27
26
  }
28
27
  const ast = Markdoc.parse(tokens);
29
28
  const usedTags = getUsedTags(ast);
30
- const userMarkdocConfig = (markdocConfigResult == null ? void 0 : markdocConfigResult.config) ?? {};
31
- const markdocConfigUrl = markdocConfigResult == null ? void 0 : markdocConfigResult.fileUrl;
29
+ const userMarkdocConfig = markdocConfigResult?.config ?? {};
30
+ const markdocConfigUrl = markdocConfigResult?.fileUrl;
32
31
  let componentConfigByTagMap = {};
33
32
  for (const tag of usedTags) {
34
- const render = (_b = (_a = userMarkdocConfig.tags) == null ? void 0 : _a[tag]) == null ? void 0 : _b.render;
33
+ const render = userMarkdocConfig.tags?.[tag]?.render;
35
34
  if (isComponentConfig(render)) {
36
35
  componentConfigByTagMap[tag] = render;
37
36
  }
38
37
  }
39
38
  let componentConfigByNodeMap = {};
40
39
  for (const [nodeType, schema] of Object.entries(userMarkdocConfig.nodes ?? {})) {
41
- const render = schema == null ? void 0 : schema.render;
40
+ const render = schema?.render;
42
41
  if (isComponentConfig(render)) {
43
42
  componentConfigByNodeMap[nodeType] = render;
44
43
  }
@@ -74,18 +73,17 @@ async function getContentEntryType({
74
73
  }
75
74
  });
76
75
  }
77
- if (astroConfig.experimental.assets) {
78
- await emitOptimizedImages(ast.children, {
79
- astroConfig,
80
- pluginContext,
81
- filePath
82
- });
83
- }
76
+ await emitOptimizedImages(ast.children, {
77
+ astroConfig,
78
+ pluginContext,
79
+ filePath
80
+ });
84
81
  const res = `import { Renderer } from '@astrojs/markdoc/components';
85
82
  import { createGetHeadings, createContentComponent } from '@astrojs/markdoc/runtime';
86
- ${markdocConfigUrl ? `import markdocConfig from ${JSON.stringify(markdocConfigUrl.pathname)};` : "const markdocConfig = {};"}${astroConfig.experimental.assets ? `
87
- import { experimentalAssetsConfig } from '@astrojs/markdoc/experimental-assets-config';
88
- markdocConfig.nodes = { ...experimentalAssetsConfig.nodes, ...markdocConfig.nodes };` : ""}
83
+ ${markdocConfigUrl ? `import markdocConfig from ${JSON.stringify(markdocConfigUrl.pathname)};` : "const markdocConfig = {};"}
84
+
85
+ import { assetsConfig } from '@astrojs/markdoc/runtime-assets-config';
86
+ markdocConfig.nodes = { ...assetsConfig.nodes, ...markdocConfig.nodes };
89
87
 
90
88
  ${getStringifiedImports(componentConfigByTagMap, "Tag", astroConfig.root)}
91
89
  ${getStringifiedImports(componentConfigByNodeMap, "Node", astroConfig.root)}
@@ -141,12 +139,11 @@ async function emitOptimizedImages(nodeChildren, ctx) {
141
139
  for (const node of nodeChildren) {
142
140
  if (node.type === "image" && typeof node.attributes.src === "string" && shouldOptimizeImage(node.attributes.src)) {
143
141
  const resolved = await ctx.pluginContext.resolve(node.attributes.src, ctx.filePath);
144
- if ((resolved == null ? void 0 : resolved.id) && fs.existsSync(new URL(prependForwardSlash(resolved.id), "file://"))) {
142
+ if (resolved?.id && fs.existsSync(new URL(prependForwardSlash(resolved.id), "file://"))) {
145
143
  const src = await emitESMImage(
146
144
  resolved.id,
147
145
  ctx.pluginContext.meta.watchMode,
148
- ctx.pluginContext.emitFile,
149
- { config: ctx.astroConfig }
146
+ ctx.pluginContext.emitFile
150
147
  );
151
148
  node.attributes.__optimizedSrc = src;
152
149
  } else {
@@ -1,5 +1,5 @@
1
- import { unescapeHTML } from "astro/runtime/server/index.js";
2
1
  import { runHighlighterWithAstro } from "@astrojs/prism/dist/highlighter";
2
+ import { unescapeHTML } from "astro/runtime/server/index.js";
3
3
  import { Markdoc } from "../config.js";
4
4
  function prism() {
5
5
  return {
@@ -1,22 +1,6 @@
1
- import { unescapeHTML } from "astro/runtime/server/index.js";
2
1
  import Markdoc from "@markdoc/markdoc";
2
+ import { unescapeHTML } from "astro/runtime/server/index.js";
3
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
4
  const ASTRO_COLOR_REPLACEMENTS = {
21
5
  "#000001": "var(--astro-code-color-text)",
22
6
  "#000002": "var(--astro-code-color-background)",
@@ -39,7 +23,6 @@ async function shiki({
39
23
  theme = "github-dark",
40
24
  wrap = false
41
25
  } = {}) {
42
- theme = normalizeTheme(theme);
43
26
  const cacheID = typeof theme === "string" ? theme : theme.name;
44
27
  if (!highlighterCache.has(cacheID)) {
45
28
  highlighterCache.set(
@@ -1,4 +1,5 @@
1
- import Markdoc from "@markdoc/markdoc";
1
+ import Markdoc, {
2
+ } from "@markdoc/markdoc";
2
3
  import Slugger from "github-slugger";
3
4
  import { getTextContent } from "./runtime.js";
4
5
  import { MarkdocError } from "./utils.js";
@@ -19,16 +20,15 @@ const heading = {
19
20
  level: { type: Number, required: true, default: 1 }
20
21
  },
21
22
  transform(node, config) {
22
- var _a, _b, _c;
23
23
  const { level, ...attributes } = node.transformAttributes(config);
24
24
  const children = node.transformChildren(config);
25
- if (!((_a = config.ctx) == null ? void 0 : _a.headingSlugger)) {
25
+ if (!config.ctx?.headingSlugger) {
26
26
  throw new MarkdocError({
27
27
  message: "Unexpected problem adding heading IDs to Markdoc file. Did you modify the `ctx.headingSlugger` property in your Markdoc config?"
28
28
  });
29
29
  }
30
30
  const slug = getSlug(attributes, children, config.ctx.headingSlugger);
31
- const render = ((_c = (_b = config.nodes) == null ? void 0 : _b.heading) == null ? void 0 : _c.render) ?? `h${level}`;
31
+ const render = config.nodes?.heading?.render ?? `h${level}`;
32
32
  const tagProps = (
33
33
  // For components, pass down `level` as a prop,
34
34
  // alongside `__collectHeading` for our `headings` collector.
@@ -1,3 +1,3 @@
1
- import { Tokenizer } from '@markdoc/markdoc';
1
+ import type { Tokenizer } from '@markdoc/markdoc';
2
2
  import type * as Token from 'markdown-it/lib/token';
3
3
  export declare function htmlTokenTransform(tokenizer: Tokenizer, tokens: Token[]): Token[];
@@ -1,2 +1,2 @@
1
1
  import type { Config as MarkdocConfig } from '@markdoc/markdoc';
2
- export declare const experimentalAssetsConfig: MarkdocConfig;
2
+ export declare const assetsConfig: MarkdocConfig;
@@ -1,6 +1,6 @@
1
1
  import Markdoc from "@markdoc/markdoc";
2
2
  import { Image } from "astro:assets";
3
- const experimentalAssetsConfig = {
3
+ const assetsConfig = {
4
4
  nodes: {
5
5
  image: {
6
6
  attributes: {
@@ -21,5 +21,5 @@ const experimentalAssetsConfig = {
21
21
  }
22
22
  };
23
23
  export {
24
- experimentalAssetsConfig
24
+ assetsConfig
25
25
  };
package/dist/runtime.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import type { MarkdownHeading } from '@astrojs/markdown-remark';
2
2
  import { type NodeType, type RenderableTreeNode } from '@markdoc/markdoc';
3
3
  import type { AstroInstance } from 'astro';
4
- import type { AstroMarkdocConfig } from './config.js';
4
+ import { type AstroMarkdocConfig } from './config.js';
5
5
  import type { MarkdocIntegrationOptions } from './options.js';
6
6
  /**
7
7
  * Merge user config with default config and set up context (ex. heading ID slugger)
@@ -25,5 +25,5 @@ export declare function getTextContent(childNodes: RenderableTreeNode[]): string
25
25
  */
26
26
  export declare function collectHeadings(children: RenderableTreeNode[], collectedHeadings: MarkdownHeading[]): void;
27
27
  export declare function createGetHeadings(stringifiedAst: string, userConfig: AstroMarkdocConfig, options: MarkdocIntegrationOptions | undefined): () => MarkdownHeading[];
28
- export declare function createContentComponent(Renderer: AstroInstance['default'], stringifiedAst: string, userConfig: AstroMarkdocConfig, options: MarkdocIntegrationOptions | undefined, tagComponentMap: Record<string, AstroInstance['default']>, nodeComponentMap: Record<NodeType, AstroInstance['default']>): any;
28
+ export declare function createContentComponent(Renderer: AstroInstance['default'], stringifiedAst: string, userConfig: AstroMarkdocConfig, options: MarkdocIntegrationOptions | undefined, tagComponentMap: Record<string, AstroInstance['default']>, nodeComponentMap: Record<NodeType, AstroInstance['default']>): import("astro/runtime/server/index.js").AstroComponentFactory;
29
29
  export {};
package/dist/runtime.js CHANGED
@@ -1,5 +1,7 @@
1
- import Markdoc from "@markdoc/markdoc";
1
+ import Markdoc, {
2
+ } from "@markdoc/markdoc";
2
3
  import { createComponent, renderComponent } from "astro/runtime/server/index.js";
4
+ import {} from "./config.js";
3
5
  import { setupHeadingConfig } from "./heading-ids.js";
4
6
  import { htmlTag } from "./html/tagdefs/html.tag.js";
5
7
  async function setupConfig(userConfig = {}, options) {
@@ -13,7 +15,7 @@ async function setupConfig(userConfig = {}, options) {
13
15
  }
14
16
  }
15
17
  let merged = mergeConfig(defaultConfig, userConfig);
16
- if (options == null ? void 0 : options.allowHTML) {
18
+ if (options?.allowHTML) {
17
19
  merged = mergeConfig(merged, HTML_CONFIG);
18
20
  }
19
21
  return merged;
@@ -21,7 +23,7 @@ async function setupConfig(userConfig = {}, options) {
21
23
  function setupConfigSync(userConfig = {}, options) {
22
24
  const defaultConfig = setupHeadingConfig();
23
25
  let merged = mergeConfig(defaultConfig, userConfig);
24
- if (options == null ? void 0 : options.allowHTML) {
26
+ if (options?.allowHTML) {
25
27
  merged = mergeConfig(merged, HTML_CONFIG);
26
28
  }
27
29
  return merged;
package/dist/tokenizer.js CHANGED
@@ -7,7 +7,7 @@ function getMarkdocTokenizer(options) {
7
7
  // Without this, they're rendered as strings!
8
8
  allowComments: true
9
9
  };
10
- if (options == null ? void 0 : options.allowHTML) {
10
+ if (options?.allowHTML) {
11
11
  tokenizerOptions.allowIndentation = true;
12
12
  tokenizerOptions.html = true;
13
13
  }
package/dist/utils.js CHANGED
@@ -1,7 +1,11 @@
1
1
  class MarkdocError extends Error {
2
+ loc;
3
+ title;
4
+ hint;
5
+ frame;
6
+ type = "MarkdocError";
2
7
  constructor(props, ...params) {
3
8
  super(...params);
4
- this.type = "MarkdocError";
5
9
  const { title = "MarkdocError", message, stack, location, hint, frame } = props;
6
10
  this.title = title;
7
11
  if (message)
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@astrojs/markdoc",
3
3
  "description": "Add support for Markdoc in your Astro site",
4
- "version": "0.4.4",
4
+ "version": "0.5.0",
5
5
  "type": "module",
6
6
  "types": "./dist/index.d.ts",
7
7
  "author": "withastro",
@@ -34,7 +34,7 @@
34
34
  ".": "./dist/index.js",
35
35
  "./components": "./components/index.ts",
36
36
  "./runtime": "./dist/runtime.js",
37
- "./experimental-assets-config": "./dist/experimental-assets-config.js",
37
+ "./runtime-assets-config": "./dist/runtime-assets-config.js",
38
38
  "./package.json": "./package.json"
39
39
  },
40
40
  "typesVersions": {
@@ -56,37 +56,37 @@
56
56
  "template"
57
57
  ],
58
58
  "dependencies": {
59
- "@astrojs/internal-helpers": "^0.1.0",
60
- "@astrojs/prism": "^2.1.2",
61
59
  "@markdoc/markdoc": "^0.3.0",
62
- "esbuild": "^0.17.19",
60
+ "esbuild": "^0.19.2",
63
61
  "github-slugger": "^2.0.0",
64
62
  "gray-matter": "^4.0.3",
65
63
  "htmlparser2": "^9.0.0",
66
64
  "kleur": "^4.1.5",
67
- "shiki": "^0.14.1",
68
- "zod": "^3.17.3"
65
+ "shiki": "^0.14.3",
66
+ "zod": "3.21.1",
67
+ "@astrojs/internal-helpers": "0.2.0",
68
+ "@astrojs/prism": "3.0.0"
69
69
  },
70
70
  "peerDependencies": {
71
- "astro": "^2.9.3"
71
+ "astro": "^3.0.0"
72
72
  },
73
73
  "devDependencies": {
74
- "@astrojs/markdown-remark": "^2.2.1",
75
74
  "@types/chai": "^4.3.5",
76
75
  "@types/html-escaper": "^3.0.0",
77
- "@types/markdown-it": "^12.2.3",
78
- "@types/mocha": "^9.1.1",
76
+ "@types/markdown-it": "^13.0.0",
77
+ "@types/mocha": "^10.0.1",
79
78
  "chai": "^4.3.7",
80
79
  "devalue": "^4.3.2",
81
- "linkedom": "^0.14.26",
82
- "mocha": "^9.2.2",
83
- "rollup": "^3.25.1",
84
- "vite": "^4.4.6",
85
- "astro": "2.9.3",
80
+ "linkedom": "^0.15.1",
81
+ "mocha": "^10.2.0",
82
+ "rollup": "^3.28.1",
83
+ "vite": "^4.4.9",
84
+ "@astrojs/markdown-remark": "3.0.0",
85
+ "astro": "3.0.0",
86
86
  "astro-scripts": "0.0.14"
87
87
  },
88
88
  "engines": {
89
- "node": ">=16.12.0"
89
+ "node": ">=18.14.1"
90
90
  },
91
91
  "scripts": {
92
92
  "build": "astro-scripts build \"src/**/*.ts\" && tsc",