Skip to content
This repository has been archived by the owner on Feb 7, 2024. It is now read-only.

Commit

Permalink
feat(rehype): custom parseMetaString (#17)
Browse files Browse the repository at this point in the history
Co-authored-by: Anthony Fu <anthonyfu117@hotmail.com>
  • Loading branch information
AntzyMo and antfu authored Nov 2, 2023
1 parent 8bb4f18 commit 3aae9d5
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 6 deletions.
29 changes: 26 additions & 3 deletions packages/rehype-shikiji/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { bundledLanguages, getHighlighter } from 'shikiji'
import { toString } from 'hast-util-to-string'
import { visit } from 'unist-util-visit'
import type { Plugin } from 'unified'
import type { Root } from 'hast'
import type { Element, Root } from 'hast'
import { parseHighlightLines } from '../../shared/line-highlight'

export type RehypeShikijiOptions = CodeOptionsThemes<BuiltinTheme> & {
Expand All @@ -20,11 +20,28 @@ export type RehypeShikijiOptions = CodeOptionsThemes<BuiltinTheme> & {
* @default true
*/
highlightLines?: boolean | string

/**
* Extra meta data to pass to the highlighter
*/
meta?: Record<string, any>

/**
* Custom meta string parser
* Return an object to merge with `meta`
*/
parseMetaString?: (
metaString: string,
node: Element,
tree: Root
) => Record<string, any> | undefined | null
}

const rehypeShikiji: Plugin<[RehypeShikijiOptions], Root> = function (options = {} as any) {
const {
highlightLines = true,
parseMetaString,
...rest
} = options

const prefix = 'language-'
Expand Down Expand Up @@ -64,12 +81,18 @@ const rehypeShikiji: Plugin<[RehypeShikijiOptions], Root> = function (options =
return

const code = toString(head as any)
const attrs = (head.data as any)?.meta
const meta = parseMetaString?.(attrs, node, tree) || {}

const codeOptions: CodeToHastOptions = {
...options,
...rest,
lang: language.slice(prefix.length),
meta: {
...rest.meta,
...meta,
},
}

const attrs = (head.data as any)?.meta
if (highlightLines && typeof attrs === 'string') {
const lines = parseHighlightLines(attrs)
if (lines) {
Expand Down
2 changes: 1 addition & 1 deletion packages/rehype-shikiji/test/fixtures/a.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

…world!

```js {3-4}
```js {3-4} fileName=test
console.log('it works!')

const a = 1
Expand Down
2 changes: 1 addition & 1 deletion packages/rehype-shikiji/test/fixtures/a.out.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<h1>Hello</h1>
<p>…world!</p>
<pre class="shiki vitesse-light" style="background-color:#ffffff;color:#393a34" tabindex="0" lang="js"><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">it works!</span><span style="color:#B5695999">'</span><span style="color:#999999">)</span></span>
<pre class="shiki vitesse-light" style="background-color:#ffffff;color:#393a34" tabindex="0" lang="js" fileName="test"><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">it works!</span><span style="color:#B5695999">'</span><span style="color:#999999">)</span></span>
<span class="line"></span>
<span class="line highlighted"><span style="color:#AB5959">const</span><span style="color:#B07D48"> a</span><span style="color:#999999"> =</span><span style="color:#2F798A"> 1</span></span>
<span class="line highlighted"><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:#B07D48">a</span><span style="color:#999999">)</span></span>
Expand Down
9 changes: 9 additions & 0 deletions packages/rehype-shikiji/test/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,15 @@ it('run', async () => {
.use(remarkRehype)
.use(rehypeShikiji, {
theme: 'vitesse-light',
parseMetaString: (str) => {
return Object.fromEntries(str.split(' ').reduce((prev: [string, boolean | string][], curr: string) => {
const [key, value] = curr.split('=')
const isNormalKey = /^[A-Za-z0-9]+$/.test(key)
if (isNormalKey)
prev = [...prev, [key, value || true]]
return prev
}, []))
},
})
.use(rehypeStringify)
.process(await fs.readFile(new URL('./fixtures/a.md', import.meta.url)))
Expand Down
1 change: 1 addition & 0 deletions packages/shikiji/src/core/renderer-hast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ export function tokensToHast(
style: options.rootStyle || `background-color:${options.bg};color:${options.fg}`,
tabindex: '0',
lang: options.lang,
...options.meta,
},
children: [],
}
Expand Down
9 changes: 8 additions & 1 deletion packages/shikiji/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,9 +215,14 @@ export type CodeOptionsThemes<Themes extends string = string> =
| CodeOptionsSingleTheme<Themes>
| CodeOptionsMultipleThemes<Themes>

export interface CodeOptionsMeta {
meta?: Record<string, any>
}

export type CodeToHastOptions<Languages extends string = string, Themes extends string = string> =
& CodeToHastOptionsCommon<Languages>
& CodeOptionsThemes<Themes>
& CodeOptionsMeta

export interface ThemeRegistrationRaw extends IRawTheme {

Expand Down Expand Up @@ -280,7 +285,7 @@ export interface HastTransformers {
token?: (hast: Element, line: number, col: number, lineElement: Element) => Element | void
}

export interface HtmlRendererOptions {
export interface HtmlRendererOptionsCommon {
lang?: string
langId?: string
fg?: string
Expand Down Expand Up @@ -308,6 +313,8 @@ export interface HtmlRendererOptions {
mergeWhitespaces?: boolean
}

export type HtmlRendererOptions = HtmlRendererOptionsCommon & CodeToHastOptions

export interface ThemedTokenScopeExplanation {
scopeName: string
themeMatches: any[]
Expand Down

0 comments on commit 3aae9d5

Please sign in to comment.