Skip to content

Commit

Permalink
feat: support passing raw theme object on generation
Browse files Browse the repository at this point in the history
  • Loading branch information
antfu committed Aug 27, 2023
1 parent 8587830 commit 03db739
Show file tree
Hide file tree
Showing 13 changed files with 95 additions and 33 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,7 @@ console.log(root)
}
]
}
]
]s
}
]
}
Expand Down
5 changes: 4 additions & 1 deletion packages/shikiji-compact/index.cjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
module.exports.getHighlighter = async (...args) => {
async function getHighlighter(...args) {
const { getHighlighter } = await import('./dist/index.mjs')
return getHighlighter(...args)
}

module.exports = getHighlighter
module.exports.getHighlighter = getHighlighter
31 changes: 21 additions & 10 deletions packages/shikiji-compact/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
import type { BuiltinLanguage, BuiltinTheme, BundledHighlighterOptions, CodeToHastOptions, CodeToThemedTokensOptions, LineOption, StringLiteralUnion, ThemedToken } from 'shikiji'
import { bundledLanguages, bundledThemes, getHighlighter as getShikiji } from 'shikiji'
import type { BuiltinLanguage, BuiltinTheme, CodeToHastOptions, CodeToThemedTokensOptions, MaybeGetter, ThemeInput, ThemedToken } from 'shikiji'
import { bundledLanguages, bundledThemes, getHighlighter as getShikiji, toShikiTheme } from 'shikiji'
import type { ThemeRegistration } from '../../shikiji/dist/core.mjs'
import type { AnsiToHtmlOptions, HighlighterOptions } from './types'

export const BUNDLED_LANGUAGES = bundledLanguages
export const BUNDLED_THEMES = bundledThemes

export * from './stub'
export * from './types'

export interface AnsiToHtmlOptions {
theme?: StringLiteralUnion<BuiltinTheme>
lineOptions?: LineOption[]
}

export interface HighlighterOptions extends BundledHighlighterOptions<BuiltinLanguage, BuiltinTheme> {
theme?: BuiltinTheme
}
export { toShikiTheme } from 'shikiji'

export async function getHighlighter(options: HighlighterOptions = {}) {
const themes = options.themes || []
Expand Down Expand Up @@ -75,3 +71,18 @@ export async function getHighlighter(options: HighlighterOptions = {}) {
},
}
}

export type Highlighter = ReturnType<typeof getHighlighter>

export async function loadTheme(theme: BuiltinTheme | ThemeInput): Promise<ThemeRegistration> {
if (typeof theme === 'string')
return toShikiTheme(await bundledThemes[theme]().then(r => r.default))
else
return toShikiTheme(await normalizeGetter(theme))
}

async function normalizeGetter<T>(p: MaybeGetter<T>): Promise<T> {
return Promise.resolve(typeof p === 'function' ? (p as any)() : p).then(r => r.default || r)
}

export default getHighlighter
17 changes: 17 additions & 0 deletions packages/shikiji-compact/src/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import type { BuiltinLanguage, BuiltinTheme, BundledHighlighterOptions, LanguageRegistration, LineOption, StringLiteralUnion, ThemeRegistration } from 'shikiji'

export interface AnsiToHtmlOptions {
theme?: StringLiteralUnion<BuiltinTheme>
lineOptions?: LineOption[]
}

export interface HighlighterOptions extends BundledHighlighterOptions<BuiltinLanguage, BuiltinTheme> {
theme?: BuiltinTheme
}

export interface IThemeRegistration extends ThemeRegistration {}

export interface ILanguageRegistration extends LanguageRegistration {}

export type Lang = StringLiteralUnion<BuiltinLanguage>
export type Theme = StringLiteralUnion<BuiltinTheme>
8 changes: 1 addition & 7 deletions packages/shikiji-compact/test/types.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { expect, expectTypeOf, test } from 'vitest'
import { expect, test } from 'vitest'
import * as shiki from 'shiki'
import * as shikiji from '../src/index'

