vuepress-plugin-md-power 1.0.0-rc.145 → 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 +3 -2
- package/lib/client/components/VPCodeTree.vue +159 -0
- package/lib/node/index.d.ts +19 -0
- package/lib/node/index.js +331 -157
- package/lib/shared/index.d.ts +19 -0
- package/package.json +11 -10
|
@@ -9,6 +9,7 @@ const props = defineProps<{
|
|
|
9
9
|
diff?: 'add' | 'remove'
|
|
10
10
|
expanded?: boolean
|
|
11
11
|
focus?: boolean
|
|
12
|
+
filepath?: string
|
|
12
13
|
}>()
|
|
13
14
|
|
|
14
15
|
const activeFileTreeNode = inject<Ref<string>>('active-file-tree-node', ref(''))
|
|
@@ -23,7 +24,7 @@ function nodeClick() {
|
|
|
23
24
|
if (props.filename === '…' || props.filename === '...')
|
|
24
25
|
return
|
|
25
26
|
|
|
26
|
-
onNodeClick(props.filename, props.type)
|
|
27
|
+
onNodeClick(props.filepath || props.filename, props.type)
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
function toggle(ev: MouseEvent) {
|
|
@@ -47,7 +48,7 @@ function toggle(ev: MouseEvent) {
|
|
|
47
48
|
[type]: true,
|
|
48
49
|
focus,
|
|
49
50
|
expanded: type === 'folder' ? active : false,
|
|
50
|
-
active: type === 'file' ? activeFileTreeNode ===
|
|
51
|
+
active: type === 'file' ? activeFileTreeNode === filepath : false,
|
|
51
52
|
diff,
|
|
52
53
|
add: diff === 'add',
|
|
53
54
|
remove: diff === 'remove',
|
|
@@ -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>
|
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;
|
|
@@ -342,6 +347,20 @@ interface MarkdownPowerPluginOptions {
|
|
|
342
347
|
* @default false
|
|
343
348
|
*/
|
|
344
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;
|
|
345
364
|
/**
|
|
346
365
|
* 是否启用 demo 语法
|
|
347
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", {
|
|
@@ -1563,9 +1814,9 @@ ${renderedIcon}${renderedComment}${children.length > 0 ? renderFileTree(children
|
|
|
1563
1814
|
}
|
|
1564
1815
|
|
|
1565
1816
|
// src/node/container/langRepl.ts
|
|
1566
|
-
import { promises as
|
|
1817
|
+
import { promises as fs3 } from "node:fs";
|
|
1567
1818
|
import { resolveModule } from "local-pkg";
|
|
1568
|
-
import { colors, logger as logger2, path as
|
|
1819
|
+
import { colors, logger as logger2, path as path4 } from "vuepress/utils";
|
|
1569
1820
|
async function langReplPlugin(app, md, {
|
|
1570
1821
|
theme,
|
|
1571
1822
|
go = false,
|
|
@@ -1589,10 +1840,10 @@ async function langReplPlugin(app, md, {
|
|
|
1589
1840
|
theme ??= { light: "github-light", dark: "github-dark" };
|
|
1590
1841
|
const data = { grammars: {} };
|
|
1591
1842
|
try {
|
|
1592
|
-
const themesPath =
|
|
1593
|
-
const grammarsPath =
|
|
1594
|
-
const readTheme = (theme2) => read(
|
|
1595
|
-
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`));
|
|
1596
1847
|
if (typeof theme === "string") {
|
|
1597
1848
|
data.theme = await readTheme(theme);
|
|
1598
1849
|
} else {
|
|
@@ -1617,7 +1868,7 @@ async function langReplPlugin(app, md, {
|
|
|
1617
1868
|
}
|
|
1618
1869
|
async function read(file) {
|
|
1619
1870
|
try {
|
|
1620
|
-
const content = await
|
|
1871
|
+
const content = await fs3.readFile(file, "utf-8");
|
|
1621
1872
|
return JSON.parse(content);
|
|
1622
1873
|
} catch {
|
|
1623
1874
|
}
|
|
@@ -2116,6 +2367,9 @@ async function containerPlugin(app, md, options) {
|
|
|
2116
2367
|
if (options.fileTree) {
|
|
2117
2368
|
fileTreePlugin(md, isPlainObject2(options.fileTree) ? options.fileTree : {});
|
|
2118
2369
|
}
|
|
2370
|
+
if (options.codeTree) {
|
|
2371
|
+
codeTreePlugin(md, app, isPlainObject2(options.codeTree) ? options.codeTree : {});
|
|
2372
|
+
}
|
|
2119
2373
|
if (options.timeline)
|
|
2120
2374
|
timelinePlugin(md);
|
|
2121
2375
|
if (options.collapse)
|
|
@@ -2129,85 +2383,6 @@ async function containerPlugin(app, md, options) {
|
|
|
2129
2383
|
// src/node/demo/demo.ts
|
|
2130
2384
|
import container2 from "markdown-it-container";
|
|
2131
2385
|
|
|
2132
|
-
// src/node/embed/createEmbedRuleBlock.ts
|
|
2133
|
-
function createEmbedRuleBlock(md, {
|
|
2134
|
-
type,
|
|
2135
|
-
name = type,
|
|
2136
|
-
syntaxPattern,
|
|
2137
|
-
beforeName = "import_code",
|
|
2138
|
-
ruleOptions = { alt: ["paragraph", "reference", "blockquote", "list"] },
|
|
2139
|
-
meta,
|
|
2140
|
-
content
|
|
2141
|
-
}) {
|
|
2142
|
-
const MIN_LENGTH = type.length + 5;
|
|
2143
|
-
const START_CODES = [64, 91, ...type.split("").map((c) => c.charCodeAt(0))];
|
|
2144
|
-
md.block.ruler.before(
|
|
2145
|
-
beforeName,
|
|
2146
|
-
name,
|
|
2147
|
-
(state, startLine, endLine, silent) => {
|
|
2148
|
-
const pos = state.bMarks[startLine] + state.tShift[startLine];
|
|
2149
|
-
const max = state.eMarks[startLine];
|
|
2150
|
-
if (pos + MIN_LENGTH > max)
|
|
2151
|
-
return false;
|
|
2152
|
-
for (let i = 0; i < START_CODES.length; i += 1) {
|
|
2153
|
-
if (state.src.charCodeAt(pos + i) !== START_CODES[i])
|
|
2154
|
-
return false;
|
|
2155
|
-
}
|
|
2156
|
-
const content2 = state.src.slice(pos, max);
|
|
2157
|
-
const match = content2.match(syntaxPattern);
|
|
2158
|
-
if (!match)
|
|
2159
|
-
return false;
|
|
2160
|
-
if (silent)
|
|
2161
|
-
return true;
|
|
2162
|
-
const token = state.push(name, "", 0);
|
|
2163
|
-
token.meta = meta(match);
|
|
2164
|
-
token.content = content2;
|
|
2165
|
-
token.map = [startLine, startLine + 1];
|
|
2166
|
-
state.line = startLine + 1;
|
|
2167
|
-
return true;
|
|
2168
|
-
},
|
|
2169
|
-
ruleOptions
|
|
2170
|
-
);
|
|
2171
|
-
md.renderer.rules[name] = (tokens, index, _, env) => {
|
|
2172
|
-
const token = tokens[index];
|
|
2173
|
-
token.content = content(token.meta, token.content, env);
|
|
2174
|
-
return token.content;
|
|
2175
|
-
};
|
|
2176
|
-
}
|
|
2177
|
-
|
|
2178
|
-
// src/node/demo/supports/file.ts
|
|
2179
|
-
import fs3 from "node:fs";
|
|
2180
|
-
import { createRequire } from "node:module";
|
|
2181
|
-
import path3 from "node:path";
|
|
2182
|
-
import process from "node:process";
|
|
2183
|
-
var require2 = createRequire(process.cwd());
|
|
2184
|
-
function findFile(app, env, url) {
|
|
2185
|
-
if (url.startsWith("/"))
|
|
2186
|
-
return app.dir.source(url.slice(1));
|
|
2187
|
-
if (url.startsWith("./") || url.startsWith("../"))
|
|
2188
|
-
return app.dir.source(path3.dirname(env.filePathRelative), url);
|
|
2189
|
-
if (url.startsWith("@source/")) {
|
|
2190
|
-
return app.dir.source(url.slice("@source/".length));
|
|
2191
|
-
}
|
|
2192
|
-
try {
|
|
2193
|
-
return require2.resolve(url);
|
|
2194
|
-
} catch {
|
|
2195
|
-
return url;
|
|
2196
|
-
}
|
|
2197
|
-
}
|
|
2198
|
-
function readFileSync(filepath2) {
|
|
2199
|
-
try {
|
|
2200
|
-
return fs3.readFileSync(filepath2, "utf-8");
|
|
2201
|
-
} catch {
|
|
2202
|
-
return false;
|
|
2203
|
-
}
|
|
2204
|
-
}
|
|
2205
|
-
function writeFileSync(filepath2, content) {
|
|
2206
|
-
const dirname = path3.dirname(filepath2);
|
|
2207
|
-
fs3.mkdirSync(dirname, { recursive: true });
|
|
2208
|
-
fs3.writeFileSync(filepath2, content, "utf-8");
|
|
2209
|
-
}
|
|
2210
|
-
|
|
2211
2386
|
// src/node/demo/markdown.ts
|
|
2212
2387
|
function markdownEmbed(app, md, env, { url, title, desc, codeSetting = "", expanded = false }) {
|
|
2213
2388
|
const filepath2 = findFile(app, env, url);
|
|
@@ -2243,7 +2418,7 @@ var markdownContainerRender = {
|
|
|
2243
2418
|
|
|
2244
2419
|
// src/node/demo/normal.ts
|
|
2245
2420
|
import fs5 from "node:fs";
|
|
2246
|
-
import
|
|
2421
|
+
import path6 from "node:path";
|
|
2247
2422
|
|
|
2248
2423
|
// src/node/demo/supports/compiler.ts
|
|
2249
2424
|
import { isPackageExists } from "local-pkg";
|
|
@@ -2324,8 +2499,8 @@ function importer(func) {
|
|
|
2324
2499
|
|
|
2325
2500
|
// src/node/demo/supports/insertScript.ts
|
|
2326
2501
|
var SCRIPT_RE = /<script.*?>/;
|
|
2327
|
-
function insertSetupScript({ export: name, path:
|
|
2328
|
-
const imports = `import ${name ? `${name} from ` : ""}'${
|
|
2502
|
+
function insertSetupScript({ export: name, path: path10 }, env) {
|
|
2503
|
+
const imports = `import ${name ? `${name} from ` : ""}'${path10}';`;
|
|
2329
2504
|
const scriptSetup = env.sfcBlocks.scriptSetup ??= {
|
|
2330
2505
|
type: "script",
|
|
2331
2506
|
content: "<script setup>\n</script>",
|
|
@@ -2341,7 +2516,7 @@ ${imports}`);
|
|
|
2341
2516
|
|
|
2342
2517
|
// src/node/demo/watcher.ts
|
|
2343
2518
|
import fs4 from "node:fs";
|
|
2344
|
-
import
|
|
2519
|
+
import path5 from "node:path";
|
|
2345
2520
|
import { watch } from "chokidar";
|
|
2346
2521
|
var renderDone = null;
|
|
2347
2522
|
var renderCount = 0;
|
|
@@ -2377,30 +2552,30 @@ function demoWatcher(app, watchers) {
|
|
|
2377
2552
|
if (!watcher) {
|
|
2378
2553
|
watcher = watch([], { ignoreInitial: true });
|
|
2379
2554
|
}
|
|
2380
|
-
Object.keys(tasks).forEach((
|
|
2381
|
-
watcher.add(
|
|
2555
|
+
Object.keys(tasks).forEach((path10) => {
|
|
2556
|
+
watcher.add(path10);
|
|
2382
2557
|
});
|
|
2383
2558
|
const code = readFileSync(app.dir.temp(target));
|
|
2384
2559
|
if (code) {
|
|
2385
2560
|
const paths = JSON.parse(code || "{}");
|
|
2386
|
-
Object.entries(paths).forEach(([
|
|
2387
|
-
watcher.add(
|
|
2388
|
-
tasks[
|
|
2561
|
+
Object.entries(paths).forEach(([path10, output]) => {
|
|
2562
|
+
watcher.add(path10);
|
|
2563
|
+
tasks[path10] = output;
|
|
2389
2564
|
});
|
|
2390
2565
|
}
|
|
2391
2566
|
updateWatchFiles(app);
|
|
2392
|
-
watcher.on("change", (
|
|
2393
|
-
if (tasks[
|
|
2394
|
-
const code2 = readFileSync(
|
|
2567
|
+
watcher.on("change", (path10) => {
|
|
2568
|
+
if (tasks[path10]) {
|
|
2569
|
+
const code2 = readFileSync(path10);
|
|
2395
2570
|
if (code2 === false)
|
|
2396
2571
|
return;
|
|
2397
2572
|
const source = parseEmbedCode(code2);
|
|
2398
|
-
compileCode(source, tasks[
|
|
2573
|
+
compileCode(source, tasks[path10]);
|
|
2399
2574
|
}
|
|
2400
2575
|
});
|
|
2401
|
-
watcher.on("unlink", (
|
|
2402
|
-
delete tasks[
|
|
2403
|
-
watcher.unwatch(
|
|
2576
|
+
watcher.on("unlink", (path10) => {
|
|
2577
|
+
delete tasks[path10];
|
|
2578
|
+
watcher.unwatch(path10);
|
|
2404
2579
|
});
|
|
2405
2580
|
watchers.push({
|
|
2406
2581
|
close: () => {
|
|
@@ -2409,17 +2584,17 @@ function demoWatcher(app, watchers) {
|
|
|
2409
2584
|
}
|
|
2410
2585
|
});
|
|
2411
2586
|
}
|
|
2412
|
-
function addTask(app,
|
|
2413
|
-
if (tasks[
|
|
2587
|
+
function addTask(app, path10, output) {
|
|
2588
|
+
if (tasks[path10])
|
|
2414
2589
|
return;
|
|
2415
|
-
tasks[
|
|
2590
|
+
tasks[path10] = output;
|
|
2416
2591
|
if (watcher) {
|
|
2417
|
-
watcher.add(
|
|
2592
|
+
watcher.add(path10);
|
|
2418
2593
|
}
|
|
2419
2594
|
updateWatchFiles(app);
|
|
2420
2595
|
}
|
|
2421
2596
|
async function updateWatchFiles(app) {
|
|
2422
|
-
await fs4.promises.mkdir(app.dir.temp(
|
|
2597
|
+
await fs4.promises.mkdir(app.dir.temp(path5.dirname(target)), { recursive: true });
|
|
2423
2598
|
await fs4.promises.writeFile(app.dir.temp(target), JSON.stringify(tasks));
|
|
2424
2599
|
}
|
|
2425
2600
|
|
|
@@ -2511,7 +2686,7 @@ function normalEmbed(app, md, env, { url, title, desc, codeSetting = "", expande
|
|
|
2511
2686
|
}
|
|
2512
2687
|
const source = parseEmbedCode(code);
|
|
2513
2688
|
const prefix = (env.filePathRelative || "").replace(/\.md$/, "").replace(/\//g, "-");
|
|
2514
|
-
const basename =
|
|
2689
|
+
const basename = path6.basename(filepath2).replace(/-|\./g, "_");
|
|
2515
2690
|
const name = `Demo${basename[0].toUpperCase()}${basename.slice(1)}`;
|
|
2516
2691
|
const demo = { type: "normal", export: name, path: filepath2 };
|
|
2517
2692
|
const output = app.dir.temp(target2, `${prefix}-${name}.js`);
|
|
@@ -2531,7 +2706,7 @@ var normalContainerRender = {
|
|
|
2531
2706
|
const { url, title, desc, expanded = false } = meta;
|
|
2532
2707
|
const name = `DemoContainer${url}`;
|
|
2533
2708
|
const prefix = (env.filePathRelative || "").replace(/\.md$/, "").replace(/\//g, "-");
|
|
2534
|
-
const output = app.dir.temp(
|
|
2709
|
+
const output = app.dir.temp(path6.join(target2, `${prefix}-${name}.js`));
|
|
2535
2710
|
env.demoFiles ??= [];
|
|
2536
2711
|
if (!env.demoFiles.some((d) => d.path === output)) {
|
|
2537
2712
|
const demo = { type: "normal", export: name, gitignore: true, path: output };
|
|
@@ -2609,7 +2784,7 @@ function normalizeAlias(info) {
|
|
|
2609
2784
|
}
|
|
2610
2785
|
|
|
2611
2786
|
// src/node/demo/vue.ts
|
|
2612
|
-
import
|
|
2787
|
+
import path7 from "node:path";
|
|
2613
2788
|
function vueEmbed(app, md, env, { url, title, desc, codeSetting = "", expanded = false }) {
|
|
2614
2789
|
const filepath2 = findFile(app, env, url);
|
|
2615
2790
|
const code = readFileSync(filepath2);
|
|
@@ -2617,8 +2792,8 @@ function vueEmbed(app, md, env, { url, title, desc, codeSetting = "", expanded =
|
|
|
2617
2792
|
console.warn("[vuepress-plugin-md-power] Cannot read vue file:", filepath2);
|
|
2618
2793
|
return "";
|
|
2619
2794
|
}
|
|
2620
|
-
const basename =
|
|
2621
|
-
const ext =
|
|
2795
|
+
const basename = path7.basename(filepath2).replace(/-|\./g, "_");
|
|
2796
|
+
const ext = path7.extname(filepath2).slice(1);
|
|
2622
2797
|
const name = `Demo${basename[0].toUpperCase()}${basename.slice(1)}`;
|
|
2623
2798
|
const demo = { type: "vue", export: name, path: filepath2 };
|
|
2624
2799
|
env.demoFiles ??= [];
|
|
@@ -2642,7 +2817,7 @@ var vueContainerRender = {
|
|
|
2642
2817
|
const componentName = `DemoContainer${url}`;
|
|
2643
2818
|
const prefix = (env.filePathRelative || "").replace(/\.md$/, "").replace(/\//g, "-");
|
|
2644
2819
|
env.demoFiles ??= [];
|
|
2645
|
-
const output = app.dir.temp(
|
|
2820
|
+
const output = app.dir.temp(path7.join(target3, `${prefix}-${componentName}`));
|
|
2646
2821
|
if (codeMap.vue || codeMap.js || codeMap.ts) {
|
|
2647
2822
|
let scriptOutput = output;
|
|
2648
2823
|
let content = "";
|
|
@@ -2699,7 +2874,7 @@ var STYLE_RE2 = /<style.*?>/;
|
|
|
2699
2874
|
function transformImports(code, filepath2) {
|
|
2700
2875
|
return code.replace(IMPORT_RE, (matched, url) => {
|
|
2701
2876
|
if (url.startsWith("./") || url.startsWith("../")) {
|
|
2702
|
-
return matched.replace(url, `${
|
|
2877
|
+
return matched.replace(url, `${path7.resolve(path7.dirname(filepath2), url)}`);
|
|
2703
2878
|
}
|
|
2704
2879
|
return matched;
|
|
2705
2880
|
});
|
|
@@ -2797,10 +2972,10 @@ function extendsPageWithDemo(page) {
|
|
|
2797
2972
|
const markdownEnv = page.markdownEnv;
|
|
2798
2973
|
const demoFiles = markdownEnv.demoFiles ?? [];
|
|
2799
2974
|
page.deps.push(
|
|
2800
|
-
...demoFiles.filter(({ type }) => type === "markdown").map(({ path:
|
|
2975
|
+
...demoFiles.filter(({ type }) => type === "markdown").map(({ path: path10 }) => path10)
|
|
2801
2976
|
);
|
|
2802
2977
|
(page.frontmatter.gitInclude ??= []).push(
|
|
2803
|
-
...demoFiles.filter(({ gitignore }) => !gitignore).map(({ path:
|
|
2978
|
+
...demoFiles.filter(({ gitignore }) => !gitignore).map(({ path: path10 }) => path10)
|
|
2804
2979
|
);
|
|
2805
2980
|
}
|
|
2806
2981
|
|
|
@@ -2933,13 +3108,6 @@ function resolveVersions(versions) {
|
|
|
2933
3108
|
};
|
|
2934
3109
|
}
|
|
2935
3110
|
|
|
2936
|
-
// src/node/utils/parseRect.ts
|
|
2937
|
-
function parseRect(str, unit = "px") {
|
|
2938
|
-
if (Number.parseFloat(str) === Number(str))
|
|
2939
|
-
return `${str}${unit}`;
|
|
2940
|
-
return str;
|
|
2941
|
-
}
|
|
2942
|
-
|
|
2943
3111
|
// src/node/embed/code/codepen.ts
|
|
2944
3112
|
var codepenPlugin = (md) => {
|
|
2945
3113
|
createEmbedRuleBlock(md, {
|
|
@@ -3030,7 +3198,7 @@ var replitPlugin = (md) => {
|
|
|
3030
3198
|
};
|
|
3031
3199
|
|
|
3032
3200
|
// src/node/embed/pdf.ts
|
|
3033
|
-
import { path as
|
|
3201
|
+
import { path as path8 } from "vuepress/utils";
|
|
3034
3202
|
var pdfPlugin = (md) => {
|
|
3035
3203
|
createEmbedRuleBlock(md, {
|
|
3036
3204
|
type: "pdf",
|
|
@@ -3046,7 +3214,7 @@ var pdfPlugin = (md) => {
|
|
|
3046
3214
|
width: attrs2.width ? parseRect(attrs2.width) : "100%",
|
|
3047
3215
|
height: attrs2.height ? parseRect(attrs2.height) : "",
|
|
3048
3216
|
ratio: attrs2.ratio ? parseRect(attrs2.ratio) : "",
|
|
3049
|
-
title:
|
|
3217
|
+
title: path8.basename(src || "")
|
|
3050
3218
|
};
|
|
3051
3219
|
},
|
|
3052
3220
|
content: (meta) => `<PDFViewer${stringifyAttrs(meta)} />`
|
|
@@ -3651,11 +3819,11 @@ function inlineSyntaxPlugin(md, options) {
|
|
|
3651
3819
|
|
|
3652
3820
|
// src/node/prepareConfigFile.ts
|
|
3653
3821
|
import { ensureEndingSlash } from "@vuepress/helper";
|
|
3654
|
-
import { getDirname, path as
|
|
3822
|
+
import { getDirname, path as path9 } from "vuepress/utils";
|
|
3655
3823
|
var { url: filepath } = import.meta;
|
|
3656
3824
|
var __dirname = getDirname(filepath);
|
|
3657
3825
|
var CLIENT_FOLDER = ensureEndingSlash(
|
|
3658
|
-
|
|
3826
|
+
path9.resolve(__dirname, "../client")
|
|
3659
3827
|
);
|
|
3660
3828
|
async function prepareConfigFile(app, options) {
|
|
3661
3829
|
const imports = /* @__PURE__ */ new Set();
|
|
@@ -3704,10 +3872,14 @@ async function prepareConfigFile(app, options) {
|
|
|
3704
3872
|
imports.add(`import CanIUse from '${CLIENT_FOLDER}components/CanIUse.vue'`);
|
|
3705
3873
|
enhances.add(`app.component('CanIUseViewer', CanIUse)`);
|
|
3706
3874
|
}
|
|
3707
|
-
if (options.fileTree) {
|
|
3875
|
+
if (options.fileTree || options.codeTree) {
|
|
3708
3876
|
imports.add(`import FileTreeNode from '${CLIENT_FOLDER}components/FileTreeNode.vue'`);
|
|
3709
3877
|
enhances.add(`app.component('FileTreeNode', FileTreeNode)`);
|
|
3710
3878
|
}
|
|
3879
|
+
if (options.codeTree) {
|
|
3880
|
+
imports.add(`import VPCodeTree from '${CLIENT_FOLDER}components/VPCodeTree.vue'`);
|
|
3881
|
+
enhances.add(`app.component('VPCodeTree', VPCodeTree)`);
|
|
3882
|
+
}
|
|
3711
3883
|
if (options.artPlayer) {
|
|
3712
3884
|
imports.add(`import ArtPlayer from '${CLIENT_FOLDER}components/ArtPlayer.vue'`);
|
|
3713
3885
|
enhances.add(`app.component('ArtPlayer', ArtPlayer)`);
|
|
@@ -3813,6 +3985,8 @@ function markdownPowerPlugin(options = {}) {
|
|
|
3813
3985
|
extendsPage: (page) => {
|
|
3814
3986
|
if (options.demo)
|
|
3815
3987
|
extendsPageWithDemo(page);
|
|
3988
|
+
if (options.codeTree)
|
|
3989
|
+
extendsPageWithCodeTree(page);
|
|
3816
3990
|
}
|
|
3817
3991
|
};
|
|
3818
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;
|
|
@@ -341,6 +346,20 @@ interface MarkdownPowerPluginOptions {
|
|
|
341
346
|
* @default false
|
|
342
347
|
*/
|
|
343
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;
|
|
344
363
|
/**
|
|
345
364
|
* 是否启用 demo 语法
|
|
346
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"
|