Skip to content

Commit

Permalink
feat: add rehype and markdown-it plugins (#12)
Browse files Browse the repository at this point in the history
  • Loading branch information
antfu authored Aug 21, 2023
1 parent 3d24591 commit f096f57
Show file tree
Hide file tree
Showing 22 changed files with 1,125 additions and 69 deletions.
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ An ESM-focused rewrite of [shiki](https://github.com/shikijs/shiki), a beautiful
- [Bundles languages/themes composedly](#fine-grained-bundle).
- [Light/Dark themes support](#lightdark-dual-themes).
- [`hast` support](#codetohast).
- Zero-dependencies.
- Simplified APIs.
- [List of breaking changes from shiki](#breaking-changes-from-shiki).
- Please don't hate me Pine 😜 ([What's Next?](#whats-next))

Expand Down
4 changes: 1 addition & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@
"esno": "^0.17.0",
"fast-glob": "^3.3.1",
"fs-extra": "^11.1.1",
"hast-util-to-html": "^9.0.0",
"hastscript": "^8.0.0",
"jsonc-parser": "^3.2.0",
"lint-staged": "^13.2.3",
"pnpm": "^8.6.12",
Expand All @@ -44,7 +42,7 @@
"shikiji": "workspace:^",
"simple-git-hooks": "^2.9.0",
"typescript": "^5.1.6",
"unbuild": "^1.2.1",
"unbuild": "^2.0.0-rc.0",
"vite": "^4.4.9",
"vitest": "^0.34.1",
"vscode-oniguruma": "^1.7.0",
Expand Down
46 changes: 46 additions & 0 deletions packages/markdown-it-shikiji/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# markdown-it-shikiji

[Markdown It](https://markdown-it.github.io/) plugin for [shikiji](https://github.com/antfu/shikiji)

## Install

```bash
npm i -D markdown-it-shikiji
```

## Usage

```ts
import MarkdownIt from 'markdown-it'
import Shikiji from 'markdown-it-shikiji'

const md = MarkdownIt()

md.use(await Shikiji({
themes: {
light: 'vitesse-light',
dark: 'vitesse-dark',
}
}))
```

## Features

### Line Highlight

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:

~~~md
# Hello World

```js {1,3-4}
console.log('line1') // highlighted
console.log('line2')
console.log('line3') // highlighted
console.log('line4') // highlighted
```
~~~

## License

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

export default defineBuildConfig({
entries: [
'src/index.ts',
],
declaration: true,
rollup: {
emitCJS: false,
},
externals: [
'hast',
],
})
44 changes: 44 additions & 0 deletions packages/markdown-it-shikiji/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"name": "markdown-it-shikiji",
"type": "module",
"version": "0.5.1",
"description": "markdown-it integration for shikiji",
"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/markdown-it-shikiji"
},
"bugs": "https://github.com/antfu/shikiji/issues",
"keywords": [
"shiki",
"markdown-it"
],
"sideEffects": false,
"exports": {
".": {
"types": "./dist/index.d.mts",
"default": "./dist/index.mjs"
}
},
"main": "./dist/index.mjs",
"module": "./dist/index.mjs",
"types": "./dist/index.d.mts",
"files": [
"dist"
],
"scripts": {
"build": "unbuild",
"dev": "unbuild --stub",
"prepublishOnly": "nr build"
},
"dependencies": {
"markdown-it": "^13.0.1",
"shikiji": "^0.5.1"
},
"devDependencies": {
"@types/markdown-it": "^13.0.0"
}
}
73 changes: 73 additions & 0 deletions packages/markdown-it-shikiji/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import type MarkdownIt from 'markdown-it'
import { bundledLanguages, getHighlighter } from 'shikiji'
import type { BuiltinLanguage, BuiltinTheme, CodeOptionsThemes, CodeToHastOptions, Highlighter, LanguageInput } from 'shikiji'
import { parseHighlightLines } from '../../shared/line-highlight'

export type MarkdownItShikijiOptions = MarkdownItShikijiSetupOptions & {
/**
* Language names to include.
*
* @default Object.keys(bundledLanguages)
*/
langs?: Array<LanguageInput | BuiltinLanguage>
}

export type MarkdownItShikijiSetupOptions = CodeOptionsThemes<BuiltinTheme> & {
/**
* Add `highlighted` class to lines defined in after codeblock
*
* @default true
*/
highlightLines?: boolean | string
}

function setup(markdownit: MarkdownIt, highlighter: Highlighter, options: MarkdownItShikijiSetupOptions) {
const {
highlightLines = true,
} = options

markdownit.options.highlight = (code, lang = 'text', attrs) => {
const codeOptions: CodeToHastOptions = {
...options,
lang,
}

codeOptions.transforms ||= {}

if (highlightLines) {
const lines = parseHighlightLines(attrs)
if (lines) {
const className = highlightLines === true
? 'highlighted'
: highlightLines

codeOptions.transforms.line = (node, line) => {
if (lines.includes(line))
node.properties.class += ` ${className}`
return node
}
}
}

codeOptions.transforms.code = (node) => {
node.properties.class = `language-${lang}`
}

return highlighter.codeToHtml(
code,
codeOptions,
)
}
}

export default async function markdownItShikiji(options: MarkdownItShikijiOptions) {
const themeNames = ('themes' in options ? Object.values(options.themes) : [options.theme]).filter(Boolean) as BuiltinTheme[]
const highlighter = await getHighlighter({
themes: themeNames,
langs: options.langs || Object.keys(bundledLanguages) as BuiltinLanguage[],
})

return function (markdownit: MarkdownIt) {
setup(markdownit, highlighter, options)
}
}
10 changes: 10 additions & 0 deletions packages/markdown-it-shikiji/test/fixtures/a.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Hello

…world!

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

const a = 1
console.log(a)
```
7 changes: 7 additions & 0 deletions packages/markdown-it-shikiji/test/fixtures/a.out.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<h1>Hello</h1>
<p>…world!</p>
<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>
<span class="line"></span>
<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>
<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>
<span class="line"></span></code></pre>
18 changes: 18 additions & 0 deletions packages/markdown-it-shikiji/test/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import fs from 'node:fs/promises'
import { expect, test } from 'vitest'
import MarkdownIt from 'markdown-it'
import Shikiji from '../src'

test('run', async () => {
const md = MarkdownIt()
md.use(await Shikiji({
themes: {
light: 'vitesse-light',
dark: 'vitesse-dark',
},
}))

const result = md.render(await fs.readFile(new URL('./fixtures/a.md', import.meta.url), 'utf-8'))

expect(result).toMatchFileSnapshot('./fixtures/a.out.html')
})
55 changes: 55 additions & 0 deletions packages/rehype-shikiji/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# rehype-shikiji

[rehype](https://github.com/rehypejs/rehype) plugin for [shikiji](https://github.com/antfu/shikiji).

## Install

```bash
npm i -D rehype-shikiji
```

## Usage

```ts
import { unified } from 'unified'
import remarkParse from 'remark-parse'
import remarkRehype from 'remark-rehype'
import rehypeStringify from 'rehype-stringify'
import rehypeShikiji from 'rehype-shikiji'
import { expect, test } from 'vitest'

const file = await unified()
.use(remarkParse)
.use(remarkRehype)
.use(rehypeShikiji, {
// or `theme` for a single theme
themes: {
light: 'vitesse-light',
dark: 'vitesse-dark',
}
})
.use(rehypeStringify)
.process(await fs.readFile('./input.md'))
```


## Features

### Line Highlight

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:

~~~md
# Hello World

```js {1,3-4}
console.log('line1') // highlighted
console.log('line2')
console.log('line3') // highlighted
console.log('line4') // highlighted
```
~~~

## License

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

export default defineBuildConfig({
entries: [
'src/index.ts',
],
declaration: true,
rollup: {
emitCJS: false,
},
externals: [
'hast',
],
})
49 changes: 49 additions & 0 deletions packages/rehype-shikiji/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"name": "rehype-shikiji",
"type": "module",
"version": "0.5.1",
"description": "rehype integration for shikiji",
"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/rethype-shikiji"
},
"bugs": "https://github.com/antfu/shikiji/issues",
"keywords": [
"shiki",
"rehype"
],
"sideEffects": false,
"exports": {
".": {
"types": "./dist/index.d.mts",
"default": "./dist/index.mjs"
}
},
"main": "./dist/index.mjs",
"module": "./dist/index.mjs",
"types": "./dist/index.d.mts",
"files": [
"dist"
],
"scripts": {
"build": "unbuild",
"dev": "unbuild --stub",
"prepublishOnly": "nr build"
},
"dependencies": {
"@types/hast": "^3.0.0",
"hast-util-to-string": "^2.0.0",
"shikiji": "^0.5.1",
"unified": "^11.0.1",
"unist-util-visit": "^5.0.0"
},
"devDependencies": {
"rehype-stringify": "^9.0.4",
"remark-parse": "^10.0.2",
"remark-rehype": "^10.1.0"
}
}
Loading

0 comments on commit f096f57

Please sign in to comment.