2025-01-21 12:58:03 +08:00

115 lines
3.2 KiB
TypeScript

import type { TransformerTwoslashOptions } from '@shikijs/twoslash/core'
import type { ShikiTransformer } from 'shiki'
import type { VueSpecificOptions } from 'twoslash-vue'
import type { WhitespacePosition } from '../utils/index.js'
import process from 'node:process'
import {
transformerCompactLineOptions,
transformerNotationDiff,
transformerNotationErrorLevel,
transformerNotationFocus,
transformerNotationHighlight,
transformerNotationWordHighlight,
transformerRemoveNotationEscape,
transformerRenderWhitespace,
} from '@shikijs/transformers'
import { defaultTwoslashOptions } from '@shikijs/twoslash/core'
import { addClassToHast } from 'shiki'
import { isPlainObject } from 'vuepress/shared'
import { defaultHoverInfoProcessor, transformerTwoslash } from '../twoslash/rendererTransformer.js'
import { attrsToLines, resolveWhitespacePosition } from '../utils/index.js'
const decorationsRE = /^\/\/ @decorations:(.*)\n/
export const baseTransformers: ShikiTransformer[] = [
transformerNotationDiff({
matchAlgorithm: 'v3',
}),
transformerNotationFocus({
matchAlgorithm: 'v3',
classActiveLine: 'has-focus',
classActivePre: 'has-focused-lines',
}),
transformerNotationHighlight({
matchAlgorithm: 'v3',
}),
transformerNotationErrorLevel({
matchAlgorithm: 'v3',
}),
transformerNotationWordHighlight({
matchAlgorithm: 'v3',
}),
{
name: 'vuepress:add-class',
pre(node) {
addClassToHast(node, 'vp-code')
},
},
{
name: 'vuepress:clean-up',
pre(node) {
delete node.properties.tabindex
delete node.properties.style
},
},
{
name: 'shiki:inline-decorations',
preprocess(code, options) {
code = code.replace(decorationsRE, (match, decorations) => {
options.decorations ||= []
options.decorations.push(...JSON.parse(decorations))
return ''
})
return code
},
},
transformerRemoveNotationEscape(),
]
const vueRE = /-vue$/
export function getInlineTransformers({ attrs, lang, enabledTwoslash, whitespace, twoslash }: {
attrs: string
lang: string
enabledTwoslash: boolean
whitespace: boolean | WhitespacePosition
twoslash?: boolean | TransformerTwoslashOptions['twoslashOptions'] & VueSpecificOptions
}): ShikiTransformer[] {
const vPre = vueRE.test(lang) ? '' : 'v-pre'
const inlineTransformers: ShikiTransformer[] = [
transformerCompactLineOptions(attrsToLines(attrs)),
]
if (enabledTwoslash) {
const { compilerOptions, ...twoslashOptions } = isPlainObject(twoslash) ? twoslash : {}
const defaultOptions = defaultTwoslashOptions()
inlineTransformers.push(transformerTwoslash({
processHoverInfo(info) {
return defaultHoverInfoProcessor(info)
},
twoslashOptions: {
...defaultOptions,
...twoslashOptions,
compilerOptions: {
baseUrl: process.cwd(),
...compilerOptions,
},
},
}))
}
else {
inlineTransformers.push({
name: 'vuepress:v-pre',
pre(node) {
if (vPre)
node.properties['v-pre'] = ''
},
})
}
const position = resolveWhitespacePosition(attrs, whitespace)
if (position)
inlineTransformers.push(transformerRenderWhitespace({ position }))
return inlineTransformers
}