-
-
Notifications
You must be signed in to change notification settings - Fork 382
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
138 additions
and
69 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import { bundledThemes } from '../themes' | ||
import { bundledLanguages, bundledLanguagesBase } from '../langs' | ||
import { getHighlighterCore } from '../core' | ||
import { getWasmInlined } from '../wasm' | ||
import type { BuiltinLanguages, BuiltinThemes, CodeToHtmlOptions, LanguageInput, PlainTextLanguage, ThemeInput } from '../types' | ||
import { isPlaintext } from '../core/utils' | ||
|
||
export interface HighlighterOptions { | ||
themes?: (ThemeInput | BuiltinThemes)[] | ||
langs?: (LanguageInput | BuiltinLanguages | PlainTextLanguage)[] | ||
} | ||
|
||
export type Highlighter = Awaited<ReturnType<typeof getHighlighter>> | ||
|
||
export async function getHighlighter(options: HighlighterOptions = {}) { | ||
function resolveLang(lang: LanguageInput | BuiltinLanguages | PlainTextLanguage): LanguageInput { | ||
if (typeof lang === 'string') { | ||
if (isPlaintext(lang)) | ||
return [] | ||
const bundle = bundledLanguages[lang as BuiltinLanguages] | ||
if (!bundle) | ||
throw new Error(`[shikiji] Language \`${lang}\` is not built-in.`) | ||
return bundle | ||
} | ||
return lang as LanguageInput | ||
} | ||
|
||
function resolveTheme(theme: ThemeInput | BuiltinThemes): ThemeInput { | ||
if (typeof theme === 'string') { | ||
const bundle = bundledThemes[theme] | ||
if (!bundle) | ||
throw new Error(`[shikiji] Theme \`${theme}\` is not built-in.`) | ||
return bundle | ||
} | ||
return theme | ||
} | ||
|
||
const _themes = (options.themes ?? ['nord']).map(resolveTheme) as ThemeInput[] | ||
|
||
const langs = (options.langs ?? Object.keys(bundledLanguagesBase) as BuiltinLanguages[]) | ||
.map(resolveLang) | ||
|
||
const core = await getHighlighterCore({ | ||
...options, | ||
themes: _themes, | ||
langs, | ||
loadWasm: getWasmInlined, | ||
}) | ||
|
||
return { | ||
...core, | ||
codeToHtml(code: string, options: CodeToHtmlOptions<BuiltinLanguages, BuiltinThemes> = {}) { | ||
return core.codeToHtml(code, options as CodeToHtmlOptions) | ||
}, | ||
loadLanguage(...langs: (LanguageInput | BuiltinLanguages | PlainTextLanguage)[]) { | ||
return core.loadLanguage(...langs.map(resolveLang)) | ||
}, | ||
loadTheme(...themes: (ThemeInput | BuiltinThemes)[]) { | ||
return core.loadTheme(...themes.map(resolveTheme)) | ||
}, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export * from './highlighter' | ||
export * from './singleton' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import type { BuiltinLanguages, BuiltinThemes, CodeToHtmlOptions, PlainTextLanguage, RequireKeys } from '../types' | ||
import { getHighlighter } from './highlighter' | ||
import type { Highlighter } from './highlighter' | ||
|
||
let _shiki: Promise<Highlighter> | ||
|
||
async function getShikiWithThemeLang(options: { theme: BuiltinThemes; lang: BuiltinLanguages | PlainTextLanguage }) { | ||
if (!_shiki) { | ||
_shiki = getHighlighter({ | ||
themes: [options.theme], | ||
langs: [options.lang], | ||
}) | ||
return _shiki | ||
} | ||
else { | ||
const s = await _shiki | ||
await Promise.all([ | ||
s.loadTheme(options.theme), | ||
s.loadLanguage(options.lang), | ||
]) | ||
return s | ||
} | ||
} | ||
|
||
/** | ||
* Shorthand for codeToHtml with auto-loaded theme and language. | ||
* A singleton highlighter it maintained internally. | ||
* | ||
* Differences from `shiki.codeToHtml()`, this function is async. | ||
*/ | ||
export async function codeToHtml(code: string, options: RequireKeys<CodeToHtmlOptions<BuiltinLanguages, BuiltinThemes>, 'theme' | 'lang'>) { | ||
const shiki = await getShikiWithThemeLang(options) | ||
return shiki.codeToHtml(code, options) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export function isPlaintext(lang: string | null | undefined) { | ||
return !lang || ['plaintext', 'txt', 'text'].includes(lang) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,64 +1,5 @@ | ||
import type { BuiltinLanguages, BuiltinThemes, CodeToHtmlOptions, LanguageInput, ThemeInput } from './types' | ||
import { bundledThemes } from './themes' | ||
import { bundledLanguages, bundledLanguagesBase } from './langs' | ||
import { getHighlighterCore } from './core' | ||
import { getWasmInlined } from './wasm' | ||
|
||
export * from './bundled' | ||
export * from './core' | ||
export * from './themes' | ||
export * from './langs' | ||
export * from './wasm' | ||
|
||
export interface HighlighterOptions { | ||
themes?: (ThemeInput | BuiltinThemes)[] | ||
langs?: (LanguageInput | BuiltinLanguages)[] | ||
} | ||
|
||
export type Highlighter = Awaited<ReturnType<typeof getHighlighter>> | ||
|
||
export async function getHighlighter(options: HighlighterOptions = {}) { | ||
function resolveLang(lang: LanguageInput | BuiltinLanguages): LanguageInput { | ||
if (typeof lang === 'string') { | ||
const bundle = bundledLanguages[lang] | ||
if (!bundle) | ||
throw new Error(`[shikiji] Language \`${lang}\` is not built-in.`) | ||
return bundle | ||
} | ||
return lang as LanguageInput | ||
} | ||
|
||
function resolveTheme(theme: ThemeInput | BuiltinThemes): ThemeInput { | ||
if (typeof theme === 'string') { | ||
const bundle = bundledThemes[theme] | ||
if (!bundle) | ||
throw new Error(`[shikiji] Theme \`${theme}\` is not built-in.`) | ||
return bundle | ||
} | ||
return theme | ||
} | ||
|
||
const _themes = (options.themes ?? ['nord']).map(resolveTheme) as ThemeInput[] | ||
|
||
const langs = (options.langs ?? Object.keys(bundledLanguagesBase) as BuiltinLanguages[]) | ||
.map(resolveLang) | ||
|
||
const core = await getHighlighterCore({ | ||
...options, | ||
themes: _themes, | ||
langs, | ||
loadWasm: getWasmInlined, | ||
}) | ||
|
||
return { | ||
...core, | ||
codeToHtml(code: string, options: CodeToHtmlOptions<BuiltinLanguages, BuiltinThemes> = {}) { | ||
return core.codeToHtml(code, options as CodeToHtmlOptions) | ||
}, | ||
loadLanguage(...langs: (LanguageInput | BuiltinLanguages)[]) { | ||
return core.loadLanguage(...langs.map(resolveLang)) | ||
}, | ||
loadTheme(...themes: (ThemeInput | BuiltinThemes)[]) { | ||
return core.loadTheme(...themes.map(resolveTheme)) | ||
}, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { describe, expect, it } from 'vitest' | ||
import { codeToHtml } from '../src' | ||
|
||
describe('should', () => { | ||
it('works', async () => { | ||
expect(await codeToHtml('console.log("hello")', { lang: 'js', theme: 'vitesse-light' })) | ||
.toMatchInlineSnapshot('"<pre class=\\"shiki vitesse-light\\" style=\\"background-color: #ffffff\\" tabindex=\\"0\\"><code><span class=\\"line\\"><span style=\\"color: #B07D48\\">console</span><span style=\\"color: #999999\\">.</span><span style=\\"color: #59873A\\">log</span><span style=\\"color: #999999\\">(</span><span style=\\"color: #B5695999\\">"</span><span style=\\"color: #B56959\\">hello</span><span style=\\"color: #B5695999\\">"</span><span style=\\"color: #999999\\">)</span></span></code></pre>"') | ||
|
||
expect(await codeToHtml('<div class="foo">bar</div>', { lang: 'html', theme: 'min-dark' })) | ||
.toMatchInlineSnapshot('"<pre class=\\"shiki min-dark\\" style=\\"background-color: #1f1f1f\\" tabindex=\\"0\\"><code><span class=\\"line\\"><span style=\\"color: #B392F0\\"><</span><span style=\\"color: #FFAB70\\">div</span><span style=\\"color: #B392F0\\"> class</span><span style=\\"color: #F97583\\">=</span><span style=\\"color: #FFAB70\\">"foo"</span><span style=\\"color: #B392F0\\">>bar</</span><span style=\\"color: #FFAB70\\">div</span><span style=\\"color: #B392F0\\">></span></span></code></pre>"') | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters