Skip to content

Commit f096f57

Browse files
authored
feat: add rehype and markdown-it plugins (#12)
1 parent 3d24591 commit f096f57

22 files changed

+1125
-69
lines changed

README.md

-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@ An ESM-focused rewrite of [shiki](https://github.com/shikijs/shiki), a beautiful
1212
- [Bundles languages/themes composedly](#fine-grained-bundle).
1313
- [Light/Dark themes support](#lightdark-dual-themes).
1414
- [`hast` support](#codetohast).
15-
- Zero-dependencies.
16-
- Simplified APIs.
1715
- [List of breaking changes from shiki](#breaking-changes-from-shiki).
1816
- Please don't hate me Pine 😜 ([What's Next?](#whats-next))
1917

package.json

+1-3
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,6 @@
2929
"esno": "^0.17.0",
3030
"fast-glob": "^3.3.1",
3131
"fs-extra": "^11.1.1",
32-
"hast-util-to-html": "^9.0.0",
33-
"hastscript": "^8.0.0",
3432
"jsonc-parser": "^3.2.0",
3533
"lint-staged": "^13.2.3",
3634
"pnpm": "^8.6.12",
@@ -44,7 +42,7 @@
4442
"shikiji": "workspace:^",
4543
"simple-git-hooks": "^2.9.0",
4644
"typescript": "^5.1.6",
47-
"unbuild": "^1.2.1",
45+
"unbuild": "^2.0.0-rc.0",
4846
"vite": "^4.4.9",
4947
"vitest": "^0.34.1",
5048
"vscode-oniguruma": "^1.7.0",
+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# markdown-it-shikiji
2+
3+
[Markdown It](https://markdown-it.github.io/) plugin for [shikiji](https://github.com/antfu/shikiji)
4+
5+
## Install
6+
7+
```bash
8+
npm i -D markdown-it-shikiji
9+
```
10+
11+
## Usage
12+
13+
```ts
14+
import MarkdownIt from 'markdown-it'
15+
import Shikiji from 'markdown-it-shikiji'
16+
17+
const md = MarkdownIt()
18+
19+
md.use(await Shikiji({
20+
themes: {
21+
light: 'vitesse-light',
22+
dark: 'vitesse-dark',
23+
}
24+
}))
25+
```
26+
27+
## Features
28+
29+
### Line Highlight
30+
31+
In addition to the features of `shikiji`, this plugin also supports line highlighting. You can add `{1,3-4}` after the language name to highlight the specified lines. For example:
32+
33+
~~~md
34+
# Hello World
35+
36+
```js {1,3-4}
37+
console.log('line1') // highlighted
38+
console.log('line2')
39+
console.log('line3') // highlighted
40+
console.log('line4') // highlighted
41+
```
42+
~~~
43+
44+
## License
45+
46+
MIT
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
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+
],
14+
})
+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
{
2+
"name": "markdown-it-shikiji",
3+
"type": "module",
4+
"version": "0.5.1",
5+
"description": "markdown-it integration for shikiji",
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/markdown-it-shikiji"
13+
},
14+
"bugs": "https://github.com/antfu/shikiji/issues",
15+
"keywords": [
16+
"shiki",
17+
"markdown-it"
18+
],
19+
"sideEffects": false,
20+
"exports": {
21+
".": {
22+
"types": "./dist/index.d.mts",
23+
"default": "./dist/index.mjs"
24+
}
25+
},
26+
"main": "./dist/index.mjs",
27+
"module": "./dist/index.mjs",
28+
"types": "./dist/index.d.mts",
29+
"files": [
30+
"dist"
31+
],
32+
"scripts": {
33+
"build": "unbuild",
34+
"dev": "unbuild --stub",
35+
"prepublishOnly": "nr build"
36+
},
37+
"dependencies": {
38+
"markdown-it": "^13.0.1",
39+
"shikiji": "^0.5.1"
40+
},
41+
"devDependencies": {
42+
"@types/markdown-it": "^13.0.0"
43+
}
44+
}
+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import type MarkdownIt from 'markdown-it'
2+
import { bundledLanguages, getHighlighter } from 'shikiji'
3+
import type { BuiltinLanguage, BuiltinTheme, CodeOptionsThemes, CodeToHastOptions, Highlighter, LanguageInput } from 'shikiji'
4+
import { parseHighlightLines } from '../../shared/line-highlight'
5+
6+
export type MarkdownItShikijiOptions = MarkdownItShikijiSetupOptions & {
7+
/**
8+
* Language names to include.
9+
*
10+
* @default Object.keys(bundledLanguages)
11+
*/
12+
langs?: Array<LanguageInput | BuiltinLanguage>
13+
}
14+
15+
export type MarkdownItShikijiSetupOptions = CodeOptionsThemes<BuiltinTheme> & {
16+
/**
17+
* Add `highlighted` class to lines defined in after codeblock
18+
*
19+
* @default true
20+
*/
21+
highlightLines?: boolean | string
22+
}
23+
24+
function setup(markdownit: MarkdownIt, highlighter: Highlighter, options: MarkdownItShikijiSetupOptions) {
25+
const {
26+
highlightLines = true,
27+
} = options
28+
29+
markdownit.options.highlight = (code, lang = 'text', attrs) => {
30+
const codeOptions: CodeToHastOptions = {
31+
...options,
32+
lang,
33+
}
34+
35+
codeOptions.transforms ||= {}
36+
37+
if (highlightLines) {
38+
const lines = parseHighlightLines(attrs)
39+
if (lines) {
40+
const className = highlightLines === true
41+
? 'highlighted'
42+
: highlightLines
43+
44+
codeOptions.transforms.line = (node, line) => {
45+
if (lines.includes(line))
46+
node.properties.class += ` ${className}`
47+
return node
48+
}
49+
}
50+
}
51+
52+
codeOptions.transforms.code = (node) => {
53+
node.properties.class = `language-${lang}`
54+
}
55+
56+
return highlighter.codeToHtml(
57+
code,
58+
codeOptions,
59+
)
60+
}
61+
}
62+
63+
export default async function markdownItShikiji(options: MarkdownItShikijiOptions) {
64+
const themeNames = ('themes' in options ? Object.values(options.themes) : [options.theme]).filter(Boolean) as BuiltinTheme[]
65+
const highlighter = await getHighlighter({
66+
themes: themeNames,
67+
langs: options.langs || Object.keys(bundledLanguages) as BuiltinLanguage[],
68+
})
69+
70+
return function (markdownit: MarkdownIt) {
71+
setup(markdownit, highlighter, options)
72+
}
73+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Hello
2+
3+
…world!
4+
5+
```js {3-4}
6+
console.log('it works!')
7+
8+
const a = 1
9+
console.log(a)
10+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<h1>Hello</h1>
2+
<p>…world!</p>
3+
<pre class="shiki shiki-themes vitesse-light vitesse-dark" style="background-color:#ffffff;--shiki-dark-bg:#121212;color:#393a34;--shiki-dark:#dbd7caee" tabindex="0"><code class="language-js"><span class="line"><span style="color:#B07D48;--shiki-dark:#BD976A">console</span><span style="color:#999999;--shiki-dark:#666666">.</span><span style="color:#59873A;--shiki-dark:#80A665">log</span><span style="color:#999999;--shiki-dark:#666666">(</span><span style="color:#B5695999;--shiki-dark:#C98A7D99">'</span><span style="color:#B56959;--shiki-dark:#C98A7D">it works!</span><span style="color:#B5695999;--shiki-dark:#C98A7D99">'</span><span style="color:#999999;--shiki-dark:#666666">)</span></span>
4+
<span class="line"></span>
5+
<span class="line highlighted"><span style="color:#AB5959;--shiki-dark:#CB7676">const</span><span style="color:#B07D48;--shiki-dark:#BD976A"> a</span><span style="color:#999999;--shiki-dark:#666666"> =</span><span style="color:#2F798A;--shiki-dark:#4C9A91"> 1</span></span>
6+
<span class="line highlighted"><span style="color:#B07D48;--shiki-dark:#BD976A">console</span><span style="color:#999999;--shiki-dark:#666666">.</span><span style="color:#59873A;--shiki-dark:#80A665">log</span><span style="color:#999999;--shiki-dark:#666666">(</span><span style="color:#B07D48;--shiki-dark:#BD976A">a</span><span style="color:#999999;--shiki-dark:#666666">)</span></span>
7+
<span class="line"></span></code></pre>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import fs from 'node:fs/promises'
2+
import { expect, test } from 'vitest'
3+
import MarkdownIt from 'markdown-it'
4+
import Shikiji from '../src'
5+
6+
test('run', async () => {
7+
const md = MarkdownIt()
8+
md.use(await Shikiji({
9+
themes: {
10+
light: 'vitesse-light',
11+
dark: 'vitesse-dark',
12+
},
13+
}))
14+
15+
const result = md.render(await fs.readFile(new URL('./fixtures/a.md', import.meta.url), 'utf-8'))
16+
17+
expect(result).toMatchFileSnapshot('./fixtures/a.out.html')
18+
})

packages/rehype-shikiji/README.md

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# rehype-shikiji
2+
3+
[rehype](https://github.com/rehypejs/rehype) plugin for [shikiji](https://github.com/antfu/shikiji).
4+
5+
## Install
6+
7+
```bash
8+
npm i -D rehype-shikiji
9+
```
10+
11+
## Usage
12+
13+
```ts
14+
import { unified } from 'unified'
15+
import remarkParse from 'remark-parse'
16+
import remarkRehype from 'remark-rehype'
17+
import rehypeStringify from 'rehype-stringify'
18+
import rehypeShikiji from 'rehype-shikiji'
19+
import { expect, test } from 'vitest'
20+
21+
const file = await unified()
22+
.use(remarkParse)
23+
.use(remarkRehype)
24+
.use(rehypeShikiji, {
25+
// or `theme` for a single theme
26+
themes: {
27+
light: 'vitesse-light',
28+
dark: 'vitesse-dark',
29+
}
30+
})
31+
.use(rehypeStringify)
32+
.process(await fs.readFile('./input.md'))
33+
```
34+
35+
36+
## Features
37+
38+
### Line Highlight
39+
40+
In addition to the features of `shikiji`, this plugin also supports line highlighting. You can add `{1,3-4}` after the language name to highlight the specified lines. For example:
41+
42+
~~~md
43+
# Hello World
44+
45+
```js {1,3-4}
46+
console.log('line1') // highlighted
47+
console.log('line2')
48+
console.log('line3') // highlighted
49+
console.log('line4') // highlighted
50+
```
51+
~~~
52+
53+
## License
54+
55+
MIT
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
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+
],
14+
})

packages/rehype-shikiji/package.json

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
{
2+
"name": "rehype-shikiji",
3+
"type": "module",
4+
"version": "0.5.1",
5+
"description": "rehype integration for shikiji",
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/rethype-shikiji"
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+
"default": "./dist/index.mjs"
24+
}
25+
},
26+
"main": "./dist/index.mjs",
27+
"module": "./dist/index.mjs",
28+
"types": "./dist/index.d.mts",
29+
"files": [
30+
"dist"
31+
],
32+
"scripts": {
33+
"build": "unbuild",
34+
"dev": "unbuild --stub",
35+
"prepublishOnly": "nr build"
36+
},
37+
"dependencies": {
38+
"@types/hast": "^3.0.0",
39+
"hast-util-to-string": "^2.0.0",
40+
"shikiji": "^0.5.1",
41+
"unified": "^11.0.1",
42+
"unist-util-visit": "^5.0.0"
43+
},
44+
"devDependencies": {
45+
"rehype-stringify": "^9.0.4",
46+
"remark-parse": "^10.0.2",
47+
"remark-rehype": "^10.1.0"
48+
}
49+
}

0 commit comments

Comments
 (0)