Skip to content

Commit

Permalink
feat: wip shikiji-compact package
Browse files Browse the repository at this point in the history
  • Loading branch information
antfu committed Aug 27, 2023
1 parent 1dc1616 commit ea2d6f3
Show file tree
Hide file tree
Showing 7 changed files with 244 additions and 0 deletions.
25 changes: 25 additions & 0 deletions packages/shikiji-compact/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# shikiji-compact

Compactible build of `shikiji` to align with `shiki`.

> Work in progress. It's not 100% compatible yet, but feedback is welcome :)
## Install

```bash
npm i -D shikiji-compact
```

Or set the alias

```json
{
"dependencies": {
"shiki": "npm:shikiji-compact@0.6"
}
}
```

## License

MIT
15 changes: 15 additions & 0 deletions packages/shikiji-compact/build.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { defineBuildConfig } from 'unbuild'

export default defineBuildConfig({
entries: [
'src/index.ts',
],
declaration: true,
rollup: {
emitCJS: false,
},
externals: [
'hast',
'shikiji',
],
})
4 changes: 4 additions & 0 deletions packages/shikiji-compact/index.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module.exports.getHighlighter = async (...args) => {
const { getHighlighter } = await import('./dist/index.mjs')
return getHighlighter(...args)
}
42 changes: 42 additions & 0 deletions packages/shikiji-compact/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"name": "shikiji-compact",
"type": "module",
"version": "0.6.1",
"description": "Shikiji with shiki compactible API",
"author": "Anthony Fu <anthonyfu117@hotmail.com>",
"license": "MIT",
"homepage": "https://github.com/antfu/shikiji#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/antfu/shikiji.git",
"directory": "packages/shikiji-compact"
},
"bugs": "https://github.com/antfu/shikiji/issues",
"keywords": [
"shiki",
"rehype"
],
"sideEffects": false,
"exports": {
".": {
"types": "./dist/index.d.mts",
"require": "./index.cjs",
"default": "./dist/index.mjs"
}
},
"main": "./dist/index.mjs",
"module": "./dist/index.mjs",
"types": "./dist/index.d.mts",
"files": [
"dist",
"index.cjs"
],
"scripts": {
"build": "unbuild",
"dev": "unbuild --stub",
"prepublishOnly": "nr build"
},
"dependencies": {
"shikiji": "workspace:*"
}
}
77 changes: 77 additions & 0 deletions packages/shikiji-compact/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import type { BuiltinLanguage, BuiltinTheme, BundledHighlighterOptions, CodeToHastOptions, CodeToThemedTokensOptions, LineOption, StringLiteralUnion, ThemedToken } from 'shikiji'
import { bundledLanguages, bundledThemes, getHighlighter as getShikiji } from 'shikiji'

export const BUNDLED_LANGUAGES = bundledLanguages
export const BUNDLED_THEMES = bundledThemes

export * from './stub'

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

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

export async function getHighlighter(options: HighlighterOptions = {}) {
const themes = options.themes || []
const langs = options.langs || []

if (options.theme)
themes.unshift(options.theme)
if (!themes.length)
themes.push('nord')

if (!langs.length)
langs.push(...Object.keys(bundledLanguages) as BuiltinLanguage[])

const shikiji = await getShikiji({
...options,
themes,
langs,
})

const defaultTheme = shikiji.getLoadedThemes()[0]

function codeToThemedTokens(code: string, options: CodeToThemedTokensOptions<BuiltinLanguage, BuiltinTheme>): ThemedToken[][]
function codeToThemedTokens(code: string, lang: BuiltinLanguage, theme?: BuiltinTheme): ThemedToken[][]
function codeToThemedTokens(code: string, lang: BuiltinLanguage | CodeToThemedTokensOptions<BuiltinLanguage, BuiltinTheme>, theme?: BuiltinTheme): ThemedToken[][] {
if (typeof lang === 'string') {
return shikiji.codeToThemedTokens(code, {
lang,
theme: (theme || defaultTheme) as BuiltinTheme,
})
}
return shikiji.codeToThemedTokens(code, lang)
}

function codeToHtml(code: string, options: Partial<CodeToHastOptions<BuiltinLanguage, BuiltinTheme>>): string
function codeToHtml(code: string, lang: BuiltinLanguage, theme?: BuiltinTheme): string
function codeToHtml(code: string, lang: any, theme?: BuiltinTheme): string {
if (typeof lang === 'string') {
return shikiji.codeToHtml(code, {
lang,
theme: (theme || defaultTheme),
})
}
return shikiji.codeToHtml(code, {
...lang,
theme: (lang.theme || defaultTheme),
})
}

return {
...shikiji,
codeToThemedTokens,
codeToHtml,
ansiToHtml(code: string, options?: AnsiToHtmlOptions) {
return shikiji.codeToHtml(code, {
lang: 'ansi',
...options,
theme: options?.theme || defaultTheme,
})
},
}
}
17 changes: 17 additions & 0 deletions packages/shikiji-compact/src/stub.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
const _warned = new Set<string>()
function warnOnce(message: string) {
if (!_warned.has(message)) {
console.warn(`[shikiji-compact]: ${message}`)
_warned.add(message)
}
}
function stubFunction(name: string) {
return () => {
warnOnce(`\`${name}\` is a stub function in \`shikiji-compact\` and does nothing.`)
}
}

export const setCDN = stubFunction('setCDN')
export const setOnigasmWASM = stubFunction('setOnigasmWASM')
export const setWasm = stubFunction('setWasm')
export const setColorReplacements = stubFunction('setColorReplacements')
64 changes: 64 additions & 0 deletions packages/shikiji-compact/test/types.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { expect, expectTypeOf, test } from 'vitest'
import * as shiki from 'shiki'
import * as shikiji from '../src/index'

test('run', async () => {
const s = await shiki.getHighlighter({
theme: 'nord',
langs: ['javascript'],
})

const sj = await shikiji.getHighlighter({
theme: 'nord',
langs: ['javascript'],
})

const group = [s, sj]

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'))

group.forEach((h) => {
h.codeToHtml('const a = 1', 'javascript')
h.codeToHtml('const a = 1', 'javascript', 'nord')
})

s.codeToHtml('const a = 1', { lang: 'javascript' })
sj.codeToHtml('const a = 1', { lang: 'javascript' })

s.ansiToHtml('const a = 1', { theme: 'nord' })
sj.ansiToHtml('const a = 1', { theme: 'nord' })

const shikiKeys = Object.keys(s)
const shikijiKeys = Object.keys(sj)
const keysDiff = shikiKeys.filter(k => !shikijiKeys.includes(k))

expect.soft(keysDiff).toMatchInlineSnapshot(`
[
"ansiToThemedTokens",
"getTheme",
"getBackgroundColor",
"getForegroundColor",
"setColorReplacements",
]
`)

const shikiExports = Object.keys(shiki)
const shikijiExports = Object.keys(shikiji)
const exportsDiff = shikiExports.filter(k => !shikijiExports.includes(k))

expect.soft(exportsDiff).toMatchInlineSnapshot(`
[
"FontStyle",
"default",
"loadTheme",
"renderToHtml",
"toShikiTheme",
]
`)
})

0 comments on commit ea2d6f3

Please sign in to comment.