mirror of https://github.com/YunYouJun/valaxy
refactor: migrate shikijs to shiki
This commit is contained in:
parent
cd475a9c63
commit
485ae82cef
|
@ -37,6 +37,7 @@
|
|||
"instantsearch",
|
||||
"jiti",
|
||||
"lightgallery",
|
||||
"shiki",
|
||||
"twikoo",
|
||||
"unconfig",
|
||||
"unhead",
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
"devDependencies": {
|
||||
"@iconify-json/simple-icons": "^1.1.90",
|
||||
"nodemon": "^3.0.3",
|
||||
"vite": "^5.0.12",
|
||||
"vitepress": "1.0.0-rc.41"
|
||||
"vite": "^5.1.1",
|
||||
"vitepress": "1.0.0-rc.42"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -157,14 +157,14 @@ All icon names added to `config.unocss.safelist` will be ready for hot reloading
|
|||
:::
|
||||
|
||||
::: zh-CN
|
||||
基于 [Shikiji](https://shikiji.netlify.app/) 实现。
|
||||
基于 [Shiki](https://shiki.style) 实现。
|
||||
Valaxy 支持 `vue` 等语法高亮,拷贝代码,高亮其中某一行。
|
||||
|
||||
譬如:
|
||||
:::
|
||||
|
||||
::: en
|
||||
Based on [Shikiji](https://shikiji.netlify.app/).
|
||||
Based on [Shiki](https://shiki.style).
|
||||
Valaxy supports syntax highlighting for languages like `vue`, and also supports copying code and
|
||||
highlighting a particular line in the code block.
|
||||
|
||||
|
|
10
package.json
10
package.json
|
@ -56,18 +56,18 @@
|
|||
"prepare": "husky install"
|
||||
},
|
||||
"dependencies": {
|
||||
"c12": "^1.6.1"
|
||||
"c12": "^1.7.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@antfu/eslint-config": "2.6.4",
|
||||
"@iconify-json/logos": "^1.1.42",
|
||||
"@iconify-json/vscode-icons": "^1.1.33",
|
||||
"@microsoft/api-extractor": "^7.39.4",
|
||||
"@microsoft/api-extractor": "^7.40.1",
|
||||
"@types/debug": "^4.1.12",
|
||||
"@types/markdown-it-attrs": "^4.1.3",
|
||||
"@types/markdown-it-container": "^2.0.9",
|
||||
"@types/markdown-it-emoji": "^2.0.4",
|
||||
"@types/node": "^20.11.16",
|
||||
"@types/node": "^20.11.17",
|
||||
"@types/prompts": "^2.4.9",
|
||||
"@types/resolve": "^1.20.6",
|
||||
"@valaxyjs/devtools": "workspace:*",
|
||||
|
@ -78,7 +78,7 @@
|
|||
"eslint-plugin-cypress": "^2.15.1",
|
||||
"https-localhost": "^4.7.1",
|
||||
"husky": "^9.0.10",
|
||||
"lint-staged": "^15.2.1",
|
||||
"lint-staged": "^15.2.2",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"prompts": "^2.4.2",
|
||||
"rimraf": "^5.0.5",
|
||||
|
@ -86,7 +86,7 @@
|
|||
"stylelint-config-recommended-vue": "^1.5.0",
|
||||
"stylelint-config-standard-scss": "^13.0.0",
|
||||
"tsup": "^8.0.1",
|
||||
"tsx": "^4.7.0",
|
||||
"tsx": "^4.7.1",
|
||||
"typescript": "^5.3.3",
|
||||
"unbuild": "^2.0.0",
|
||||
"valaxy": "workspace:*",
|
||||
|
|
|
@ -34,6 +34,6 @@
|
|||
"devDependencies": {
|
||||
"typescript": "^5.3.3",
|
||||
"unbuild": "^2.0.0",
|
||||
"vite": "^5.0.12"
|
||||
"vite": "^5.1.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,6 +58,7 @@ export async function setupMarkdownPlugins(
|
|||
) {
|
||||
const mdOptions = options?.config.markdown || {}
|
||||
const theme = mdOptions.theme ?? defaultCodeTheme
|
||||
const hasSingleTheme = typeof theme === 'string' || 'name' in theme
|
||||
const siteConfig = options?.config.siteConfig || {}
|
||||
|
||||
if (mdOptions.preConfig)
|
||||
|
@ -70,8 +71,10 @@ export async function setupMarkdownPlugins(
|
|||
.use(preWrapperPlugin, { theme, siteConfig })
|
||||
.use(snippetPlugin, options?.userRoot)
|
||||
.use(containerPlugin, {
|
||||
hasSingleTheme,
|
||||
}, {
|
||||
...mdOptions.blocks,
|
||||
theme,
|
||||
...mdOptions?.container,
|
||||
})
|
||||
.use(cssI18nContainer, {
|
||||
languages: options?.config.siteConfig.languages,
|
||||
|
@ -123,7 +126,7 @@ export async function setupMarkdownPlugins(
|
|||
} as FrontmatterPluginOptions)
|
||||
.use(headersPlugin, {
|
||||
slugify,
|
||||
...mdOptions.headers,
|
||||
...(typeof mdOptions.headers === 'boolean' ? undefined : mdOptions.headers),
|
||||
} as HeadersPluginOptions)
|
||||
.use(sfcPlugin, {
|
||||
...mdOptions.sfc,
|
||||
|
|
|
@ -8,15 +8,14 @@ import {
|
|||
transformerNotationErrorLevel,
|
||||
transformerNotationFocus,
|
||||
transformerNotationHighlight,
|
||||
} from 'shikiji-transformers'
|
||||
import type { ShikijiTransformer } from 'shikiji'
|
||||
} from '@shikijs/transformers'
|
||||
import type { ShikiTransformer } from 'shiki'
|
||||
import {
|
||||
addClassToHast,
|
||||
bundledLanguages,
|
||||
getHighlighter,
|
||||
isPlaintext as isPlainLang,
|
||||
isSpecialLang,
|
||||
} from 'shikiji'
|
||||
} from 'shiki'
|
||||
import type { Logger } from 'vite'
|
||||
import type { MarkdownOptions, ThemeOptions } from '../types'
|
||||
|
||||
|
@ -67,15 +66,15 @@ export async function highlight(
|
|||
|
||||
const highlighter = await getHighlighter({
|
||||
themes:
|
||||
(typeof theme === 'string' || 'name' in theme)
|
||||
? [theme]
|
||||
: [theme.light, theme.dark],
|
||||
typeof theme === 'object' && 'light' in theme && 'dark' in theme
|
||||
? [theme.light, theme.dark]
|
||||
: [theme],
|
||||
langs: [...Object.keys(bundledLanguages), ...(options.languages || [])],
|
||||
langAlias: options.languageAlias,
|
||||
})
|
||||
|
||||
await options?.shikijiSetup?.(highlighter)
|
||||
const transformers: ShikijiTransformer[] = [
|
||||
await options?.shikiSetup?.(highlighter)
|
||||
const transformers: ShikiTransformer[] = [
|
||||
transformerNotationDiff(),
|
||||
transformerNotationFocus({
|
||||
classActiveLine: 'has-focus',
|
||||
|
@ -113,7 +112,7 @@ export async function highlight(
|
|||
|
||||
if (lang) {
|
||||
const langLoaded = highlighter.getLoadedLanguages().includes(lang as any)
|
||||
if (!langLoaded && !isPlainLang(lang) && !isSpecialLang(lang)) {
|
||||
if (!langLoaded && !isSpecialLang(lang)) {
|
||||
logger.warn(
|
||||
c.yellow(
|
||||
`\nThe language '${lang}' is not loaded, falling back to '${
|
||||
|
@ -148,13 +147,6 @@ export async function highlight(
|
|||
return s
|
||||
}
|
||||
|
||||
const fillEmptyHighlightedLine = (s: string) => {
|
||||
return s.replace(
|
||||
/(<span class="line highlighted">)(<\/span>)/g,
|
||||
'$1<wbr>$2',
|
||||
)
|
||||
}
|
||||
|
||||
str = removeMustache(str).trimEnd()
|
||||
|
||||
const highlighted = highlighter.codeToHtml(str, {
|
||||
|
@ -169,19 +161,37 @@ export async function highlight(
|
|||
node.properties['v-pre'] = ''
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'valaxy:empty-line',
|
||||
code(hast) {
|
||||
hast.children.forEach((span) => {
|
||||
if (
|
||||
span.type === 'element'
|
||||
&& span.tagName === 'span'
|
||||
&& Array.isArray(span.properties.class)
|
||||
&& span.properties.class.includes('line')
|
||||
&& span.children.length === 0
|
||||
) {
|
||||
span.children.push({
|
||||
type: 'element',
|
||||
tagName: 'wbr',
|
||||
properties: {},
|
||||
children: [],
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
},
|
||||
...userTransformers,
|
||||
],
|
||||
meta: {
|
||||
__raw: attrs,
|
||||
},
|
||||
...(typeof theme === 'string' || 'name' in theme
|
||||
? { theme }
|
||||
: {
|
||||
themes: theme,
|
||||
defaultColor: false,
|
||||
}),
|
||||
...(typeof theme === 'object' && 'light' in theme && 'dark' in theme
|
||||
? { themes: theme, defaultColor: false }
|
||||
: { theme }),
|
||||
})
|
||||
|
||||
return fillEmptyHighlightedLine(restoreMustache(highlighted))
|
||||
return restoreMustache(highlighted)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -111,11 +111,11 @@ const defaultBlocksOptions: ContainerOptions = {
|
|||
},
|
||||
}
|
||||
|
||||
export function containerPlugin(md: MarkdownIt, options: ContainerOptions = {}) {
|
||||
export function containerPlugin(md: MarkdownIt, options: Options, containerOptions: ContainerOptions = {}) {
|
||||
Object.keys(defaultBlocksOptions).forEach((optionKey) => {
|
||||
const option: BlockItem = {
|
||||
...defaultBlocksOptions[optionKey as keyof Blocks],
|
||||
...(options[optionKey as keyof Blocks] || {}),
|
||||
...(containerOptions[optionKey as keyof Blocks] || {}),
|
||||
}
|
||||
|
||||
md.use(...createContainer(optionKey, option))
|
||||
|
@ -135,7 +135,7 @@ export function containerPlugin(md: MarkdownIt, options: ContainerOptions = {})
|
|||
})
|
||||
}
|
||||
|
||||
function createCodeGroup(options: ContainerOptions): ContainerArgs {
|
||||
function createCodeGroup(options: Options): ContainerArgs {
|
||||
return [
|
||||
container,
|
||||
'code-group',
|
||||
|
@ -177,9 +177,7 @@ function createCodeGroup(options: ContainerOptions): ContainerArgs {
|
|||
}
|
||||
|
||||
return `<div class="vp-code-group${getAdaptiveThemeMarker(
|
||||
{
|
||||
theme: options.theme!,
|
||||
},
|
||||
options,
|
||||
)}"><div class="tabs">${tabs}</div><div class="blocks">\n`
|
||||
}
|
||||
return `</div></div>\n`
|
||||
|
|
|
@ -4,6 +4,7 @@ import type { SiteConfig } from 'valaxy/types'
|
|||
import type { ThemeOptions } from '../../types'
|
||||
|
||||
export interface Options {
|
||||
hasSingleTheme: boolean
|
||||
theme: ThemeOptions
|
||||
siteConfig?: SiteConfig
|
||||
}
|
||||
|
@ -19,16 +20,7 @@ export function extractLang(info: string) {
|
|||
}
|
||||
|
||||
export function getAdaptiveThemeMarker(options: Options) {
|
||||
const { theme } = options
|
||||
const hasSingleTheme = typeof theme === 'string' || 'name' in theme
|
||||
let marker = ''
|
||||
if (hasSingleTheme) {
|
||||
marker = ' va-adaptive-theme'
|
||||
const themeName = typeof theme === 'string' ? theme : theme.name
|
||||
const isDark = themeName.includes('dark') || themeName.includes('night')
|
||||
marker = isDark ? ' dark' : ' light'
|
||||
}
|
||||
return marker
|
||||
return options.hasSingleTheme ? '' : ' vp-adaptive-theme'
|
||||
}
|
||||
|
||||
export function extractTitle(info: string, html = false) {
|
||||
|
|
|
@ -4,10 +4,10 @@ import type {
|
|||
BuiltinTheme,
|
||||
Highlighter,
|
||||
LanguageInput,
|
||||
ShikijiTransformer,
|
||||
ShikiTransformer,
|
||||
ThemeRegistration
|
||||
,
|
||||
} from 'shikiji'
|
||||
} from 'shiki'
|
||||
import type anchorPlugin from 'markdown-it-anchor'
|
||||
|
||||
import type { KatexOptions } from 'katex'
|
||||
|
@ -26,7 +26,7 @@ import type { TocPluginOptions } from '@mdit-vue/plugin-toc'
|
|||
import type {
|
||||
ComponentPluginOptions,
|
||||
} from '@mdit-vue/plugin-component'
|
||||
import type { Blocks } from './plugins/markdown-it/container'
|
||||
import type { Blocks, ContainerOptions } from './plugins/markdown-it/container'
|
||||
|
||||
export type ThemeOptions =
|
||||
| ThemeRegistration
|
||||
|
@ -56,6 +56,8 @@ export interface MarkdownOptions {
|
|||
allowedAttributes?: string[]
|
||||
disable?: boolean
|
||||
}
|
||||
/* ==================== Syntax Highlighting ==================== */
|
||||
|
||||
/**
|
||||
* Custom theme for syntax highlighting.
|
||||
*
|
||||
|
@ -65,21 +67,21 @@ export interface MarkdownOptions {
|
|||
* @example { theme: { light: 'github-light', dark: 'github-dark' } }
|
||||
*
|
||||
* You can use an existing theme.
|
||||
* @see https://github.com/antfu/shikiji/blob/main/docs/themes.md#all-themes
|
||||
* @see https://shiki.style/themes
|
||||
* Or add your own theme.
|
||||
* @see https://github.com/antfu/shikiji/blob/main/docs/themes.md#load-custom-themes
|
||||
* @see https://shiki.style/guide/load-theme
|
||||
*/
|
||||
theme?: ThemeOptions
|
||||
/**
|
||||
* Languages for syntax highlighting.
|
||||
* @see https://github.com/antfu/shikiji/blob/main/docs/languages.md#all-themes
|
||||
* @see https://shiki.style/languages
|
||||
*/
|
||||
languages?: LanguageInput[]
|
||||
/**
|
||||
* Custom language aliases.
|
||||
*
|
||||
* @example { 'my-lang': 'js' }
|
||||
* @see https://github.com/antfu/shikiji/tree/main#custom-language-aliases
|
||||
* @see https://shiki.style/guide/load-lang#custom-language-aliases
|
||||
*/
|
||||
languageAlias?: Record<string, string>
|
||||
/**
|
||||
|
@ -93,23 +95,51 @@ export interface MarkdownOptions {
|
|||
defaultHighlightLang?: string
|
||||
/**
|
||||
* Transformers applied to code blocks
|
||||
* @see https://github.com/antfu/shikiji#hast-transformers
|
||||
* @see https://shiki.style/guide/transformers
|
||||
*/
|
||||
codeTransformers?: ShikijiTransformer[]
|
||||
codeTransformers?: ShikiTransformer[]
|
||||
/**
|
||||
* Setup Shikiji instance
|
||||
* Setup Shiki instance
|
||||
*/
|
||||
shikijiSetup?: (shikiji: Highlighter) => void | Promise<void>
|
||||
shikiSetup?: (shiki: Highlighter) => void | Promise<void>
|
||||
|
||||
/* ==================== Markdown It Plugins ==================== */
|
||||
// mdit-vue plugins
|
||||
/**
|
||||
* Options for `@mdit-vue/plugin-frontmatter`
|
||||
* @see https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-frontmatter
|
||||
*/
|
||||
frontmatter?: FrontmatterPluginOptions
|
||||
headers?: HeadersPluginOptions
|
||||
/**
|
||||
* Options for `@mdit-vue/plugin-headers`
|
||||
* @see https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-headers
|
||||
*/
|
||||
headers?: HeadersPluginOptions | boolean
|
||||
/**
|
||||
* Options for `@mdit-vue/plugin-sfc`
|
||||
* @see https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-sfc
|
||||
*/
|
||||
sfc?: SfcPluginOptions
|
||||
/**
|
||||
* Options for `@mdit-vue/plugin-toc`
|
||||
* @see https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-toc
|
||||
*/
|
||||
toc?: TocPluginOptions
|
||||
/**
|
||||
* Options for `markdown-it-container`
|
||||
* @see https://github.com/markdown-it/markdown-it-container
|
||||
*/
|
||||
container?: ContainerOptions
|
||||
/**
|
||||
* Custom block configurations based on `markdown-it-container`
|
||||
*/
|
||||
blocks?: Blocks
|
||||
/**
|
||||
* Options for `@mdit-vue/plugin-component`
|
||||
* @see https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-component
|
||||
*/
|
||||
component?: ComponentPluginOptions
|
||||
|
||||
/**
|
||||
* @see [markdown-it-image-figures](https://www.npmjs.com/package/markdown-it-image-figures)
|
||||
*/
|
||||
|
@ -124,10 +154,6 @@ export interface MarkdownOptions {
|
|||
* @see https://katex.org/docs/options.html
|
||||
*/
|
||||
katex?: KatexOptions
|
||||
/**
|
||||
* Custom block configurations
|
||||
*/
|
||||
blocks?: Blocks
|
||||
|
||||
externalLinks?: Record<string, string>
|
||||
/* lazyload?: {
|
||||
|
|
|
@ -65,7 +65,7 @@
|
|||
"dependencies": {
|
||||
"@antfu/utils": "^0.7.7",
|
||||
"@ctrl/tinycolor": "^4.0.3",
|
||||
"@iconify-json/carbon": "^1.1.28",
|
||||
"@iconify-json/carbon": "^1.1.29",
|
||||
"@iconify-json/ri": "^1.1.19",
|
||||
"@intlify/unplugin-vue-i18n": "^2.0.0",
|
||||
"@types/body-scroll-lock": "^3.1.2",
|
||||
|
@ -74,7 +74,7 @@
|
|||
"@unhead/schema-org": "^1.8.10",
|
||||
"@unhead/vue": "^1.8.10",
|
||||
"@valaxyjs/devtools": "workspace:*",
|
||||
"@vitejs/plugin-vue": "^5.0.3",
|
||||
"@vitejs/plugin-vue": "^5.0.4",
|
||||
"@vue/devtools-api": "^7.0.14",
|
||||
"@vueuse/core": "^10.7.2",
|
||||
"@vueuse/integrations": "^10.7.2",
|
||||
|
@ -113,20 +113,19 @@
|
|||
"pinia": "^2.1.7",
|
||||
"qrcode": "^1.5.3",
|
||||
"sass": "^1.70.0",
|
||||
"shikiji": "0.9.7",
|
||||
"shikiji-transformers": "0.9.7",
|
||||
"shiki": "^1.1.1",
|
||||
"star-markdown-css": "^0.4.2",
|
||||
"unconfig": "^0.3.11",
|
||||
"unocss": "^0.58.4",
|
||||
"unocss": "^0.58.5",
|
||||
"unplugin-vue-components": "^0.26.0",
|
||||
"unplugin-vue-router": "^0.7.0",
|
||||
"vanilla-lazyload": "^17.8.5",
|
||||
"vite": "^5.0.12",
|
||||
"vanilla-lazyload": "^17.8.8",
|
||||
"vite": "^5.1.1",
|
||||
"vite-plugin-vue-devtools": "^7.0.14",
|
||||
"vite-plugin-vue-layouts": "0.11.0",
|
||||
"vite-ssg": "0.23.6",
|
||||
"vite-ssg-sitemap": "0.6.1",
|
||||
"vue": "^3.4.15",
|
||||
"vue": "^3.4.18",
|
||||
"vue-i18n": "^9.9.1",
|
||||
"vue-router": "^4.2.5",
|
||||
"yargs": "^17.7.2"
|
||||
|
|
1809
pnpm-lock.yaml
1809
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue