valaxy 0.6.2 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/client/components/PostCard.vue +26 -29
- package/client/config.ts +1 -1
- package/client/index.ts +5 -0
- package/client/locales/en.yml +18 -17
- package/client/locales/zh-CN.yml +5 -4
- package/client/main.ts +3 -0
- package/client/setup/main.ts +11 -0
- package/client/setups.ts +16 -0
- package/client/styles/common/custom-blocks.scss +7 -0
- package/client/styles/common/markdown.scss +0 -4
- package/dist/chunk-35O5DRGK.mjs +2270 -0
- package/dist/chunk-4VSND5ZW.mjs +1 -0
- package/dist/chunk-CDIW2WTI.js +1 -0
- package/dist/chunk-RGBLPQZ2.js +2270 -0
- package/dist/{index.d.ts → client/index.d.ts} +16 -160
- package/dist/client/index.js +1 -0
- package/dist/client/index.mjs +1 -0
- package/dist/index-a6b0a69b.d.ts +16 -0
- package/dist/{config-112ac884.d.ts → index-afca77df.d.ts} +223 -6
- package/dist/node/cli.js +13 -8
- package/dist/node/cli.mjs +13 -8
- package/dist/node/index.d.ts +13 -35
- package/dist/node/index.js +1 -1
- package/dist/node/index.mjs +1 -1
- package/dist/types/index.d.ts +10 -0
- package/dist/types/index.js +1 -0
- package/dist/types/index.mjs +0 -0
- package/package.json +27 -22
- package/shared/index.ts +19 -0
- package/config/index.ts +0 -18
- package/dist/chunk-23IW567G.mjs +0 -40
- package/dist/chunk-EAN2KU6W.mjs +0 -1
- package/dist/chunk-U5OMNIOK.js +0 -1
- package/dist/chunk-YUC5WP5Y.js +0 -40
- package/dist/index.js +0 -1
- package/dist/index.mjs +0 -1
- package/index.ts +0 -3
- package/node/build.ts +0 -31
- package/node/cli.ts +0 -192
- package/node/config.ts +0 -156
- package/node/index.ts +0 -1
- package/node/markdown/check.ts +0 -14
- package/node/markdown/highlight.ts +0 -38
- package/node/markdown/index.ts +0 -109
- package/node/markdown/markdown-it/container.ts +0 -61
- package/node/markdown/markdown-it/headings.ts +0 -32
- package/node/markdown/markdown-it/highlightLines.ts +0 -96
- package/node/markdown/markdown-it/katex.ts +0 -210
- package/node/markdown/markdown-it/parseHeader.ts +0 -72
- package/node/markdown/markdownToVue.ts +0 -275
- package/node/markdown/slugify.ts +0 -24
- package/node/options.ts +0 -108
- package/node/plugins/extendConfig.ts +0 -46
- package/node/plugins/index.ts +0 -224
- package/node/plugins/preset.ts +0 -186
- package/node/plugins/unocss.ts +0 -110
- package/node/plugins/valaxy.ts +0 -1
- package/node/rss.ts +0 -127
- package/node/server.ts +0 -23
- package/node/shims.d.ts +0 -33
- package/node/utils/cli.ts +0 -103
- package/node/utils/getGitTimestamp.ts +0 -13
- package/node/utils/index.ts +0 -59
- package/node/utils/net.ts +0 -20
- package/node/vite.ts +0 -52
- package/tsup.config.ts +0 -25
- package/types/config.ts +0 -217
- package/types/data.ts +0 -31
- package/types/index.ts +0 -3
- package/types/posts.ts +0 -122
package/node/config.ts
DELETED
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
// import { loadConfig } from 'c12'
|
|
2
|
-
import fs from 'fs'
|
|
3
|
-
import { loadConfig } from 'unconfig'
|
|
4
|
-
import defu from 'defu'
|
|
5
|
-
import type { ValaxyConfig } from '../types'
|
|
6
|
-
import type { ValaxyEntryOptions } from './options'
|
|
7
|
-
|
|
8
|
-
const defaultValaxyConfig: ValaxyConfig = {
|
|
9
|
-
url: '/',
|
|
10
|
-
lang: 'en',
|
|
11
|
-
title: 'Valaxy Blog',
|
|
12
|
-
description: 'A blog generated by Valaxy.',
|
|
13
|
-
subtitle: 'Next Generation Static Blog Framework.',
|
|
14
|
-
author: {
|
|
15
|
-
avatar: 'https://cdn.jsdelivr.net/gh/YunYouJun/yun/images/meme/yun-good-with-bg.jpg',
|
|
16
|
-
email: 'me@yunyoujun.cn',
|
|
17
|
-
link: 'https://www.yunyoujun.cn',
|
|
18
|
-
name: 'YunYouJun',
|
|
19
|
-
status: {
|
|
20
|
-
emoji: '😊',
|
|
21
|
-
message: 'All at sea.',
|
|
22
|
-
},
|
|
23
|
-
},
|
|
24
|
-
favicon: '/favicon.svg',
|
|
25
|
-
feed: {
|
|
26
|
-
name: '',
|
|
27
|
-
favicon: 'favicon.svg',
|
|
28
|
-
},
|
|
29
|
-
social: [],
|
|
30
|
-
|
|
31
|
-
lastUpdated: true,
|
|
32
|
-
|
|
33
|
-
license: {
|
|
34
|
-
enabled: true,
|
|
35
|
-
language: '',
|
|
36
|
-
type: 'by-nc-sa',
|
|
37
|
-
},
|
|
38
|
-
|
|
39
|
-
sponsor: {
|
|
40
|
-
enable: true,
|
|
41
|
-
title: '我很可爱,请给我钱',
|
|
42
|
-
methods: [
|
|
43
|
-
{
|
|
44
|
-
name: '支付宝',
|
|
45
|
-
url: 'https://cdn.jsdelivr.net/gh/YunYouJun/cdn/img/donate/alipay-qrcode.jpg',
|
|
46
|
-
color: '#00A3EE',
|
|
47
|
-
icon: 'i-ri-alipay-line',
|
|
48
|
-
},
|
|
49
|
-
{
|
|
50
|
-
name: 'QQ 支付',
|
|
51
|
-
url: 'https://cdn.jsdelivr.net/gh/YunYouJun/cdn/img/donate/qqpay-qrcode.png',
|
|
52
|
-
color: '#12B7F5',
|
|
53
|
-
icon: 'i-ri-qq-line',
|
|
54
|
-
},
|
|
55
|
-
{
|
|
56
|
-
name: '微信支付',
|
|
57
|
-
url: 'https://cdn.jsdelivr.net/gh/YunYouJun/cdn/img/donate/wechatpay-qrcode.jpg',
|
|
58
|
-
color: '#2DC100',
|
|
59
|
-
icon: 'i-ri-wechat-pay-line',
|
|
60
|
-
},
|
|
61
|
-
|
|
62
|
-
],
|
|
63
|
-
},
|
|
64
|
-
|
|
65
|
-
search: {
|
|
66
|
-
enable: true,
|
|
67
|
-
algolia: {
|
|
68
|
-
enable: false,
|
|
69
|
-
appId: '',
|
|
70
|
-
apiKey: '',
|
|
71
|
-
indexName: '',
|
|
72
|
-
},
|
|
73
|
-
},
|
|
74
|
-
|
|
75
|
-
comment: {
|
|
76
|
-
waline: {
|
|
77
|
-
enable: false,
|
|
78
|
-
serverURL: '',
|
|
79
|
-
},
|
|
80
|
-
twikoo: {
|
|
81
|
-
enable: false,
|
|
82
|
-
envId: 'https://twikoo.vercel.app',
|
|
83
|
-
},
|
|
84
|
-
},
|
|
85
|
-
|
|
86
|
-
features: {
|
|
87
|
-
katex: true,
|
|
88
|
-
},
|
|
89
|
-
|
|
90
|
-
theme: 'yun',
|
|
91
|
-
themeConfig: {
|
|
92
|
-
pkg: {
|
|
93
|
-
name: '',
|
|
94
|
-
version: '',
|
|
95
|
-
},
|
|
96
|
-
},
|
|
97
|
-
|
|
98
|
-
unocss: {},
|
|
99
|
-
|
|
100
|
-
// markdown: {
|
|
101
|
-
// excerpt: '<!-- more -->',
|
|
102
|
-
// },
|
|
103
|
-
|
|
104
|
-
markdownIt: {
|
|
105
|
-
toc: {
|
|
106
|
-
includeLevel: [1, 2, 3, 4],
|
|
107
|
-
listType: 'ol',
|
|
108
|
-
},
|
|
109
|
-
katex: {},
|
|
110
|
-
},
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
// for user config
|
|
114
|
-
export async function resolveConfig(options: ValaxyEntryOptions = {}) {
|
|
115
|
-
// c12 merge array twice, so i deprecated it
|
|
116
|
-
// const { config, configFile } = await loadConfig<ValaxyConfig>({
|
|
117
|
-
// name: 'valaxy',
|
|
118
|
-
// defaults: defaultValaxyConfig,
|
|
119
|
-
// })
|
|
120
|
-
|
|
121
|
-
const { config: userConfig, sources } = await loadConfig<ValaxyConfig>({
|
|
122
|
-
sources: [
|
|
123
|
-
{
|
|
124
|
-
files: 'valaxy.config',
|
|
125
|
-
extensions: ['ts', 'js', 'mjs', 'cjs', 'json'],
|
|
126
|
-
},
|
|
127
|
-
],
|
|
128
|
-
merge: false,
|
|
129
|
-
})
|
|
130
|
-
const configFile = sources[0]
|
|
131
|
-
const config = defu(userConfig, defaultValaxyConfig)
|
|
132
|
-
|
|
133
|
-
const theme = options.theme || config.theme || 'yun'
|
|
134
|
-
|
|
135
|
-
try {
|
|
136
|
-
const { defaultThemeConfig } = await import(`valaxy-theme-${theme}`)
|
|
137
|
-
config.themeConfig = defu(config.themeConfig, defaultThemeConfig)
|
|
138
|
-
}
|
|
139
|
-
catch (e) {
|
|
140
|
-
console.error(`valaxy-theme-${theme} doesn't have default config`)
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
try {
|
|
144
|
-
const pkg = fs.readFileSync(require.resolve(`valaxy-theme-${theme}/package.json`), 'utf-8')
|
|
145
|
-
config.themeConfig.pkg = JSON.parse(pkg)
|
|
146
|
-
}
|
|
147
|
-
catch (e) {
|
|
148
|
-
console.error(`valaxy-theme-${theme} doesn't have package.json`)
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
return {
|
|
152
|
-
config,
|
|
153
|
-
configFile,
|
|
154
|
-
theme,
|
|
155
|
-
}
|
|
156
|
-
}
|
package/node/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './server'
|
package/node/markdown/check.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { cyan, red, yellow } from 'kolorist'
|
|
2
|
-
import consola from 'consola'
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* check Markdown content
|
|
6
|
-
* @param content
|
|
7
|
-
*/
|
|
8
|
-
export function checkMd(content: string, path: string) {
|
|
9
|
-
if (content.includes('{%') && content.includes('%}')) {
|
|
10
|
-
consola.error(
|
|
11
|
-
`${`${path}\n`} Please ${red('remove')} ${cyan('{% %}')}, because it conflicts with ${yellow('markdown-it-attrs')}.`,
|
|
12
|
-
)
|
|
13
|
-
}
|
|
14
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { getHighlighter } from 'shiki'
|
|
2
|
-
import consola from 'consola'
|
|
3
|
-
import type { ThemeOptions } from '../markdown'
|
|
4
|
-
|
|
5
|
-
export async function highlight(theme: ThemeOptions = 'material-palenight') {
|
|
6
|
-
const themes = typeof theme === 'string' ? [theme] : [theme.dark, theme.light]
|
|
7
|
-
const highlighter = await getHighlighter({ themes })
|
|
8
|
-
const preRE = /^<pre.*?>/
|
|
9
|
-
|
|
10
|
-
return (str: string, lang: string) => {
|
|
11
|
-
lang = lang || 'text'
|
|
12
|
-
|
|
13
|
-
// https://stackoverflow.com/questions/22268952/what-is-the-difference-between-yaml-and-yml-extension
|
|
14
|
-
// use yaml better
|
|
15
|
-
|
|
16
|
-
// adaptive
|
|
17
|
-
if (lang === 'yml') {
|
|
18
|
-
lang = 'yaml'
|
|
19
|
-
consola.warn('[shiki] It is recommended to use `.yaml` instead of `.yml`.')
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
if (typeof theme === 'string') {
|
|
23
|
-
return highlighter
|
|
24
|
-
.codeToHtml(str, { lang, theme })
|
|
25
|
-
.replace(preRE, '<pre v-pre>')
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const dark = highlighter
|
|
29
|
-
.codeToHtml(str, { lang, theme: theme.dark })
|
|
30
|
-
.replace(preRE, '<pre v-pre class="vp-code-dark">')
|
|
31
|
-
|
|
32
|
-
const light = highlighter
|
|
33
|
-
.codeToHtml(str, { lang, theme: theme.light })
|
|
34
|
-
.replace(preRE, '<pre v-pre class="vp-code-light">')
|
|
35
|
-
|
|
36
|
-
return dark + light
|
|
37
|
-
}
|
|
38
|
-
}
|
package/node/markdown/index.ts
DELETED
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
import MarkdownIt from 'markdown-it'
|
|
2
|
-
|
|
3
|
-
import type { Theme } from 'shiki'
|
|
4
|
-
|
|
5
|
-
import Anchor from 'markdown-it-anchor'
|
|
6
|
-
import Emoji from 'markdown-it-emoji'
|
|
7
|
-
import LinkAttributes from 'markdown-it-link-attributes'
|
|
8
|
-
import TOC from 'markdown-it-table-of-contents'
|
|
9
|
-
import TaskLists from 'markdown-it-task-lists'
|
|
10
|
-
import attrs from 'markdown-it-attrs'
|
|
11
|
-
|
|
12
|
-
import type { KatexOptions } from 'katex'
|
|
13
|
-
import type { Header } from '../../types'
|
|
14
|
-
import Katex from './markdown-it/katex'
|
|
15
|
-
import { containerPlugin } from './markdown-it/container'
|
|
16
|
-
import { headingPlugin } from './markdown-it/headings'
|
|
17
|
-
import { slugify } from './slugify'
|
|
18
|
-
import { parseHeader } from './markdown-it/parseHeader'
|
|
19
|
-
import { highlight } from './highlight'
|
|
20
|
-
import { highlightLinePlugin, preWrapperPlugin } from './markdown-it/highlightLines'
|
|
21
|
-
|
|
22
|
-
export type ThemeOptions = Theme | { light: Theme; dark: Theme }
|
|
23
|
-
|
|
24
|
-
export interface MarkdownParsedData {
|
|
25
|
-
hoistedTags?: string[]
|
|
26
|
-
links?: string[]
|
|
27
|
-
headers?: Header[]
|
|
28
|
-
}
|
|
29
|
-
export interface MarkdownRenderer extends MarkdownIt {
|
|
30
|
-
__path: string
|
|
31
|
-
__relativePath: string
|
|
32
|
-
__data: MarkdownParsedData
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export interface MarkdownOptions extends MarkdownIt.Options {
|
|
36
|
-
config?: (md: MarkdownIt) => void
|
|
37
|
-
anchor?: {
|
|
38
|
-
permalink?: Anchor.AnchorOptions['permalink']
|
|
39
|
-
}
|
|
40
|
-
// https://github.com/Oktavilla/markdown-it-table-of-contents
|
|
41
|
-
toc?: {
|
|
42
|
-
includeLevel?: number[]
|
|
43
|
-
[key: string]: any
|
|
44
|
-
}
|
|
45
|
-
katex?: KatexOptions
|
|
46
|
-
/**
|
|
47
|
-
* shiki
|
|
48
|
-
*/
|
|
49
|
-
theme?: ThemeOptions
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export async function setupMarkdownPlugins(md: MarkdownIt, mdOptions: MarkdownOptions = {}) {
|
|
53
|
-
md
|
|
54
|
-
.use(highlightLinePlugin)
|
|
55
|
-
.use(preWrapperPlugin)
|
|
56
|
-
.use(containerPlugin)
|
|
57
|
-
// conflict with {% %}
|
|
58
|
-
.use(attrs)
|
|
59
|
-
// generate toc in client
|
|
60
|
-
.use(headingPlugin, mdOptions?.toc?.includeLevel)
|
|
61
|
-
// .use(lineNumberPlugin)
|
|
62
|
-
// https://github.com/arve0/markdown-it-attrs
|
|
63
|
-
// add classes
|
|
64
|
-
md
|
|
65
|
-
.use(LinkAttributes, {
|
|
66
|
-
matcher: (link: string) => /^https?:\/\//.test(link),
|
|
67
|
-
attrs: {
|
|
68
|
-
target: '_blank',
|
|
69
|
-
rel: 'noopener',
|
|
70
|
-
},
|
|
71
|
-
})
|
|
72
|
-
md.use(Katex, mdOptions.katex)
|
|
73
|
-
.use(Anchor, {
|
|
74
|
-
slugify,
|
|
75
|
-
permalink: Anchor.permalink.ariaHidden({}),
|
|
76
|
-
})
|
|
77
|
-
.use(TOC, {
|
|
78
|
-
slugify,
|
|
79
|
-
includeLevel: [2, 3, 4],
|
|
80
|
-
format: parseHeader,
|
|
81
|
-
...mdOptions.toc,
|
|
82
|
-
})
|
|
83
|
-
.use(Emoji)
|
|
84
|
-
.use(TaskLists)
|
|
85
|
-
|
|
86
|
-
const originalRender = md.render
|
|
87
|
-
md.render = (...args) => {
|
|
88
|
-
(md as MarkdownRenderer).__data = {}
|
|
89
|
-
return originalRender.call(md, ...args)
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
return md as MarkdownRenderer
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
export const createMarkdownRenderer = async (
|
|
96
|
-
srcDir: string,
|
|
97
|
-
options: MarkdownOptions = {},
|
|
98
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
99
|
-
base = '/',
|
|
100
|
-
): Promise<MarkdownRenderer> => {
|
|
101
|
-
const md = MarkdownIt({
|
|
102
|
-
html: true,
|
|
103
|
-
linkify: true,
|
|
104
|
-
highlight: await highlight(options.theme),
|
|
105
|
-
...options,
|
|
106
|
-
}) as MarkdownRenderer
|
|
107
|
-
await setupMarkdownPlugins(md)
|
|
108
|
-
return md
|
|
109
|
-
}
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
// ref vitepress
|
|
2
|
-
// src/node/markdown/plugins/containers.ts
|
|
3
|
-
|
|
4
|
-
import type MarkdownIt from 'markdown-it'
|
|
5
|
-
import type Token from 'markdown-it/lib/token'
|
|
6
|
-
import container from 'markdown-it-container'
|
|
7
|
-
|
|
8
|
-
type ContainerArgs = [
|
|
9
|
-
typeof container,
|
|
10
|
-
string,
|
|
11
|
-
{
|
|
12
|
-
render(tokens: Token[], idx: number): string
|
|
13
|
-
},
|
|
14
|
-
]
|
|
15
|
-
|
|
16
|
-
function createContainer(classes: string, defaultTitle: string): ContainerArgs {
|
|
17
|
-
return [
|
|
18
|
-
container,
|
|
19
|
-
classes,
|
|
20
|
-
{
|
|
21
|
-
render(tokens, idx) {
|
|
22
|
-
const token = tokens[idx]
|
|
23
|
-
const info = token.info.trim().slice(classes.length).trim()
|
|
24
|
-
if (token.nesting === 1) {
|
|
25
|
-
if (classes === 'details') {
|
|
26
|
-
return `<details class="${classes} custom-block">${
|
|
27
|
-
`<summary>${info}</summary>`
|
|
28
|
-
}\n`
|
|
29
|
-
}
|
|
30
|
-
return `<div class="${classes} custom-block"><p class="custom-block-title">${
|
|
31
|
-
info || defaultTitle
|
|
32
|
-
}</p>\n`
|
|
33
|
-
}
|
|
34
|
-
else {
|
|
35
|
-
return classes === 'details' ? '</details>\n' : '</div>\n'
|
|
36
|
-
}
|
|
37
|
-
},
|
|
38
|
-
},
|
|
39
|
-
]
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export const containerPlugin = (md: MarkdownIt) => {
|
|
43
|
-
md.use(...createContainer('tip', 'TIP'))
|
|
44
|
-
.use(...createContainer('info', 'INFO'))
|
|
45
|
-
.use(...createContainer('warning', 'WARNING'))
|
|
46
|
-
.use(...createContainer('danger', 'WARNING'))
|
|
47
|
-
.use(...createContainer('details', 'Details'))
|
|
48
|
-
// explicitly escape Vue syntax
|
|
49
|
-
.use(container, 'v-pre', {
|
|
50
|
-
render: (tokens: Token[], idx: number) =>
|
|
51
|
-
tokens[idx].nesting === 1 ? '<div v-pre>\n' : '</div>\n',
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
const languages = ['zh-CN', 'en']
|
|
55
|
-
languages.forEach((lang) => {
|
|
56
|
-
md.use(container, lang, {
|
|
57
|
-
render: (tokens: Token[], idx: number) =>
|
|
58
|
-
tokens[idx].nesting === 1 ? `<div lang="${lang}">\n` : '</div>\n',
|
|
59
|
-
})
|
|
60
|
-
})
|
|
61
|
-
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
// ref vitepress
|
|
2
|
-
import type MarkdownIt from 'markdown-it'
|
|
3
|
-
import type { MarkdownRenderer } from '..'
|
|
4
|
-
import { slugify } from '../slugify'
|
|
5
|
-
import { deeplyParseHeader } from './parseHeader'
|
|
6
|
-
|
|
7
|
-
export const headingPlugin = (md: MarkdownIt, include = [1, 2, 3, 4]) => {
|
|
8
|
-
md.renderer.rules.heading_open = (tokens, i, options, env, self) => {
|
|
9
|
-
const token = tokens[i]
|
|
10
|
-
const tags = include.map(item => `h${item}`)
|
|
11
|
-
if (tags.includes(token.tag)) {
|
|
12
|
-
const content = tokens[i + 1].content
|
|
13
|
-
const idAttr = token.attrs!.find(([name]) => name === 'id')
|
|
14
|
-
const slug = idAttr && idAttr[1]
|
|
15
|
-
const data = (md as MarkdownRenderer).__data
|
|
16
|
-
const headers = data.headers || (data.headers = [])
|
|
17
|
-
// remove {} after head
|
|
18
|
-
const leftDeli = content.indexOf('{')
|
|
19
|
-
const title = leftDeli === -1 ? content : content.slice(0, leftDeli).trim()
|
|
20
|
-
|
|
21
|
-
const matched = content.match(/\{lang=\"(.*)\"\}/)
|
|
22
|
-
const lang = matched ? matched[1] : ''
|
|
23
|
-
headers.push({
|
|
24
|
-
level: parseInt(token.tag.slice(1), 10),
|
|
25
|
-
title: deeplyParseHeader(title),
|
|
26
|
-
slug: slug || slugify(title),
|
|
27
|
-
lang,
|
|
28
|
-
})
|
|
29
|
-
}
|
|
30
|
-
return self.renderToken(tokens, i, options)
|
|
31
|
-
}
|
|
32
|
-
}
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
// Modified from https://github.com/egoist/markdown-it-highlight-lines
|
|
2
|
-
import type MarkdownIt from 'markdown-it'
|
|
3
|
-
|
|
4
|
-
const wrapperRE = /^<pre .*?><code>/
|
|
5
|
-
|
|
6
|
-
export const highlightLinePlugin = (md: MarkdownIt) => {
|
|
7
|
-
const fence = md.renderer.rules.fence!
|
|
8
|
-
md.renderer.rules.fence = (...args) => {
|
|
9
|
-
const [tokens, idx, options] = args
|
|
10
|
-
const token = tokens[idx]
|
|
11
|
-
|
|
12
|
-
// due to use of markdown-it-attrs, the {0} syntax would have been converted
|
|
13
|
-
// to attrs on the token
|
|
14
|
-
const attr = token.attrs && token.attrs[0]
|
|
15
|
-
if (!attr)
|
|
16
|
-
return fence(...args)
|
|
17
|
-
|
|
18
|
-
const lines = attr[0]
|
|
19
|
-
if (!lines || !/[\d,-]+/.test(lines))
|
|
20
|
-
return fence(...args)
|
|
21
|
-
|
|
22
|
-
const lineNumbers = lines
|
|
23
|
-
.split(',')
|
|
24
|
-
.map(v => v.split('-').map(v => parseInt(v, 10)))
|
|
25
|
-
|
|
26
|
-
const code = options.highlight
|
|
27
|
-
? options.highlight(token.content, token.info, '')
|
|
28
|
-
: token.content
|
|
29
|
-
|
|
30
|
-
const rawCode = code.replace(wrapperRE, '')
|
|
31
|
-
const highlightLinesCode = rawCode
|
|
32
|
-
.split('\n')
|
|
33
|
-
.map((split, index) => {
|
|
34
|
-
const lineNumber = index + 1
|
|
35
|
-
const inRange = lineNumbers.some(([start, end]) => {
|
|
36
|
-
if (start && end)
|
|
37
|
-
return lineNumber >= start && lineNumber <= end
|
|
38
|
-
|
|
39
|
-
return lineNumber === start
|
|
40
|
-
})
|
|
41
|
-
if (inRange)
|
|
42
|
-
return '<div class="highlighted"> </div>'
|
|
43
|
-
|
|
44
|
-
return '<br>'
|
|
45
|
-
})
|
|
46
|
-
.join('')
|
|
47
|
-
|
|
48
|
-
const highlightLinesWrapperCode = `<div class="highlight-lines">${highlightLinesCode}</div>`
|
|
49
|
-
|
|
50
|
-
return highlightLinesWrapperCode + code
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// markdown-it plugin for wrapping <pre> ... </pre>.
|
|
55
|
-
//
|
|
56
|
-
// If your plugin was chained before preWrapper, you can add additional element directly.
|
|
57
|
-
// If your plugin was chained after preWrapper, you can use these slots:
|
|
58
|
-
// 1. <!--beforebegin-->
|
|
59
|
-
// 2. <!--afterbegin-->
|
|
60
|
-
// 3. <!--beforeend-->
|
|
61
|
-
// 4. <!--afterend-->
|
|
62
|
-
export const preWrapperPlugin = (md: MarkdownIt) => {
|
|
63
|
-
const fence = md.renderer.rules.fence!
|
|
64
|
-
md.renderer.rules.fence = (...args) => {
|
|
65
|
-
const [tokens, idx] = args
|
|
66
|
-
const token = tokens[idx]
|
|
67
|
-
const rawCode = fence(...args)
|
|
68
|
-
return `<div class="language-${token.info.trim()}"><span class="copy"></span>${rawCode}</div>`
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// markdown-it plugin for generating line numbers.
|
|
73
|
-
// It depends on preWrapper plugin.
|
|
74
|
-
export const lineNumberPlugin = (md: MarkdownIt) => {
|
|
75
|
-
const fence = md.renderer.rules.fence!
|
|
76
|
-
md.renderer.rules.fence = (...args) => {
|
|
77
|
-
const rawCode = fence(...args)
|
|
78
|
-
const code = rawCode.slice(
|
|
79
|
-
rawCode.indexOf('<code>'),
|
|
80
|
-
rawCode.indexOf('</code>'),
|
|
81
|
-
)
|
|
82
|
-
|
|
83
|
-
const lines = code.split('\n')
|
|
84
|
-
const lineNumbersCode = [...Array(lines.length - 1)]
|
|
85
|
-
.map((line, index) => `<span class="line-number">${index + 1}</span><br>`)
|
|
86
|
-
.join('')
|
|
87
|
-
|
|
88
|
-
const lineNumbersWrapperCode = `<div class="line-numbers-wrapper">${lineNumbersCode}</div>`
|
|
89
|
-
|
|
90
|
-
const finalCode = rawCode
|
|
91
|
-
.replace(/<\/div>$/, `${lineNumbersWrapperCode}</div>`)
|
|
92
|
-
.replace(/"(language-\w+)"/, '"$1 line-numbers-mode"')
|
|
93
|
-
|
|
94
|
-
return finalCode
|
|
95
|
-
}
|
|
96
|
-
}
|