Skip to content

Commit

Permalink
Add shikiji twoslash (#2612)
Browse files Browse the repository at this point in the history
* chore: upgrade deps

作者:  Jellli <[email protected]>

* feat: add twoslash transformer

* feat: update plugins to fit rehype-pretty-code's updates

* fix: prevent the crash from not receiving the style prop

* feat: handle when classname is a array

* feat: fix darkmode support

* feat: update snapshot

* docs: add twoslash support document

* update

* prettier

* prettier

* more

* more

* more

* more

* aa

* Update .changeset/rich-apricots-bake.md

---------

Co-authored-by: Dimitri POSTOLOV <[email protected]>
Co-authored-by: Dimitri POSTOLOV <[email protected]>
  • Loading branch information
3 people authored Feb 2, 2024
1 parent 9f55bd1 commit 3043826
Show file tree
Hide file tree
Showing 7 changed files with 379 additions and 40 deletions.
9 changes: 9 additions & 0 deletions .changeset/rich-apricots-bake.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
'nextra-theme-blog': minor
'nextra-theme-docs': minor
'nextra': minor
---

add shikiji twoslash

Demo feature: https://nextra-v2-na3obnhub-shuding1.vercel.app/docs/guide/twoslash-support
64 changes: 64 additions & 0 deletions docs/pages/docs/guide/twoslash-support.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Twoslash Support

Twoslash provides an inline type hove inside the code block.

## Basic usage

You can enable twoslash to your code blocks by adding a `twoslash` metadata:

````md copy=false filename="Markdown"
```ts twoslash
// @errors: 2540
interface Todo {
title: string
}

const todo: Readonly<Todo> = {
title: 'Delete inactive users'.toUpperCase()
// ^?
}

todo.title = 'Hello'

Number.parseInt('123', 10)
// ^|
```
````

Renders:

```ts twoslash
// @errors: 2540
interface Todo {
title: string
}

const todo: Readonly<Todo> = {
title: 'Delete inactive users'.toUpperCase()
// ^?
}

todo.title = 'Hello'

Number.parseInt('123', 10)
// ^|
```

## Custom log message

You can add log message to your code by adding:

- `@log: <message>` Custom log message
- `@error: <message>` Custom error message
- `@warn: <message>` Custom warn message
- `@annotate: <message>` Custom annotate message

```ts twoslash
// @log: Custom log message
const a = 1
// @error: Custom error message
const b = 1
// @warn: Custom warning message
const c = 1
// @annotate: Custom annotation message
```
1 change: 1 addition & 0 deletions packages/nextra/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@
"remark-reading-time": "^2.0.1",
"remark-smartypants": "^2.1.0",
"shikiji": "^0.10.2",
"shikiji-twoslash": "^0.10.2",
"slash": "^5.1.0",
"title": "^3.5.3",
"unist-util-remove": "^4.0.0",
Expand Down
11 changes: 11 additions & 0 deletions packages/nextra/src/server/compile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import remarkGfm from 'remark-gfm'
import remarkMath from 'remark-math'
import remarkReadingTime from 'remark-reading-time'
import remarkSmartypants from 'remark-smartypants'
import { rendererRich, transformerTwoslash } from 'shikiji-twoslash'
import type { Pluggable, Plugin } from 'unified'
import type {
FrontMatter,
Expand Down Expand Up @@ -276,6 +277,16 @@ export async function compileMdx(
rehypePrettyCode,
{
...DEFAULT_REHYPE_PRETTY_CODE_OPTIONS,
// TODO: For some reason I get Error: Cannot find module 'path' in remote content,
// disable twoslash temporarily
transformers: isRemoteContent
? []
: [
transformerTwoslash({
renderer: rendererRich(),
explicitTrigger: true
})
],
...rehypePrettyCodeOptions
}
] as any,
Expand Down
17 changes: 13 additions & 4 deletions packages/nextra/src/server/rehype-plugins/rehype.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { Element } from 'hast'
import type { Options as RehypePrettyCodeOptions } from 'rehype-pretty-code'
import { bundledLanguages, getHighlighter } from 'shikiji'
import type { Plugin } from 'unified'
import { visit } from 'unist-util-visit'

Expand All @@ -22,11 +23,18 @@ export const DEFAULT_REHYPE_PRETTY_CODE_OPTIONS: RehypePrettyCodeOptions = {
}
delete node.properties['data-line']
},
filterMetaString: meta => meta.replace(CODE_BLOCK_FILENAME_REGEX, ''),
theme: {
light: 'github-light',
dark: 'github-dark'
}
},
getHighlighter(opts) {
return getHighlighter({
...opts,
// Without `getHighlighter` option ```mdx lang is not highlighted...
langs: Object.keys(bundledLanguages)
})
},
filterMetaString: meta => meta.replace(CODE_BLOCK_FILENAME_REGEX, '')
}

export const rehypeParseCodeMeta: Plugin<
Expand Down Expand Up @@ -63,7 +71,8 @@ export const rehypeAttachCodeMeta: Plugin<[], any> = () => ast => {
const isRehypePrettyCode =
'data-rehype-pretty-code-figure' in node.properties
if (!isRehypePrettyCode) return
// remove <div data-rehype-pretty-code-fragment /> element that wraps <pre /> element

// remove <figure data-rehype-pretty-code-figure /> element that wraps <pre /> element
// because we'll wrap with our own <div />
const preEl: PreElement = Object.assign(node, node.children[0])
delete preEl.properties['data-theme']
Expand Down Expand Up @@ -93,7 +102,7 @@ export const rehypeAttachCodeMeta: Plugin<[], any> = () => ast => {
...Object.entries(node.properties).map(([name, value]) => ({
type: 'mdxJsxAttribute',
name,
value
value: Array.isArray(value) ? value.join(' ') : value
}))
)
}
Expand Down
Loading

0 comments on commit 3043826

Please sign in to comment.