diff options
Diffstat (limited to 'packages/integrations/markdoc/src')
| -rw-r--r-- | packages/integrations/markdoc/src/config.ts | 1 | ||||
| -rw-r--r-- | packages/integrations/markdoc/src/extensions/prism.ts | 24 | ||||
| -rw-r--r-- | packages/integrations/markdoc/src/extensions/shiki.ts | 14 | ||||
| -rw-r--r-- | packages/integrations/markdoc/src/index.ts | 26 | ||||
| -rw-r--r-- | packages/integrations/markdoc/src/runtime.ts | 30 | 
5 files changed, 62 insertions, 33 deletions
| diff --git a/packages/integrations/markdoc/src/config.ts b/packages/integrations/markdoc/src/config.ts index a8f202424..23ff744f7 100644 --- a/packages/integrations/markdoc/src/config.ts +++ b/packages/integrations/markdoc/src/config.ts @@ -12,7 +12,6 @@ export type ResolvedAstroMarkdocConfig = Omit<AstroMarkdocConfig, 'extends'>;  export const Markdoc = _Markdoc;  export const nodes = { ...Markdoc.nodes, heading }; -export { shiki } from './extensions/shiki.js';  export function defineMarkdocConfig(config: AstroMarkdocConfig): AstroMarkdocConfig {  	return config; diff --git a/packages/integrations/markdoc/src/extensions/prism.ts b/packages/integrations/markdoc/src/extensions/prism.ts new file mode 100644 index 000000000..e28112c9a --- /dev/null +++ b/packages/integrations/markdoc/src/extensions/prism.ts @@ -0,0 +1,24 @@ +// leave space, so organize imports doesn't mess up comments +// @ts-expect-error Cannot find module 'astro/runtime/server/index.js' or its corresponding type declarations. +import { unescapeHTML } from 'astro/runtime/server/index.js'; + +import { runHighlighterWithAstro } from '@astrojs/prism/dist/highlighter'; +import { Markdoc, type AstroMarkdocConfig } from '../config.js'; + +export default function prism(): AstroMarkdocConfig { +	return { +		nodes: { +			fence: { +				attributes: Markdoc.nodes.fence.attributes!, +				transform({ attributes: { language, content } }) { +					const { html, classLanguage } = runHighlighterWithAstro(language, content); + +					// Use `unescapeHTML` to return `HTMLString` for Astro renderer to inline as HTML +					return unescapeHTML( +						`<pre class="${classLanguage}"><code class="${classLanguage}">${html}</code></pre>` +					); +				}, +			}, +		}, +	}; +} diff --git a/packages/integrations/markdoc/src/extensions/shiki.ts b/packages/integrations/markdoc/src/extensions/shiki.ts index d03a60139..491deed56 100644 --- a/packages/integrations/markdoc/src/extensions/shiki.ts +++ b/packages/integrations/markdoc/src/extensions/shiki.ts @@ -2,11 +2,11 @@  // @ts-expect-error Cannot find module 'astro/runtime/server/index.js' or its corresponding type declarations.  import { unescapeHTML } from 'astro/runtime/server/index.js'; -import Markdoc from '@markdoc/markdoc';  import type { ShikiConfig } from 'astro';  import type * as shikiTypes from 'shiki';  import type { AstroMarkdocConfig } from '../config.js'; -import { MarkdocError } from '../utils.js'; +import Markdoc from '@markdoc/markdoc'; +import { getHighlighter } from 'shiki';  // Map of old theme names to new names to preserve compatibility when we upgrade shiki  const compatThemes: Record<string, string> = { @@ -51,19 +51,11 @@ const INLINE_STYLE_SELECTOR = /style="(.*?)"/;   */  const highlighterCache = new Map<string, shikiTypes.Highlighter>(); -export async function shiki({ +export default async function shiki({  	langs = [],  	theme = 'github-dark',  	wrap = false,  }: ShikiConfig = {}): Promise<AstroMarkdocConfig> { -	let getHighlighter: (options: shikiTypes.HighlighterOptions) => Promise<shikiTypes.Highlighter>; -	try { -		getHighlighter = (await import('shiki')).getHighlighter; -	} catch { -		throw new MarkdocError({ -			message: 'Shiki is not installed. Run `npm install shiki` to use the `shiki` extension.', -		}); -	}  	theme = normalizeTheme(theme);  	const cacheID: string = typeof theme === 'string' ? theme : theme.name; diff --git a/packages/integrations/markdoc/src/index.ts b/packages/integrations/markdoc/src/index.ts index 64ae4cbc0..0486a44b5 100644 --- a/packages/integrations/markdoc/src/index.ts +++ b/packages/integrations/markdoc/src/index.ts @@ -32,7 +32,19 @@ export default function markdocIntegration(legacyConfig?: any): AstroIntegration  		name: '@astrojs/markdoc',  		hooks: {  			'astro:config:setup': async (params) => { -				const { config: astroConfig, addContentEntryType } = params as SetupHookParams; +				const { +					config: astroConfig, +					updateConfig, +					addContentEntryType, +				} = params as SetupHookParams; + +				updateConfig({ +					vite: { +						ssr: { +							external: ['@astrojs/markdoc/prism', '@astrojs/markdoc/shiki'], +						}, +					}, +				});  				markdocConfigResult = await loadMarkdocConfig(astroConfig);  				const userMarkdocConfig = markdocConfigResult?.config ?? {}; @@ -52,11 +64,7 @@ export default function markdocIntegration(legacyConfig?: any): AstroIntegration  					async getRenderModule({ entry, viteId }) {  						const ast = Markdoc.parse(entry.body);  						const pluginContext = this; -						const markdocConfig = setupConfig( -							userMarkdocConfig, -							entry, -							markdocConfigResult?.fileUrl.pathname -						); +						const markdocConfig = await setupConfig(userMarkdocConfig, entry);  						const validationErrors = Markdoc.validate(ast, markdocConfig).filter((e) => {  							return ( @@ -94,7 +102,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, setupConfig, Markdoc } from '@astrojs/markdoc/runtime'; +						import { collectHeadings, setupConfig, setupConfigSync, Markdoc } from '@astrojs/markdoc/runtime';  import * as entry from ${JSON.stringify(viteId + '?astroContentCollectionEntry')};  ${  	markdocConfigResult @@ -118,13 +126,13 @@ export function getHeadings() {  		''  	}  	const headingConfig = userConfig.nodes?.heading; -	const config = setupConfig(headingConfig ? { nodes: { heading: headingConfig } } : {}, entry); +	const config = setupConfigSync(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) { -	const config = setupConfig({ +	const config = await setupConfig({  		...userConfig,  		variables: { ...userConfig.variables, ...props },  	}, entry); diff --git a/packages/integrations/markdoc/src/runtime.ts b/packages/integrations/markdoc/src/runtime.ts index 5a59d5fef..939e6d602 100644 --- a/packages/integrations/markdoc/src/runtime.ts +++ b/packages/integrations/markdoc/src/runtime.ts @@ -13,26 +13,19 @@ export { default as Markdoc } from '@markdoc/markdoc';   * Called on each file's individual transform.   * TODO: virtual module to merge configs per-build instead of per-file?   */ -export function setupConfig( +export async function setupConfig(  	userConfig: AstroMarkdocConfig, -	entry: ContentEntryModule, -	markdocConfigPath?: string -): Omit<AstroMarkdocConfig, 'extends'> { +	entry: ContentEntryModule +): Promise<Omit<AstroMarkdocConfig, 'extends'>> {  	let defaultConfig: AstroMarkdocConfig = {  		...setupHeadingConfig(),  		variables: { entry },  	};  	if (userConfig.extends) { -		for (const extension of userConfig.extends) { +		for (let extension of userConfig.extends) {  			if (extension instanceof Promise) { -				throw new MarkdocError({ -					message: 'An extension passed to `extends` in your markdoc config returns a Promise.', -					hint: 'Call `await` for async extensions. Example: `extends: [await myExtension()]`', -					location: { -						file: markdocConfigPath, -					}, -				}); +				extension = await extension;  			}  			defaultConfig = mergeConfig(defaultConfig, extension); @@ -42,6 +35,19 @@ export function setupConfig(  	return mergeConfig(defaultConfig, userConfig);  } +/** Used for synchronous `getHeadings()` function */ +export function setupConfigSync( +	userConfig: AstroMarkdocConfig, +	entry: ContentEntryModule +): Omit<AstroMarkdocConfig, 'extends'> { +	let defaultConfig: AstroMarkdocConfig = { +		...setupHeadingConfig(), +		variables: { entry }, +	}; + +	return mergeConfig(defaultConfig, userConfig); +} +  /** Merge function from `@markdoc/markdoc` internals */  function mergeConfig(configA: AstroMarkdocConfig, configB: AstroMarkdocConfig): AstroMarkdocConfig {  	return { | 
