Skip to content

Commit be9debf

Browse files
committed
feat: use shiki
1 parent 2f9348d commit be9debf

File tree

6 files changed

+14477
-11871
lines changed

6 files changed

+14477
-11871
lines changed
+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
@import '~@shikijs/twoslash/style-rich.css';
2+
3+
.sourceCode__container {
4+
> pre {
5+
max-height: 350px;
6+
padding: 20px 24px;
7+
margin: 0;
8+
background-color: #f9f9f9 !important;
9+
10+
*::selection {
11+
color: inherit;
12+
background-color: rgba(30, 128, 240, 0.15);
13+
}
14+
}
15+
16+
code {
17+
counter-reset: step;
18+
counter-increment: step 0;
19+
}
20+
21+
code .line::before {
22+
content: counter(step);
23+
counter-increment: step;
24+
width: 1rem;
25+
margin-right: 1.5rem;
26+
display: inline-block;
27+
text-align: right;
28+
color: rgba(115, 138, 148, 0.4);
29+
}
30+
}
31+
32+
.sourceCode__loading {
33+
width: 100%;
34+
margin: 20px;
35+
text-align: center;
36+
}
+93
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import React, { useEffect, useRef, useState } from 'react';
2+
import { default as OriginalSourceCode } from 'dumi/theme-default/builtins/SourceCode';
3+
import { codeToHtml } from 'shiki';
4+
import { createTransformerFactory, rendererRich } from '@shikijs/twoslash/core';
5+
import { createTwoslashFromCDN } from 'twoslash-cdn';
6+
import { createStorage } from 'unstorage';
7+
import indexedDbDriver from 'unstorage/drivers/indexedb';
8+
import './index.less';
9+
10+
type ISourceCodeProps = Parameters<typeof OriginalSourceCode>[0];
11+
12+
const storage = createStorage({
13+
driver: indexedDbDriver({ base: 'twoslash-cdn' }),
14+
});
15+
const twoslash = createTwoslashFromCDN({
16+
storage,
17+
compilerOptions: {
18+
strict: false,
19+
lib: ['esnext', 'dom'],
20+
},
21+
twoSlashOptionsOverrides: {
22+
handbookOptions: {
23+
noErrors: true,
24+
},
25+
},
26+
});
27+
const transformerTwoslash = createTransformerFactory(twoslash.runSync)({
28+
renderer: rendererRich(),
29+
});
30+
31+
const specificVersionForATA = (str: string) => {
32+
const versions = {
33+
react: '18.2.0',
34+
antd: '4.22.5',
35+
};
36+
const text = str
37+
.replace(/import .* from 'react';/g, (i) => i + ' // types: ' + versions.react)
38+
.replace(/import .*from 'antd.*;/g, (i) => i + ' // types: ' + versions.antd)
39+
.replace('dt-react-component', '.dt-react-component');
40+
return text;
41+
};
42+
43+
export default function SourceCode({ children, lang, highlightLines }: ISourceCodeProps) {
44+
const [code, setCode] = useState('');
45+
const [loading, setLoading] = useState(false);
46+
47+
const ref = useRef<HTMLDivElement>(null);
48+
49+
useEffect(() => {
50+
setLoading(true);
51+
twoslash
52+
.prepareTypes(specificVersionForATA(children))
53+
.then(() => {
54+
return codeToHtml(children, {
55+
lang,
56+
theme: 'vitesse-light',
57+
transformers: [transformerTwoslash],
58+
});
59+
})
60+
.then(setCode)
61+
.finally(() => {
62+
setLoading(false);
63+
});
64+
}, [children]);
65+
66+
useEffect(() => {
67+
const handleKeyDown = (e: KeyboardEvent) => {
68+
if (e.key === 'a' && (e.metaKey || e.ctrlKey)) {
69+
e.preventDefault();
70+
// Ctrl + A
71+
const selection = window.getSelection();
72+
selection?.removeAllRanges();
73+
const range = new Range();
74+
range.selectNodeContents(ref.current!);
75+
selection?.addRange(range);
76+
}
77+
};
78+
ref.current?.addEventListener('keydown', handleKeyDown);
79+
return () => {
80+
ref.current?.removeEventListener('keydown', handleKeyDown);
81+
};
82+
}, []);
83+
84+
if (loading) return <div className="sourceCode__loading">loading...</div>;
85+
return (
86+
<div
87+
ref={ref}
88+
className="sourceCode__container"
89+
tabIndex={-1}
90+
dangerouslySetInnerHTML={{ __html: code }}
91+
/>
92+
);
93+
}

package.json

+13-2
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@
7575
"@commitlint/cli": "^17.1.2",
7676
"@commitlint/config-conventional": "^17.1.0",
7777
"@faker-js/faker": "^7.6.0",
78+
"@shikijs/rehype": "^2.4.2",
79+
"@shikijs/twoslash": "^2.4.2",
7880
"@testing-library/jest-dom": "^5.16.5",
7981
"@testing-library/react": "^13.4.0",
8082
"@testing-library/react-hooks": "^8.0.1",
@@ -93,6 +95,7 @@
9395
"father": "~4.1.0",
9496
"gh-pages": "^4.0.0",
9597
"husky": "^8.0.1",
98+
"idb-keyval": "^6.2.1",
9699
"jest": "^29.3.1",
97100
"jest-environment-jsdom": "^29.3.1",
98101
"ko-lint-config": "2.2.21",
@@ -102,10 +105,13 @@
102105
"react": "^18.0.0",
103106
"react-dom": "^18.0.0",
104107
"react-test-renderer": "^18.2.0",
108+
"shiki": "^2.4.2",
105109
"standard-version": "^9.5.0",
106110
"stylelint": "^14.9.1",
107111
"ts-jest": "^29.0.3",
108-
"typescript": "~4.5.2"
112+
"twoslash-cdn": "^0.2.12",
113+
"typescript": "~4.5.2",
114+
"unstorage": "^1.14.4"
109115
},
110116
"dependencies": {
111117
"@ant-design/icons": "^4.7.0",
@@ -130,5 +136,10 @@
130136
"resolutions": {
131137
"rc-motion": "2.6.2"
132138
},
133-
"packageManager": "[email protected]"
139+
"packageManager": "[email protected]",
140+
"pnpm": {
141+
"patchedDependencies": {
142+
"twoslash-cdn": "patches/twoslash-cdn.patch"
143+
}
144+
}
134145
}

