90 lines
4.0 KiB
TypeScript
90 lines
4.0 KiB
TypeScript
import { ExpressiveCodeEngine, type ExpressiveCodeTheme, type ExpressiveCodeEngineConfig, type ExpressiveCodePlugin } from '@expressive-code/core'
|
|
import { type PluginFramesOptions, pluginFrames } from '@expressive-code/plugin-frames'
|
|
import type { PluginShikiOptions } from '@expressive-code/plugin-shiki'
|
|
import { loadShikiTheme, pluginShiki, type BundledShikiTheme } from '@expressive-code/plugin-shiki'
|
|
import { pluginTextMarkers } from '@expressive-code/plugin-text-markers'
|
|
import { pluginLineNumbers } from '@expressive-code/plugin-line-numbers'
|
|
|
|
export * from '@expressive-code/core'
|
|
export * from '@expressive-code/plugin-frames'
|
|
export * from '@expressive-code/plugin-shiki'
|
|
export * from '@expressive-code/plugin-text-markers'
|
|
|
|
export interface ExpressiveCodeConfig extends ExpressiveCodeEngineConfig {
|
|
/**
|
|
* The Shiki plugin adds syntax highlighting to code blocks.
|
|
*
|
|
* This plugin is enabled by default. Set this to `false` to disable it.
|
|
* You can also configure the plugin by setting this to an options object.
|
|
*/
|
|
shiki?: PluginShikiOptions | boolean | undefined
|
|
/**
|
|
* The Text Markers plugin allows to highlight lines and inline ranges
|
|
* in code blocks in various styles (e.g. marked, inserted, deleted).
|
|
*
|
|
* This plugin is enabled by default. Set this to `false` to disable it.
|
|
*/
|
|
textMarkers?: boolean | undefined
|
|
/**
|
|
* The Frames plugin adds an editor or terminal frame around code blocks,
|
|
* including an optional title displayed as a tab or window caption.
|
|
*
|
|
* This plugin is enabled by default. Set this to `false` to disable it.
|
|
* You can also configure the plugin by setting this to an options object.
|
|
*/
|
|
frames?: PluginFramesOptions | boolean | undefined
|
|
themes?: ExpressiveCodeTheme[] | undefined;
|
|
}
|
|
|
|
|
|
export async function getTheme(themeName: BundledShikiTheme): Promise<ExpressiveCodeTheme> {
|
|
return await loadShikiTheme(themeName)
|
|
}
|
|
|
|
const darkTheme = await getTheme('catppuccin-macchiato')
|
|
const lightTheme = await getTheme('catppuccin-latte')
|
|
|
|
export class ExpressiveCode extends ExpressiveCodeEngine {
|
|
constructor({ shiki, textMarkers, frames, themes, ...baseConfig }: ExpressiveCodeConfig = {}) {
|
|
// Collect all default plugins with their configuration,
|
|
// but skip those that were disabled or already added to plugins
|
|
const pluginsToPrepend: ExpressiveCodePlugin[] = []
|
|
const baseConfigPlugins = baseConfig.plugins?.flat() || []
|
|
const notPresentInPlugins = (name: string) => baseConfigPlugins.every((plugin) => plugin.name !== name)
|
|
if (shiki !== false && notPresentInPlugins('Shiki')) {
|
|
pluginsToPrepend.push(pluginShiki(shiki !== true ? shiki : undefined))
|
|
}
|
|
if (textMarkers !== false && notPresentInPlugins('TextMarkers')) {
|
|
if (typeof textMarkers === 'object' && (textMarkers as { styleOverrides: unknown }).styleOverrides) {
|
|
throw new Error(
|
|
`The Expressive Code config option "textMarkers" can no longer be an object,
|
|
but only undefined or a boolean. Please move any style settings into the
|
|
top-level "styleOverrides" object below the new "textMarkers" key.`.replace(/\s+/g, ' ')
|
|
)
|
|
}
|
|
pluginsToPrepend.push(pluginTextMarkers())
|
|
}
|
|
if (frames !== false && notPresentInPlugins('Frames')) {
|
|
if (typeof frames === 'object' && (frames as { styleOverrides: unknown }).styleOverrides) {
|
|
throw new Error(
|
|
`The config option "frames" no longer has its own "styleOverrides" object.
|
|
Please move any style settings into the top-level "styleOverrides" object
|
|
below the new "frames" key.`.replace(/\s+/g, ' ')
|
|
)
|
|
}
|
|
pluginsToPrepend.push(pluginFrames(frames !== true ? frames : undefined))
|
|
}
|
|
|
|
pluginsToPrepend.push(pluginLineNumbers())
|
|
|
|
// Create a new plugins array with the default plugins prepended
|
|
const pluginsWithDefaults = [...pluginsToPrepend, ...(baseConfig.plugins || [])]
|
|
|
|
if (!themes) {
|
|
themes = [darkTheme, lightTheme]
|
|
}
|
|
|
|
// Call the base constructor with the new plugins array
|
|
super({ ...baseConfig, themes, plugins: pluginsWithDefaults })
|
|
}
|
|
} |