@@ -2,34 +2,63 @@ import { IApi } from 'dumi';
2
2
import ReactTechStack from 'dumi/dist/techStacks/react' ;
3
3
import type { ExampleBlockAsset } from 'dumi-assets-types' ;
4
4
import ts from 'typescript' ;
5
+ import { ShikiTransformerContextCommon } from 'shiki' ;
6
+ import type { Element , ElementContent } from 'hast' ;
7
+ import type { fromMarkdown } from 'mdast-util-from-markdown' ;
8
+ import type { gfmFromMarkdown } from 'mdast-util-gfm' ;
9
+ import type { defaultHandlers , toHast } from 'mdast-util-to-hast' ;
5
10
6
11
class DTReactTech extends ReactTechStack {
7
12
async generateMetadata ( asset : ExampleBlockAsset ) {
8
13
// workaround for esm module
9
14
const { transformerTwoslash } = await import ( '@shikijs/twoslash' ) ;
10
15
const { codeToHtml } = await import ( 'shiki' ) ;
11
- for ( const [ filename , dep ] of Object . entries ( asset . dependencies ) ) {
12
- if ( dep . type === 'FILE' && asset . id === 'blockheader-demo-basic' ) {
13
- const html = await codeToHtml ( dep . value , {
14
- lang : 'tsx' ,
15
- theme : 'vitesse-light' ,
16
- transformers : [
17
- transformerTwoslash ( {
18
- twoslashOptions : {
19
- compilerOptions : {
20
- jsx : ts . JsxEmit . React ,
16
+ const { fromMarkdown } = await import ( 'mdast-util-from-markdown' ) ;
17
+ const { gfmFromMarkdown } = await import ( 'mdast-util-gfm' ) ;
18
+ const { defaultHandlers, toHast } = await import ( 'mdast-util-to-hast' ) ;
19
+ const handler = {
20
+ fromMarkdown,
21
+ gfmFromMarkdown,
22
+ defaultHandlers,
23
+ toHast,
24
+ } ;
25
+ await Promise . all (
26
+ Object . entries ( asset . dependencies ) . map ( ( [ filename , dep ] ) => {
27
+ if ( dep . type === 'FILE' ) {
28
+ return codeToHtml ( dep . value , {
29
+ lang : 'tsx' ,
30
+ theme : 'vitesse-light' ,
31
+ transformers : [
32
+ transformerTwoslash ( {
33
+ twoslashOptions : {
34
+ compilerOptions : {
35
+ jsx : ts . JsxEmit . React ,
36
+ } ,
37
+ handbookOptions : {
38
+ noErrors : true ,
39
+ } ,
21
40
} ,
22
- handbookOptions : {
23
- noErrors : true ,
41
+ rendererRich : {
42
+ renderMarkdown : function ( md ) {
43
+ return renderMarkdown . call ( this , md , handler ) ;
44
+ } ,
45
+ renderMarkdownInline : function ( md , context ) {
46
+ return renderMarkdownInline . call (
47
+ this ,
48
+ handler ,
49
+ md ,
50
+ context
51
+ ) ;
52
+ } ,
24
53
} ,
25
- } ,
26
- } ) ,
27
- ] ,
28
- } ) ;
29
-
30
- asset . dependencies [ filename ] = < any > { ... dep , jsx : html } ;
31
- }
32
- }
54
+ } ) ,
55
+ ] ,
56
+ } ) . then ( ( html ) => {
57
+ asset . dependencies [ filename ] = < any > { ... dep , jsx : html } ;
58
+ } ) ;
59
+ }
60
+ } )
61
+ ) ;
33
62
return asset ;
34
63
}
35
64
}
@@ -39,3 +68,58 @@ const AssetsPlugin = async (api: IApi) => {
39
68
} ;
40
69
41
70
export default AssetsPlugin ;
71
+
72
+ type Handler = {
73
+ fromMarkdown : typeof fromMarkdown ;
74
+ gfmFromMarkdown : typeof gfmFromMarkdown ;
75
+ toHast : typeof toHast ;
76
+ defaultHandlers : typeof defaultHandlers ;
77
+ } ;
78
+ /**
79
+ * refer:https://github.com/shikijs/shiki/blob/main/packages/vitepress-twoslash/src/renderer-floating-vue.ts#L130-L131
80
+ */
81
+ function renderMarkdown ( this : ShikiTransformerContextCommon , md : string , handler : Handler ) {
82
+ const { fromMarkdown, gfmFromMarkdown, toHast, defaultHandlers } = handler ;
83
+ const mdast = fromMarkdown (
84
+ md . replace ( / \{ @ l i n k ( [ ^ } ] * ) \} / g, '$1' ) , // replace jsdoc links
85
+ { mdastExtensions : [ gfmFromMarkdown ( ) ] }
86
+ ) ;
87
+
88
+ return (
89
+ toHast ( mdast , {
90
+ handlers : {
91
+ code : ( state , node ) => {
92
+ const lang = node . lang || '' ;
93
+ if ( lang ) {
94
+ return < Element > {
95
+ type : 'element' ,
96
+ tagName : 'code' ,
97
+ properties : { } ,
98
+ children : this . codeToHast ( node . value , {
99
+ ...this . options ,
100
+ transformers : [ ] ,
101
+ lang,
102
+ structure : node . value . trim ( ) . includes ( '\n' ) ? 'classic' : 'inline' ,
103
+ } ) . children ,
104
+ } ;
105
+ }
106
+ return defaultHandlers . code ( state , node ) ;
107
+ } ,
108
+ } ,
109
+ } ) as Element
110
+ ) . children ;
111
+ }
112
+
113
+ function renderMarkdownInline (
114
+ this : ShikiTransformerContextCommon ,
115
+ handler : Handler ,
116
+ md : string ,
117
+ context ?: string
118
+ ) : ElementContent [ ] {
119
+ if ( context === 'tag:param' ) md = md . replace ( / ^ ( [ \w $ - ] + ) / , '`$1` ' ) ;
120
+
121
+ const children = renderMarkdown . call ( this , md , handler ) ;
122
+ if ( children . length === 1 && children [ 0 ] . type === 'element' && children [ 0 ] . tagName === 'p' )
123
+ return children [ 0 ] . children ;
124
+ return children ;
125
+ }
0 commit comments