|
1 | 1 | import type { ShikiTransformer } from "shiki"; |
2 | 2 |
|
3 | | -const showLineNumbers = (): ShikiTransformer => { |
| 3 | +interface ShowLineNumbersOptions { |
| 4 | + /** |
| 5 | + * Always show line numbers regardless of meta properties |
| 6 | + * @default false |
| 7 | + */ |
| 8 | + activateByDefault?: boolean; |
| 9 | +} |
| 10 | + |
| 11 | +const showLineNumbers = ( |
| 12 | + options: ShowLineNumbersOptions = {}, |
| 13 | +): ShikiTransformer => { |
| 14 | + const { activateByDefault = false } = options; |
| 15 | + |
4 | 16 | return { |
5 | 17 | name: "AddLineNumbers", |
6 | 18 | pre(node) { |
7 | 19 | const rawMeta = this.options.meta?.__raw; |
8 | | - const addLineNumbers = rawMeta?.includes("lineNumbers") || false; |
| 20 | + const hasLineNumbersMeta = rawMeta?.includes("lineNumbers") ?? false; |
| 21 | + const addLineNumbers = activateByDefault || hasLineNumbersMeta; |
9 | 22 |
|
10 | 23 | if (!addLineNumbers) { |
11 | 24 | return; |
12 | 25 | } |
13 | 26 |
|
14 | 27 | const existingClass = node.properties.class; |
| 28 | + const className = "shiki-line-numbers"; |
| 29 | + |
15 | 30 | if (Array.isArray(existingClass)) { |
16 | | - existingClass.push("shiki-line-numbers"); |
| 31 | + if (!existingClass.includes(className)) { |
| 32 | + existingClass.push(className); |
| 33 | + } |
17 | 34 | } else if (typeof existingClass === "string") { |
18 | | - node.properties.class = `${existingClass} shiki-line-numbers`; |
| 35 | + const classes = existingClass.split(" "); |
| 36 | + if (!classes.includes(className)) { |
| 37 | + node.properties.class = `${existingClass} ${className}`; |
| 38 | + } |
19 | 39 | } else { |
20 | | - node.properties.class = "shiki-line-numbers"; |
| 40 | + node.properties.class = [className]; |
21 | 41 | } |
22 | 42 | }, |
23 | 43 | }; |
|
0 commit comments