feat: introduce new twoslash feature into vitepress with its associated plugin usage documentation

This commit is contained in:
Anda Toshiki 2023-06-12 00:28:14 +08:00
parent 4f2b400e3e
commit 931faa61c3
27 changed files with 5506 additions and 1749 deletions

6
.gitignore vendored
View File

@ -39,6 +39,7 @@ bower_components
build/Release build/Release
# Dependency directories # Dependency directories
docs/node_modules/
node_modules/ node_modules/
jspm_packages/ jspm_packages/
@ -133,4 +134,7 @@ dist
cache cache
# node generated xmlhttprequest file # node generated xmlhttprequest file
.node-xmlhttprequest-sync-* .node-xmlhttprequest-sync-*]
# frontmatter cms config
.frontmatter

View File

@ -4,6 +4,7 @@ import { markdown } from './config/markdown'
import { metaData } from './config/constants' import { metaData } from './config/constants'
import { head } from './config/head' import { head } from './config/head'
import { themeConfig } from './config/theme' import { themeConfig } from './config/theme'
import { withTwoslash } from '@andatoshiki/vitepress-plugin-shiki-twoslash'
import { SitemapStream } from 'sitemap' import { SitemapStream } from 'sitemap'
import { createWriteStream } from 'node:fs' import { createWriteStream } from 'node:fs'
@ -11,7 +12,8 @@ import { resolve } from 'node:path'
const links: { url: string; lastmod: PageData['lastUpdated'] }[] = [] const links: { url: string; lastmod: PageData['lastUpdated'] }[] = []
export default defineConfig({ export default withTwoslash(
defineConfig({
lang: metaData.lang, // i18n default english translation lang: metaData.lang, // i18n default english translation
title: metaData.title, // title from metadata config title: metaData.title, // title from metadata config
description: metaData.description, // description from metadata config description: metaData.description, // description from metadata config
@ -59,5 +61,54 @@ export default defineConfig({
await new Promise(r => writeStream.on('finish', r)) await new Promise(r => writeStream.on('finish', r))
}, },
}) })
)
// defineConfig ({
// lang: metaData.lang, // i18n default english translation
// title: metaData.title, // title from metadata config
// description: metaData.description, // description from metadata config
// markdown: markdown, // markdown config
// lastUpdated: true, // whether enabling lastupdated or not
// head, // documentation head tag options
// themeConfig, // default exported theme config
// cleanUrls: true, // clean urls configs to remove standard genreated page file type extensions
// outDir: '../dist', // specify staic pages build output dir
// // vue template options for preventing katex build crashes
// vue: {
// template: {
// compilerOptions: {
// isCustomElement: tag => customElements.includes(tag),
// },
// },
// },
// // i18n localization config
// locales: {
// '/': {
// label: 'English',
// lang: 'en-US',
// },
// '/jp/': {
// label: 'Japanese',
// title: 'Vue Test Utils',
// lang: 'jp-JP',
// description: 'La documentation officielle de Vue Test Utils',
// },
// },
// ignoreDeadLinks: true,
// transformHtml: (_, id, { pageData }) => {
// if (!/[\\/]404\.html$/.test(id))
// links.push({
// url: pageData.relativePath.replace(/((^|\/)index)?\.md$/, '$2'),
// lastmod: pageData.lastUpdated,
// })
// },
// buildEnd: async ({ outDir }) => {
// const sitemap = new SitemapStream({ hostname: 'https://note.toshiki.dev/' })
// const writeStream = createWriteStream(resolve(outDir, 'sitemap.xml'))
// sitemap.pipe(writeStream)
// links.forEach(link => sitemap.write(link))
// sitemap.end()
// await new Promise(r => writeStream.on('finish', r))
// },
// })
customElements // custom element tags of markdown-it-katex in vitepress customElements // custom element tags of markdown-it-katex in vitepress

View File

@ -7,8 +7,8 @@ import mdLink from 'markdown-it-link-preview'
export const markdown: MarkdownOptions = { export const markdown: MarkdownOptions = {
html: true, html: true,
theme: { theme: {
light: 'one-dark-pro', light: 'solarized-light',
dark: 'material-theme-palenight', dark: 'solarized-dark',
}, },
lineNumbers: true, lineNumbers: true,
config: md => { config: md => {

View File

@ -60,7 +60,7 @@ export const nav: DefaultTheme.Config['nav'] = [
link: '/application/markdown-it-katex/how-to-use', link: '/application/markdown-it-katex/how-to-use',
activeMatch: '/application/markdown-it-katex/', activeMatch: '/application/markdown-it-katex/',
}, },
{ text: '', link: '', activeMatch: '' }, { text: 'vitepress-plugin-shiki-twoslash', link: '/application/vitepress-plugin-shiki-twoslash/index', activeMatch: '/application/vitepress-plugin-shiki-twoslash/index' },
], ],
}, },
], ],

View File

@ -1,3 +1,4 @@
import { groupCollapsed } from 'console'
import { DefaultTheme } from 'vitepress/theme' import { DefaultTheme } from 'vitepress/theme'
export const sidebar: DefaultTheme.Config['sidebar'] = { export const sidebar: DefaultTheme.Config['sidebar'] = {
@ -168,7 +169,7 @@ export const sidebar: DefaultTheme.Config['sidebar'] = {
}, },
], ],
'/application/': [ '/application/markdown-it-katex/': [
{ {
text: 'markdown-it-katex', text: 'markdown-it-katex',
collapsed: false, collapsed: false,
@ -191,4 +192,81 @@ export const sidebar: DefaultTheme.Config['sidebar'] = {
], ],
}, },
], ],
'/application/vitepress-plugin-shiki-twoslash/': [
{
text: 'Guide',
collapsed: false,
items: [
{
text: 'Getting Started',
link: '/application/vitepress-plugin-shiki-twoslash/',
},
{
text: 'Markdown Extensions',
link: '/application/vitepress-plugin-shiki-twoslash/guide/markdown-extensions',
},
{
text: 'Using a Custom Theme',
link: '/application/vitepress-plugin-shiki-twoslash/guide/custom-theme',
},
],
},
{
text: 'Features',
collapsed: false,
items: [
{
text: 'Queries',
link: '/application/vitepress-plugin-shiki-twoslash/api/queries',
},
{
text: 'Errors',
link: '/application/vitepress-plugin-shiki-twoslash/api/errors',
},
{
text: 'Emit',
link: '/application/vitepress-plugin-shiki-twoslash/api/emit',
},
{
text: 'Cutting',
link: '/application/vitepress-plugin-shiki-twoslash/api/cutting',
},
{
text: 'Multi-file',
link: '/application/vitepress-plugin-shiki-twoslash/api/multi-file',
},
{
text: '@types',
link: '/application/vitepress-plugin-shiki-twoslash/api/types',
},
{
text: 'Meta Annotations',
link: '/application/vitepress-plugin-shiki-twoslash/api/annotations',
},
{
text: 'Logging',
link: '/application/vitepress-plugin-shiki-twoslash/api/logging',
},
{
text: 'Includes',
link: '/application/vitepress-plugin-shiki-twoslash/api/includes',
},
],
},
{
text: 'Config',
collapsed: false,
items: [
{
text: 'Reference',
link: '/application/vitepress-plugin-shiki-twoslash/config/reference',
},
{
text: 'Compiler Flags',
link: '/application/vitepress-plugin-shiki-twoslash/config/flags',
},
],
},
],
} }