Expand All @@ -18,8 +18,6 @@ test('run', async () => {
expect(s.getLoadedThemes()).toEqual(sj.getLoadedThemes())
expect(s.getLoadedLanguages()).toEqual(sj.getLoadedLanguages())

expectTypeOf(s.codeToHtml).toMatchTypeOf(sj.codeToHtml)

expect(sj.codeToThemedTokens('const a = 1', 'javascript'))
.toEqual(s.codeToThemedTokens('const a = 1', 'javascript'))

Expand All @@ -41,7 +39,6 @@ test('run', async () => {
expect.soft(keysDiff).toMatchInlineSnapshot(`
[
"ansiToThemedTokens",
"getTheme",
"getBackgroundColor",
"getForegroundColor",
"setColorReplacements",
Expand All @@ -55,10 +52,7 @@ test('run', async () => {
expect.soft(exportsDiff).toMatchInlineSnapshot(`
[
"FontStyle",
"default",
"loadTheme",
"renderToHtml",
"toShikiTheme",
]
`)
})
7 changes: 5 additions & 2 deletions packages/shikiji/src/core/bundle-factory.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { BundledHighlighterOptions, CodeToHastOptions, CodeToThemedTokensOptions, CodeToTokensWithThemesOptions, HighlighterCoreOptions, HighlighterGeneric, LanguageInput, MaybeArray, RequireKeys, SpecialLanguage, ThemeInput } from '../types'
import type { BundledHighlighterOptions, CodeToHastOptions, CodeToThemedTokensOptions, CodeToTokensWithThemesOptions, HighlighterCoreOptions, HighlighterGeneric, LanguageInput, MaybeArray, RequireKeys, SpecialLanguage, ThemeInput, ThemeRegistration, ThemeRegistrationRaw } from '../types'
import { isSpecialLang, toArray } from './utils'
import { getHighlighterCore } from './highlighter'

Expand Down Expand Up @@ -68,7 +68,10 @@ export function createdBundledHighlighter<BundledLangs extends string, BundledTh
export function createSingletonShorthands<L extends string, T extends string >(getHighlighter: GetHighlighterFactory<L, T>) {
let _shiki: ReturnType<typeof getHighlighter>

async function _getHighlighter(options: { theme: MaybeArray<T>; lang: MaybeArray<L | SpecialLanguage> }) {
async function _getHighlighter(options: {
theme: MaybeArray<T | ThemeRegistration | ThemeRegistrationRaw>
lang: MaybeArray<L | SpecialLanguage>
}) {
if (!_shiki) {
_shiki = getHighlighter({
themes: toArray(options.theme),
Expand Down
6 changes: 3 additions & 3 deletions packages/shikiji/src/core/context.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { HighlighterCoreOptions, LanguageInput, MaybeGetter, ShikiContext, ThemeInput } from '../types'
import type { HighlighterCoreOptions, LanguageInput, MaybeGetter, ShikiContext, ThemeInput, ThemeRegistration } from '../types'
import { createOnigScanner, createOnigString, loadWasm } from '../oniguruma'
import { Registry } from './registry'
import { Resolver } from './resolver'
Expand Down Expand Up @@ -48,14 +48,14 @@ export async function getShikiContext(options: HighlighterCoreOptions = {}): Pro
return _lang
}

function getTheme(name: string) {
function getTheme(name: string | ThemeRegistration) {
const _theme = _registry.getTheme(name!)
if (!_theme)
throw new Error(`[shikiji] Theme \`${name}\` not found, you may need to load it first`)
return _theme
}

function setTheme(name: string) {
function setTheme(name: string | ThemeRegistration) {
const theme = getTheme(name)
_registry.setTheme(theme)
const colorMap = _registry.getColorMap()
Expand Down
3 changes: 3 additions & 0 deletions packages/shikiji/src/core/highlighter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ export async function getHighlighterCore(options: HighlighterCoreOptions = {}):

loadLanguage: context.loadLanguage,
loadTheme: context.loadTheme,

getTheme: context.getTheme,

getLoadedThemes: context.getLoadedThemes,
getLoadedLanguages: context.getLoadedLanguages,
}
Expand Down
2 changes: 2 additions & 0 deletions packages/shikiji/src/core/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ export { loadWasm } from '../oniguruma'
export * from './context'
export * from './highlighter'
export * from './bundle-factory'

export { toShikiTheme } from './normalize'
6 changes: 3 additions & 3 deletions packages/shikiji/src/core/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,14 @@ export class Registry extends TextMateRegistry {
if (typeof theme === 'string')
return this._resolvedThemes[theme]
else
return theme
return this.loadTheme(theme)
}

public loadTheme(theme: ThemeRegistration | ThemeRegistrationRaw) {
public loadTheme(theme: ThemeRegistration | ThemeRegistrationRaw): ThemeRegistration {
const _theme = toShikiTheme(theme)
if (_theme.name)
this._resolvedThemes[_theme.name] = _theme
return theme
return _theme
}

public getLoadedThemes() {
Expand Down
15 changes: 9 additions & 6 deletions packages/shikiji/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,12 @@ export type StringLiteralUnion<T extends U, U = string> = T | (U & Nothing)
export type ResolveBundleKey<T extends string> = never extends T ? string : T

export interface ShikiContext {
setTheme(name: string): {
setTheme(name: string | ThemeRegistration | ThemeRegistrationRaw): {
theme: ThemeRegistration
colorMap: string[]
}

getTheme(name: string): ThemeRegistration
getTheme(name: string | ThemeRegistration | ThemeRegistrationRaw): ThemeRegistration
getLangGrammar(name: string): IGrammar

getLoadedThemes(): string[]
Expand Down Expand Up @@ -67,6 +67,9 @@ export interface HighlighterGeneric<BundledLangKeys extends string, BundledTheme

loadTheme(...themes: (ThemeInput | BundledThemeKeys)[]): Promise<void>
loadLanguage(...langs: (LanguageInput | BundledLangKeys | SpecialLanguage)[]): Promise<void>

getTheme(name: string | ThemeRegistration | ThemeRegistrationRaw): ThemeRegistration

getLoadedLanguages(): string[]
getLoadedThemes(): string[]
}
Expand Down Expand Up @@ -109,7 +112,7 @@ export interface LanguageRegistration extends IRawGrammar {

export interface CodeToThemedTokensOptions<Languages = string, Themes = string> {
lang?: Languages | SpecialLanguage
theme?: Themes
theme?: Themes | ThemeRegistration | ThemeRegistrationRaw
/**
* Include explanation of why a token is given a color.
*
Expand Down Expand Up @@ -144,11 +147,11 @@ export interface CodeToTokensWithThemesOptions<Languages = string, Themes = stri
* }
* ```
*/
themes: Partial<Record<string, Themes>>
themes: Partial<Record<string, Themes | ThemeRegistration | ThemeRegistrationRaw>>
}

export interface CodeOptionsSingleTheme<Themes = string> {
theme: Themes
theme: Themes | ThemeRegistration | ThemeRegistrationRaw
}

export interface CodeOptionsMultipleThemes<Themes = string> {
Expand All @@ -174,7 +177,7 @@ export interface CodeOptionsMultipleThemes<Themes = string> {
*
* @see https://github.com/antfu/shikiji#lightdark-dual-themes
*/
themes: Partial<Record<string, Themes>>
themes: Partial<Record<string, Themes | ThemeRegistration | ThemeRegistrationRaw>>

/**
* The default theme applied to the code (via inline `color` style).
Expand Down
20 changes: 20 additions & 0 deletions packages/shikiji/test/core.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { getHighlighterCore } from '../src/core'

import js from '../src/assets/langs/javascript'
import nord from '../dist/themes/nord.mjs'
import mtp from '../dist/themes/material-theme-palenight.mjs'

// @ts-expect-error no-types
import onig from '../dist/onig.mjs'
Expand Down Expand Up @@ -109,4 +110,23 @@ describe('errors', () => {
await expect(() => shiki.codeToHtml('console.log("Hi")', { lang: 'abc', theme: 'nord' }))
.toThrowErrorMatchingInlineSnapshot('"[shikiji] Language `abc` not found, you may need to load it first"')
})

it('highlight with raw theme registation', async () => {
const shiki = await getHighlighterCore({
themes: [nord],
langs: [js as any],
loadWasm: {
instantiator: obj => WebAssembly.instantiate(onig, obj),
},
})

const code = shiki.codeToHtml('console.log("Hi")', { lang: 'javascript', theme: mtp })
expect.soft(code)
.toMatchInlineSnapshot('"<pre class=\\"shiki material-theme-palenight\\" style=\\"background-color:#292D3E;color:#A6ACCD\\" tabindex=\\"0\\"><code><span class=\\"line\\"><span style=\\"color:#A6ACCD\\">console</span><span style=\\"color:#89DDFF\\">.</span><span style=\\"color:#82AAFF\\">log</span><span style=\\"color:#A6ACCD\\">(</span><span style=\\"color:#89DDFF\\">\\"</span><span style=\\"color:#C3E88D\\">Hi</span><span style=\\"color:#89DDFF\\">\\"</span><span style=\\"color:#A6ACCD\\">)</span></span></code></pre>"')

expect.soft(shiki.getLoadedThemes()).toContain('material-theme-palenight')

const code2 = shiki.codeToHtml('console.log("Hi")', { lang: 'javascript', theme: 'material-theme-palenight' })
expect.soft(code2).toBe(code)
})
})
6 changes: 6 additions & 0 deletions vitest.config.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { fileURLToPath } from 'node:url'
import { defineConfig } from 'vitest/config'

// @ts-expect-error no types
Expand All @@ -7,6 +8,11 @@ export default defineConfig({
plugins: [
wasmPlugin(),
],
resolve: {
alias: {
shikiji: fileURLToPath(new URL('./packages/shikiji/src/index.ts', import.meta.url)),
},
},
test: {
server: {
deps: {
Expand Down

0 comments on commit 03db739

Please sign in to comment.