summaryrefslogtreecommitdiff
path: root/packages/integrations/markdoc/src
diff options
context:
space:
mode:
Diffstat (limited to 'packages/integrations/markdoc/src')
-rw-r--r--packages/integrations/markdoc/src/index.ts12
-rw-r--r--packages/integrations/markdoc/src/nodes/heading.ts32
-rw-r--r--packages/integrations/markdoc/src/nodes/index.ts2
-rw-r--r--packages/integrations/markdoc/src/runtime.ts46
4 files changed, 65 insertions, 27 deletions
diff --git a/packages/integrations/markdoc/src/index.ts b/packages/integrations/markdoc/src/index.ts
index 4360800a0..627f08c77 100644
--- a/packages/integrations/markdoc/src/index.ts
+++ b/packages/integrations/markdoc/src/index.ts
@@ -10,7 +10,7 @@ import { emitESMImage } from 'astro/assets';
import { bold, red, yellow } from 'kleur/colors';
import type * as rollup from 'rollup';
import { loadMarkdocConfig, type MarkdocConfigResult } from './load-config.js';
-import { applyDefaultConfig } from './runtime.js';
+import { setupConfig } from './runtime.js';
type SetupHookParams = HookParameters<'astro:config:setup'> & {
// `contentEntryType` is not a public API
@@ -52,7 +52,7 @@ export default function markdocIntegration(legacyConfig?: any): AstroIntegration
async getRenderModule({ entry, viteId }) {
const ast = Markdoc.parse(entry.body);
const pluginContext = this;
- const markdocConfig = applyDefaultConfig(userMarkdocConfig, entry);
+ const markdocConfig = setupConfig(userMarkdocConfig, entry);
const validationErrors = Markdoc.validate(ast, markdocConfig).filter((e) => {
return (
@@ -90,7 +90,7 @@ export default function markdocIntegration(legacyConfig?: any): AstroIntegration
const res = `import { jsx as h } from 'astro/jsx-runtime';
import { Renderer } from '@astrojs/markdoc/components';
- import { collectHeadings, applyDefaultConfig, Markdoc, headingSlugger } from '@astrojs/markdoc/runtime';
+ import { collectHeadings, setupConfig, Markdoc } from '@astrojs/markdoc/runtime';
import * as entry from ${JSON.stringify(viteId + '?astroContentCollectionEntry')};
${
markdocConfigResult
@@ -113,16 +113,14 @@ export function getHeadings() {
instead of the Content component. Would remove double-transform and unlock variable resolution in heading slugs. */
''
}
- headingSlugger.reset();
const headingConfig = userConfig.nodes?.heading;
- const config = applyDefaultConfig(headingConfig ? { nodes: { heading: headingConfig } } : {}, entry);
+ const config = setupConfig(headingConfig ? { nodes: { heading: headingConfig } } : {}, entry);
const ast = Markdoc.Ast.fromJSON(stringifiedAst);
const content = Markdoc.transform(ast, config);
return collectHeadings(Array.isArray(content) ? content : content.children);
}
export async function Content (props) {
- headingSlugger.reset();
- const config = applyDefaultConfig({
+ const config = setupConfig({
...userConfig,
variables: { ...userConfig.variables, ...props },
}, entry);
diff --git a/packages/integrations/markdoc/src/nodes/heading.ts b/packages/integrations/markdoc/src/nodes/heading.ts
index 8adf57612..19a988b63 100644
--- a/packages/integrations/markdoc/src/nodes/heading.ts
+++ b/packages/integrations/markdoc/src/nodes/heading.ts
@@ -1,10 +1,19 @@
-import Markdoc, { type RenderableTreeNode, type Schema } from '@markdoc/markdoc';
+import Markdoc, { type RenderableTreeNode, type Schema, type ConfigType } from '@markdoc/markdoc';
import Slugger from 'github-slugger';
import { getTextContent } from '../runtime.js';
-export const headingSlugger = new Slugger();
+type ConfigTypeWithCtx = ConfigType & {
+ // TODO: decide on `ctx` as a convention for config merging
+ ctx: {
+ headingSlugger: Slugger;
+ };
+};
-function getSlug(attributes: Record<string, any>, children: RenderableTreeNode[]): string {
+function getSlug(
+ attributes: Record<string, any>,
+ children: RenderableTreeNode[],
+ headingSlugger: Slugger
+): string {
if (attributes.id && typeof attributes.id === 'string') {
return attributes.id;
}
@@ -21,11 +30,11 @@ export const heading: Schema = {
id: { type: String },
level: { type: Number, required: true, default: 1 },
},
- transform(node, config) {
+ transform(node, config: ConfigTypeWithCtx) {
const { level, ...attributes } = node.transformAttributes(config);
const children = node.transformChildren(config);
- const slug = getSlug(attributes, children);
+ const slug = getSlug(attributes, children, config.ctx.headingSlugger);
const render = config.nodes?.heading?.render ?? `h${level}`;
const tagProps =
@@ -39,3 +48,16 @@ export const heading: Schema = {
return new Markdoc.Tag(render, tagProps, children);
},
};
+
+export function setupHeadingConfig(): ConfigTypeWithCtx {
+ const headingSlugger = new Slugger();
+
+ return {
+ ctx: {
+ headingSlugger,
+ },
+ nodes: {
+ heading,
+ },
+ };
+}
diff --git a/packages/integrations/markdoc/src/nodes/index.ts b/packages/integrations/markdoc/src/nodes/index.ts
index c25b03f27..4cd7e3667 100644
--- a/packages/integrations/markdoc/src/nodes/index.ts
+++ b/packages/integrations/markdoc/src/nodes/index.ts
@@ -1,4 +1,4 @@
import { heading } from './heading.js';
-export { headingSlugger } from './heading.js';
+export { setupHeadingConfig } from './heading.js';
export const nodes = { heading };
diff --git a/packages/integrations/markdoc/src/runtime.ts b/packages/integrations/markdoc/src/runtime.ts
index 61b38fd02..3164cda13 100644
--- a/packages/integrations/markdoc/src/runtime.ts
+++ b/packages/integrations/markdoc/src/runtime.ts
@@ -4,27 +4,45 @@ import Markdoc, {
type RenderableTreeNode,
} from '@markdoc/markdoc';
import type { ContentEntryModule } from 'astro';
-import { nodes as astroNodes } from './nodes/index.js';
+import { setupHeadingConfig } from './nodes/index.js';
-/** Used to reset Slugger cache on each build at runtime */
+/** Used to call `Markdoc.transform()` and `Markdoc.Ast` in runtime modules */
export { default as Markdoc } from '@markdoc/markdoc';
-export { headingSlugger } from './nodes/index.js';
-export function applyDefaultConfig(
- config: MarkdocConfig,
- entry: ContentEntryModule
-): MarkdocConfig {
+/**
+ * Merge user config with default config and set up context (ex. heading ID slugger)
+ * Called on each file's individual transform
+ */
+export function setupConfig(userConfig: MarkdocConfig, entry: ContentEntryModule): MarkdocConfig {
+ const defaultConfig: MarkdocConfig = {
+ // `setupXConfig()` could become a "plugin" convention as well?
+ ...setupHeadingConfig(),
+ variables: { entry },
+ };
+ return mergeConfig(defaultConfig, userConfig);
+}
+
+/** Merge function from `@markdoc/markdoc` internals */
+function mergeConfig(configA: MarkdocConfig, configB: MarkdocConfig): MarkdocConfig {
return {
- ...config,
- variables: {
- entry,
- ...config.variables,
+ ...configA,
+ ...configB,
+ tags: {
+ ...configA.tags,
+ ...configB.tags,
},
nodes: {
- ...astroNodes,
- ...config.nodes,
+ ...configA.nodes,
+ ...configB.nodes,
+ },
+ functions: {
+ ...configA.functions,
+ ...configB.functions,
+ },
+ variables: {
+ ...configA.variables,
+ ...configB.variables,
},
- // TODO: Syntax highlighting
};
}