View File

@ -10,9 +10,13 @@ import mediumZoom from 'medium-zoom'
import vitepressNprogress from '@andatoshiki/vitepress-plugin-nprogress' import vitepressNprogress from '@andatoshiki/vitepress-plugin-nprogress'
import '@andatoshiki/vitepress-plugin-nprogress/lib/css/index.css' import '@andatoshiki/vitepress-plugin-nprogress/lib/css/index.css'
import '@andatoshiki/vitepress-plugin-shiki-twoslash/styles.css'
// custom styles import // custom styles import
import './styles/index.scss' import './styles/index.scss'
import './styles/component/twoslash.scss'
// @ts-ignore // @ts-ignore
// custom components and vue template layouts // custom components and vue template layouts
import CustomLayout from './CustomLayout.vue' import CustomLayout from './CustomLayout.vue'
@ -22,6 +26,8 @@ import AsideSponsors from './components/AsideSponsors.vue'
import Copyright from './components/Copyright.vue' import Copyright from './components/Copyright.vue'
// @ts-ignore // @ts-ignore
import Comment from './components/layout/Comment.vue' import Comment from './components/layout/Comment.vue'
// @ts-ignore
import ArticleMetadata from './components/ArticleMetadata.vue'
// import CodeTitle from './components/CodeTitle.vue' // import CodeTitle from './components/CodeTitle.vue'

View File

@ -0,0 +1,129 @@
/* Dark/light theme */
:root:not(.dark) {
--vp-code-block-bg: rgba(125,125,125,0.04);
--vp-code-copy-code-active-text: var(--vp-c-text-2);
--vp-code-copy-code-hover-bg: rgba(125,125,125,0.1);
--vp-code-tab-divider: var(--vp-c-mute-dark);
--vp-code-tab-hover-text-color: var(--vp-c-text-1);
/* fix contrast: lang name on gray code block */
--vp-c-text-dark-3: rgba(180, 180, 180, 0.7);
}
:root.dark {
--vp-code-block-bg: rgba(0,0,0,0.2);
/* fix lang name: check the same above (this is the default) */
--vp-c-text-dark-3: rgba(235, 235, 235, 0.38);
}
/* Hide block based on theme */
html:not(.dark) pre.shiki[class*="dark"] {
display: none;
}
html:not(.dark) pre.shiki[class*="light"] {
display: block;
}
html.dark pre.shiki[class*="dark"] {
display: block;
}
html.dark pre.shiki[class*="light"] {
display: none;
}
/* VitePress Twoslash */
:root {
--vp-twoslash-c-annotation-fg: var(--vp-c-text-1);
--vp-twoslash-c-brand: var(--vp-c-brand);
--vp-twoslash-c-error-bg: var(--vp-c-red-dimm-2);
--vp-twoslash-c-error-fg: var(--vp-c-text-1);
--vp-twoslash-c-logger-error-bg: var(--vp-c-red-dimm-2);
--vp-twoslash-c-logger-error-fg: var(--vp-c-red-dark);
--vp-twoslash-c-logger-fg: var(--vp-c-text-1);
--vp-twoslash-c-logger-log-bg: var(--vp-c-mute-dark);
--vp-twoslash-c-logger-log-fg: var(--vp-c-gray);
--vp-twoslash-c-logger-warn-bg: var(--vp-c-yellow-dimm-2);
--vp-twoslash-c-logger-warn-fg: var(--vp-c-yellow-dark);
--vp-twoslash-c-lsp-bg: var(--vp-c-bg-elv);
--vp-twoslash-c-lsp-border: var(--vp-c-divider);
--vp-twoslash-c-lsp-fg: var(--vp-c-text-1);
--vp-twoslash-c-lsp-underline: var(--vp-c-text-2);
--vp-twoslash-lsp-shadow: var(--vp-shadow-2);
--vp-twoslash-c-query-bg: var(--vp-c-mute-dark);
--vp-twoslash-c-query-fg-2: var(--vp-c-text-2);
--vp-twoslash-c-query-fg: var(--vp-c-text-1);
}
/* Fix tab color */
.vp-code-group .tabs label {
background-color: transparent;
--vp-code-tab-text-color: var(--vp-c-text-2);
--vp-code-tab-active-text-color: var(--vp-c-text-1);
}
/**
* Component: Button
* -------------------------------------------------------------------------- */
:root {
--vp-button-brand-border: var(--vp-c-brand-light);
--vp-button-brand-text: var(--vp-c-text-dark-1);
--vp-button-brand-bg: var(--vp-c-brand);
--vp-button-brand-hover-border: var(--vp-c-brand-light);
--vp-button-brand-hover-text: var(--vp-c-text-dark-1);
--vp-button-brand-hover-bg: var(--vp-c-brand-light);
--vp-button-brand-active-border: var(--vp-c-brand-light);
--vp-button-brand-active-text: var(--vp-c-text-dark-1);
--vp-button-brand-active-bg: var(--vp-button-brand-bg);
}
/**
* Component: Algolia
* -------------------------------------------------------------------------- */
.DocSearch {
--docsearch-primary-color: var(--vp-c-brand) !important;
}
/**
* Site
* -------------------------------------------------------------------------- */
.VPImage.logo {
height: 1rem;
}
.dark [img-light] {
display: none;
}
html:not(.dark) [img-dark] {
display: none;
}
/* Overrides */
.VPSocialLink {
transform: scale(0.9);
}
.vp-doc th, .vp-doc td {
padding: 6px 10px;
border: 1px solid #8882;
}
/* h3 breaks SEO => replaced with h2 with the same size */
.home-content h2 {
margin-top: 2rem;
font-size: 1.35rem;
border-bottom: none;
margin-bottom: 0;
}
img.resizable-img {
width: unset;
height: unset;
}

View File

@ -0,0 +1,45 @@
/**
*
*
* @param date
* @returns (YYYY/MM/dd AM hh:mm)
*/
export function formatDate(date) {
const formatDate = new Date(date)
return formatDate.toLocaleString('en', {
year: 'numeric',
month: 'numeric',
day: 'numeric',
hour: 'numeric',
minute: 'numeric',
})
}
/**
* URL
*
* @param paramName
* @returns
*/
export function getQueryParam(paramName) {
const reg = new RegExp('(^|&)' + paramName + '=([^&]*)(&|$)')
let value = decodeURIComponent(window.location.search.substr(1)).match(reg)
if (value != null) {
return unescape(value[2])
}
return null
}
/**
*
*
* @param paramName
* @param paramValue
*/
export function goToLink(url, paramName, paramValue) {
if (paramName) {
window.location.href = url + '?' + paramName + '=' + paramValue
} else {
window.location.href = url
}
}

