Skip to content

@shikijs/transformers

NPM versionNPM downloadsGitHub

shiki-processor 启发,为 Shiki 设计的常用转换器(Transformers)集合。

安装

sh
npm i -D @shikijs/transformers
sh
yarn add -D @shikijs/transformers
sh
pnpm add -D @shikijs/transformers
sh
bun add -D @shikijs/transformers
sh
deno add npm:@shikijs/transformers

使用方法

ts
import {
  
transformerNotationDiff
,
// ... } from '@shikijs/transformers' import {
codeToHtml
,
} from 'shiki' const
code
= `console.log('hello')`
const
html
= await
codeToHtml
(
code
, {
lang
: 'ts',
theme
: 'nord',
transformers
: [
transformerNotationDiff
(),
// ... ], })

无样式

转换器只应用到类,并不带有样式,你可以提供自己的 CSS 规则来样式化它们。

Match Algorithm

We found that the comment matching algorithm in v1 was sometimes not intuitive enough, and we are fixing it in a gradual manner. Starting from v1.29.0, we introduced a new matchAlgorithm option for most transformers, allowing you to switch between different matching algorithms. Currently, the default option is v1, which is the old algorithm, while v3 is the new algorithm. When Shiki v3 is released, the default will be v3.

ts
const html = await codeToHtml(code, {
  lang: 'ts',
  theme: 'nord',
  transformers: [
    transformerNotationDiff({
      matchAlgorithm: 'v3', 
    }),
  ],
})

matchAlgorithm: 'v1'

The matching algorithm mainly affects single-line comments. In v1, it counts the comment line as the first line, while in v3, it starts counting from the line with the comment:

ts
// [!code highlight:3]
console.log('highlighted')
console.log('highlighted')
console.log('not highlighted')

matchAlgorithm: 'v3'

In v3, the matching algorithm starts counting from the line below the comment:

ts
// [!code highlight:2]
console.log('highlighted')
console.log('highlighted')
console.log('not highlighted')

转换器

transformerNotationDiff

Use [!code ++] and [!code --] to mark added and removed lines.

md
```ts
console.log('hewwo') // [!code --]
console.log('hello') // [!code ++]
console.log('goodbye')
```

Rendered as (styled):

ts
console.log('hewwo')
console.log('hello')
console.log('goodbye')
  • // [!code ++] outputs: <span class="line diff add">
  • // [!code --] outputs: <span class="line diff remove">
  • The outer <pre> tag is changed to: <pre class="has-diff">
HTML output
html
<!-- 输出(为了清晰,已去除 style 属性) -->
<pre class="shiki has-diff"> <!-- 注意这里是 `has-diff` -->
  <code>
    <span class="line"></span>
    <span class="line"><span>function</span><span>()</span><span></span><span>{</span></span>
    <span class="line diff remove">  <!-- 注意这里是 `diff` 和 `remove` -->
      <span></span><span>console</span><span>.</span><span>log</span><span>(</span><span>&#39;</span><span>hewwo</span><span>&#39;</span><span>) </span>
    </span>
    <span class="line diff add">  <!-- 注意这里是 `diff` 和 `add` -->
      <span></span><span>console</span><span>.</span><span>log</span><span>(</span><span>&#39;</span><span>hello</span><span>&#39;</span><span>) </span>
    </span>
    <span class="line"><span></span><span>}</span></span>
    <span class="line"><span></span></span>
  </code>
</pre>

transformerNotationHighlight

使用 [!code highlight] 来高亮显示行:

md
```ts
console.log('Not highlighted')
console.log('Highlighted') // [!code highlight]
console.log('Not highlighted')
```

渲染成(已样式化):

ts
console.log('Not highlighted')
console.log('Highlighted')
console.log('Not highlighted')
  • // [!code highlight] 输出:<span class="line highlighted">
  • 外围的 <pre> 标签被修改为:<pre class="has-highlighted">

你也可以使用单个注释来高亮多行:

md
```ts
// [!code highlight:3]
console.log('Highlighted')
console.log('Highlighted')
console.log('Highlighted')
console.log('Not highlighted')
```

```ts
console.log('Not highlighted')
// [!code highlight:1]
console.log('Highlighted')
console.log('Not highlighted')
```

渲染为:

ts
console.log('Highlighted')
console.log('Highlighted')
console.log('Highlighted')
console.log('Not highlighted')
ts
console.log('Not highlighted')
console.log('Highlighted')
console.log('Not highlighted')

transformerNotationWordHighlight

Use [!code word:Hello] to highlight all instances of Hello in the subsequent code.

md
```ts
// [!code word:Hello]
const message = 'Hello World'
console.log(message) // prints Hello World
```

Rendered as (styled):

ts
const message = 'Hello World'
console.log(message) // prints Hello World

Output: matched words will become <span class="highlighted-word">Hello</span>

You can also specify how many times to highlight it, for example [!code word:Hello:2] will highlight the most recent Hello.

md
```ts
// [!code word:Hello:1]
const message = 'Hello World'
console.log(message) // prints Hello World
```

Rendered as:

ts
const message = 'Hello World'
console.log(message) // prints Hello World

transformerNotationFocus

Use [!code focus] to highlight lines:

md
```ts
console.log('Not focused');
console.log('Focused') // [!code focus]
console.log('Not focused');
```

Rendered as (styled):

ts
console.log('Not focused')
console.log('Focused')
console.log('Not focused')
  • Output: <span class="line focused">
  • The outer <pre> tag is modified to: <pre class="has-focused">

You can also use a single comment to highlight multiple lines:

md
```ts
// [!code focus:3]
console.log('Focused')
console.log('Focused')
console.log('Focused')
console.log('Not focused')
```

Rendered as:

ts
console.log('Focused')
console.log('Focused')
console.log('Focused')
console.log('Not focused')

transformerNotationErrorLevel

使用 [!code error][!code warning][!code info] 来标记行的错误、警告或信息级别。

md
```ts
console.log('没有错误或警告')
console.error('错误') // [!code error]
console.warn('警告') // [!code warning]
console.log('信息') // [!code info]
```
  • 输出:错误为 <span class="line highlighted error">
  • 输出:警告为 <span class="line highlighted warning">
  • 输出:信息为 <span class="line highlighted info">
  • 外围的 <pre> 标签被修改为:<pre class="has-highlighted">

加上一些额外的 CSS 规则,它们看起来可能像这样:

ts
console.log('没有错误或警告')
console.error('错误')
console.warn('警告')
console.log('信息')

transformerRenderWhitespace

将空白字符(Tab 和空格)渲染为单独的标签(具有 tabspace 类名)。

选项:

  • position'all' | 'boundary' | 'trailing' | 'leading',默认值为 'all'

结合一些额外的 CSS 规则,你可以让它看起来像这样:

js
function block( ) {
  space( )
		tab( ) 
}
示例 CSS
css
pre.shiki .tab,
pre.shiki .space {
  position: relative;
}

pre.shiki .tab::before {
  content: '';
  position: absolute;
  opacity: 0.3;
}

pre.shiki .space::before {
  content: '·';
  position: absolute;
  opacity: 0.3;
}

transformerRenderIndentGuides

将缩进渲染为单独的 span,类名为 indent

通过一些额外的 CSS 规则,你可以让它看起来像这样:

js
function func() {
  console.log(1);

  for (const i of []) {
    console.log(2);
  }
}
示例 CSS
css
pre.shiki .indent {
  display: inline-block;
  position: relative;
  left: var(--indent-offset);
}

pre.shiki .indent:empty {
  height: 1lh;
  vertical-align: bottom;
}

pre.shiki .indent::before {
  content: '';
  position: absolute;
  opacity: 0.15;
  width: 1px;
  height: 100%;
  background-color: currentColor;
}

transformerMetaHighlight

根据代码片段上提供的元字符串,高亮显示行。

md
```js {1,3-4}
console.log('1')
console.log('2')
console.log('3')
console.log('4')
```

渲染成 (已样式化):

js
console.log('1')
console.log('2')
console.log('3')
console.log('4')
  • 输出:包含的行为 <span class="line highlighted">

transformerMetaWordHighlight

根据代码片段中提供的元字符串,高亮显示词。

md
```js /Hello/
const msg = 'Hello World'
console.log(msg)
console.log(msg) // 打印 Hello World
```

渲染成 (已样式化):

js
const msg = 'Hello World'
console.log(msg) // 打印 Hello World

输出:匹配的词为 <span class="highlighted-word">Hello</span>


transformerCompactLineOptions

shiki 中删除对 shiki v0 的 lineOptions 的支持。


transformerRemoveLineBreak

删除 <span class="line"> 之间的换行符。这在你在 CSS 中将 .line 设置为 display: block 时可能有用。


transformerRemoveNotationEscape

// [\!code ...] 转换为 // [!code ...]

避免将转义符号语法渲染为字面量。


transformerStyleToClass

将 Shiki 的内联样式转换为唯一类名。

类名是根据样式对象的哈希值生成的,前缀/后缀由你提供。你可以在多个高亮处理过程中放置此转换器,然后在最后获取 CSS 以重用完全相同的样式。由于 Shiki 不生成 CSS,所以由你的集成决定如何提取和应用/打包 CSS。

例如:

ts
import { transformerStyleToClass } from '@shikijs/transformers'
import { codeToHtml } from 'shiki'

const toClass = transformerStyleToClass({ 
  classPrefix: '__shiki_',
})

const code = `console.log('hello')`
const html = await codeToHtml(code, {
  lang: 'ts',
  themes: {
    dark: 'vitesse-dark',
    light: 'vitesse-light',
  },
  defaultColor: false,
  transformers: [toClass], 
})

// 转换器实例暴露了一些方法用来获取 CSS
const css = toClass.getCSS()

// 在你的应用中使用 `html` 和 `css`

HTML 输出:

html
<pre class="shiki shiki-themes vitesse-dark vitesse-light __shiki_9knfln" tabindex="0"><code><span class="line">
  <span class="__shiki_14cn0u">console</span>
  <span class="__shiki_ps5uht">.</span>
  <span class="__shiki_1zrdwt">log</span>
  <span class="__shiki_ps5uht">(</span>
  <span class="__shiki_236mh3">'</span>
  <span class="__shiki_1g4r39">hello</span>
  <span class="__shiki_236mh3">'</span>
  <span class="__shiki_ps5uht">)</span>
</span></code></pre>

CSS 输出:

css
.__shiki_14cn0u {
  --shiki-dark: #bd976a;
  --shiki-light: #b07d48;
}
.__shiki_ps5uht {
  --shiki-dark: #666666;
  --shiki-light: #999999;
}
.__shiki_1zrdwt {
  --shiki-dark: #80a665;
  --shiki-light: #59873a;
}
.__shiki_236mh3 {
  --shiki-dark: #c98a7d77;
  --shiki-light: #b5695977;
}
.__shiki_1g4r39 {
  --shiki-dark: #c98a7d;
  --shiki-light: #b56959;
}
.__shiki_9knfln {
  --shiki-dark: #dbd7caee;
  --shiki-light: #393a34;
  --shiki-dark-bg: #121212;
  --shiki-light-bg: #ffffff;
}

transformerRemoveComments

从代码中移除注释。它通过检查内部语法标记元数据来判断该标记是否为注释。

此转换器需要 includeExplanation: true 才能生效。

ts
import { transformerRemoveComments } from '@shikijs/transformers'

const html = await codeToHtml(code, {
  lang: 'ts',
  includeExplanation: true, 
  transformers: [
    transformerRemoveComments(), 
  ],
})

选项:

  • removeEmptyLines:删除移除注释后变为空的行,默认值为 true

例如:

md
```js
// 这是一个注释
const x = 1 // 行内注释
/* 块注释 */
const y = 2

// 另一条注释
```

将渲染为:

js
const x = 1
const y = 2