patches/twoslash-cdn.patch

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
diff --git a/dist/index.mjs b/dist/index.mjs
2+
index 278a623a5747249444c510cea633ae8fd9271529..a552d41d2cb27de186a02b94a768f12187e3969e 100644
3+
--- a/dist/index.mjs
4+
+++ b/dist/index.mjs
5+
@@ -176,9 +176,9 @@ var setupTypeAcquisition = (config) => {
6+
const mightBeOnDT = treesOnly.filter((t) => !hasDTS.includes(t));
7+
const dtTrees = yield Promise.all(
8+
// TODO: Switch from 'latest' to the version from the original tree which is user-controlled
9+
- mightBeOnDT.map((f) => getFileTreeForModuleWithTag(config, `@types/${getDTName(f.moduleName)}`, "latest"))
10+
+ mightBeOnDT.map((f) => getFileTreeForModuleWithTag(config, `@types/${getDTName(f.moduleName)}`, f.version))
11+
);
12+
- const dtTreesOnly = dtTrees.filter((t) => !("error" in t));
13+
+ const dtTreesOnly = dtTrees.filter((t) => !("error" in t) && t.status === 200);
14+
const dtsFilesFromDT = dtTreesOnly.map((t) => treeToDTSFiles(t, `/node_modules/@types/${getDTName(t.moduleName).replace("types__", "")}`));
15+
const allDTSFiles = dtsFilesFromNPM.concat(dtsFilesFromDT).reduce((p, c) => p.concat(c), []);
16+
estimatedToDownload += allDTSFiles.length;

0 commit comments

Comments
 (0)