View File

@ -5,9 +5,15 @@ lastUpdated: true
showArticleMetadata: true showArticleMetadata: true
categories: categories:
- Chemistry - Chemistry
tags: keywords:
- Java - chemistry
- JVM - reaction
- mechanism
- reaction-mechanism
- tutorial
- explanation
- textbook
- reference
--- ---
# 12-5: Reaction Mechanism # 12-5: Reaction Mechanism

View File

@ -0,0 +1,112 @@
---
description: 'Annotations provide a way to provide outside commentary on your code.'
title: 'Meta Annotations'
---
# Queries
Sometimes the thing you want to say is about the code, annotations provide a way to provide outside commentary on your code.
## `@annotate: [left|right] [overrides] - [text]`
Annotate has a lot more controls than most of the other Twoslash commands, because each use of it probably needs to feel a bit different. Here's an example based on the TypeScript home page, click it to get it running so we can talk about what it does:
::: code-group
```ts twoslash [output]
// @errors: 2304
// @strict: false
function compact(arr) {
if (orr.length > 10) return arr.trim(0, 10)
return arr
}
// @annotate: left { "arrowRot": "90deg 8px 27px", "textDegree": "3deg", "top": "0rem" } - Discovered a typo, the param is arr, not orr!
```
````md [markdown]
```ts twoslash
// @errors: 2304
// @strict: false
function compact(arr) {
if (orr.length > 10) return arr.trim(0, 10)
return arr
}
// @annotate: left { "arrowRot": "90deg 8px 27px", "textDegree": "3deg", "top": "0rem" } - Discovered a typo, the param is arr, not orr!
```
````
:::
First up, cool — it adds some text to the left hand side of the code. It features quite a few different options, so lets go through them one by one:
- `left` or `right`: It's currently `left`. It's worth noting the arrow flips also, and `90deg` isn't a great option. Let's look at that next.
- `{ "arrrowRot": "90deg 8px 27px" }` - This JSON object is used to manipulate the annotation, you have 3 controls for arrow positioning and rotation: `degrees x y`. I recommend keeping those in degrees and px, but it's your life. These are overrides from defaults which are okay, but not really something you ever want to ship.
- `{ "textDegree": "3deg" }` - Rotates the text, you probably want something between `-3deg` and `3deg`. Optional, defaults to `0`.
- `{ "top": "0rem" }` - Sets the y coordinates for the annotation relative to the code sample, if it's not included then it becomes `[lineNum]rem`.
What's not included in this sample is `flipped`, which can be used to flip the arrow's orientation. Here's some examples:
A horizontal right example:
::: code-group
```ts twoslash [output]
// @errors: 2304
// @strict: false
function compact(arr) {
if (orr.length > 10) return arr.trim(0, 10)
return arr
}
// @annotate: right { "arrowRot": "-50deg -10px -10px", "top": "3rem" } - Discovered a typo, the param is arr, not orr!
```
````md [markdown]
```ts twoslash
// @errors: 2304
// @strict: false
function compact(arr) {
if (orr.length > 10) return arr.trim(0, 10)
return arr
}
// @annotate: left { "arrowRot": "90deg 8px 27px", "textDegree": "3deg", "top": "0rem" } - Discovered a typo, the param is arr, not orr!
```
````
:::
Upside down arrow pointing at the error, using flipped to re-flip the arrow:
::: code-group
```ts twoslash [output]
// @errors: 2304
// @strict: false
function compact(arr) {
if (orr.length > 10) return arr.trim(0, 10)
return arr
}
// @annotate: right { "arrowRot": "190deg 8px 46px", "flipped": false, "textDegree": "-3deg", "top": "-0.7rem" } - Discovered a typo, the param is arr, not orr!
```
````md [markdown]
```ts twoslash
// @errors: 2304
// @strict: false
function compact(arr) {
if (orr.length > 10) return arr.trim(0, 10)
return arr
}
// @annotate: left { "arrowRot": "90deg 8px 27px", "textDegree": "3deg", "top": "0rem" } - Discovered a typo, the param is arr, not orr!
```
````
:::

View File

@ -0,0 +1,89 @@
---
description: 'Remove unnecessary code from your examples.'
title: 'Cutting'
---
# Cutting
Every Twoslash code example needs to be a complete TypeScript program so it can compile. Quite often to make it compile, there is a bunch of code which isn't relevant to the user. This can be extracted out of the code examples via cut comments.
## `---cut---`
Cut works after TypeScript has generated the project and pulled out all the editor information (like identifiers, queries, highlights etc) and then amends all of their offsets and lines to re-fit the smaller output. What your user sees is everything below the `---cut---`.
::: code-group
```ts twoslash [output]
const level: string = 'Danger'
// ---cut---
console.log(level)
```
````md [markdown]
```ts twoslash
const level: string = 'Danger'
// ---cut---
console.log(level)
```
````
:::
Cutting even works across [multiple files](multi-file). This is why `// @filename: [file]` is specifically the only Twoslash command which is not removed, because if it's not relevant it can be `---cut---` away.
::: code-group
```ts twoslash [output]
// @filename: a.ts
export const helloWorld: string = 'Hi'
// @filename: b.ts
// ---cut---
import { helloWorld } from './a'
console.log(helloWorld)
```
````md [markdown]
```ts twoslash
// @filename: a.ts
export const helloWorld: string = 'Hi'
// @filename: b.ts
// ---cut---
import { helloWorld } from './a'
console.log(helloWorld)
```
````
:::
## `---cut-after---`
The sibling to `---cut---`, which trims anything after the sigil:
::: code-group
```tsx twoslash [output]
//@noErrors
const Page = () => (
// ---cut---
<Container>
<ImportantComponent />
</Container>
// ---cut-after---
)
```
````md [markdown]
```tsx twoslash
const Page = () => (
// ---cut---
<Container>
<ImportantComponent />
</Container>
// ---cut-after---
)
```
````
:::

View File

