Skip to content

Commit ea2d6f3

Browse files
committed
feat: wip shikiji-compact package
1 parent 1dc1616 commit ea2d6f3

File tree

7 files changed

+244
-0
lines changed

7 files changed

+244
-0
lines changed

packages/shikiji-compact/README.md

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# shikiji-compact
2+
3+
Compactible build of `shikiji` to align with `shiki`.
4+
5+
> Work in progress. It's not 100% compatible yet, but feedback is welcome :)
6+
7+
## Install
8+
9+
```bash
10+
npm i -D shikiji-compact
11+
```
12+
13+
Or set the alias
14+
15+
```json
16+
{
17+
"dependencies": {
18+
"shiki": "npm:shikiji-compact@0.6"
19+
}
20+
}
21+
```
22+
23+
## License
24+
25+
MIT
+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { defineBuildConfig } from 'unbuild'
2+
3+
export default defineBuildConfig({
4+
entries: [
5+
'src/index.ts',
6+
],
7+
declaration: true,
8+
rollup: {
9+
emitCJS: false,
10+
},
11+
externals: [
12+
'hast',
13+
'shikiji',
14+
],
15+
})

packages/shikiji-compact/index.cjs

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module.exports.getHighlighter = async (...args) => {
2+
const { getHighlighter } = await import('./dist/index.mjs')
3+
return getHighlighter(...args)
4+
}

packages/shikiji-compact/package.json

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
{
2+
"name": "shikiji-compact",
3+
"type": "module",
4+
"version": "0.6.1",
5+
"description": "Shikiji with shiki compactible API",
6+
"author": "Anthony Fu <anthonyfu117@hotmail.com>",
7+
"license": "MIT",
8+
"homepage": "https://github.com/antfu/shikiji#readme",
9+
"repository": {
10+
"type": "git",
11+
"url": "git+https://github.com/antfu/shikiji.git",
12+
"directory": "packages/shikiji-compact"
13+
},
14+
"bugs": "https://github.com/antfu/shikiji/issues",
15+
"keywords": [
16+
"shiki",
17+
"rehype"
18+
],
19+
"sideEffects": false,
20+
"exports": {
21+
".": {
22+
"types": "./dist/index.d.mts",
23+
"require": "./index.cjs",
24+
"default": "./dist/index.mjs"
25+
}
26+
},
27+
"main": "./dist/index.mjs",
28+
"module": "./dist/index.mjs",
29+
"types": "./dist/index.d.mts",
30+
"files": [
31+
"dist",
32+
"index.cjs"
33+
],
34+
"scripts": {
35+
"build": "unbuild",
36+
"dev": "unbuild --stub",
37+
"prepublishOnly": "nr build"
38+
},
39+
"dependencies": {
40+
"shikiji": "workspace:*"
41+
}
42+
}

packages/shikiji-compact/src/index.ts

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import type { BuiltinLanguage, BuiltinTheme, BundledHighlighterOptions, CodeToHastOptions, CodeToThemedTokensOptions, LineOption, StringLiteralUnion, ThemedToken } from 'shikiji'
2+
import { bundledLanguages, bundledThemes, getHighlighter as getShikiji } from 'shikiji'
3+
4+
export const BUNDLED_LANGUAGES = bundledLanguages
5+
export const BUNDLED_THEMES = bundledThemes
6+
7+
export * from './stub'
8+
9+
export interface AnsiToHtmlOptions {
10+
theme?: StringLiteralUnion<BuiltinTheme>
11+
lineOptions?: LineOption[]
12+
}
13+
14+
export interface HighlighterOptions extends BundledHighlighterOptions<BuiltinLanguage, BuiltinTheme> {
15+
theme?: BuiltinTheme
16+
}
17+
18+
export async function getHighlighter(options: HighlighterOptions = {}) {
19+
const themes = options.themes || []
20+
const langs = options.langs || []
21+
22+
if (options.theme)
23+
themes.unshift(options.theme)
24+
if (!themes.length)
25+
themes.push('nord')
26+
27+
if (!langs.length)
28+
langs.push(...Object.keys(bundledLanguages) as BuiltinLanguage[])
29+
30+
const shikiji = await getShikiji({
31+
...options,
32+
themes,
33+
langs,
34+
})
35+
36+
const defaultTheme = shikiji.getLoadedThemes()[0]
37+
38+
function codeToThemedTokens(code: string, options: CodeToThemedTokensOptions<BuiltinLanguage, BuiltinTheme>): ThemedToken[][]
39+
function codeToThemedTokens(code: string, lang: BuiltinLanguage, theme?: BuiltinTheme): ThemedToken[][]
40+
function codeToThemedTokens(code: string, lang: BuiltinLanguage | CodeToThemedTokensOptions<BuiltinLanguage, BuiltinTheme>, theme?: BuiltinTheme): ThemedToken[][] {
41+
if (typeof lang === 'string') {
42+
return shikiji.codeToThemedTokens(code, {
43+
lang,
44+
theme: (theme || defaultTheme) as BuiltinTheme,
45+
})
46+
}
47+
return shikiji.codeToThemedTokens(code, lang)
48+
}
49+
50+
function codeToHtml(code: string, options: Partial<CodeToHastOptions<BuiltinLanguage, BuiltinTheme>>): string
51+
function codeToHtml(code: string, lang: BuiltinLanguage, theme?: BuiltinTheme): string
52+
function codeToHtml(code: string, lang: any, theme?: BuiltinTheme): string {
53+
if (typeof lang === 'string') {
54+
return shikiji.codeToHtml(code, {
55+
lang,
56+
theme: (theme || defaultTheme),
57+
})
58+
}
59+
return shikiji.codeToHtml(code, {
60+
...lang,
61+
theme: (lang.theme || defaultTheme),
62+
})
63+
}
64+
65+
return {
66+
...shikiji,
67+
codeToThemedTokens,
68+
codeToHtml,
69+
ansiToHtml(code: string, options?: AnsiToHtmlOptions) {
70+
return shikiji.codeToHtml(code, {
71+
lang: 'ansi',
72+
...options,
73+
theme: options?.theme || defaultTheme,
74+
})
75+
},
76+
}
77+
}

