vuepress-plugin-md-power 1.0.0-rc.144 → 1.0.0-rc.146
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/lib/client/components/FileTreeNode.vue +34 -16
- package/lib/client/components/VPCodeTree.vue +159 -0
- package/lib/client/components/VPField.vue +94 -0
- package/lib/node/index.d.ts +25 -0
- package/lib/node/index.js +367 -160
- package/lib/shared/index.d.ts +25 -0
- package/package.json +11 -10
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import type { Ref } from 'vue'
|
|
3
|
-
import { FadeInExpandTransition } from '@vuepress/helper/client'
|
|
4
3
|
import { inject, ref } from 'vue'
|
|
5
4
|
|
|
6
|
-
import '@vuepress/helper/transition/fade-in-height-expand.css'
|
|
7
|
-
|
|
8
5
|
const props = defineProps<{
|
|
9
6
|
type: 'file' | 'folder'
|
|
10
7
|
filename: string
|
|
8
|
+
level: number
|
|
9
|
+
diff?: 'add' | 'remove'
|
|
11
10
|
expanded?: boolean
|
|
12
11
|
focus?: boolean
|
|
12
|
+
filepath?: string
|
|
13
13
|
}>()
|
|
14
14
|
|
|
15
15
|
const activeFileTreeNode = inject<Ref<string>>('active-file-tree-node', ref(''))
|
|
@@ -24,7 +24,7 @@ function nodeClick() {
|
|
|
24
24
|
if (props.filename === '…' || props.filename === '...')
|
|
25
25
|
return
|
|
26
26
|
|
|
27
|
-
onNodeClick(props.filename, props.type)
|
|
27
|
+
onNodeClick(props.filepath || props.filename, props.type)
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
function toggle(ev: MouseEvent) {
|
|
@@ -48,19 +48,21 @@ function toggle(ev: MouseEvent) {
|
|
|
48
48
|
[type]: true,
|
|
49
49
|
focus,
|
|
50
50
|
expanded: type === 'folder' ? active : false,
|
|
51
|
-
active: type === 'file' ? activeFileTreeNode ===
|
|
51
|
+
active: type === 'file' ? activeFileTreeNode === filepath : false,
|
|
52
|
+
diff,
|
|
53
|
+
add: diff === 'add',
|
|
54
|
+
remove: diff === 'remove',
|
|
52
55
|
}"
|
|
56
|
+
:style="{ '--file-tree-level': -level }"
|
|
53
57
|
@click="toggle"
|
|
54
58
|
>
|
|
55
59
|
<slot name="icon" />
|
|
56
60
|
<span class="name" :class="[type]">{{ filename }}</span>
|
|
57
61
|
<span v-if="$slots.comment" class="comment"><slot name="comment" /></span>
|
|
58
62
|
</p>
|
|
59
|
-
<
|
|
60
|
-
<
|
|
61
|
-
|
|
62
|
-
</div>
|
|
63
|
-
</FadeInExpandTransition>
|
|
63
|
+
<div v-if="type === 'folder'" v-show="active" class="group">
|
|
64
|
+
<slot />
|
|
65
|
+
</div>
|
|
64
66
|
</div>
|
|
65
67
|
</template>
|
|
66
68
|
|
|
@@ -100,24 +102,40 @@ function toggle(ev: MouseEvent) {
|
|
|
100
102
|
|
|
101
103
|
.vp-file-tree .vp-file-tree-info::after {
|
|
102
104
|
position: absolute;
|
|
103
|
-
top:
|
|
104
|
-
right:
|
|
105
|
-
bottom:
|
|
106
|
-
left: -
|
|
105
|
+
top: 0;
|
|
106
|
+
right: -16px;
|
|
107
|
+
bottom: 0;
|
|
108
|
+
left: calc(var(--file-tree-level) * 28px - 32px);
|
|
107
109
|
z-index: 0;
|
|
108
110
|
display: block;
|
|
109
111
|
pointer-events: none;
|
|
110
112
|
content: "";
|
|
111
113
|
background-color: transparent;
|
|
112
|
-
border-radius: 6px;
|
|
113
114
|
transition: background-color var(--vp-t-color);
|
|
114
115
|
}
|
|
115
116
|
|
|
116
117
|
.vp-file-tree .vp-file-tree-info.active::after,
|
|
117
|
-
.vp-file-tree .vp-file-tree-info:hover::after {
|
|
118
|
+
.vp-file-tree .vp-file-tree-info:not(.diff):hover::after {
|
|
118
119
|
background-color: var(--vp-c-default-soft);
|
|
119
120
|
}
|
|
120
121
|
|
|
122
|
+
.vp-file-tree .vp-file-tree-info.diff::after {
|
|
123
|
+
padding-left: 4px;
|
|
124
|
+
font-size: 1.25em;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.vp-file-tree .vp-file-tree-info.diff.add::after {
|
|
128
|
+
color: var(--vp-c-success-1);
|
|
129
|
+
content: "+";
|
|
130
|
+
background-color: var(--vp-c-success-soft);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.vp-file-tree .vp-file-tree-info.diff.remove::after {
|
|
134
|
+
color: var(--vp-c-danger-1);
|
|
135
|
+
content: "-";
|
|
136
|
+
background-color: var(--vp-c-danger-soft);
|
|
137
|
+
}
|
|
138
|
+
|
|
121
139
|
.vp-file-tree .vp-file-tree-info.folder {
|
|
122
140
|
cursor: pointer;
|
|
123
141
|
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { onMounted, provide, ref, useTemplateRef, watch } from 'vue'
|
|
3
|
+
|
|
4
|
+
const props = withDefaults(defineProps<{
|
|
5
|
+
title?: string
|
|
6
|
+
height?: string
|
|
7
|
+
entryFile?: string
|
|
8
|
+
}>(), { height: '320px' })
|
|
9
|
+
|
|
10
|
+
const activeNode = ref(props.entryFile || '')
|
|
11
|
+
const isEmpty = ref(true)
|
|
12
|
+
const codePanel = useTemplateRef<HTMLDivElement>('codePanel')
|
|
13
|
+
|
|
14
|
+
provide('active-file-tree-node', activeNode)
|
|
15
|
+
provide('on-file-tree-node-click', (filepath: string, type: 'file' | 'folder') => {
|
|
16
|
+
if (type === 'file') {
|
|
17
|
+
activeNode.value = filepath
|
|
18
|
+
}
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
onMounted(() => {
|
|
22
|
+
watch(
|
|
23
|
+
() => activeNode.value,
|
|
24
|
+
() => {
|
|
25
|
+
if (codePanel.value) {
|
|
26
|
+
const items = Array.from(codePanel.value.querySelectorAll('.code-block-title'))
|
|
27
|
+
let hasActive = false
|
|
28
|
+
items.forEach((item) => {
|
|
29
|
+
if (item.getAttribute('data-title') === activeNode.value) {
|
|
30
|
+
item.classList.add('active')
|
|
31
|
+
hasActive = true
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
item.classList.remove('active')
|
|
35
|
+
}
|
|
36
|
+
})
|
|
37
|
+
isEmpty.value = !hasActive
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
{ immediate: true },
|
|
41
|
+
)
|
|
42
|
+
})
|
|
43
|
+
</script>
|
|
44
|
+
|
|
45
|
+
<template>
|
|
46
|
+
<div class="vp-code-tree">
|
|
47
|
+
<div class="code-tree-panel" :style="{ 'max-height': props.height }">
|
|
48
|
+
<div v-if="title" class="code-tree-title" :title="title">
|
|
49
|
+
<span>{{ title }}</span>
|
|
50
|
+
</div>
|
|
51
|
+
<div class="vp-file-tree">
|
|
52
|
+
<slot name="file-tree" />
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
<div ref="codePanel" class="code-panel" :style="{ height: props.height }">
|
|
56
|
+
<slot />
|
|
57
|
+
<div v-if="isEmpty" class="code-tree-empty">
|
|
58
|
+
<span class="vpi-code-tree-empty" />
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
</template>
|
|
63
|
+
|
|
64
|
+
<style>
|
|
65
|
+
.vp-code-tree {
|
|
66
|
+
width: 100%;
|
|
67
|
+
margin: 16px 0;
|
|
68
|
+
overflow: hidden;
|
|
69
|
+
border: solid 1px var(--vp-c-divider);
|
|
70
|
+
border-radius: 6px;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
@media (min-width: 768px) {
|
|
74
|
+
.vp-code-tree {
|
|
75
|
+
display: grid;
|
|
76
|
+
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.vp-code-tree .code-tree-panel {
|
|
81
|
+
display: flex;
|
|
82
|
+
flex-direction: column;
|
|
83
|
+
border-bottom: solid 1px var(--vp-c-divider);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
@media (min-width: 768px) {
|
|
87
|
+
.vp-code-tree .code-tree-panel {
|
|
88
|
+
border-right: solid 1px var(--vp-c-divider);
|
|
89
|
+
border-bottom: none;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.vp-code-tree .code-tree-panel .code-tree-title {
|
|
94
|
+
height: 40px;
|
|
95
|
+
padding: 0 16px;
|
|
96
|
+
overflow: hidden;
|
|
97
|
+
font-weight: 500;
|
|
98
|
+
line-height: 40px;
|
|
99
|
+
text-overflow: ellipsis;
|
|
100
|
+
white-space: nowrap;
|
|
101
|
+
border-bottom: solid 1px var(--vp-c-divider);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.vp-code-tree .code-tree-panel .vp-file-tree {
|
|
105
|
+
flex: 1 2;
|
|
106
|
+
margin: 0;
|
|
107
|
+
overflow: auto;
|
|
108
|
+
background-color: transparent;
|
|
109
|
+
border: none;
|
|
110
|
+
border-radius: 0;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.vp-code-tree .code-tree-panel .vp-file-tree .vp-file-tree-info.file {
|
|
114
|
+
cursor: pointer;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.vp-code-tree .code-panel {
|
|
118
|
+
grid-column: span 2 / span 2;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.vp-code-tree .code-panel [class*="language-"] {
|
|
122
|
+
flex: 1 2;
|
|
123
|
+
margin: 16px 0 0;
|
|
124
|
+
overflow: auto;
|
|
125
|
+
border-bottom-right-radius: 0;
|
|
126
|
+
border-bottom-left-radius: 0;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.vp-code-tree .code-panel .code-block-title {
|
|
130
|
+
display: none;
|
|
131
|
+
height: 100%;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.vp-code-tree .code-panel .code-block-title.active {
|
|
135
|
+
display: flex;
|
|
136
|
+
flex-direction: column;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.vp-code-tree .code-panel .code-block-title .code-block-title-bar {
|
|
140
|
+
margin-top: 0;
|
|
141
|
+
border-radius: 0;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.vp-code-tree .code-panel .code-tree-empty {
|
|
145
|
+
display: flex;
|
|
146
|
+
align-items: center;
|
|
147
|
+
justify-content: center;
|
|
148
|
+
width: 100%;
|
|
149
|
+
height: 100%;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.vp-code-tree .code-panel .code-tree-empty .vpi-code-tree-empty {
|
|
153
|
+
--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='256' height='256' viewBox='0 0 256 256'%3E%3Cpath fill='%23000' d='m198.24 62.63l15.68-17.25a8 8 0 0 0-11.84-10.76L186.4 51.86A95.95 95.95 0 0 0 57.76 193.37l-15.68 17.25a8 8 0 1 0 11.84 10.76l15.68-17.24A95.95 95.95 0 0 0 198.24 62.63M48 128a80 80 0 0 1 127.6-64.25l-107 117.73A79.63 79.63 0 0 1 48 128m80 80a79.55 79.55 0 0 1-47.6-15.75l107-117.73A79.95 79.95 0 0 1 128 208'/%3E%3C/svg%3E");
|
|
154
|
+
|
|
155
|
+
width: 128px;
|
|
156
|
+
height: 128px;
|
|
157
|
+
color: var(--vp-c-default-soft);
|
|
158
|
+
}
|
|
159
|
+
</style>
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
defineProps<{
|
|
3
|
+
name: string
|
|
4
|
+
type?: string
|
|
5
|
+
required?: boolean
|
|
6
|
+
optional?: boolean
|
|
7
|
+
defaultValue?: string
|
|
8
|
+
}>()
|
|
9
|
+
</script>
|
|
10
|
+
|
|
11
|
+
<template>
|
|
12
|
+
<div class="vp-field">
|
|
13
|
+
<p class="field-meta">
|
|
14
|
+
<span class="name">{{ name }}</span>
|
|
15
|
+
<span v-if="required || optional" :class="{ required, optional }">{{ required ? 'Required' : optional ? 'Optional' : '' }}</span>
|
|
16
|
+
<span v-if="type" class="type"><code>{{ type }}</code></span>
|
|
17
|
+
</p>
|
|
18
|
+
<p v-if="defaultValue" class="default-value">
|
|
19
|
+
<code>{{ defaultValue }}</code>
|
|
20
|
+
</p>
|
|
21
|
+
<div v-if="$slots.default" class="description">
|
|
22
|
+
<slot />
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
25
|
+
</template>
|
|
26
|
+
|
|
27
|
+
<style>
|
|
28
|
+
.vp-field {
|
|
29
|
+
width: 100%;
|
|
30
|
+
margin: 16px 0;
|
|
31
|
+
transition: border-color var(--vp-t-color);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.vp-field + .vp-field {
|
|
35
|
+
padding-top: 8px;
|
|
36
|
+
border-top: solid 1px var(--vp-c-divider);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.vp-field .field-meta {
|
|
40
|
+
display: flex;
|
|
41
|
+
gap: 8px;
|
|
42
|
+
align-items: flex-start;
|
|
43
|
+
margin: 8px 0;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.vp-field .field-meta .name {
|
|
47
|
+
font-size: 18px;
|
|
48
|
+
font-weight: 500;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.vp-field .field-meta .required,
|
|
52
|
+
.vp-field .field-meta .optional {
|
|
53
|
+
display: inline-block;
|
|
54
|
+
padding: 2px 8px;
|
|
55
|
+
font-size: 12px;
|
|
56
|
+
font-style: italic;
|
|
57
|
+
line-height: 1;
|
|
58
|
+
border-radius: 8px;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.vp-field .field-meta .required {
|
|
62
|
+
color: var(--vp-c-success-2);
|
|
63
|
+
border: solid 1px var(--vp-c-success-2);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.vp-field .field-meta .optional {
|
|
67
|
+
color: var(--vp-c-text-3);
|
|
68
|
+
border: solid 1px var(--vp-c-divider);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.vp-field .field-meta .type {
|
|
72
|
+
flex: 1 2;
|
|
73
|
+
text-align: right;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.vp-field .default-value {
|
|
77
|
+
margin: 0;
|
|
78
|
+
font-size: 14px;
|
|
79
|
+
line-height: 1;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.vp-field .description :where(p, ul, ol) {
|
|
83
|
+
margin: 8px 0;
|
|
84
|
+
line-height: 24px;
|
|
85
|
+
color: var(--vp-c-text-2);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.vp-field-group {
|
|
89
|
+
padding: 0 20px;
|
|
90
|
+
margin: 16px 0;
|
|
91
|
+
border: solid 1px var(--vp-c-divider);
|
|
92
|
+
border-radius: 6px;
|
|
93
|
+
}
|
|
94
|
+
</style>
|
package/lib/node/index.d.ts
CHANGED
|
@@ -153,6 +153,11 @@ interface PlotOptions {
|
|
|
153
153
|
trigger?: 'hover' | 'click';
|
|
154
154
|
}
|
|
155
155
|
|
|
156
|
+
interface CodeTreeOptions {
|
|
157
|
+
icon?: FileTreeIconMode;
|
|
158
|
+
height?: string | number;
|
|
159
|
+
}
|
|
160
|
+
|
|
156
161
|
type ThemeOptions = BuiltinTheme | {
|
|
157
162
|
light: BuiltinTheme;
|
|
158
163
|
dark: BuiltinTheme;
|
|
@@ -268,6 +273,12 @@ interface MarkdownPowerPluginOptions {
|
|
|
268
273
|
* @default false
|
|
269
274
|
*/
|
|
270
275
|
chat?: boolean;
|
|
276
|
+
/**
|
|
277
|
+
* 是否启用 field / field-group 容器
|
|
278
|
+
*
|
|
279
|
+
* @default false
|
|
280
|
+
*/
|
|
281
|
+
field?: boolean;
|
|
271
282
|
/**
|
|
272
283
|
* 是否启用 bilibili 视频嵌入
|
|
273
284
|
*
|
|
@@ -336,6 +347,20 @@ interface MarkdownPowerPluginOptions {
|
|
|
336
347
|
* @default false
|
|
337
348
|
*/
|
|
338
349
|
fileTree?: boolean | FileTreeOptions;
|
|
350
|
+
/**
|
|
351
|
+
* 是否启用 代码树 容器语法 和 嵌入语法
|
|
352
|
+
*
|
|
353
|
+
* ```md
|
|
354
|
+
* ::: code-tree
|
|
355
|
+
* :::
|
|
356
|
+
* ```
|
|
357
|
+
*
|
|
358
|
+
* `@[code-tree](file_path)`
|
|
359
|
+
*
|
|
360
|
+
*
|
|
361
|
+
* @default false
|
|
362
|
+
*/
|
|
363
|
+
codeTree?: boolean | CodeTreeOptions;
|
|
339
364
|
/**
|
|
340
365
|
* 是否启用 demo 语法
|
|
341
366
|
*/
|
package/lib/node/index.js
CHANGED
|
@@ -947,7 +947,7 @@ import { fs, logger, path } from "vuepress/utils";
|
|
|
947
947
|
|
|
948
948
|
// src/node/utils/resolveAttrs.ts
|
|
949
949
|
import { camelCase } from "@pengzhanbo/utils";
|
|
950
|
-
var RE_ATTR_VALUE = /(?:^|\s+)(?<attr>[\w-]+)(
|
|
950
|
+
var RE_ATTR_VALUE = /(?:^|\s+)(?<attr>[\w-]+)(?:=(?<quote>['"])(?<valueWithQuote>.+?)\k<quote>|=(?<valueWithoutQuote>\S+))?(?:\s+|$)/;
|
|
951
951
|
function resolveAttrs(info) {
|
|
952
952
|
info = info.trim();
|
|
953
953
|
if (!info)
|
|
@@ -956,17 +956,25 @@ function resolveAttrs(info) {
|
|
|
956
956
|
const rawAttrs = info;
|
|
957
957
|
let matched;
|
|
958
958
|
while (matched = info.match(RE_ATTR_VALUE)) {
|
|
959
|
-
const { attr,
|
|
959
|
+
const { attr, valueWithQuote, valueWithoutQuote } = matched.groups;
|
|
960
|
+
const value = valueWithQuote || valueWithoutQuote || true;
|
|
960
961
|
let v = typeof value === "string" ? value.trim() : value;
|
|
961
962
|
if (v === "true")
|
|
962
963
|
v = true;
|
|
963
964
|
else if (v === "false")
|
|
964
965
|
v = false;
|
|
966
|
+
else if (v === '""' || v === "''")
|
|
967
|
+
v = "";
|
|
965
968
|
attrs2[camelCase(attr)] = v;
|
|
966
969
|
info = info.slice(matched[0].length);
|
|
967
970
|
}
|
|
968
971
|
return { attrs: attrs2, rawAttrs };
|
|
969
972
|
}
|
|
973
|
+
function resolveAttr(info, key) {
|
|
974
|
+
const pattern = new RegExp(`(?:^|\\s+)${key}(?:=(?<quote>['"])(?<valueWithQuote>.+?)\\k<quote>|=(?<valueWithoutQuote>\\S+))?(?:\\s+|$)`);
|
|
975
|
+
const groups = info.match(pattern)?.groups;
|
|
976
|
+
return groups?.valueWithQuote || groups?.valueWithoutQuote;
|
|
977
|
+
}
|
|
970
978
|
|
|
971
979
|
// src/node/enhance/imageSize.ts
|
|
972
980
|
var REG_IMG = /!\[.*?\]\(.*?\)/g;
|
|
@@ -1146,8 +1154,121 @@ async function resolveImageSize(app, url, remote = false) {
|
|
|
1146
1154
|
import { addViteOptimizeDepsInclude } from "@vuepress/helper";
|
|
1147
1155
|
import { isPackageExists as isPackageExists3 } from "local-pkg";
|
|
1148
1156
|
|
|
1149
|
-
// src/node/container/
|
|
1150
|
-
import
|
|
1157
|
+
// src/node/container/codeTree.ts
|
|
1158
|
+
import path3 from "node:path";
|
|
1159
|
+
import { globSync } from "tinyglobby";
|
|
1160
|
+
import { removeLeadingSlash } from "vuepress/shared";
|
|
1161
|
+
|
|
1162
|
+
// src/node/demo/supports/file.ts
|
|
1163
|
+
import fs2 from "node:fs";
|
|
1164
|
+
import { createRequire } from "node:module";
|
|
1165
|
+
import path2 from "node:path";
|
|
1166
|
+
import process from "node:process";
|
|
1167
|
+
var require2 = createRequire(process.cwd());
|
|
1168
|
+
function findFile(app, env, url) {
|
|
1169
|
+
if (url.startsWith("/"))
|
|
1170
|
+
return app.dir.source(url.slice(1));
|
|
1171
|
+
if (url.startsWith("./") || url.startsWith("../"))
|
|
1172
|
+
return app.dir.source(path2.dirname(env.filePathRelative), url);
|
|
1173
|
+
if (url.startsWith("@source/")) {
|
|
1174
|
+
return app.dir.source(url.slice("@source/".length));
|
|
1175
|
+
}
|
|
1176
|
+
try {
|
|
1177
|
+
return require2.resolve(url);
|
|
1178
|
+
} catch {
|
|
1179
|
+
return url;
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
function readFileSync(filepath2) {
|
|
1183
|
+
try {
|
|
1184
|
+
return fs2.readFileSync(filepath2, "utf-8");
|
|
1185
|
+
} catch {
|
|
1186
|
+
return false;
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
1189
|
+
function writeFileSync(filepath2, content) {
|
|
1190
|
+
const dirname = path2.dirname(filepath2);
|
|
1191
|
+
fs2.mkdirSync(dirname, { recursive: true });
|
|
1192
|
+
fs2.writeFileSync(filepath2, content, "utf-8");
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
// src/node/embed/createEmbedRuleBlock.ts
|
|
1196
|
+
function createEmbedRuleBlock(md, {
|
|
1197
|
+
type,
|
|
1198
|
+
name = type,
|
|
1199
|
+
syntaxPattern,
|
|
1200
|
+
beforeName = "import_code",
|
|
1201
|
+
ruleOptions = { alt: ["paragraph", "reference", "blockquote", "list"] },
|
|
1202
|
+
meta,
|
|
1203
|
+
content
|
|
1204
|
+
}) {
|
|
1205
|
+
const MIN_LENGTH = type.length + 5;
|
|
1206
|
+
const START_CODES = [64, 91, ...type.split("").map((c) => c.charCodeAt(0))];
|
|
1207
|
+
md.block.ruler.before(
|
|
1208
|
+
beforeName,
|
|
1209
|
+
name,
|
|
1210
|
+
(state, startLine, endLine, silent) => {
|
|
1211
|
+
const pos = state.bMarks[startLine] + state.tShift[startLine];
|
|
1212
|
+
const max = state.eMarks[startLine];
|
|
1213
|
+
if (pos + MIN_LENGTH > max)
|
|
1214
|
+
return false;
|
|
1215
|
+
for (let i = 0; i < START_CODES.length; i += 1) {
|
|
1216
|
+
if (state.src.charCodeAt(pos + i) !== START_CODES[i])
|
|
1217
|
+
return false;
|
|
1218
|
+
}
|
|
1219
|
+
const content2 = state.src.slice(pos, max);
|
|
1220
|
+
const match = content2.match(syntaxPattern);
|
|
1221
|
+
if (!match)
|
|
1222
|
+
return false;
|
|
1223
|
+
if (silent)
|
|
1224
|
+
return true;
|
|
1225
|
+
const token = state.push(name, "", 0);
|
|
1226
|
+
token.meta = meta(match);
|
|
1227
|
+
token.content = content2;
|
|
1228
|
+
token.map = [startLine, startLine + 1];
|
|
1229
|
+
state.line = startLine + 1;
|
|
1230
|
+
return true;
|
|
1231
|
+
},
|
|
1232
|
+
ruleOptions
|
|
1233
|
+
);
|
|
1234
|
+
md.renderer.rules[name] = (tokens, index, _, env) => {
|
|
1235
|
+
const token = tokens[index];
|
|
1236
|
+
token.content = content(token.meta, token.content, env);
|
|
1237
|
+
return token.content;
|
|
1238
|
+
};
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
// src/node/utils/parseRect.ts
|
|
1242
|
+
function parseRect(str, unit = "px") {
|
|
1243
|
+
if (Number.parseFloat(str) === Number(str))
|
|
1244
|
+
return `${str}${unit}`;
|
|
1245
|
+
return str;
|
|
1246
|
+
}
|
|
1247
|
+
|
|
1248
|
+
// src/node/utils/stringifyAttrs.ts
|
|
1249
|
+
import { isBoolean, isNull, isNumber, isString, isUndefined, kebabCase } from "@pengzhanbo/utils";
|
|
1250
|
+
function stringifyAttrs(attrs2, withUndefined = false) {
|
|
1251
|
+
const result = Object.entries(attrs2).map(([key, value]) => {
|
|
1252
|
+
const k = kebabCase(key);
|
|
1253
|
+
if (isUndefined(value) || value === "undefined")
|
|
1254
|
+
return withUndefined ? `:${k}="undefined"` : "";
|
|
1255
|
+
if (isNull(value) || value === "null")
|
|
1256
|
+
return withUndefined ? `:${k}="null"` : "";
|
|
1257
|
+
if (value === "true")
|
|
1258
|
+
value = true;
|
|
1259
|
+
if (value === "false")
|
|
1260
|
+
value = false;
|
|
1261
|
+
if (isBoolean(value))
|
|
1262
|
+
return value ? `${k}` : "";
|
|
1263
|
+
if (isNumber(value))
|
|
1264
|
+
return `:${k}="${value}"`;
|
|
1265
|
+
if (isString(value) && (value[0] === "{" || value[0] === "["))
|
|
1266
|
+
return `:${k}="${value.replaceAll('"', "'")}"`;
|
|
1267
|
+
const hasDynamic = key[0] === ":";
|
|
1268
|
+
return `${hasDynamic ? ":" : ""}${k}="${String(value)}"`;
|
|
1269
|
+
}).filter(Boolean).join(" ");
|
|
1270
|
+
return result ? ` ${result}` : "";
|
|
1271
|
+
}
|
|
1151
1272
|
|
|
1152
1273
|
// src/node/container/createContainer.ts
|
|
1153
1274
|
import container from "markdown-it-container";
|
|
@@ -1210,6 +1331,161 @@ function createContainerSyntaxPlugin(md, type, render) {
|
|
|
1210
1331
|
md.renderer.rules[`${type}_container`] = render ?? defaultRender;
|
|
1211
1332
|
}
|
|
1212
1333
|
|
|
1334
|
+
// src/node/container/codeTree.ts
|
|
1335
|
+
var UNSUPPORTED_FILE_TYPES = [
|
|
1336
|
+
/* image */
|
|
1337
|
+
"jpg",
|
|
1338
|
+
"jpeg",
|
|
1339
|
+
"png",
|
|
1340
|
+
"gif",
|
|
1341
|
+
"avif",
|
|
1342
|
+
"webp",
|
|
1343
|
+
/* media */
|
|
1344
|
+
"mp3",
|
|
1345
|
+
"mp4",
|
|
1346
|
+
"ogg",
|
|
1347
|
+
"m3u8",
|
|
1348
|
+
"m3u",
|
|
1349
|
+
"flv",
|
|
1350
|
+
"webm",
|
|
1351
|
+
"wav",
|
|
1352
|
+
"flac",
|
|
1353
|
+
"aac",
|
|
1354
|
+
/* document */
|
|
1355
|
+
"pdf",
|
|
1356
|
+
"doc",
|
|
1357
|
+
"docx",
|
|
1358
|
+
"ppt",
|
|
1359
|
+
"pptx",
|
|
1360
|
+
"xls",
|
|
1361
|
+
"xlsx"
|
|
1362
|
+
];
|
|
1363
|
+
function parseFileNodes(files) {
|
|
1364
|
+
const nodes = [];
|
|
1365
|
+
for (const file of files) {
|
|
1366
|
+
const parts = removeLeadingSlash(file).split("/");
|
|
1367
|
+
let node = nodes;
|
|
1368
|
+
for (let i = 0; i < parts.length; i++) {
|
|
1369
|
+
const part = parts[i];
|
|
1370
|
+
const isFile = i === parts.length - 1;
|
|
1371
|
+
let child = node.find((n) => n.filename === part);
|
|
1372
|
+
if (!child) {
|
|
1373
|
+
child = {
|
|
1374
|
+
level: i + 1,
|
|
1375
|
+
filename: part,
|
|
1376
|
+
filepath: isFile ? file : void 0,
|
|
1377
|
+
children: isFile ? void 0 : []
|
|
1378
|
+
};
|
|
1379
|
+
node.push(child);
|
|
1380
|
+
}
|
|
1381
|
+
if (!isFile && child.children)
|
|
1382
|
+
node = child.children;
|
|
1383
|
+
}
|
|
1384
|
+
}
|
|
1385
|
+
return nodes;
|
|
1386
|
+
}
|
|
1387
|
+
function codeTreePlugin(md, app, options = {}) {
|
|
1388
|
+
const getIcon = (filename, type, mode) => {
|
|
1389
|
+
mode ||= options.icon || "colored";
|
|
1390
|
+
if (mode === "simple")
|
|
1391
|
+
return type === "folder" ? defaultFolder : defaultFile;
|
|
1392
|
+
return getFileIcon(filename, type);
|
|
1393
|
+
};
|
|
1394
|
+
function renderFileTree(nodes, mode) {
|
|
1395
|
+
return nodes.map((node) => {
|
|
1396
|
+
const props = {
|
|
1397
|
+
filename: node.filename,
|
|
1398
|
+
level: node.level,
|
|
1399
|
+
type: node.children?.length ? "folder" : "file",
|
|
1400
|
+
expanded: true,
|
|
1401
|
+
filepath: node.filepath
|
|
1402
|
+
};
|
|
1403
|
+
return `<FileTreeNode${stringifyAttrs(props)}>
|
|
1404
|
+
<template #icon><VPIcon name="${getIcon(node.filename, props.type, mode)}" /></template>
|
|
1405
|
+
${node.children?.length ? renderFileTree(node.children, mode) : ""}
|
|
1406
|
+
</FileTreeNode>`;
|
|
1407
|
+
}).join("\n");
|
|
1408
|
+
}
|
|
1409
|
+
createContainerPlugin(md, "code-tree", {
|
|
1410
|
+
before: (info, tokens, index) => {
|
|
1411
|
+
const files = [];
|
|
1412
|
+
let activeFile;
|
|
1413
|
+
for (let i = index + 1; !(tokens[i].nesting === -1 && tokens[i].type === "container_code-tree_close"); i++) {
|
|
1414
|
+
const token = tokens[i];
|
|
1415
|
+
if (token.type === "fence" && token.tag === "code") {
|
|
1416
|
+
const fenceInfo = md.utils.unescapeAll(token.info);
|
|
1417
|
+
const title2 = resolveAttr(fenceInfo, "title");
|
|
1418
|
+
if (title2) {
|
|
1419
|
+
files.push(title2);
|
|
1420
|
+
if (fenceInfo.includes(":active"))
|
|
1421
|
+
activeFile = title2;
|
|
1422
|
+
}
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1425
|
+
const { attrs: attrs2 } = resolveAttrs(info);
|
|
1426
|
+
const { title, icon, height, entry } = attrs2;
|
|
1427
|
+
const fileTreeNodes = parseFileNodes(files);
|
|
1428
|
+
const entryFile = activeFile || entry || files[0];
|
|
1429
|
+
const h = height || String(options.height);
|
|
1430
|
+
return `<VPCodeTree${stringifyAttrs({ title, entryFile, height: h ? parseRect(h) : void 0 })}><template #file-tree>${renderFileTree(fileTreeNodes, icon)}</template>`;
|
|
1431
|
+
},
|
|
1432
|
+
after: () => "</VPCodeTree>"
|
|
1433
|
+
});
|
|
1434
|
+
createEmbedRuleBlock(md, {
|
|
1435
|
+
type: "code-tree",
|
|
1436
|
+
syntaxPattern: /^@\[code-tree([^\]]*)\]\(([^)]*)\)/,
|
|
1437
|
+
meta: ([, info, dir]) => {
|
|
1438
|
+
const { attrs: attrs2 } = resolveAttrs(info);
|
|
1439
|
+
const h = attrs2.height || String(options.height);
|
|
1440
|
+
return {
|
|
1441
|
+
title: attrs2.title,
|
|
1442
|
+
entryFile: attrs2.entry,
|
|
1443
|
+
icon: attrs2.icon,
|
|
1444
|
+
height: h ? parseRect(h) : void 0,
|
|
1445
|
+
dir
|
|
1446
|
+
};
|
|
1447
|
+
},
|
|
1448
|
+
content: ({ dir, icon, ...props }, _, env) => {
|
|
1449
|
+
const codeTreeFiles = env.codeTreeFiles ??= [];
|
|
1450
|
+
const root = findFile(app, env, dir);
|
|
1451
|
+
const files = globSync("**/*", {
|
|
1452
|
+
cwd: root,
|
|
1453
|
+
onlyFiles: true,
|
|
1454
|
+
dot: true,
|
|
1455
|
+
ignore: ["**/node_modules/**", "**/.DS_Store", "**/.gitkeep"]
|
|
1456
|
+
}).sort((a, b) => {
|
|
1457
|
+
const al = a.split("/").length;
|
|
1458
|
+
const bl = b.split("/").length;
|
|
1459
|
+
return bl - al;
|
|
1460
|
+
});
|
|
1461
|
+
props.entryFile ||= files[0];
|
|
1462
|
+
const codeContent = files.map((file) => {
|
|
1463
|
+
const ext = path3.extname(file).slice(1);
|
|
1464
|
+
if (UNSUPPORTED_FILE_TYPES.includes(ext)) {
|
|
1465
|
+
return "";
|
|
1466
|
+
}
|
|
1467
|
+
const filepath2 = path3.join(root, file);
|
|
1468
|
+
codeTreeFiles.push(filepath2);
|
|
1469
|
+
const content = readFileSync(filepath2);
|
|
1470
|
+
return `\`\`\`${ext || "txt"} title="${file}"
|
|
1471
|
+
${content}
|
|
1472
|
+
\`\`\``;
|
|
1473
|
+
}).filter(Boolean).join("\n");
|
|
1474
|
+
const fileTreeNodes = parseFileNodes(files);
|
|
1475
|
+
return `<VPCodeTree${stringifyAttrs(props)}><template #file-tree>${renderFileTree(fileTreeNodes, icon)}</template>${md.render(codeContent, cleanMarkdownEnv(env))}</VPCodeTree>`;
|
|
1476
|
+
}
|
|
1477
|
+
});
|
|
1478
|
+
}
|
|
1479
|
+
function extendsPageWithCodeTree(page) {
|
|
1480
|
+
const markdownEnv = page.markdownEnv;
|
|
1481
|
+
const codeTreeFiles = markdownEnv.codeTreeFiles ?? [];
|
|
1482
|
+
if (codeTreeFiles.length)
|
|
1483
|
+
page.deps.push(...codeTreeFiles);
|
|
1484
|
+
}
|
|
1485
|
+
|
|
1486
|
+
// src/node/container/index.ts
|
|
1487
|
+
import { isPlainObject as isPlainObject2 } from "@vuepress/helper";
|
|
1488
|
+
|
|
1213
1489
|
// src/node/container/align.ts
|
|
1214
1490
|
var alignList = ["left", "center", "right", "justify"];
|
|
1215
1491
|
function alignPlugin(md) {
|
|
@@ -1220,31 +1496,6 @@ function alignPlugin(md) {
|
|
|
1220
1496
|
}
|
|
1221
1497
|
}
|
|
1222
1498
|
|
|
1223
|
-
// src/node/utils/stringifyAttrs.ts
|
|
1224
|
-
import { isBoolean, isNull, isNumber, isString, isUndefined, kebabCase } from "@pengzhanbo/utils";
|
|
1225
|
-
function stringifyAttrs(attrs2, withUndefined = false) {
|
|
1226
|
-
const result = Object.entries(attrs2).map(([key, value]) => {
|
|
1227
|
-
const k = kebabCase(key);
|
|
1228
|
-
if (isUndefined(value) || value === "undefined")
|
|
1229
|
-
return withUndefined ? `:${k}="undefined"` : "";
|
|
1230
|
-
if (isNull(value) || value === "null")
|
|
1231
|
-
return withUndefined ? `:${k}="null"` : "";
|
|
1232
|
-
if (value === "true")
|
|
1233
|
-
value = true;
|
|
1234
|
-
if (value === "false")
|
|
1235
|
-
value = false;
|
|
1236
|
-
if (isBoolean(value))
|
|
1237
|
-
return value ? `${k}` : "";
|
|
1238
|
-
if (isNumber(value))
|
|
1239
|
-
return `:${k}="${value}"`;
|
|
1240
|
-
if (isString(value) && (value[0] === "{" || value[0] === "["))
|
|
1241
|
-
return `:${k}="${value.replaceAll('"', "'")}"`;
|
|
1242
|
-
const hasDynamic = key[0] === ":";
|
|
1243
|
-
return `${hasDynamic ? ":" : ""}${k}="${String(value)}"`;
|
|
1244
|
-
}).filter(Boolean).join(" ");
|
|
1245
|
-
return result ? ` ${result}` : "";
|
|
1246
|
-
}
|
|
1247
|
-
|
|
1248
1499
|
// src/node/container/card.ts
|
|
1249
1500
|
function cardPlugin(md) {
|
|
1250
1501
|
createContainerPlugin(md, "card", {
|
|
@@ -1448,6 +1699,23 @@ function demoWrapperPlugin(md) {
|
|
|
1448
1699
|
});
|
|
1449
1700
|
}
|
|
1450
1701
|
|
|
1702
|
+
// src/node/container/field.ts
|
|
1703
|
+
import { isUndefined as isUndefined2 } from "@pengzhanbo/utils";
|
|
1704
|
+
function fieldPlugin(md) {
|
|
1705
|
+
createContainerPlugin(md, "field", {
|
|
1706
|
+
before: (info) => {
|
|
1707
|
+
const { attrs: attrs2 } = resolveAttrs(info);
|
|
1708
|
+
const { name, type, required, optional, default: defaultValue } = attrs2;
|
|
1709
|
+
const props = stringifyAttrs({ name, required, optional });
|
|
1710
|
+
return `<VPField${props}${!isUndefined2(type) ? ` type="${type}"` : ""}${!isUndefined2(defaultValue) ? ` default-value="${defaultValue}"` : ""}>`;
|
|
1711
|
+
},
|
|
1712
|
+
after: () => "</VPField>"
|
|
1713
|
+
});
|
|
1714
|
+
createContainerPlugin(md, "field-group", {
|
|
1715
|
+
before: () => '<div class="vp-field-group">'
|
|
1716
|
+
});
|
|
1717
|
+
}
|
|
1718
|
+
|
|
1451
1719
|
// src/node/container/fileTree.ts
|
|
1452
1720
|
import { removeEndingSlash } from "vuepress/shared";
|
|
1453
1721
|
function parseFileTreeRawContent(content) {
|
|
@@ -1477,6 +1745,14 @@ function parseFileTreeNodeInfo(info) {
|
|
|
1477
1745
|
let focus = false;
|
|
1478
1746
|
let expanded = true;
|
|
1479
1747
|
let type = "file";
|
|
1748
|
+
let diff;
|
|
1749
|
+
if (info.startsWith("++")) {
|
|
1750
|
+
info = info.slice(2).trim();
|
|
1751
|
+
diff = "add";
|
|
1752
|
+
} else if (info.startsWith("--")) {
|
|
1753
|
+
info = info.slice(2).trim();
|
|
1754
|
+
diff = "remove";
|
|
1755
|
+
}
|
|
1480
1756
|
info = info.replace(RE_FOCUS, (_, matched) => {
|
|
1481
1757
|
filename = matched;
|
|
1482
1758
|
focus = true;
|
|
@@ -1493,7 +1769,7 @@ function parseFileTreeNodeInfo(info) {
|
|
|
1493
1769
|
expanded = false;
|
|
1494
1770
|
filename = removeEndingSlash(filename);
|
|
1495
1771
|
}
|
|
1496
|
-
return { filename, comment, focus, expanded, type };
|
|
1772
|
+
return { filename, comment, focus, expanded, type, diff };
|
|
1497
1773
|
}
|
|
1498
1774
|
function fileTreePlugin(md, options = {}) {
|
|
1499
1775
|
const getIcon = (filename, type, mode) => {
|
|
@@ -1504,7 +1780,7 @@ function fileTreePlugin(md, options = {}) {
|
|
|
1504
1780
|
};
|
|
1505
1781
|
const renderFileTree = (nodes, meta) => nodes.map((node) => {
|
|
1506
1782
|
const { info, level, children } = node;
|
|
1507
|
-
const { filename, comment, focus, expanded, type } = parseFileTreeNodeInfo(info);
|
|
1783
|
+
const { filename, comment, focus, expanded, type, diff } = parseFileTreeNodeInfo(info);
|
|
1508
1784
|
const isOmit = filename === "\u2026" || filename === "...";
|
|
1509
1785
|
if (children.length === 0 && type === "folder") {
|
|
1510
1786
|
children.push({ info: "\u2026", level: level + 1, children: [] });
|
|
@@ -1516,7 +1792,9 @@ function fileTreePlugin(md, options = {}) {
|
|
|
1516
1792
|
expanded: nodeType === "folder" ? expanded : false,
|
|
1517
1793
|
focus,
|
|
1518
1794
|
type: nodeType,
|
|
1519
|
-
|
|
1795
|
+
diff,
|
|
1796
|
+
filename,
|
|
1797
|
+
level
|
|
1520
1798
|
};
|
|
1521
1799
|
return `<FileTreeNode${stringifyAttrs(props)}>
|
|
1522
1800
|
${renderedIcon}${renderedComment}${children.length > 0 ? renderFileTree(children, meta) : ""}
|
|
@@ -1536,9 +1814,9 @@ ${renderedIcon}${renderedComment}${children.length > 0 ? renderFileTree(children
|
|
|
1536
1814
|
}
|
|
1537
1815
|
|
|
1538
1816
|
// src/node/container/langRepl.ts
|
|
1539
|
-
import { promises as
|
|
1817
|
+
import { promises as fs3 } from "node:fs";
|
|
1540
1818
|
import { resolveModule } from "local-pkg";
|
|
1541
|
-
import { colors, logger as logger2, path as
|
|
1819
|
+
import { colors, logger as logger2, path as path4 } from "vuepress/utils";
|
|
1542
1820
|
async function langReplPlugin(app, md, {
|
|
1543
1821
|
theme,
|
|
1544
1822
|
go = false,
|
|
@@ -1562,10 +1840,10 @@ async function langReplPlugin(app, md, {
|
|
|
1562
1840
|
theme ??= { light: "github-light", dark: "github-dark" };
|
|
1563
1841
|
const data = { grammars: {} };
|
|
1564
1842
|
try {
|
|
1565
|
-
const themesPath =
|
|
1566
|
-
const grammarsPath =
|
|
1567
|
-
const readTheme = (theme2) => read(
|
|
1568
|
-
const readGrammar = (grammar) => read(
|
|
1843
|
+
const themesPath = path4.dirname(resolveModule("tm-themes"));
|
|
1844
|
+
const grammarsPath = path4.dirname(resolveModule("tm-grammars"));
|
|
1845
|
+
const readTheme = (theme2) => read(path4.join(themesPath, "themes", `${theme2}.json`));
|
|
1846
|
+
const readGrammar = (grammar) => read(path4.join(grammarsPath, "grammars", `${grammar}.json`));
|
|
1569
1847
|
if (typeof theme === "string") {
|
|
1570
1848
|
data.theme = await readTheme(theme);
|
|
1571
1849
|
} else {
|
|
@@ -1590,7 +1868,7 @@ async function langReplPlugin(app, md, {
|
|
|
1590
1868
|
}
|
|
1591
1869
|
async function read(file) {
|
|
1592
1870
|
try {
|
|
1593
|
-
const content = await
|
|
1871
|
+
const content = await fs3.readFile(file, "utf-8");
|
|
1594
1872
|
return JSON.parse(content);
|
|
1595
1873
|
} catch {
|
|
1596
1874
|
}
|
|
@@ -2089,96 +2367,22 @@ async function containerPlugin(app, md, options) {
|
|
|
2089
2367
|
if (options.fileTree) {
|
|
2090
2368
|
fileTreePlugin(md, isPlainObject2(options.fileTree) ? options.fileTree : {});
|
|
2091
2369
|
}
|
|
2370
|
+
if (options.codeTree) {
|
|
2371
|
+
codeTreePlugin(md, app, isPlainObject2(options.codeTree) ? options.codeTree : {});
|
|
2372
|
+
}
|
|
2092
2373
|
if (options.timeline)
|
|
2093
2374
|
timelinePlugin(md);
|
|
2094
2375
|
if (options.collapse)
|
|
2095
2376
|
collapsePlugin(md);
|
|
2096
2377
|
if (options.chat)
|
|
2097
2378
|
chatPlugin(md);
|
|
2379
|
+
if (options.field)
|
|
2380
|
+
fieldPlugin(md);
|
|
2098
2381
|
}
|
|
2099
2382
|
|
|
2100
2383
|
// src/node/demo/demo.ts
|
|
2101
2384
|
import container2 from "markdown-it-container";
|
|
2102
2385
|
|
|
2103
|
-
// src/node/embed/createEmbedRuleBlock.ts
|
|
2104
|
-
function createEmbedRuleBlock(md, {
|
|
2105
|
-
type,
|
|
2106
|
-
name = type,
|
|
2107
|
-
syntaxPattern,
|
|
2108
|
-
beforeName = "import_code",
|
|
2109
|
-
ruleOptions = { alt: ["paragraph", "reference", "blockquote", "list"] },
|
|
2110
|
-
meta,
|
|
2111
|
-
content
|
|
2112
|
-
}) {
|
|
2113
|
-
const MIN_LENGTH = type.length + 5;
|
|
2114
|
-
const START_CODES = [64, 91, ...type.split("").map((c) => c.charCodeAt(0))];
|
|
2115
|
-
md.block.ruler.before(
|
|
2116
|
-
beforeName,
|
|
2117
|
-
name,
|
|
2118
|
-
(state, startLine, endLine, silent) => {
|
|
2119
|
-
const pos = state.bMarks[startLine] + state.tShift[startLine];
|
|
2120
|
-
const max = state.eMarks[startLine];
|
|
2121
|
-
if (pos + MIN_LENGTH > max)
|
|
2122
|
-
return false;
|
|
2123
|
-
for (let i = 0; i < START_CODES.length; i += 1) {
|
|
2124
|
-
if (state.src.charCodeAt(pos + i) !== START_CODES[i])
|
|
2125
|
-
return false;
|
|
2126
|
-
}
|
|
2127
|
-
const content2 = state.src.slice(pos, max);
|
|
2128
|
-
const match = content2.match(syntaxPattern);
|
|
2129
|
-
if (!match)
|
|
2130
|
-
return false;
|
|
2131
|
-
if (silent)
|
|
2132
|
-
return true;
|
|
2133
|
-
const token = state.push(name, "", 0);
|
|
2134
|
-
token.meta = meta(match);
|
|
2135
|
-
token.content = content2;
|
|
2136
|
-
token.map = [startLine, startLine + 1];
|
|
2137
|
-
state.line = startLine + 1;
|
|
2138
|
-
return true;
|
|
2139
|
-
},
|
|
2140
|
-
ruleOptions
|
|
2141
|
-
);
|
|
2142
|
-
md.renderer.rules[name] = (tokens, index, _, env) => {
|
|
2143
|
-
const token = tokens[index];
|
|
2144
|
-
token.content = content(token.meta, token.content, env);
|
|
2145
|
-
return token.content;
|
|
2146
|
-
};
|
|
2147
|
-
}
|
|
2148
|
-
|
|
2149
|
-
// src/node/demo/supports/file.ts
|
|
2150
|
-
import fs3 from "node:fs";
|
|
2151
|
-
import { createRequire } from "node:module";
|
|
2152
|
-
import path3 from "node:path";
|
|
2153
|
-
import process from "node:process";
|
|
2154
|
-
var require2 = createRequire(process.cwd());
|
|
2155
|
-
function findFile(app, env, url) {
|
|
2156
|
-
if (url.startsWith("/"))
|
|
2157
|
-
return app.dir.source(url.slice(1));
|
|
2158
|
-
if (url.startsWith("./") || url.startsWith("../"))
|
|
2159
|
-
return app.dir.source(path3.dirname(env.filePathRelative), url);
|
|
2160
|
-
if (url.startsWith("@source/")) {
|
|
2161
|
-
return app.dir.source(url.slice("@source/".length));
|
|
2162
|
-
}
|
|
2163
|
-
try {
|
|
2164
|
-
return require2.resolve(url);
|
|
2165
|
-
} catch {
|
|
2166
|
-
return url;
|
|
2167
|
-
}
|
|
2168
|
-
}
|
|
2169
|
-
function readFileSync(filepath2) {
|
|
2170
|
-
try {
|
|
2171
|
-
return fs3.readFileSync(filepath2, "utf-8");
|
|
2172
|
-
} catch {
|
|
2173
|
-
return false;
|
|
2174
|
-
}
|
|
2175
|
-
}
|
|
2176
|
-
function writeFileSync(filepath2, content) {
|
|
2177
|
-
const dirname = path3.dirname(filepath2);
|
|
2178
|
-
fs3.mkdirSync(dirname, { recursive: true });
|
|
2179
|
-
fs3.writeFileSync(filepath2, content, "utf-8");
|
|
2180
|
-
}
|
|
2181
|
-
|
|
2182
2386
|
// src/node/demo/markdown.ts
|
|
2183
2387
|
function markdownEmbed(app, md, env, { url, title, desc, codeSetting = "", expanded = false }) {
|
|
2184
2388
|
const filepath2 = findFile(app, env, url);
|
|
@@ -2214,7 +2418,7 @@ var markdownContainerRender = {
|
|
|
2214
2418
|
|
|
2215
2419
|
// src/node/demo/normal.ts
|
|
2216
2420
|
import fs5 from "node:fs";
|
|
2217
|
-
import
|
|
2421
|
+
import path6 from "node:path";
|
|
2218
2422
|
|
|
2219
2423
|
// src/node/demo/supports/compiler.ts
|
|
2220
2424
|
import { isPackageExists } from "local-pkg";
|
|
@@ -2295,8 +2499,8 @@ function importer(func) {
|
|
|
2295
2499
|
|
|
2296
2500
|
// src/node/demo/supports/insertScript.ts
|
|
2297
2501
|
var SCRIPT_RE = /<script.*?>/;
|
|
2298
|
-
function insertSetupScript({ export: name, path:
|
|
2299
|
-
const imports = `import ${name ? `${name} from ` : ""}'${
|
|
2502
|
+
function insertSetupScript({ export: name, path: path10 }, env) {
|
|
2503
|
+
const imports = `import ${name ? `${name} from ` : ""}'${path10}';`;
|
|
2300
2504
|
const scriptSetup = env.sfcBlocks.scriptSetup ??= {
|
|
2301
2505
|
type: "script",
|
|
2302
2506
|
content: "<script setup>\n</script>",
|
|
@@ -2312,7 +2516,7 @@ ${imports}`);
|
|
|
2312
2516
|
|
|
2313
2517
|
// src/node/demo/watcher.ts
|
|
2314
2518
|
import fs4 from "node:fs";
|
|
2315
|
-
import
|
|
2519
|
+
import path5 from "node:path";
|
|
2316
2520
|
import { watch } from "chokidar";
|
|
2317
2521
|
var renderDone = null;
|
|
2318
2522
|
var renderCount = 0;
|
|
@@ -2348,30 +2552,30 @@ function demoWatcher(app, watchers) {
|
|
|
2348
2552
|
if (!watcher) {
|
|
2349
2553
|
watcher = watch([], { ignoreInitial: true });
|
|
2350
2554
|
}
|
|
2351
|
-
Object.keys(tasks).forEach((
|
|
2352
|
-
watcher.add(
|
|
2555
|
+
Object.keys(tasks).forEach((path10) => {
|
|
2556
|
+
watcher.add(path10);
|
|
2353
2557
|
});
|
|
2354
2558
|
const code = readFileSync(app.dir.temp(target));
|
|
2355
2559
|
if (code) {
|
|
2356
2560
|
const paths = JSON.parse(code || "{}");
|
|
2357
|
-
Object.entries(paths).forEach(([
|
|
2358
|
-
watcher.add(
|
|
2359
|
-
tasks[
|
|
2561
|
+
Object.entries(paths).forEach(([path10, output]) => {
|
|
2562
|
+
watcher.add(path10);
|
|
2563
|
+
tasks[path10] = output;
|
|
2360
2564
|
});
|
|
2361
2565
|
}
|
|
2362
2566
|
updateWatchFiles(app);
|
|
2363
|
-
watcher.on("change", (
|
|
2364
|
-
if (tasks[
|
|
2365
|
-
const code2 = readFileSync(
|
|
2567
|
+
watcher.on("change", (path10) => {
|
|
2568
|
+
if (tasks[path10]) {
|
|
2569
|
+
const code2 = readFileSync(path10);
|
|
2366
2570
|
if (code2 === false)
|
|
2367
2571
|
return;
|
|
2368
2572
|
const source = parseEmbedCode(code2);
|
|
2369
|
-
compileCode(source, tasks[
|
|
2573
|
+
compileCode(source, tasks[path10]);
|
|
2370
2574
|
}
|
|
2371
2575
|
});
|
|
2372
|
-
watcher.on("unlink", (
|
|
2373
|
-
delete tasks[
|
|
2374
|
-
watcher.unwatch(
|
|
2576
|
+
watcher.on("unlink", (path10) => {
|
|
2577
|
+
delete tasks[path10];
|
|
2578
|
+
watcher.unwatch(path10);
|
|
2375
2579
|
});
|
|
2376
2580
|
watchers.push({
|
|
2377
2581
|
close: () => {
|
|
@@ -2380,17 +2584,17 @@ function demoWatcher(app, watchers) {
|
|
|
2380
2584
|
}
|
|
2381
2585
|
});
|
|
2382
2586
|
}
|
|
2383
|
-
function addTask(app,
|
|
2384
|
-
if (tasks[
|
|
2587
|
+
function addTask(app, path10, output) {
|
|
2588
|
+
if (tasks[path10])
|
|
2385
2589
|
return;
|
|
2386
|
-
tasks[
|
|
2590
|
+
tasks[path10] = output;
|
|
2387
2591
|
if (watcher) {
|
|
2388
|
-
watcher.add(
|
|
2592
|
+
watcher.add(path10);
|
|
2389
2593
|
}
|
|
2390
2594
|
updateWatchFiles(app);
|
|
2391
2595
|
}
|
|
2392
2596
|
async function updateWatchFiles(app) {
|
|
2393
|
-
await fs4.promises.mkdir(app.dir.temp(
|
|
2597
|
+
await fs4.promises.mkdir(app.dir.temp(path5.dirname(target)), { recursive: true });
|
|
2394
2598
|
await fs4.promises.writeFile(app.dir.temp(target), JSON.stringify(tasks));
|
|
2395
2599
|
}
|
|
2396
2600
|
|
|
@@ -2482,7 +2686,7 @@ function normalEmbed(app, md, env, { url, title, desc, codeSetting = "", expande
|
|
|
2482
2686
|
}
|
|
2483
2687
|
const source = parseEmbedCode(code);
|
|
2484
2688
|
const prefix = (env.filePathRelative || "").replace(/\.md$/, "").replace(/\//g, "-");
|
|
2485
|
-
const basename =
|
|
2689
|
+
const basename = path6.basename(filepath2).replace(/-|\./g, "_");
|
|
2486
2690
|
const name = `Demo${basename[0].toUpperCase()}${basename.slice(1)}`;
|
|
2487
2691
|
const demo = { type: "normal", export: name, path: filepath2 };
|
|
2488
2692
|
const output = app.dir.temp(target2, `${prefix}-${name}.js`);
|
|
@@ -2502,7 +2706,7 @@ var normalContainerRender = {
|
|
|
2502
2706
|
const { url, title, desc, expanded = false } = meta;
|
|
2503
2707
|
const name = `DemoContainer${url}`;
|
|
2504
2708
|
const prefix = (env.filePathRelative || "").replace(/\.md$/, "").replace(/\//g, "-");
|
|
2505
|
-
const output = app.dir.temp(
|
|
2709
|
+
const output = app.dir.temp(path6.join(target2, `${prefix}-${name}.js`));
|
|
2506
2710
|
env.demoFiles ??= [];
|
|
2507
2711
|
if (!env.demoFiles.some((d) => d.path === output)) {
|
|
2508
2712
|
const demo = { type: "normal", export: name, gitignore: true, path: output };
|
|
@@ -2580,7 +2784,7 @@ function normalizeAlias(info) {
|
|
|
2580
2784
|
}
|
|
2581
2785
|
|
|
2582
2786
|
// src/node/demo/vue.ts
|
|
2583
|
-
import
|
|
2787
|
+
import path7 from "node:path";
|
|
2584
2788
|
function vueEmbed(app, md, env, { url, title, desc, codeSetting = "", expanded = false }) {
|
|
2585
2789
|
const filepath2 = findFile(app, env, url);
|
|
2586
2790
|
const code = readFileSync(filepath2);
|
|
@@ -2588,8 +2792,8 @@ function vueEmbed(app, md, env, { url, title, desc, codeSetting = "", expanded =
|
|
|
2588
2792
|
console.warn("[vuepress-plugin-md-power] Cannot read vue file:", filepath2);
|
|
2589
2793
|
return "";
|
|
2590
2794
|
}
|
|
2591
|
-
const basename =
|
|
2592
|
-
const ext =
|
|
2795
|
+
const basename = path7.basename(filepath2).replace(/-|\./g, "_");
|
|
2796
|
+
const ext = path7.extname(filepath2).slice(1);
|
|
2593
2797
|
const name = `Demo${basename[0].toUpperCase()}${basename.slice(1)}`;
|
|
2594
2798
|
const demo = { type: "vue", export: name, path: filepath2 };
|
|
2595
2799
|
env.demoFiles ??= [];
|
|
@@ -2613,7 +2817,7 @@ var vueContainerRender = {
|
|
|
2613
2817
|
const componentName = `DemoContainer${url}`;
|
|
2614
2818
|
const prefix = (env.filePathRelative || "").replace(/\.md$/, "").replace(/\//g, "-");
|
|
2615
2819
|
env.demoFiles ??= [];
|
|
2616
|
-
const output = app.dir.temp(
|
|
2820
|
+
const output = app.dir.temp(path7.join(target3, `${prefix}-${componentName}`));
|
|
2617
2821
|
if (codeMap.vue || codeMap.js || codeMap.ts) {
|
|
2618
2822
|
let scriptOutput = output;
|
|
2619
2823
|
let content = "";
|
|
@@ -2670,7 +2874,7 @@ var STYLE_RE2 = /<style.*?>/;
|
|
|
2670
2874
|
function transformImports(code, filepath2) {
|
|
2671
2875
|
return code.replace(IMPORT_RE, (matched, url) => {
|
|
2672
2876
|
if (url.startsWith("./") || url.startsWith("../")) {
|
|
2673
|
-
return matched.replace(url, `${
|
|
2877
|
+
return matched.replace(url, `${path7.resolve(path7.dirname(filepath2), url)}`);
|
|
2674
2878
|
}
|
|
2675
2879
|
return matched;
|
|
2676
2880
|
});
|
|
@@ -2768,10 +2972,10 @@ function extendsPageWithDemo(page) {
|
|
|
2768
2972
|
const markdownEnv = page.markdownEnv;
|
|
2769
2973
|
const demoFiles = markdownEnv.demoFiles ?? [];
|
|
2770
2974
|
page.deps.push(
|
|
2771
|
-
...demoFiles.filter(({ type }) => type === "markdown").map(({ path:
|
|
2975
|
+
...demoFiles.filter(({ type }) => type === "markdown").map(({ path: path10 }) => path10)
|
|
2772
2976
|
);
|
|
2773
2977
|
(page.frontmatter.gitInclude ??= []).push(
|
|
2774
|
-
...demoFiles.filter(({ gitignore }) => !gitignore).map(({ path:
|
|
2978
|
+
...demoFiles.filter(({ gitignore }) => !gitignore).map(({ path: path10 }) => path10)
|
|
2775
2979
|
);
|
|
2776
2980
|
}
|
|
2777
2981
|
|
|
@@ -2904,13 +3108,6 @@ function resolveVersions(versions) {
|
|
|
2904
3108
|
};
|
|
2905
3109
|
}
|
|
2906
3110
|
|
|
2907
|
-
// src/node/utils/parseRect.ts
|
|
2908
|
-
function parseRect(str, unit = "px") {
|
|
2909
|
-
if (Number.parseFloat(str) === Number(str))
|
|
2910
|
-
return `${str}${unit}`;
|
|
2911
|
-
return str;
|
|
2912
|
-
}
|
|
2913
|
-
|
|
2914
3111
|
// src/node/embed/code/codepen.ts
|
|
2915
3112
|
var codepenPlugin = (md) => {
|
|
2916
3113
|
createEmbedRuleBlock(md, {
|
|
@@ -3001,7 +3198,7 @@ var replitPlugin = (md) => {
|
|
|
3001
3198
|
};
|
|
3002
3199
|
|
|
3003
3200
|
// src/node/embed/pdf.ts
|
|
3004
|
-
import { path as
|
|
3201
|
+
import { path as path8 } from "vuepress/utils";
|
|
3005
3202
|
var pdfPlugin = (md) => {
|
|
3006
3203
|
createEmbedRuleBlock(md, {
|
|
3007
3204
|
type: "pdf",
|
|
@@ -3017,7 +3214,7 @@ var pdfPlugin = (md) => {
|
|
|
3017
3214
|
width: attrs2.width ? parseRect(attrs2.width) : "100%",
|
|
3018
3215
|
height: attrs2.height ? parseRect(attrs2.height) : "",
|
|
3019
3216
|
ratio: attrs2.ratio ? parseRect(attrs2.ratio) : "",
|
|
3020
|
-
title:
|
|
3217
|
+
title: path8.basename(src || "")
|
|
3021
3218
|
};
|
|
3022
3219
|
},
|
|
3023
3220
|
content: (meta) => `<PDFViewer${stringifyAttrs(meta)} />`
|
|
@@ -3622,11 +3819,11 @@ function inlineSyntaxPlugin(md, options) {
|
|
|
3622
3819
|
|
|
3623
3820
|
// src/node/prepareConfigFile.ts
|
|
3624
3821
|
import { ensureEndingSlash } from "@vuepress/helper";
|
|
3625
|
-
import { getDirname, path as
|
|
3822
|
+
import { getDirname, path as path9 } from "vuepress/utils";
|
|
3626
3823
|
var { url: filepath } = import.meta;
|
|
3627
3824
|
var __dirname = getDirname(filepath);
|
|
3628
3825
|
var CLIENT_FOLDER = ensureEndingSlash(
|
|
3629
|
-
|
|
3826
|
+
path9.resolve(__dirname, "../client")
|
|
3630
3827
|
);
|
|
3631
3828
|
async function prepareConfigFile(app, options) {
|
|
3632
3829
|
const imports = /* @__PURE__ */ new Set();
|
|
@@ -3675,10 +3872,14 @@ async function prepareConfigFile(app, options) {
|
|
|
3675
3872
|
imports.add(`import CanIUse from '${CLIENT_FOLDER}components/CanIUse.vue'`);
|
|
3676
3873
|
enhances.add(`app.component('CanIUseViewer', CanIUse)`);
|
|
3677
3874
|
}
|
|
3678
|
-
if (options.fileTree) {
|
|
3875
|
+
if (options.fileTree || options.codeTree) {
|
|
3679
3876
|
imports.add(`import FileTreeNode from '${CLIENT_FOLDER}components/FileTreeNode.vue'`);
|
|
3680
3877
|
enhances.add(`app.component('FileTreeNode', FileTreeNode)`);
|
|
3681
3878
|
}
|
|
3879
|
+
if (options.codeTree) {
|
|
3880
|
+
imports.add(`import VPCodeTree from '${CLIENT_FOLDER}components/VPCodeTree.vue'`);
|
|
3881
|
+
enhances.add(`app.component('VPCodeTree', VPCodeTree)`);
|
|
3882
|
+
}
|
|
3682
3883
|
if (options.artPlayer) {
|
|
3683
3884
|
imports.add(`import ArtPlayer from '${CLIENT_FOLDER}components/ArtPlayer.vue'`);
|
|
3684
3885
|
enhances.add(`app.component('ArtPlayer', ArtPlayer)`);
|
|
@@ -3716,6 +3917,10 @@ async function prepareConfigFile(app, options) {
|
|
|
3716
3917
|
if (options.chat) {
|
|
3717
3918
|
imports.add(`import '${CLIENT_FOLDER}styles/chat.css'`);
|
|
3718
3919
|
}
|
|
3920
|
+
if (options.field) {
|
|
3921
|
+
imports.add(`import VPField from '${CLIENT_FOLDER}components/VPField.vue'`);
|
|
3922
|
+
enhances.add(`app.component('VPField', VPField)`);
|
|
3923
|
+
}
|
|
3719
3924
|
return app.writeTemp(
|
|
3720
3925
|
"md-power/config.js",
|
|
3721
3926
|
`import { defineClientConfig } from 'vuepress/client'
|
|
@@ -3780,6 +3985,8 @@ function markdownPowerPlugin(options = {}) {
|
|
|
3780
3985
|
extendsPage: (page) => {
|
|
3781
3986
|
if (options.demo)
|
|
3782
3987
|
extendsPageWithDemo(page);
|
|
3988
|
+
if (options.codeTree)
|
|
3989
|
+
extendsPageWithCodeTree(page);
|
|
3783
3990
|
}
|
|
3784
3991
|
};
|
|
3785
3992
|
}
|
package/lib/shared/index.d.ts
CHANGED
|
@@ -152,6 +152,11 @@ interface PlotOptions {
|
|
|
152
152
|
trigger?: 'hover' | 'click';
|
|
153
153
|
}
|
|
154
154
|
|
|
155
|
+
interface CodeTreeOptions {
|
|
156
|
+
icon?: FileTreeIconMode;
|
|
157
|
+
height?: string | number;
|
|
158
|
+
}
|
|
159
|
+
|
|
155
160
|
type ThemeOptions = BuiltinTheme | {
|
|
156
161
|
light: BuiltinTheme;
|
|
157
162
|
dark: BuiltinTheme;
|
|
@@ -267,6 +272,12 @@ interface MarkdownPowerPluginOptions {
|
|
|
267
272
|
* @default false
|
|
268
273
|
*/
|
|
269
274
|
chat?: boolean;
|
|
275
|
+
/**
|
|
276
|
+
* 是否启用 field / field-group 容器
|
|
277
|
+
*
|
|
278
|
+
* @default false
|
|
279
|
+
*/
|
|
280
|
+
field?: boolean;
|
|
270
281
|
/**
|
|
271
282
|
* 是否启用 bilibili 视频嵌入
|
|
272
283
|
*
|
|
@@ -335,6 +346,20 @@ interface MarkdownPowerPluginOptions {
|
|
|
335
346
|
* @default false
|
|
336
347
|
*/
|
|
337
348
|
fileTree?: boolean | FileTreeOptions;
|
|
349
|
+
/**
|
|
350
|
+
* 是否启用 代码树 容器语法 和 嵌入语法
|
|
351
|
+
*
|
|
352
|
+
* ```md
|
|
353
|
+
* ::: code-tree
|
|
354
|
+
* :::
|
|
355
|
+
* ```
|
|
356
|
+
*
|
|
357
|
+
* `@[code-tree](file_path)`
|
|
358
|
+
*
|
|
359
|
+
*
|
|
360
|
+
* @default false
|
|
361
|
+
*/
|
|
362
|
+
codeTree?: boolean | CodeTreeOptions;
|
|
338
363
|
/**
|
|
339
364
|
* 是否启用 demo 语法
|
|
340
365
|
*/
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vuepress-plugin-md-power",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.0.0-rc.
|
|
4
|
+
"version": "1.0.0-rc.146",
|
|
5
5
|
"description": "The Plugin for VuePress 2 - markdown power",
|
|
6
6
|
"author": "pengzhanbo <volodymyr@foxmail.com>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"peerDependencies": {
|
|
34
34
|
"artplayer": "^5.2.3",
|
|
35
35
|
"dashjs": "^5.0.1",
|
|
36
|
-
"esbuild": "^0.25.
|
|
36
|
+
"esbuild": "^0.25.4",
|
|
37
37
|
"hls.js": "^1.6.2",
|
|
38
38
|
"less": "^4.3.0",
|
|
39
39
|
"markdown-it": "^14.1.0",
|
|
@@ -61,15 +61,15 @@
|
|
|
61
61
|
}
|
|
62
62
|
},
|
|
63
63
|
"dependencies": {
|
|
64
|
-
"@mdit/plugin-attrs": "^0.
|
|
65
|
-
"@mdit/plugin-footnote": "^0.
|
|
66
|
-
"@mdit/plugin-mark": "^0.
|
|
67
|
-
"@mdit/plugin-sub": "^0.
|
|
68
|
-
"@mdit/plugin-sup": "^0.
|
|
69
|
-
"@mdit/plugin-tab": "^0.
|
|
70
|
-
"@mdit/plugin-tasklist": "^0.
|
|
64
|
+
"@mdit/plugin-attrs": "^0.18.0",
|
|
65
|
+
"@mdit/plugin-footnote": "^0.18.0",
|
|
66
|
+
"@mdit/plugin-mark": "^0.18.0",
|
|
67
|
+
"@mdit/plugin-sub": "^0.18.0",
|
|
68
|
+
"@mdit/plugin-sup": "^0.18.0",
|
|
69
|
+
"@mdit/plugin-tab": "^0.18.0",
|
|
70
|
+
"@mdit/plugin-tasklist": "^0.18.0",
|
|
71
71
|
"@pengzhanbo/utils": "^2.1.0",
|
|
72
|
-
"@vuepress/helper": "2.0.0-rc.
|
|
72
|
+
"@vuepress/helper": "2.0.0-rc.99",
|
|
73
73
|
"@vueuse/core": "^13.1.0",
|
|
74
74
|
"chokidar": "3.6.0",
|
|
75
75
|
"image-size": "^2.0.2",
|
|
@@ -78,6 +78,7 @@
|
|
|
78
78
|
"markdown-it-container": "^4.0.0",
|
|
79
79
|
"nanoid": "^5.1.5",
|
|
80
80
|
"shiki": "^3.3.0",
|
|
81
|
+
"tinyglobby": "0.2.13",
|
|
81
82
|
"tm-grammars": "^1.23.16",
|
|
82
83
|
"tm-themes": "^1.10.5",
|
|
83
84
|
"vue": "^3.5.13"
|