@ -0,0 +1,98 @@
---
description: 'You can replace the contents of your code examples with the results of running TypeScript over the project.'
title: 'Emit'
---
# Emit
Running a Twoslash code example is a full TypeScript compiler run that will create files inside the virtual file system. You can replace the contents of your code examples with the results of running TypeScript over the project.
## `@showEmit`
`// @showEmit` is the main command to tell Shiki Twoslash that you want to replace the output of your code example with the equivalent `.js` file.
::: code-group
```ts twoslash [output]
// @showEmit
const level: string = 'Danger'
```
````md [markdown]
```ts twoslash
// @showEmit
const level: string = 'Danger'
```
````
:::
## `@showEmittedFile: [file]`
While the `.js` file is probably the most useful file out of the box, TypeScript does emit other files if you have the right flags enabled (`.d.ts` and `.map`) but also when you have a multi-file code sample — you might need to tell Twoslash which file to show. For all these cases you can also add `@showEmittedFile: [file]` to tell Twoslash which file you want to show.
Shows emitted `.d.ts` for a TypeScript code example:
::: code-group
````md [markdown]
```ts twoslash
// @declaration
// @showEmit
// @showEmittedFile: index.d.ts
export const hello = 'world'
```
````
```ts twoslash [output]
// @declaration
// @showEmit
// @showEmittedFile: index.d.ts
export const hello = 'world'
```
:::
Shows emitted `.map` files:
::: code-group
````md [markdown]
```ts twoslash
// @sourceMap
// @showEmit
// @showEmittedFile: index.js.map
export const hello = 'world'
```
````
```ts twoslash [output]
// @sourceMap
// @showEmit
// @showEmittedFile: index.js.map
export const hello = 'world'
```
:::
::: code-group
````md [markdown]
```ts twoslash
// @declaration
// @declarationMap
// @showEmit
// @showEmittedFile: index.d.ts.map
export const hello = 'world'
```
````
```ts twoslash [output]
// @declaration
// @declarationMap
// @showEmit
// @showEmittedFile: index.d.ts.map
export const hello = 'world'
```
:::

View File

