Skip to content

Commit 85a4ff9

Browse files
committed
feat(core): support object style htmlStyle in themed token, support new htmlAttrs
1 parent bba452c commit 85a4ff9

File tree

7 files changed

+61
-19
lines changed

7 files changed

+61
-19
lines changed

packages/core/src/highlight/code-to-hast.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,11 +171,14 @@ export function tokensToHast(
171171
let tokenNode: Element = {
172172
type: 'element',
173173
tagName: 'span',
174-
properties: {},
174+
properties: {
175+
...token.htmlAttrs,
176+
},
175177
children: [{ type: 'text', value: token.content }],
176178
}
177179

178-
const style = token.htmlStyle || stringifyTokenStyle(getTokenStyleObject(token))
180+
// TODO: Shiki2: Deprecate `string` type of `htmlStyle`
181+
const style = stringifyTokenStyle(token.htmlStyle || getTokenStyleObject(token))
179182
if (style)
180183
tokenNode.properties.style = style
181184

packages/core/src/highlight/code-to-tokens.ts

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { CodeToTokensOptions, ShikiInternal, ThemedToken, ThemedTokenWithVariants, TokensResult } from '@shikijs/types'
22
import { ShikiError } from '../../../types/src/error'
3-
import { applyColorReplacements, getTokenStyleObject, resolveColorReplacements, stringifyTokenStyle } from '../utils'
3+
import { applyColorReplacements, getTokenStyleObject, resolveColorReplacements } from '../utils'
44
import { codeToTokensBase } from './code-to-tokens-base'
55
import { codeToTokensWithThemes } from './code-to-tokens-themes'
66

@@ -103,27 +103,23 @@ function mergeToken(
103103

104104
// Get all style keys, for themes that missing some style, we put `inherit` to override as needed
105105
const styleKeys = new Set(styles.flatMap(t => Object.keys(t)))
106-
const mergedStyles = styles.reduce((acc, cur, idx) => {
106+
const mergedStyles: Record<string, string> = {}
107+
108+
styles.forEach((cur, idx) => {
107109
for (const key of styleKeys) {
108110
const value = cur[key] || 'inherit'
109111

110112
if (idx === 0 && defaultColor) {
111-
acc[key] = value
113+
mergedStyles[key] = value
112114
}
113115
else {
114116
const keyName = key === 'color' ? '' : key === 'background-color' ? '-bg' : `-${key}`
115117
const varKey = cssVariablePrefix + variantsOrder[idx] + (key === 'color' ? '' : keyName)
116-
if (acc[key])
117-
acc[key] += `;${varKey}:${value}`
118-
else
119-
acc[key] = `${varKey}:${value}`
118+
mergedStyles[varKey] = value
120119
}
121120
}
122-
return acc
123-
}, {} as Record<string, string>)
121+
})
124122

125-
token.htmlStyle = defaultColor
126-
? stringifyTokenStyle(mergedStyles)
127-
: Object.values(mergedStyles).join(';')
123+
token.htmlStyle = mergedStyles
128124
return token
129125
}

packages/core/src/utils.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,9 @@ export function getTokenStyleObject(token: TokenStyles): Record<string, string>
210210
return styles
211211
}
212212

213-
export function stringifyTokenStyle(token: Record<string, string>): string {
213+
export function stringifyTokenStyle(token: string | Record<string, string>): string {
214+
if (typeof token === 'string')
215+
return token
214216
return Object.entries(token).map(([key, value]) => `${key}:${value}`).join(';')
215217
}
216218

packages/shiki/test/out/multiple-themes.html

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/shiki/test/themes.test.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,9 @@ function toggleTheme() {
183183
})
184184

185185
expect(code1)
186-
.toContain('font-style:italic;--shiki-dark-font-style:inherit')
186+
.toContain('font-style:italic')
187+
expect(code1)
188+
.toContain('--shiki-dark-font-style:inherit')
187189

188190
const code2 = await codeToHtml(input, {
189191
lang: 'js',
@@ -195,7 +197,9 @@ function toggleTheme() {
195197
})
196198

197199
expect(code2)
198-
.toContain('font-style:inherit;--shiki-light-font-style:italic')
200+
.toContain('font-style:inherit')
201+
expect(code2)
202+
.toContain('--shiki-light-font-style:italic')
199203
})
200204

201205
it('should not have empty style', async () => {
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { expect, it } from 'vitest'
2+
import { createHighlighter } from '../src'
3+
4+
it('transformers tokens', async () => {
5+
const shiki = await createHighlighter({
6+
themes: ['vitesse-light'],
7+
langs: ['javascript'],
8+
})
9+
10+
expect(shiki.codeToHtml('console.log', {
11+
lang: 'js',
12+
theme: 'vitesse-light',
13+
transformers: [
14+
{
15+
name: 'test',
16+
tokens(tokens) {
17+
for (const line of tokens) {
18+
for (const token of line) {
19+
token.htmlAttrs = { class: 'test' }
20+
if (typeof token.htmlStyle !== 'string') {
21+
token.htmlStyle ||= {}
22+
token.htmlStyle.display = 'block'
23+
}
24+
}
25+
}
26+
return tokens
27+
},
28+
},
29+
],
30+
}))
31+
.toMatchInlineSnapshot(`"<pre class="shiki vitesse-light" style="background-color:#ffffff;color:#393a34" tabindex="0"><code><span class="line"><span class="test" style="display:block">console</span><span class="test" style="display:block">.</span><span class="test" style="display:block">log</span></span></code></pre>"`)
32+
})

packages/types/src/tokens.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,13 @@ export interface TokenStyles {
143143
/**
144144
* Override with custom inline style for HTML renderer.
145145
* When specified, `color` and `fontStyle` will be ignored.
146+
* Prefer use object style for merging with other styles.
146147
*/
147-
htmlStyle?: string
148+
htmlStyle?: string | Record<string, string>
149+
/**
150+
* Extra HTML attributes for the token.
151+
*/
152+
htmlAttrs?: Record<string, string>
148153
}
149154

150155
export interface ThemedTokenWithVariants extends TokenBase {

0 commit comments

Comments
 (0)