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 { |