@ -0,0 +1,56 @@
---
description: 'Raise compiler errors in your code examples to show incorrect states.'
title: 'Errors'
---
# Errors
Most of the time, you want to avoid errors in your code examples. Strictly speaking, this usually means setting the right compiler flags and environment in each code example.
Sometimes however, you do want to raise a compiler error — to show incorrect states. In those cases, twoslash has a way to mark the compiler errors you expect.
## `@errors: [num]`
All TypeScript compiler errors have a number, this number is relatively arbitrary and can change between TypeScript versions. For our case these numbers are useul in declaring what we expect to see.
You can use `// @errors: [num]` to tell Twoslash that you expect this error to occur. This moves the compiler error message into the code example.
::: code-group
```ts twoslash [output]
// @errors: 2588
const a = '123'
a = 132
```
````md [markdown]
```ts twoslash
// @errors: 2588
const a = '123'
a = 132
```
````
:::
## `@noErrors`
Sometimes you have needs in which a broken TypeScript build is okay. A good example of this is using a [completion query](queries#completions), which requires a broken TypeScript project to work. You can use `// @noErrors` to supress all errors in a code sample, and not have them show inline.
::: code-group
```ts twoslash [output]
// @noErrors
const a = '123'
a = 132
```
````md [markdown]
```ts twoslash
// @noErrors
const a = '123'
a = 132
```
````
:::

View File

@ -0,0 +1,137 @@
---
description: 'Include re-usable TypeScript blocks in your code examples.'
title: 'Includes'
---
# Includes
As your documentation grows, you may need a way of re-using code blocks to prevent code duplication. Shiki Twoslash provides a simple includes system.
## Defining a re-usable block
Re-usable code blocks are defined by the `twoslash` language, followed by the `include` keyword and the reference name of your choice.
````md
```twoslash include myBlock
type SomeString = string
```
````
### Incremental steps
Shiki Twoslash also provide the ability to define incremental steps through the definition of re-usable blocks. This means whenever a new step is delimited down the code, it will also include previous steps. These are **not groups**.
- Incremental steps are delimited by `// - [name of the step]`
- They are named **at the end** of the actual code
````md
```twoslash include myBlockWithSteps
type SomeString = string
// - base
type SomeUser = { name: string; mail?: SomeUserMail }
type SomeUserMail = { content: string; verified: boolean }
// - afterUserDefinitions
type SomeGroup = { name: string; members: SomeUser[] }
// - afterGroupDefinitions
```
````
## Including a whole block
To include a re-usable block, add `// @include: [block name]` in your code block.
```twoslash include myBlock
type SomeString = string
```
::: code-group
```ts twoslash [output]
// @include: myBlock
const a: SomeString = 'string'
```
````md [markdown]
```twoslash include myBlock
type SomeString = string
```
```ts twoslash
// @include: myBlock
const a: SomeString = 'string'
```
````
:::
## Including a block step
To include a re-usable block at a specific step, add `// @include: [block name]-[step name]` in your code block.
```twoslash include myBlockWithSteps
type SomeString = string
// - base
type SomeUser = { name: string; mail?: SomeUserMail }
type SomeUserMail = { content: string; verified: boolean }
// - afterUserDefinitions
type SomeGroup = { name: string; members: SomeUser[] }
// - afterGroupDefinitions
```
::: code-group
```ts twoslash [output]
// @include: myBlockWithSteps-afterUserDefinitions
const mail: SomeUserMail = { content: 'some-email', verified: true }
```
````md [markdown]
```twoslash include myBlockWithSteps
type SomeString = string
// - base
type SomeUser = { name: string; mail?: SomeUserMail }
type SomeUserMail = { content: string; verified: boolean }
// - afterUserDefinitions
type SomeGroup = { name: string; members: SomeUser[] }
// - afterGroupDefinitions
```
```ts twoslash
// @include: myBlockWithSteps-afterUserDefinitions
const mail: SomeUserMail = { content: 'some-email', verified: true }
```
````
:::
## Hiding re-used code
Re-using a lot of TypeScript code can easily bloat your documentation and obstruct the main point of your code block. You can hide re-used code to keep your code blocks clean and concise by [cutting](cutting) right after the `@include` statement.
::: code-group
```ts twoslash [output]
// @include: myBlockWithSteps-afterUserDefinitions
// ---cut---
const mail: SomeUserMail = { content: 'some-email', verified: true }
```
````md [markdown]
```twoslash include myBlockWithSteps
type SomeString = string
// - base
type SomeUser = { name: string; mail?: SomeUserMail }
type SomeUserMail = { content: string; verified: boolean }
// - afterUserDefinitions
type SomeGroup = { name: string; members: SomeUser[] }
// - afterGroupDefinitions
```
```ts twoslash
// @include: myBlockWithSteps-afterUserDefinitions
// ---cut---
const mail: SomeUserMail = { content: 'some-email', verified: true }
```
````
:::

View File

@ -0,0 +1,48 @@
---
description: 'Display formatted output for code examples.'
title: 'Logging'
keywords:
- console
- javascript
- typescript
- showcase
- snippets
---
# Logging
When you first see a Twoslash code example with an inline compiler error, you instinctively trust that the compiler error is correct because the design shows that it is not a part of the code sample. The logging tools lets you do that, but abuses the systemic trust because your code is not being evaluated to generate the logs.
This feature is effectively a facade, people will trust your output and it will look better.
## `@log:`, `@warn:`, `@error:`
The names are based on the functions on the `console` object:
::: code-group
```ts twoslash [output]
console.log('Hello log')
// @log: Hello log
console.warn('Hello warn')
// @warn: Hello warn
console.error('Hello error')
// @error: Hello error
```
````md [markdown]
```ts twoslash
console.log('Hello log')
// @log: Hello log
console.warn('Hello warn')
// @warn: Hello warn
console.error('Hello error')
// @error: Hello error
```
````
:::

View File

@ -0,0 +1,160 @@
---
description: "Twoslash code examples aren't limited to creating a single file. You can write any file to the virtual file system used by TypeScript to power your code examples."
title: 'Multi-file'
---
# Multi-file
Twoslash code examples aren't limited to creating a single file, by using `// @filename: [file]` you can write any file to the virtual file system used by TypeScript to power your code examples.
## `@filename: [file]`
Most of the time, you don't need to think about the underlaying virtual file system in a code example, but when you have imports between them it becomes important to know. Twoslash will default to creating an `index.[type]` based on the langauge passed to the code example:
::: code-group
```ts twoslash [output]
// I'm index.ts
```
````md [markdown]
```ts twoslash
// I'm index.ts
```
````
:::
::: code-group
```tsx twoslash [output]
// I'm index.tsx
```
````md [markdown]
```tsx twoslash
// I'm index.tsx
```
````
:::
::: code-group
```js twoslash [output]
// I'm index.tjs
```
````md [markdown]
```js twoslash
// I'm index.tjs
```
````
:::
Then until Twoslash hits another `// @filename: [file]`, the parser keeps adding new lines into the same file. After seeing `@filename` Twoslash creates a new virtual file-system file and adds the new lines to that. You can't edit a file after it was created, but you can overwrite it.
It can be any file. For example, if you want to quickly fake a node module:
::: code-group
```ts twoslash [output]
// @filename: node_modules/@types/mylib/index.d.ts
export function doit(): string
// @filename: index.ts
import { doit } from 'mylib'
console.log(doit)
```
This code example sets up the types for a non-existent npm module, and TypeScript picks it up as the definitions in the same way it would in a non-virtual TypeScript project.
````md [markdown]
```ts twoslash
// @filename: node_modules/@types/mylib/index.d.ts
export function doit(): string
// @filename: index.ts
import { doit } from 'mylib'
console.log(doit)
```
````
:::
You can also set up a JSON object which can be imported in a TypeScript file:
::: code-group
```ts twoslash [output]
// @resolveJsonModule
// @filename: app.json
{ "version": "23.2.3" }
// @filename: index.ts
import appSettings from "./app.json"
appSettings.version
// ^?
```
````md [markdown]
```ts twoslash
// @resolveJsonModule
// @filename: app.json
{ "version": "23.2.3" }
// @filename: index.ts
import appSettings from "./app.json"
appSettings.version
// ^?
```
````
:::
Finally, the following code allows importing non-TypeScript content. There is a `.d.ts` file which globally says 'md files are OK to import' and 'the module "react" exists, but don't worry about the details'.
Then for a user, they only see the imports and exports inside `index.tsx`.
::: code-group
```ts twoslash [output]
// @filename: ambient.d.ts
declare module '*.mdx' {
export default any
}
declare module "react"
// @filename: MultiFileDocs.mdx
## Hello world
// @filename: index.tsx
// ---cut---
import React from "react"
import MultiFileDocs from "./MultiFileDocs.mdx"
export default () => <MultiFileDocs/>
```
````md [markdown]
```ts twoslash
// @filename: ambient.d.ts
declare module '*.mdx' {
export default any
}
declare module "react"
// @filename: MultiFileDocs.mdx
## Hello world
// @filename: index.tsx
// ---cut---
import React from "react"
import MultiFileDocs from "./MultiFileDocs.mdx"
export default () => <MultiFileDocs/>
```
````
:::

View File

@ -0,0 +1,56 @@
---
description: 'One of the key features of Twoslash is the ability to use the TypeScript compiler to pull out type information about your code.'
title: 'Queries'
---
# Queries
One of the key features of Twoslash is the ability to use the TypeScript compiler to pull out type information about your code. Twoslash comes with two different ways to query your code: `?^` and `?|`.
## Extract Type `^?`
Using `^?` you can pull out type information about a particular identifier in the line of code above it.
::: code-group
```ts twoslash [output]
const hi = 'Hello'
const msg = hi + ', world'
// ^?
```
````md [markdown]
```ts twoslash
const hi = 'Hello'
const msg = hi + ', world'
// ^?
```
````
:::
## Completions `^|`
Using `^|` you can pull out information about a what the auto-complete looks like at a particular location.
::: code-group
```ts twoslash [output]
// @noErrors
console.e
// ^|
```
````md [markdown]
```ts twoslash
// @noErrors
console.e
// ^|
```
````
:::
::: info
Note that the compiler flag for [`// @noErrors`](errors#noerrors) is set, because `console.e` is a failing TypeScript code sample but we don't really care about that.
:::

View File

@ -0,0 +1,88 @@
---
description: 'Using external libraries with Twoslash code examples.'
title: '@types'
---
# @types
For most examples, you probably need to import external libraries into your code examples.
Twoslash works by faking a virtual file system over your existing file system. This means any `@types` or libraries with TypeScript definitions should work out of the box with no config.
## Local Sources
Simply import locally installed libraries and Twoslash can pick up types:
::: code-group
```ts twoslash [output]
import { defineConfig } from 'vitepress'
const config = defineConfig({})
// ^?
export default config
```
````md [markdown]
```ts twoslash
import { defineConfig } from 'vitepress'
const config = defineConfig({})
// ^?
export default config
```
````
:::
## Globals
Setting up globals is a little bit more complex, but not drastically. You need to use the [triple slash reference](https://www.typescriptlang.org/docs/handbook/triple-slash-directives.html#-reference-types-) which adds a particular library to the global scope.
For example, setting up Node imports and globals etc.
::: code-group
```ts twoslash [output]
/// <reference types="node" />
// ---cut---
import { writeFileSync } from 'fs'
writeFileSync('myfile.txt', '// TODO')
```
````md [markdown]
```ts twoslash
/// <reference types="node" />
// ---cut---
import { writeFileSync } from 'fs'
writeFileSync('myfile.txt', '// TODO')
```
````
:::
APIs like [Vitest](https://vitest.dev) are similar cases where you would use a triple slash reference.
::: code-group
```ts twoslash [output]
/// <reference types="vitest/globals" />
// ---cut---
test('my tests', () => {
expect('hello').toEqual('hello')
// ^?
})
```
````md [markdown]
```ts twoslash
/// <reference types="vitest/globals" />
// ---cut---
test('my tests', () => {
expect('hello').toEqual('hello')
// ^?
})
```
````
:::

View File

@ -0,0 +1,304 @@
---
title: 'Compiler Flags'
---
# Compiler Flags
```
// @allowJs
Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files..
// @allowSyntheticDefaultImports
Allow 'import x from y' when a module doesn't have a default export..
// @allowUmdGlobalAccess
Allow accessing UMD globals from modules..
// @allowUnreachableCode
Disable error reporting for unreachable code..
// @allowUnusedLabels
Disable error reporting for unused labels..
// @alwaysStrict
Ensure 'use strict' is always emitted..
// @assumeChangesOnlyAffectDirectDependencies
Have recompiles in projects that use `incremental` and `watch` mode assume that changes within a file will only affect files directly depending on it..
// @baseUrl
Specify the base directory to resolve non-relative module names..
// @charset
No longer supported. In early versions, manually set the text encoding for reading files..
// @checkJs
Enable error reporting in type-checked JavaScript files..
// @composite
Enable constraints that allow a TypeScript project to be used with project references..
// @declaration
Generate .d.ts files from TypeScript and JavaScript files in your project..
// @declarationDir
Specify the output directory for generated declaration files..
// @declarationMap
Create sourcemaps for d.ts files..
// @diagnostics
Output compiler performance information after building..
// @disableReferencedProjectLoad
Reduce the number of projects loaded automatically by TypeScript..
// @disableSizeLimit
Remove the 20mb cap on total source code size for JavaScript files in the TypeScript language server..
// @disableSolutionSearching
Opt a project out of multi-project reference checking when editing..
// @disableSourceOfProjectReferenceRedirect
Disable preferring source files instead of declaration files when referencing composite projects.
// @downlevelIteration
Emit more compliant, but verbose and less performant JavaScript for iteration..
// @emitBOM
Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files..
// @emitDeclarationOnly
Only output d.ts files and not JavaScript files..
// @emitDecoratorMetadata
Emit design-type metadata for decorated declarations in source files..
// @esModuleInterop
Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility..
// @exactOptionalPropertyTypes
Interpret optional property types as written, rather than adding 'undefined'..
// @experimentalDecorators
Enable experimental support for TC39 stage 2 draft decorators..
// @explainFiles
Print files read during the compilation including why it was included..
// @extendedDiagnostics
Output more detailed compiler performance information after building..
// @forceConsistentCasingInFileNames
Ensure that casing is correct in imports..
// @generateCpuProfile
Emit a v8 CPU profile of the compiler run for debugging..
// @importHelpers
Allow importing helper functions from tslib once per project, instead of including them per-file..
// @importsNotUsedAsValues
Specify emit/checking behavior for imports that are only used for types.
// @incremental
Enable incremental compilation.
// @inlineSourceMap
Include sourcemap files inside the emitted JavaScript..
// @inlineSources
Include source code in the sourcemaps inside the emitted JavaScript..
// @isolatedModules
Ensure that each file can be safely transpiled without relying on other imports..
// @jsx
Specify what JSX code is generated..
// @jsxFactory
Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'.
// @jsxFragmentFactory
Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'..
// @jsxImportSource
Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.`.
// @keyofStringsOnly
Make keyof only return strings instead of string, numbers or symbols. Legacy option..
// @lib
Specify a set of bundled library declaration files that describe the target runtime environment..
// @listEmittedFiles
Print the names of emitted files after a compilation..
// @listFiles
Print all of the files read during the compilation..
// @mapRoot
Specify the location where debugger should locate map files instead of generated locations..
// @maxNodeModuleJsDepth
Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`..
// @module
Specify what module code is generated..
// @moduleResolution
Specify how TypeScript looks up a file from a given module specifier..
// @newLine
Set the newline character for emitting files..
// @noEmit
Disable emitting file from a compilation..
// @noEmitHelpers
Disable generating custom helper functions like `__extends` in compiled output..
// @noEmitOnError
Disable emitting files if any type checking errors are reported..
// @noErrorTruncation
Disable truncating types in error messages..
// @noFallthroughCasesInSwitch
Enable error reporting for fallthrough cases in switch statements..
// @noImplicitAny
Enable error reporting for expressions and declarations with an implied `any` type...
// @noImplicitOverride
Add `undefined` to a type when accessed using an index..
// @noImplicitReturns
Enable error reporting for codepaths that do not explicitly return in a function..
// @noImplicitThis
Enable error reporting when `this` is given the type `any`..
// @noImplicitUseStrict
Disable adding 'use strict' directives in emitted JavaScript files..
// @noLib
Disable including any library files, including the default lib.d.ts..
// @noPropertyAccessFromIndexSignature
Enforces using indexed accessors for keys declared using an indexed type.
// @noResolve
Disallow `import`s, `require`s or ``s from expanding the number of files TypeScript should add to a project..
// @noStrictGenericChecks
Disable strict checking of generic signatures in function types..
// @noUncheckedIndexedAccess
Include 'undefined' in index signature results.
// @noUnusedLocals
Enable error reporting when a local variables aren't read..
// @noUnusedParameters
Raise an error when a function parameter isn't read.
// @out
Deprecated setting. Use `outFile` instead..
// @outDir
Specify an output folder for all emitted files..
// @outFile
Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output..
// @paths
Specify a set of entries that re-map imports to additional lookup locations..
// @plugins
List of language service plugins..
// @preserveConstEnums
Disable erasing `const enum` declarations in generated code..
// @preserveSymlinks
Disable resolving symlinks to their realpath. This correlates to the same flag in node..
// @preserveWatchOutput
Disable wiping the console in watch mode.
// @pretty
Enable color and formatting in output to make compiler errors easier to read.
// @reactNamespace
Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit..
// @removeComments
Disable emitting comments..
// @resolveJsonModule
Enable importing .json files.
// @rootDir
Specify the root folder within your source files..
// @rootDirs
Allow multiple folders to be treated as one when resolving modules..
// @skipDefaultLibCheck
Skip type checking .d.ts files that are included with TypeScript..
// @skipLibCheck
Skip type checking all .d.ts files..
// @sourceMap
Create source map files for emitted JavaScript files..
// @sourceRoot
Specify the root path for debuggers to find the reference source code..
// @strict
Enable all strict type-checking options..
// @strictBindCallApply
Check that the arguments for `bind`, `call`, and `apply` methods match the original function..
// @strictFunctionTypes
When assigning functions, check to ensure parameters and the return values are subtype-compatible..
// @strictNullChecks
When type checking, take into account `null` and `undefined`..
// @strictPropertyInitialization
Check for class properties that are declared but not set in the constructor..
// @stripInternal
Disable emitting declarations that have `@internal` in their JSDoc comments..
// @suppressExcessPropertyErrors
Disable reporting of excess property errors during the creation of object literals..
// @suppressImplicitAnyIndexErrors
Suppress `noImplicitAny` errors when indexing objects that lack index signatures..
// @target
Set the JavaScript language version for emitted JavaScript and include compatible library declarations..
// @traceResolution
Log paths used during the `moduleResolution` process..
// @tsBuildInfoFile
Specify the folder for .tsbuildinfo incremental compilation files..
// @typeRoots
Specify multiple folders that act like `./node_modules/@types`..
// @types
Specify type package names to be included without being referenced in a source file..
// @useDefineForClassFields
Emit ECMAScript-standard-compliant class fields..
// @useUnknownInCatchVariables
Type catch clause variables as 'unknown' instead of 'any'..
```

View File

@ -0,0 +1,132 @@
---
description: 'You can configure Twoslash to change code example output.'
title: 'Config'
---
# Config
## Overview
You can configure VitePress Twoslash using the `twoslash` property added to `defineConfig`.
```ts twoslash
// .vitepress/config.[ext]
import { defineConfig } from 'vitepress'
import { withTwoslash, TwoslashConfigSettings } from '@andatoshiki/vitepress-plugin-shiki-twoslash'
export default withTwoslash(
defineConfig({
twoslash: {
// Your VitePress Twoslash options
},
})
)
```
::: info
In addition to the below config options, VitePress Twoslash also supports all [`shiki`](https://github.com/shikijs/shiki) `HighlighterOptions` and [`@typescript/twoslash`](https://github.com/microsoft/TypeScript-Website/tree/v2/packages/ts-twoslasher) `TwoSlashOptions`.
:::
## Options
### `addTryButton`
A way to turn on the try buttons seen on the TS website.
- **Type**: `boolean`
- **Default**: `false`
```ts
export default withTwoslash(
defineConfig({
twoslash: {
addTryButton: true, // [!code focus]
},
})
)
```
### `alwayRaiseForTwoslashExceptions`
Instead of showing twoslash exceptions inline, throw the entire process like it will on CI.
- **Type**: `boolean`
- **Default**: `false`
```ts
export default withTwoslash(
defineConfig({
twoslash: {
alwayRaiseForTwoslashExceptions: true, // [!code focus]
},
})
)
```
### `disableImplicitReactImport`
A way to disable implicit React imports on tsx/jsx language codeblocks
- **Type**: `boolean`
- **Default**: `false`
```ts
export default withTwoslash(
defineConfig({
twoslash: {
disableImplicitReactImport: true, // [!code focus]
},
})
)
```
### `includeJSDocInHover`
Include JSDoc comments in the hovers.
- **Type**: `boolean`
- **Default**: `false`
```ts
export default withTwoslash(
defineConfig({
twoslash: {
includeJSDocInHover: true, // [!code focus]
},
})
)
```
### `ignoreCodeblocksWithCodefenceMeta`
Ignore transforming certain code blocks.
- **Type**: `boolean`
- **Default**: `false`
```ts
export default withTwoslash(
defineConfig({
twoslash: {
ignoreCodeblocksWithCodefenceMeta: true, // [!code focus]
},
})
)
```
### `wrapFragments`
A way to add a div wrapper for multi-theme outputs.
- **Type**: `boolean`
- **Default**: `false`
```ts
export default withTwoslash(
defineConfig({
twoslash: {
wrapFragments: true, // [!code focus]
},
})
)
```

View File

@ -0,0 +1,77 @@
---
description: 'Customize the Twoslash interface to match your theme.'
title: 'Using a Custom Theme'
---
# Using a Custom Theme
Twoslash uses your `markdown.theme` for syntax highlighting, but there are a few other things you can do to customize the look and feel of your code examples — particulary the generated Twoslash interface.
## CSS Variables
The following CSS variables (and their defaults) are available to style Twoslash interface:
```css
:root {
--vp-twoslash-c-annotation-fg: var(--vp-c-text-1);
--vp-twoslash-c-brand: var(--vp-c-brand);
--vp-twoslash-c-error-bg: var(--vp-c-red-dimm-2);
--vp-twoslash-c-error-fg: var(--vp-c-text-1);
--vp-twoslash-c-logger-error-bg: var(--vp-c-red-dimm-2);
--vp-twoslash-c-logger-error-fg: var(--vp-c-red-dark);
--vp-twoslash-c-logger-fg: var(--vp-c-text-1);
--vp-twoslash-c-logger-log-bg: var(--vp-c-mute-dark);
--vp-twoslash-c-logger-log-fg: var(--vp-c-gray);
--vp-twoslash-c-logger-warn-bg: var(--vp-c-yellow-dimm-2);
--vp-twoslash-c-logger-warn-fg: var(--vp-c-yellow-dark);
--vp-twoslash-c-lsp-bg: var(--vp-c-bg-elv);
--vp-twoslash-c-lsp-border: var(--vp-c-divider);
--vp-twoslash-c-lsp-fg: var(--vp-c-text-1);
--vp-twoslash-c-lsp-underline: var(--vp-c-text-2);
--vp-twoslash-lsp-shadow: var(--vp-shadow-2);
--vp-twoslash-c-query-bg: var(--vp-c-mute-darker);
--vp-twoslash-c-query-fg-2: var(--vp-c-text-2);
--vp-twoslash-c-query-fg: var(--vp-c-text-1);
}
```
## Dark/Light Theme
If you pass a responsive theme to `markdown.theme`, you probably also want to hide/show the correct theme based on the user's settings.
```ts twoslash
import { defineConfig } from 'vitepress'
// ---cut---
export default defineConfig({
markdown: {
theme: { dark: 'vitesse-dark', light: 'vitesse-light' },
},
})
```
You can do this with the following CSS:
```css
/*
* Hide block based on theme
* `[class*='-dark']` matches `'vitesse-dark'`
* `[class*='-light']` matches `'vitesse-light'`
*/
html:not(.dark) pre.shiki[class*='-dark'] {
display: none;
}
html:not(.dark) pre.shiki[class*='-light'] {
display: block;
}
html.dark pre.shiki[class*='-dark'] {
display: block;
}
html.dark pre.shiki[class*='-light'] {
display: none;
}
```

View File

@ -0,0 +1,44 @@
---
title: 'Markdown Extensions'
---
# Markdown Extensions
## Code Groups
[Code Groups](https://vitepress.dev/guide/markdown#code-groups) and Twoslash [multi-file](/api/multi-file) support.
::: code-group
```ts twoslash [index.ts]
// @module: esnext
// @filename: name.ts
export const name = 'twoslash'
// @filename: index.ts
// ---cut---
import { name } from './name'
export function hello(name: string) {
console.log(`Hello, ${name}!`)
}
hello(name)
// ^?
```
```ts twoslash [name.ts]
export const name = 'twoslash'
```
:::
## Unsupported Extensions
Since VitePress Twoslash uses it's own [Shiki](https://github.com/shikijs/shiki) highlighter, the following syntax highlighting extensions are not currently compatible.
- [Line Highlighting in Code Blocks](https://vitepress.dev/guide/markdown#line-highlighting-in-code-blocks)
- [Focus in Code Blocks](https://vitepress.dev/guide/markdown#focus-in-code-blocks)
- [Colored Diffs in Code Blocks](https://vitepress.dev/guide/markdown#colored-diffs-in-code-blocks)
- [Errors and Warnings in Code Blocks](https://vitepress.dev/guide/markdown#errors-and-warnings-in-code-blocks)
- [Line Numbers](https://vitepress.dev/guide/markdown#line-numbers)
- [Import Code Snippets](https://vitepress.dev/guide/markdown#import-code-snippets)
If you are interested in adding support, please start a new [GitHub Discussion](https://github.com/andatoshiki/@andatoshiki/vitepress-plugin-shiki-twoslash).

View File

@ -0,0 +1,149 @@
---
description: Static code examples for VitePress using Shiki Twoslash.
title: "VitePress Twoslash: VitePress Plugin for Shiki Twoslash"
titleTemplate: false
keywords:
- getting-started
- intro
---
# @andatoshiki/vitepress-plugin-shiki-twoslash
> Static code examples for [VitePress](https://vitepress.dev) using [Shiki Twoslash](https://github.com/shikijs/twoslash) — powered by the syntax engine of Visual Studio Code and the TypeScript compiler.
## Overview
Try moving your cursor into the code block below:
```ts twoslash
// Removes 'readonly' attributes from a type's properties
type CreateMutable<Type> = {
-readonly [Property in keyof Type]: Type[Property]
}
type LockedAccount = {
readonly id: string
readonly name: string
}
type UnlockedAccount = CreateMutable<LockedAccount>
```
Pretty neat, right? To some extent, anything your editor can show you about code, Twoslash can show. For example, here is the real auto-complete for a VitePress config:
```ts twoslash
// @noErrors
import { defineConfig } from 'vitepress'
export default defineConfig({
ti,
//^|
})
```
The name Twoslash refers to specially formatted comments (e.g. `// ^?`) which can be used to set up your environment, like compiler flags or separate input files. It couldn't be easier to set up and start creating incredible code examples!
## Install
Install `@andatoshiki/vitepress-plugin-shiki-twoslash` (requires `vitepress@>=1.0.0-alpha.61`).
::: code-group
```bash [pnpm]
pnpm add @andatoshiki/vitepress-plugin-shiki-twoslash
```
```bash [npm]
npm i @andatoshiki/vitepress-plugin-shiki-twoslash
```
```bash [yarn]
yarn add @andatoshiki/vitepress-plugin-shiki-twoslash
```
:::
::: warning
Until `shiki-twoslash` uses the same version of `shiki` as VitePress, you must override the following packages' `shiki` versions for syntax highlighting to look the same.
```json
{
"pnpm": {
"overrides": {
"remark-shiki-twoslash>shiki": "^0.14.1",
"shiki-twoslash>shiki": "^0.14.1"
}
}
}
```
Tracked in an upstream issue: https://github.com/shikijs/twoslash/issues/180
:::
## Configure
First, wrap your VitePress config file with the `withTwoslash` wrapper.
```ts twoslash
// .vitepress/config.[ext]
import { defineConfig } from 'vitepress'
import { withTwoslash } from '@andatoshiki/vitepress-plugin-shiki-twoslash'
export default withTwoslash(
defineConfig({
// Your VitePress config
})
)
```
Then, import `@andatoshiki/vitepress-plugin-shiki-twoslash/styles.css` into your theme.
```ts twoslash
// .vitepress/theme/index.ts
import defaultTheme from 'vitepress/theme'
import '@andatoshiki/vitepress-plugin-shiki-twoslash/styles.css'
export default defaultTheme
```
::: tip
You can [configure VitePress Twoslash](./config/reference) using the `twoslash` property added to `defineConfig`.
:::
## Add Twoslash
Finally, add the `twoslash` attribute to markdown fenced code blocks.
````md [markdown]
```ts twoslash
// Removes 'readonly' attributes from a type's properties
type CreateMutable<Type> = {
-readonly [Property in keyof Type]: Type[Property]
}
type LockedAccount = {
readonly id: string
readonly name: string
}
type UnlockedAccount = CreateMutable<LockedAccount>
// ^?
```
````
And your code blocks will be twoslashified!
```ts twoslash [twoslash]
// Removes 'readonly' attributes from a type's properties
type CreateMutable<Type> = {
-readonly [Property in keyof Type]: Type[Property]
}
type LockedAccount = {
readonly id: string
readonly name: string
}
type UnlockedAccount = CreateMutable<LockedAccount>
// ^?
```

View File

@ -27,6 +27,8 @@
"devDependencies": { "devDependencies": {
"@andatoshiki/markdown-it-image-caption": "0.0.2", "@andatoshiki/markdown-it-image-caption": "0.0.2",
"@andatoshiki/vitepress-plugin-nprogress": "^0.0.1", "@andatoshiki/vitepress-plugin-nprogress": "^0.0.1",
"@andatoshiki/vitepress-plugin-shiki-twoslash": "0.0.1",
"@antv/g2plot": "^2.4.31",
"@arco-design/web-vue": "^2.46.0", "@arco-design/web-vue": "^2.46.0",
"@luckrya/markdown-it-link-to-card": "^0.3.3", "@luckrya/markdown-it-link-to-card": "^0.3.3",
"@mdit-vue/shared": "^0.12.0", "@mdit-vue/shared": "^0.12.0",
@ -35,6 +37,7 @@
"artplayer": "^4.6.2", "artplayer": "^4.6.2",
"blueimp-md5": "^2.19.0", "blueimp-md5": "^2.19.0",
"conventional-changelog-cli": "^2.2.2", "conventional-changelog-cli": "^2.2.2",
"dayjs": "^1.11.8",
"dplayer": "^1.27.1", "dplayer": "^1.27.1",
"feed": "^4.2.2", "feed": "^4.2.2",
"flv.js": "^1.6.2", "flv.js": "^1.6.2",
@ -68,9 +71,19 @@
}, },
"dependencies": { "dependencies": {
"@andatoshiki/markdown-it-katex": "^0.0.3", "@andatoshiki/markdown-it-katex": "^0.0.3",
"markdown-it": "^13.0.1" "@types/react": "^18.2.9",
"markdown-it": "^13.0.1",
"react": "^18.2.0",
"vitest": "^0.32.0"
}, },
"pnpm": { "pnpm": {
"overrides": {
"remark-shiki-twoslash>shiki": "^0.14.1",
"shiki-twoslash>shiki": "^0.14.1",
"@antv/g-base": "0.5.11",
"@antv/path-util": "2.0.15",
"@antv/attr": "0.3.5"
},
"peerDependencyRules": { "peerDependencyRules": {
"ignoreMissing": [ "ignoreMissing": [
"@algolia/client-search" "@algolia/client-search"

File diff suppressed because it is too large Load Diff

4
pnpm-workspace.yaml Normal file
View File

@ -0,0 +1,4 @@
prefer-workspace-packages: true
packages:
- '.'
- 'docs'

3973
yarn.lock

File diff suppressed because it is too large Load Diff