Skip to content

Commit a0d124c

Browse files
committed
chore: tweaks
1 parent 0b28076 commit a0d124c

File tree

8 files changed

+134
-102
lines changed

8 files changed

+134
-102
lines changed

plugins/plugin-prismjs/src/node/parser/notation.ts

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,14 @@
1515
* - `// [!code ++:3]`
1616
* - ...more
1717
*/
18+
import { escapeRegExp } from '../utils/index.js'
1819
import type { NodeOpen, Parser } from './parse.js'
1920

20-
const commentEmptyTag = /<span class="token comment">\s*?<\/span>/
21+
const COMMENT_EMPTY_TAG = /<span class="token comment">\s*?<\/span>/
22+
23+
const toArray = <T>(value: T | T[]): T[] =>
24+
Array.isArray(value) ? value : [value]
25+
2126
export interface NotationOption {
2227
classMap: Record<string, string | string[]>
2328
classPre?: string
@@ -57,7 +62,7 @@ export const notationBase = (parser: Parser, options: NotationOption): void => {
5762
})
5863
if (
5964
replaced &&
60-
!(node.content = node.content.replace(commentEmptyTag, '')).trim()
65+
!(node.content = node.content.replace(COMMENT_EMPTY_TAG, '')).trim()
6166
) {
6267
nodeRemove.push(node)
6368
}
@@ -66,14 +71,6 @@ export const notationBase = (parser: Parser, options: NotationOption): void => {
6671
parser.lines.splice(parser.lines.indexOf(node), 1)
6772
}
6873