packages/shikiji-compact/src/stub.ts

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
const _warned = new Set<string>()
2+
function warnOnce(message: string) {
3+
if (!_warned.has(message)) {
4+
console.warn(`[shikiji-compact]: ${message}`)
5+
_warned.add(message)
6+
}
7+
}
8+
function stubFunction(name: string) {
9+
return () => {
10+
warnOnce(`\`${name}\` is a stub function in \`shikiji-compact\` and does nothing.`)
11+
}
12+
}
13+
14+
export const setCDN = stubFunction('setCDN')
15+
export const setOnigasmWASM = stubFunction('setOnigasmWASM')
16+
export const setWasm = stubFunction('setWasm')
17+
export const setColorReplacements = stubFunction('setColorReplacements')
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import { expect, expectTypeOf, test } from 'vitest'
2+
import * as shiki from 'shiki'
3+
import * as shikiji from '../src/index'
4+
5+
test('run', async () => {
6+
const s = await shiki.getHighlighter({
7+
theme: 'nord',
8+
langs: ['javascript'],
9+
})
10+
11+
const sj = await shikiji.getHighlighter({
12+
theme: 'nord',
13+
langs: ['javascript'],
14+
})
15+
16+
const group = [s, sj]
17+
18+
expect(s.getLoadedThemes()).toEqual(sj.getLoadedThemes())
19+
expect(s.getLoadedLanguages()).toEqual(sj.getLoadedLanguages())
20+
21+
expectTypeOf(s.codeToHtml).toMatchTypeOf(sj.codeToHtml)
22+
23+
expect(sj.codeToThemedTokens('const a = 1', 'javascript'))
24+
.toEqual(s.codeToThemedTokens('const a = 1', 'javascript'))
25+
26+
group.forEach((h) => {
27+
h.codeToHtml('const a = 1', 'javascript')
28+
h.codeToHtml('const a = 1', 'javascript', 'nord')
29+
})
30+
31+
s.codeToHtml('const a = 1', { lang: 'javascript' })
32+
sj.codeToHtml('const a = 1', { lang: 'javascript' })
33+
34+
s.ansiToHtml('const a = 1', { theme: 'nord' })
35+
sj.ansiToHtml('const a = 1', { theme: 'nord' })
36+
37+
const shikiKeys = Object.keys(s)
38+
const shikijiKeys = Object.keys(sj)
39+
const keysDiff = shikiKeys.filter(k => !shikijiKeys.includes(k))
40+
41+
expect.soft(keysDiff).toMatchInlineSnapshot(`
42+
[
43+
"ansiToThemedTokens",
44+
"getTheme",
45+
"getBackgroundColor",
46+
"getForegroundColor",
47+
"setColorReplacements",
48+
]
49+
`)
50+
51+
const shikiExports = Object.keys(shiki)
52+
const shikijiExports = Object.keys(shikiji)
53+
const exportsDiff = shikiExports.filter(k => !shikijiExports.includes(k))
54+
55+
expect.soft(exportsDiff).toMatchInlineSnapshot(`
56+
[
57+
"FontStyle",
58+
"default",
59+
"loadTheme",
60+
"renderToHtml",
61+
"toShikiTheme",
62+
]
63+
`)
64+
})

0 commit comments

Comments
 (0)