Skip to content

Commit 2661779

Browse files
committed
refactor: move renderer-floating-vue out
1 parent 4c45180 commit 2661779

File tree

2 files changed

+161
-153
lines changed

2 files changed

+161
-153
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,9 @@
1-
import { rendererRich, transformerTwoSlash } from 'shikiji-twoslash'
2-
import type { TransformerTwoSlashOptions, TwoSlashRenderers } from 'shikiji-twoslash'
3-
import type { Element, Text } from 'hast'
4-
import type { ShikijiTransformer, ShikijiTransformerContext } from 'shikiji'
5-
import { gfmFromMarkdown } from 'mdast-util-gfm'
6-
import { fromMarkdown } from 'mdast-util-from-markdown'
7-
import { defaultHandlers, toHast } from 'mdast-util-to-hast'
8-
import { addClassToHast } from 'shikiji/core'
1+
import { transformerTwoSlash } from 'shikiji-twoslash'
2+
import type { TransformerTwoSlashOptions } from 'shikiji-twoslash'
3+
import type { ShikijiTransformer } from 'shikiji'
4+
import { rendererFloatingVue } from './renderer-floating-vue'
95

10-
const regexType = /^[A-Z][a-zA-Z0-9_]*(\<[^\>]*\>)?:/
11-
const regexFunction = /^[a-zA-Z0-9_]*\(/
6+
export * from './renderer-floating-vue'
127

138
export interface VitePressPluginTwoSlashOptions extends TransformerTwoSlashOptions {
149
/**
@@ -52,146 +47,3 @@ export function transformerTwoslash(options: VitePressPluginTwoSlashOptions = {}
5247
},
5348
}
5449
}
55-
56-
export function defaultInfoProcessor(type: string) {
57-
let content = type
58-
// remove leading `(property)` or `(method)` on each line
59-
.replace(/^\(([\w-]+?)\)\s+/mg, '')
60-
// remove import statement
61-
.replace(/\nimport .*$/, '')
62-
// remove interface or namespace lines with only the name
63-
.replace(/^(interface|namespace) \w+$/mg, '')
64-
.trim()
65-
66-
// Add `type` or `function` keyword if needed
67-
if (content.match(regexType))
68-
content = `type ${content}`
69-
else if (content.match(regexFunction))
70-
content = `function ${content}`
71-
72-
return content
73-
}
74-
75-
export function rendererFloatingVue(options: VitePressPluginTwoSlashOptions = {}): TwoSlashRenderers {
76-
const {
77-
processHoverInfo = defaultInfoProcessor,
78-
processHoverDocs = docs => docs,
79-
} = options
80-
81-
const rich = rendererRich({
82-
classExtra: 'vp-copy-ignore',
83-
})
84-
85-
function createFloatingVueWarpper(this: ShikijiTransformerContext, text: string, docs: string | undefined, node: Element | Text, presisted = false): Element | undefined {
86-
const content = processHoverInfo(text)
87-
88-
if ((!content || content === 'any'))
89-
return undefined
90-
91-
const themedContent = (this.codeToHast(
92-
content,
93-
{
94-
...this.options,
95-
transformers: [],
96-
transforms: undefined,
97-
},
98-
).children[0] as Element).children as Element[]
99-
100-
// Add class to type nodes
101-
themedContent.forEach((node) => {
102-
addClassToHast(node, 'twoslash-popup-type')
103-
})
104-
105-
if (docs) {
106-
docs = processHoverDocs(docs) ?? docs
107-
const mdast = fromMarkdown(docs, {
108-
mdastExtensions: [gfmFromMarkdown()],
109-
})
110-
const hast = toHast(mdast, {
111-
handlers: {
112-
code: (state, node) => {
113-
const lang = node.lang || ''
114-
if (lang) {
115-
return this.codeToHast(
116-
node.value,
117-
{
118-
...this.options,
119-
transformers: [],
120-
transforms: undefined,
121-
lang,
122-
},
123-
).children[0] as Element
124-
}
125-
return defaultHandlers.code(state, node)
126-
},
127-
},
128-
})
129-
themedContent.push({
130-
type: 'element',
131-
tagName: 'div',
132-
properties: {
133-
class: 'twoslash-popup-jsdoc vp-doc',
134-
},
135-
children: (hast as any).children,
136-
})
137-
}
138-
139-
// Mark all nodes as v-pre for performance
140-
themedContent.forEach((node) => {
141-
node.properties ||= {}
142-
node.properties['v-pre'] = true
143-
})
144-
145-
return {
146-
type: 'element',
147-
tagName: 'v-menu',
148-
properties: {
149-
'class': 'twoslash-hover',
150-
'popper-class': 'vp-code shiki floating-vue-twoslash vp-copy-ignore',
151-
'placement': 'bottom-start',
152-
'theme': 'twoslash',
153-
':arrow-padding': '8',
154-
...presisted && {
155-
':shown': 'true',
156-
':triggers': '[]',
157-
':popper-triggers': '[]',
158-
':auto-hide': 'false',
159-
},
160-
},
161-
children: [
162-
{
163-
type: 'element',
164-
tagName: 'span',
165-
properties: {},
166-
children: [
167-
node,
168-
],
169-
},
170-
{
171-
type: 'element',
172-
tagName: 'template',
173-
properties: {
174-
'v-slot:popper': '{}',
175-
},
176-
content: {
177-
type: 'root',
178-
children: themedContent,
179-
},
180-
children: [],
181-
},
182-
],
183-
}
184-
}
185-
186-
return {
187-
...rich,
188-
nodeStaticInfo(info, node) {
189-
return createFloatingVueWarpper.call(this, info.text, info.docs, node) || {}
190-
},
191-
nodeQuery(query, node) {
192-
if (!query.text)
193-
return {}
194-
return createFloatingVueWarpper.call(this, query.text, query.docs, node, true) || {}
195-
},
196-
}
197-
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
import { rendererRich } from 'shikiji-twoslash'
2+
import type { RendererRichOptions, TwoSlashRenderers } from 'shikiji-twoslash'
3+
import type { Element, Text } from 'hast'
4+
import type { ShikijiTransformerContext } from 'shikiji'
5+
import { gfmFromMarkdown } from 'mdast-util-gfm'
6+
import { fromMarkdown } from 'mdast-util-from-markdown'
7+
import { defaultHandlers, toHast } from 'mdast-util-to-hast'
8+
import { addClassToHast } from 'shikiji/core'
9+
import type { VitePressPluginTwoSlashOptions } from 'vitepress-plugin-twoslash'
10+
11+
const regexType = /^[A-Z][a-zA-Z0-9_]*(\<[^\>]*\>)?:/
12+
const regexFunction = /^[a-zA-Z0-9_]*\(/
13+
14+
export function defaultInfoProcessor(type: string) {
15+
let content = type
16+
// remove leading `(property)` or `(method)` on each line
17+
.replace(/^\(([\w-]+?)\)\s+/mg, '')
18+
// remove import statement
19+
.replace(/\nimport .*$/, '')
20+
// remove interface or namespace lines with only the name
21+
.replace(/^(interface|namespace) \w+$/mg, '')
22+
.trim()
23+
24+
// Add `type` or `function` keyword if needed
25+
if (content.match(regexType))
26+
content = `type ${content}`
27+
else if (content.match(regexFunction))
28+
content = `function ${content}`
29+
30+
return content
31+
}
32+
33+
export function rendererFloatingVue(options: VitePressPluginTwoSlashOptions & RendererRichOptions = {}): TwoSlashRenderers {
34+
const {
35+
processHoverInfo = defaultInfoProcessor,
36+
processHoverDocs = docs => docs,
37+
} = options
38+
39+
const rich = rendererRich({
40+
classExtra: 'vp-copy-ignore',
41+
...options,
42+
})
43+
44+
function createFloatingVueWarpper(this: ShikijiTransformerContext, text: string, docs: string | undefined, node: Element | Text, presisted = false): Element | undefined {
45+
const content = processHoverInfo(text)
46+
47+
if ((!content || content === 'any'))
48+
return undefined
49+
50+
const themedContent = (this.codeToHast(
51+
content,
52+
{
53+
...this.options,
54+
transformers: [],
55+
transforms: undefined,
56+
},
57+
).children[0] as Element).children as Element[]
58+
59+
// Add class to type nodes
60+
themedContent.forEach((node) => {
61+
addClassToHast(node, 'twoslash-popup-type')
62+
})
63+
64+
if (docs) {
65+
docs = processHoverDocs(docs) ?? docs
66+
const mdast = fromMarkdown(docs, {
67+
mdastExtensions: [gfmFromMarkdown()],
68+
})
69+
const hast = toHast(mdast, {
70+
handlers: {
71+
code: (state, node) => {
72+
const lang = node.lang || ''
73+
if (lang) {
74+
return this.codeToHast(
75+
node.value,
76+
{
77+
...this.options,
78+
transformers: [],
79+
transforms: undefined,
80+
lang,
81+
},
82+
).children[0] as Element
83+
}
84+
return defaultHandlers.code(state, node)
85+
},
86+
},
87+
})
88+
themedContent.push({
89+
type: 'element',
90+
tagName: 'div',
91+
properties: {
92+
class: 'twoslash-popup-jsdoc vp-doc',
93+
},
94+
children: (hast as any).children,
95+
})
96+
}
97+
98+
// Mark all nodes as v-pre for performance
99+
themedContent.forEach((node) => {
100+
node.properties ||= {}
101+
node.properties['v-pre'] = true
102+
})
103+
104+
return {
105+
type: 'element',
106+
tagName: 'v-menu',
107+
properties: {
108+
'class': 'twoslash-hover',
109+
'popper-class': 'vp-code shiki floating-vue-twoslash vp-copy-ignore',
110+
'placement': 'bottom-start',
111+
'theme': 'twoslash',
112+
':arrow-padding': '8',
113+
...presisted && {
114+
':shown': 'true',
115+
':triggers': '[]',
116+
':popper-triggers': '[]',
117+
':auto-hide': 'false',
118+
},
119+
},
120+
children: [
121+
{
122+
type: 'element',
123+
tagName: 'span',
124+
properties: {},
125+
children: [
126+
node,
127+
],
128+
},
129+
{
130+
type: 'element',
131+
tagName: 'template',
132+
properties: {
133+
'v-slot:popper': '{}',
134+
},
135+
content: {
136+
type: 'root',
137+
children: themedContent,
138+
},
139+
children: [],
140+
},
141+
],
142+
}
143+
}
144+
145+
return {
146+
...rich,
147+
nodeStaticInfo(info, node) {
148+
return createFloatingVueWarpper.call(this, info.text, info.docs, node) || {}
149+
},
150+
nodeQuery(query, node) {
151+
if (!query.text)
152+
return {}
153+
return createFloatingVueWarpper.call(this, query.text, query.docs, node, true) || {}
154+
},
155+
}
156+
}

0 commit comments

Comments
 (0)