69-
function escapeRegExp(str: string): string {
70-
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
71-
}
72-
73-
function toArray<T>(value: T | T[]): T[] {
74-
return Array.isArray(value) ? value : [value]
75-
}
76-
7774
/**
7875
* line highlight
7976
*

plugins/plugin-prismjs/src/node/parser/parse.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,11 @@ export interface Parser {
4242
const splitLines = (code: string): string[] => {
4343
const parts = code.split(SPLIT_RE)
4444
const lines: string[] = []
45+
4546
for (let i = 0; i < parts.length; i += 2) {
4647
lines.push(parts[i])
4748
}
49+
4850
return lines
4951
}
5052

@@ -54,6 +56,7 @@ const createNodeOpen = (
5456
classes: string[] = [],
5557
): NodeOpen => {
5658
const match = html.match(CLASS_RE)
59+
5760
if (!match) {
5861
const hashHtml = html.length > 1
5962
return {
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export const escapeRegExp = (str: string): string =>
2+
str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')

plugins/plugin-prismjs/src/node/utils/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
export * from './escapeRegExp.js'
12
export * from './languages.js'
23
export * from './resolveLanguage.js'
34
export * from './resolveAttr.js'

plugins/plugin-shiki/src/node/resolveHighlight.ts

Lines changed: 22 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,18 @@
1-
import {
2-
transformerCompactLineOptions,
3-
transformerNotationDiff,
4-
transformerNotationErrorLevel,
5-
transformerNotationFocus,
6-
transformerNotationHighlight,
7-
} from '@shikijs/transformers'
8-
import type { ShikiTransformer } from 'shiki'
1+
import { transformerCompactLineOptions } from '@shikijs/transformers'
92
import {
103
bundledLanguages,
114
getHighlighter,
125
isPlainLang,
136
isSpecialLang,
147
} from 'shiki'
158
import { colors, logger } from 'vuepress/utils'
9+
import { getTransformers } from './transformers/getTransformers.js'
1610
import type { ShikiPluginOptions } from './types.js'
1711
import { attrsToLines, nanoid, resolveLanguage } from './utils.js'
1812

1913
const DEFAULT_LANGS = Object.keys(bundledLanguages)
2014

21-
const RE_ESCAPE = /\[\\!code/g
22-
const mustacheRE = /\{\{.*?\}\}/g
15+
const MUSTACHE_REG = /\{\{[\s\S]*?\}\}/g
2316

2417
export const resolveHighlight = async ({
2518
langs = DEFAULT_LANGS,
@@ -38,50 +31,7 @@ export const resolveHighlight = async ({
3831

3932
await options.shikiSetup?.(highlighter)
4033

41-
const transformers: ShikiTransformer[] = []
42-
43-
if (options.notationDiff) {
44-
transformers.push(transformerNotationDiff())
45-
}
46-
47-
if (options.notationFocus) {
48-
transformers.push(
49-
transformerNotationFocus({
50-
classActiveLine: 'has-focus',
51-
classActivePre: 'has-focused-lines',
52-
}),
53-
)
54-
}
55-
56-
if (options.notationHighlight) {
57-
transformers.push(transformerNotationHighlight())
58-
}
59-
60-
if (options.notationErrorLevel) {
61-
transformers.push(transformerNotationErrorLevel())
62-
}
63-
64-
transformers.push(
65-
...([
66-
{
67-
name: 'vuepress:add-class',
68-
pre(node) {
69-
this.addClassToHast(node, 'vp-code')
70-
},
71-
},
72-
{
73-
name: 'vuepress:clean-up',
74-
pre(node) {
75-
delete node.properties.tabindex
76-
delete node.properties.style
77-
},
78-
},
79-
{
80-
name: 'vuepress:remove-escape',
81-
postprocess: (code) => code.replace(RE_ESCAPE, '[!code'),
82-
},
83-
] as ShikiTransformer[]),
84-
)
34+
const transformers = getTransformers(options)
8535

8636
return (str, language, attrs) => {
8737
let lang = resolveLanguage(language)
@@ -98,60 +48,40 @@ export const resolveHighlight = async ({
9848
}
9949
}
10050

101-
const codeTransformers: ShikiTransformer[] = [
102-
{
103-
name: 'vuepress:empty-line',
104-
code(hast) {
105-
hast.children.forEach((span) => {
106-
if (
107-
span.type === 'element' &&
108-
span.tagName === 'span' &&
109-
Array.isArray(span.properties.class) &&
110-
span.properties.class.includes('line') &&
111-
span.children.length === 0
112-
) {
113-
span.children.push({
114-
type: 'element',
115-
tagName: 'wbr',
116-
properties: {},
117-
children: [],
118-
})
119-
}
120-
})
121-
},
122-
},
123-
]
124-
125-
if (options.highlightLines ?? true) {
126-
codeTransformers.push(transformerCompactLineOptions(attrsToLines(attrs)))
127-
}
51+
const codeMustaches = new Map<string, string>()
12852

129-
const mustaches = new Map<string, string>()
53+
const removeMustache = (str: string): string =>
54+
str.replace(MUSTACHE_REG, (match) => {
55+
let marker = codeMustaches.get(match)
13056

131-
const removeMustache = (s: string): string => {
132-
return s.replace(mustacheRE, (match) => {
133-
let marker = mustaches.get(match)
13457
if (!marker) {
13558
marker = nanoid()
136-
mustaches.set(match, marker)
59+
codeMustaches.set(match, marker)
13760
}
61+
13862
return marker
13963
})
140-
}
14164

142-
const restoreMustache = (s: string): string => {
143-
mustaches.forEach((marker, match) => {
144-
s = s.replaceAll(marker, match)
65+
const restoreMustache = (str: string): string => {
66+
codeMustaches.forEach((marker, match) => {
67+
str = str.replaceAll(marker, match)
14568
})
146-
return s
69+
70+
return str
14771
}
14872

14973
str = removeMustache(str).trimEnd()
15074

15175
const highlighted = highlighter.codeToHtml(str, {
15276
lang,
15377
meta: { __raw: attrs },
154-
transformers: [...transformers, ...codeTransformers, ...userTransformers],
78+
transformers: [
79+
...transformers,
80+
...(options.highlightLines ?? true
81+
? [transformerCompactLineOptions(attrsToLines(attrs))]
82+
: []),
83+
...userTransformers,
84+
],
15585
...(themes ? { themes, defaultColor: options.defaultColor } : { theme }),
15686
})
15787

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import {
2+
transformerNotationDiff,
3+
transformerNotationErrorLevel,
4+
transformerNotationFocus,
5+
transformerNotationHighlight,
6+
} from '@shikijs/transformers'
7+
import type { ShikiTransformer } from 'shiki'
8+
import type { ShikiPluginOptions } from '../types.js'
9+
import {
10+
addClassTransformer,
11+
cleanUpTransformer,
12+
emptyLineTransformer,
13+
removeEscapeTransformer,
14+
} from './vuepressTransformers.js'
15+
16+
export const getTransformers = (
17+
options: ShikiPluginOptions,
18+
): ShikiTransformer[] => {
19+
const transformers: ShikiTransformer[] = []
20+
21+
if (options.notationDiff) {
22+
transformers.push(transformerNotationDiff())
23+
}
24+
25+
if (options.notationFocus) {
26+
transformers.push(
27+
transformerNotationFocus({
28+
classActiveLine: 'has-focus',
29+
classActivePre: 'has-focused-lines',
30+
}),
31+
)
32+
}
33+
34+
if (options.notationHighlight) {
35+
transformers.push(transformerNotationHighlight())
36+
}
37+
38+
if (options.notationErrorLevel) {
39+
transformers.push(transformerNotationErrorLevel())
40+
}
41+
42+
transformers.push(
43+
addClassTransformer,
44+
cleanUpTransformer,
45+
removeEscapeTransformer,
46+
emptyLineTransformer,
47+
)
48+
49+
return transformers
50+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './getTransformers.js'
2+
export * from './vuepressTransformers.js'
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import type { ShikiTransformer } from 'shiki'
2+
3+
const ESCAPE_RE = /\[\\!code/g
4+
5+
export const addClassTransformer: ShikiTransformer = {
6+
name: 'vuepress:add-class',
7+
pre(node) {
8+
this.addClassToHast(node, 'vp-code')
9+
},
10+
}
11+
12+
export const cleanUpTransformer: ShikiTransformer = {
13+
name: 'vuepress:clean-up',
14+
pre(node) {
15+
delete node.properties.tabindex
16+
delete node.properties.style
17+
},
18+
}
19+
20+
export const removeEscapeTransformer: ShikiTransformer = {
21+
name: 'vuepress:remove-escape',
22+
postprocess(code) {
23+
return code.replace(ESCAPE_RE, '[!code')
24+
},
25+
}
26+
27+
export const emptyLineTransformer: ShikiTransformer = {
28+
name: 'vuepress:empty-line',
29+
code(hast) {
30+
hast.children.forEach((span) => {
31+
if (
32+
span.type === 'element' &&
33+
span.tagName === 'span' &&
34+
Array.isArray(span.properties.class) &&
35+
span.properties.class.includes('line') &&
36+
span.children.length === 0
37+
) {
38+
span.children.push({
39+
type: 'element',
40+
tagName: 'wbr',
41+
properties: {},
42+
children: [],
43+
})
44+
}
45+
})
46+
},
47+
}

0 commit comments

Comments
 (0)