valaxy 0.22.13 → 0.22.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/client/App.vue +2 -0
- package/client/app/data.ts +19 -0
- package/client/components/ValaxyOverlay.vue +1 -1
- package/client/composables/common.ts +10 -6
- package/client/config.ts +4 -1
- package/client/main.ts +11 -3
- package/dist/chunk-HAPQ2BMO.js +426 -0
- package/dist/chunk-ID2ZSEKA.js +4812 -0
- package/dist/chunk-UO3OS4ER.js +19 -0
- package/dist/node/cli/index.js +14 -1
- package/dist/node/index.d.ts +4 -2
- package/dist/node/index.js +108 -1
- package/dist/node/worker_shikiResolveLang.js +13 -1
- package/dist/types/index.js +1 -1
- package/package.json +19 -14
- package/dist/chunk-2TIFAWAJ.js +0 -2
- package/dist/chunk-3KRYIAHJ.js +0 -2
- package/dist/chunk-LNIYNCJL.js +0 -165
|
@@ -0,0 +1,4812 @@
|
|
|
1
|
+
import {createRequire as __createRequire} from 'module';var require=__createRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
createSyncFn
|
|
4
|
+
} from "./chunk-HAPQ2BMO.js";
|
|
5
|
+
import {
|
|
6
|
+
__require
|
|
7
|
+
} from "./chunk-UO3OS4ER.js";
|
|
8
|
+
|
|
9
|
+
// node/cli/index.ts
|
|
10
|
+
import process14 from "node:process";
|
|
11
|
+
import yargs from "yargs";
|
|
12
|
+
import { hideBin } from "yargs/helpers";
|
|
13
|
+
|
|
14
|
+
// package.json
|
|
15
|
+
var version = "0.22.15";
|
|
16
|
+
|
|
17
|
+
// node/modules/fuse.ts
|
|
18
|
+
import path4 from "node:path";
|
|
19
|
+
import consola9 from "consola";
|
|
20
|
+
import { colors as colors7 } from "consola/utils";
|
|
21
|
+
import fg2 from "fast-glob";
|
|
22
|
+
import fs7 from "fs-extra";
|
|
23
|
+
import matter from "gray-matter";
|
|
24
|
+
|
|
25
|
+
// node/modules/index.ts
|
|
26
|
+
function defineValaxyModule(module) {
|
|
27
|
+
return module;
|
|
28
|
+
}
|
|
29
|
+
function setupModules(node, modules2) {
|
|
30
|
+
modules2.forEach((module) => {
|
|
31
|
+
module.setup?.(node);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// node/cli/options.ts
|
|
36
|
+
function commonOptions(args) {
|
|
37
|
+
return args.positional("root", {
|
|
38
|
+
default: ".",
|
|
39
|
+
type: "string",
|
|
40
|
+
describe: "root folder of your source files"
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// node/options.ts
|
|
45
|
+
import { dirname as dirname2 } from "node:path";
|
|
46
|
+
import process4 from "node:process";
|
|
47
|
+
import { ensureSuffix, uniq } from "@antfu/utils";
|
|
48
|
+
import consola7 from "consola";
|
|
49
|
+
import { colors as colors6 } from "consola/utils";
|
|
50
|
+
import _debug from "debug";
|
|
51
|
+
import fg from "fast-glob";
|
|
52
|
+
import fs5 from "fs-extra";
|
|
53
|
+
import { resolve as resolve4 } from "pathe";
|
|
54
|
+
|
|
55
|
+
// node/build/bundle.ts
|
|
56
|
+
import path from "node:path";
|
|
57
|
+
var cache = /* @__PURE__ */ new Map();
|
|
58
|
+
var cacheTheme = /* @__PURE__ */ new Map();
|
|
59
|
+
function escapeRegExp(str) {
|
|
60
|
+
return str.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&").replace(/-/g, "\\x2d");
|
|
61
|
+
}
|
|
62
|
+
var CSS_LANGS_RE = /\.(css|less|sass|scss|styl|stylus|pcss|postcss|sss)(?:$|\?)/;
|
|
63
|
+
function isEagerChunk(id, getModuleInfo) {
|
|
64
|
+
if (id.includes("node_modules") && !CSS_LANGS_RE.test(id) && staticImportedByEntry(id, getModuleInfo, cache)) {
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function staticImportedByEntry(id, getModuleInfo, cache3, entryRE = null, importStack = []) {
|
|
69
|
+
if (cache3.has(id)) {
|
|
70
|
+
return !!cache3.get(id);
|
|
71
|
+
}
|
|
72
|
+
if (importStack.includes(id)) {
|
|
73
|
+
cache3.set(id, false);
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
const mod = getModuleInfo(id);
|
|
77
|
+
if (!mod) {
|
|
78
|
+
cache3.set(id, false);
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
if (entryRE ? entryRE.test(id) : mod.isEntry) {
|
|
82
|
+
cache3.set(id, true);
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
const someImporterIs = mod.importers.some(
|
|
86
|
+
(importer) => staticImportedByEntry(
|
|
87
|
+
importer,
|
|
88
|
+
getModuleInfo,
|
|
89
|
+
cache3,
|
|
90
|
+
entryRE,
|
|
91
|
+
importStack.concat(id)
|
|
92
|
+
)
|
|
93
|
+
);
|
|
94
|
+
cache3.set(id, someImporterIs);
|
|
95
|
+
return someImporterIs;
|
|
96
|
+
}
|
|
97
|
+
function getRollupOptions(options) {
|
|
98
|
+
const excludedModules = [
|
|
99
|
+
"/@siteData",
|
|
100
|
+
"node_modules/@vueuse/core/",
|
|
101
|
+
"node_modules/@vueuse/shared/",
|
|
102
|
+
"node_modules/vue/",
|
|
103
|
+
"node_modules/vue-demi/",
|
|
104
|
+
options.clientRoot
|
|
105
|
+
];
|
|
106
|
+
const themeEntryRE = new RegExp(
|
|
107
|
+
`^${escapeRegExp(
|
|
108
|
+
path.resolve(options.themeRoot, "index.ts").replace(/\\/g, "/")
|
|
109
|
+
)}`
|
|
110
|
+
);
|
|
111
|
+
const assetsDir = "assets";
|
|
112
|
+
const rollupOptions = {
|
|
113
|
+
...options.config.vite?.build?.rollupOptions,
|
|
114
|
+
external: [],
|
|
115
|
+
// important so that each page chunk and the index export things for each
|
|
116
|
+
// other
|
|
117
|
+
preserveEntrySignatures: "allow-extension",
|
|
118
|
+
output: {
|
|
119
|
+
assetFileNames: `${assetsDir}/[name].[hash].[ext]`,
|
|
120
|
+
entryFileNames: `${assetsDir}/[name].[hash].js`,
|
|
121
|
+
chunkFileNames() {
|
|
122
|
+
return `${assetsDir}/[name].[hash].js`;
|
|
123
|
+
},
|
|
124
|
+
manualChunks(id, ctx) {
|
|
125
|
+
if (id.startsWith("\0vite")) {
|
|
126
|
+
return "framework";
|
|
127
|
+
}
|
|
128
|
+
if (id.includes("plugin-vue:export-helper")) {
|
|
129
|
+
return "framework";
|
|
130
|
+
}
|
|
131
|
+
const libs = [
|
|
132
|
+
"@vueuse/motion",
|
|
133
|
+
"dayjs",
|
|
134
|
+
"vue-i18n",
|
|
135
|
+
"vue-router",
|
|
136
|
+
"nprogress",
|
|
137
|
+
"pinia"
|
|
138
|
+
];
|
|
139
|
+
for (const lib of libs) {
|
|
140
|
+
if (id.includes(lib)) {
|
|
141
|
+
return `chunks/${lib}`;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
if (isEagerChunk(id, ctx.getModuleInfo) && /@vue\/(runtime|shared|reactivity)/.test(id)) {
|
|
145
|
+
return "framework";
|
|
146
|
+
}
|
|
147
|
+
if ((id.startsWith(options.themeRoot) || !excludedModules.some((i) => id.includes(i))) && staticImportedByEntry(
|
|
148
|
+
id,
|
|
149
|
+
ctx.getModuleInfo,
|
|
150
|
+
cacheTheme,
|
|
151
|
+
themeEntryRE
|
|
152
|
+
)) {
|
|
153
|
+
return "theme";
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
return rollupOptions;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// node/config/addon.ts
|
|
162
|
+
import path2 from "node:path";
|
|
163
|
+
import fs2 from "fs-extra";
|
|
164
|
+
|
|
165
|
+
// node/config/valaxy.ts
|
|
166
|
+
import process2 from "node:process";
|
|
167
|
+
import { isFunction } from "@antfu/utils";
|
|
168
|
+
import consola4 from "consola";
|
|
169
|
+
import { colors as colors2 } from "consola/utils";
|
|
170
|
+
import { createDefu } from "defu";
|
|
171
|
+
import { mergeConfig as mergeViteConfig } from "vite";
|
|
172
|
+
|
|
173
|
+
// node/utils/performance.ts
|
|
174
|
+
import consola from "consola";
|
|
175
|
+
function countPerformanceTime() {
|
|
176
|
+
const start = performance.now();
|
|
177
|
+
return () => {
|
|
178
|
+
const end = performance.now();
|
|
179
|
+
const duration = end - start;
|
|
180
|
+
if (duration > 1e3)
|
|
181
|
+
return `${(duration / 1e3).toFixed(2)}s`;
|
|
182
|
+
return `${duration.toFixed(2)}ms`;
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// node/config/site.ts
|
|
187
|
+
import { webcrypto } from "node:crypto";
|
|
188
|
+
import consola3 from "consola";
|
|
189
|
+
import { colors } from "consola/utils";
|
|
190
|
+
import { options as floatingVueOptions } from "floating-vue";
|
|
191
|
+
|
|
192
|
+
// node/config/utils.ts
|
|
193
|
+
import process from "node:process";
|
|
194
|
+
import consola2 from "consola";
|
|
195
|
+
import fs from "fs-extra";
|
|
196
|
+
import { createJiti } from "jiti";
|
|
197
|
+
import { resolve } from "pathe";
|
|
198
|
+
var jiti = createJiti(import.meta.url, {
|
|
199
|
+
// for hmr
|
|
200
|
+
moduleCache: false
|
|
201
|
+
});
|
|
202
|
+
async function loadConfig(options) {
|
|
203
|
+
const { name, cwd } = options;
|
|
204
|
+
const filePath = resolve(cwd, `${name}.config.ts`);
|
|
205
|
+
let data = {};
|
|
206
|
+
if (await fs.exists(filePath)) {
|
|
207
|
+
try {
|
|
208
|
+
data = await jiti.import(filePath, { default: true });
|
|
209
|
+
} catch (e) {
|
|
210
|
+
console.error(e);
|
|
211
|
+
consola2.error(`Failed to load config file: ${filePath}`);
|
|
212
|
+
}
|
|
213
|
+
} else {
|
|
214
|
+
consola2.debug(`Config file not found: ${filePath}`);
|
|
215
|
+
}
|
|
216
|
+
return {
|
|
217
|
+
config: data,
|
|
218
|
+
configFile: filePath
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
async function loadConfigFromFile(file, options = {}) {
|
|
222
|
+
const { config, configFile } = await loadConfig({
|
|
223
|
+
name: file,
|
|
224
|
+
cwd: options.cwd || process.cwd()
|
|
225
|
+
});
|
|
226
|
+
let userConfig = config;
|
|
227
|
+
if (typeof config === "function")
|
|
228
|
+
userConfig = await config(options.valaxyOptions || {});
|
|
229
|
+
return {
|
|
230
|
+
config: userConfig,
|
|
231
|
+
configFile
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// node/config/site.ts
|
|
236
|
+
var defaultSiteConfig = {
|
|
237
|
+
mode: "auto",
|
|
238
|
+
url: "/",
|
|
239
|
+
lang: "en",
|
|
240
|
+
languages: ["en", "zh-CN"],
|
|
241
|
+
timezone: "",
|
|
242
|
+
title: "Valaxy Blog",
|
|
243
|
+
description: "A blog generated by Valaxy.",
|
|
244
|
+
subtitle: "Next Generation Static Blog Framework.",
|
|
245
|
+
author: {
|
|
246
|
+
avatar: "https://valaxy.site/valaxy-logo.png",
|
|
247
|
+
email: "i@valaxy.site",
|
|
248
|
+
link: "https://valaxy.site",
|
|
249
|
+
name: "VALAXY Developer",
|
|
250
|
+
status: {
|
|
251
|
+
emoji: "\u{1F30C}",
|
|
252
|
+
message: "The moonlight is beautiful."
|
|
253
|
+
}
|
|
254
|
+
},
|
|
255
|
+
favicon: "/favicon.svg",
|
|
256
|
+
feed: {
|
|
257
|
+
name: "",
|
|
258
|
+
favicon: "/favicon.svg"
|
|
259
|
+
},
|
|
260
|
+
social: [],
|
|
261
|
+
lastUpdated: true,
|
|
262
|
+
license: {
|
|
263
|
+
enabled: true,
|
|
264
|
+
language: "",
|
|
265
|
+
type: "by-nc-sa"
|
|
266
|
+
},
|
|
267
|
+
sponsor: {
|
|
268
|
+
enable: true,
|
|
269
|
+
description: "\u8FD9\u662F\u5173\u4E8E\u8D5E\u52A9\u7684\u4E00\u4E9B\u63CF\u8FF0",
|
|
270
|
+
methods: []
|
|
271
|
+
},
|
|
272
|
+
search: {
|
|
273
|
+
enable: false,
|
|
274
|
+
type: "fuse"
|
|
275
|
+
},
|
|
276
|
+
fuse: {
|
|
277
|
+
dataPath: "valaxy-fuse-list.json",
|
|
278
|
+
options: {
|
|
279
|
+
keys: []
|
|
280
|
+
}
|
|
281
|
+
},
|
|
282
|
+
comment: {
|
|
283
|
+
enable: false
|
|
284
|
+
},
|
|
285
|
+
frontmatter: {
|
|
286
|
+
time_warning: 180 * 24 * 60 * 60 * 1e3
|
|
287
|
+
},
|
|
288
|
+
cdn: {
|
|
289
|
+
prefix: "https://unpkg.com/"
|
|
290
|
+
},
|
|
291
|
+
mediumZoom: {
|
|
292
|
+
enable: false,
|
|
293
|
+
selector: "",
|
|
294
|
+
options: {}
|
|
295
|
+
},
|
|
296
|
+
vanillaLazyload: {
|
|
297
|
+
enable: false,
|
|
298
|
+
options: {}
|
|
299
|
+
},
|
|
300
|
+
floatingVue: floatingVueOptions,
|
|
301
|
+
statistics: {
|
|
302
|
+
enable: false,
|
|
303
|
+
readTime: {
|
|
304
|
+
speed: {
|
|
305
|
+
cn: 300,
|
|
306
|
+
en: 100
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
},
|
|
310
|
+
pageSize: 7,
|
|
311
|
+
encrypt: {
|
|
312
|
+
enable: false,
|
|
313
|
+
algorithm: "AES-CBC",
|
|
314
|
+
salt: webcrypto.getRandomValues(new Uint8Array(16)),
|
|
315
|
+
iv: webcrypto.getRandomValues(new Uint8Array(16))
|
|
316
|
+
},
|
|
317
|
+
redirects: {
|
|
318
|
+
useVueRouter: true,
|
|
319
|
+
rules: []
|
|
320
|
+
}
|
|
321
|
+
};
|
|
322
|
+
function defineSiteConfig(config) {
|
|
323
|
+
return config;
|
|
324
|
+
}
|
|
325
|
+
async function resolveSiteConfigFromRoot(root) {
|
|
326
|
+
return loadConfigFromFile("site", {
|
|
327
|
+
cwd: root
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
async function resolveSiteConfig(root) {
|
|
331
|
+
const endCount = countPerformanceTime();
|
|
332
|
+
const { config: userSiteConfig, configFile: siteConfigFile } = await resolveSiteConfigFromRoot(root);
|
|
333
|
+
const duration = endCount();
|
|
334
|
+
if (userSiteConfig && siteConfigFile)
|
|
335
|
+
consola3.success(`Resolve ${colors.cyan("siteConfig")} from ${colors.dim(siteConfigFile)} ${colors.yellow(duration)}`);
|
|
336
|
+
return {
|
|
337
|
+
siteConfig: userSiteConfig,
|
|
338
|
+
siteConfigFile
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// node/config/valaxy.ts
|
|
343
|
+
var defaultValaxyConfig = {
|
|
344
|
+
siteConfig: defaultSiteConfig,
|
|
345
|
+
theme: "yun",
|
|
346
|
+
themeConfig: {
|
|
347
|
+
pkg: {
|
|
348
|
+
name: "",
|
|
349
|
+
version: ""
|
|
350
|
+
}
|
|
351
|
+
},
|
|
352
|
+
build: {
|
|
353
|
+
ssgForPagination: false
|
|
354
|
+
},
|
|
355
|
+
deploy: {},
|
|
356
|
+
// markdown: {
|
|
357
|
+
// excerpt: '<!-- more -->',
|
|
358
|
+
// },
|
|
359
|
+
runtimeConfig: {
|
|
360
|
+
addons: {},
|
|
361
|
+
redirects: {
|
|
362
|
+
useVueRouter: true,
|
|
363
|
+
redirectRoutes: []
|
|
364
|
+
}
|
|
365
|
+
},
|
|
366
|
+
modules: {
|
|
367
|
+
rss: {
|
|
368
|
+
enable: true,
|
|
369
|
+
fullText: false
|
|
370
|
+
}
|
|
371
|
+
},
|
|
372
|
+
features: {
|
|
373
|
+
katex: true
|
|
374
|
+
},
|
|
375
|
+
vite: {
|
|
376
|
+
build: {
|
|
377
|
+
emptyOutDir: true
|
|
378
|
+
// cssCodeSplit: false,
|
|
379
|
+
}
|
|
380
|
+
},
|
|
381
|
+
devtools: true
|
|
382
|
+
};
|
|
383
|
+
function defineValaxyConfig(config) {
|
|
384
|
+
return config;
|
|
385
|
+
}
|
|
386
|
+
var defineConfig = defineValaxyConfig;
|
|
387
|
+
async function resolveValaxyConfigFromRoot(root, options) {
|
|
388
|
+
const c = await loadConfigFromFile("valaxy", {
|
|
389
|
+
cwd: root,
|
|
390
|
+
valaxyOptions: options
|
|
391
|
+
});
|
|
392
|
+
return c;
|
|
393
|
+
}
|
|
394
|
+
var mergeValaxyConfig = createDefu((obj, key, value) => {
|
|
395
|
+
if (isFunction(obj[key]) && isFunction(value)) {
|
|
396
|
+
obj[key] = function(...args) {
|
|
397
|
+
obj[key].call(this, ...args);
|
|
398
|
+
value.call(this, ...args);
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
if (key === "vite") {
|
|
402
|
+
obj[key] = mergeViteConfig(obj[key], value);
|
|
403
|
+
return true;
|
|
404
|
+
}
|
|
405
|
+
});
|
|
406
|
+
async function resolveValaxyConfig(options) {
|
|
407
|
+
const configRoot = options.userRoot || process2.cwd();
|
|
408
|
+
const endCount = countPerformanceTime();
|
|
409
|
+
const { config: userValaxyConfig, configFile } = await resolveValaxyConfigFromRoot(configRoot);
|
|
410
|
+
const duration = endCount();
|
|
411
|
+
if (configFile && userValaxyConfig && Object.keys(userValaxyConfig).length !== 0)
|
|
412
|
+
consola4.success(`Resolve ${colors2.cyan("userValaxyConfig")} from ${colors2.dim(configFile)} ${colors2.yellow(duration)}`);
|
|
413
|
+
const theme = options.theme || userValaxyConfig?.theme || "yun";
|
|
414
|
+
return {
|
|
415
|
+
config: userValaxyConfig,
|
|
416
|
+
configFile,
|
|
417
|
+
theme
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
// node/config/addon.ts
|
|
422
|
+
function defineValaxyAddon(addonFunc) {
|
|
423
|
+
return addonFunc;
|
|
424
|
+
}
|
|
425
|
+
var defineAddon = defineValaxyAddon;
|
|
426
|
+
async function resolveAddonsConfig(addons, options) {
|
|
427
|
+
let valaxyConfig = {};
|
|
428
|
+
for (const addon of addons) {
|
|
429
|
+
const addonConfigPath = path2.resolve(addon.root, "valaxy.config.ts");
|
|
430
|
+
if (!await fs2.exists(addonConfigPath))
|
|
431
|
+
continue;
|
|
432
|
+
const { config, configFile } = await resolveValaxyConfigFromRoot(addon.root, options);
|
|
433
|
+
if (!config)
|
|
434
|
+
continue;
|
|
435
|
+
addon.configFile = configFile;
|
|
436
|
+
valaxyConfig = mergeValaxyConfig(config, valaxyConfig);
|
|
437
|
+
}
|
|
438
|
+
return valaxyConfig;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
// node/config/theme.ts
|
|
442
|
+
import { colors as colors4 } from "consola/utils";
|
|
443
|
+
import defu from "defu";
|
|
444
|
+
|
|
445
|
+
// node/logger/index.ts
|
|
446
|
+
import consola5 from "consola";
|
|
447
|
+
import { colors as colors3 } from "consola/utils";
|
|
448
|
+
import ora from "ora";
|
|
449
|
+
var logger = consola5.create({});
|
|
450
|
+
var valaxyPrefix = colors3.magenta("[valaxy]");
|
|
451
|
+
var vLogger = {
|
|
452
|
+
success: (...args) => logger.success(valaxyPrefix, ...args),
|
|
453
|
+
info: (...args) => logger.info(valaxyPrefix, ...args),
|
|
454
|
+
ready: (...args) => logger.ready(valaxyPrefix, ...args)
|
|
455
|
+
};
|
|
456
|
+
async function callHookWithLog(hookName, valaxyApp) {
|
|
457
|
+
const hookNameStr = `${colors3.cyan("[HOOK]")} ${colors3.magenta(hookName)}`;
|
|
458
|
+
const s = ora(`${hookNameStr} calling...`).start();
|
|
459
|
+
await valaxyApp.hooks.callHook(hookName);
|
|
460
|
+
s.succeed(`${hookNameStr} done.`);
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
// node/config/theme.ts
|
|
464
|
+
async function resolveThemeConfigFromRoot(root) {
|
|
465
|
+
return loadConfigFromFile("theme", {
|
|
466
|
+
cwd: root
|
|
467
|
+
});
|
|
468
|
+
}
|
|
469
|
+
async function resolveUserThemeConfig(options) {
|
|
470
|
+
let { config: userThemeConfig, configFile: themeConfigFile } = await resolveThemeConfigFromRoot(options.userRoot);
|
|
471
|
+
if (userThemeConfig && themeConfigFile)
|
|
472
|
+
logger.info(`Resolve ${colors4.cyan("themeConfig")} from ${colors4.dim(themeConfigFile)}`);
|
|
473
|
+
if (options?.themeRoot) {
|
|
474
|
+
const { config: defaultThemeConfig } = await resolveThemeConfigFromRoot(options.themeRoot);
|
|
475
|
+
userThemeConfig = defu(userThemeConfig || {}, defaultThemeConfig);
|
|
476
|
+
}
|
|
477
|
+
return {
|
|
478
|
+
themeConfig: userThemeConfig,
|
|
479
|
+
themeConfigFile
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
function defineValaxyTheme(theme) {
|
|
483
|
+
return theme;
|
|
484
|
+
}
|
|
485
|
+
var defineTheme = defineValaxyTheme;
|
|
486
|
+
|
|
487
|
+
// node/config/index.ts
|
|
488
|
+
function defineUnoSetup(fn) {
|
|
489
|
+
return fn;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// node/config/merge.ts
|
|
493
|
+
import { createDefu as createDefu2 } from "defu";
|
|
494
|
+
var replaceArrMerge = createDefu2((obj, key, value) => {
|
|
495
|
+
if (key && obj[key] && Array.isArray(obj[key]) && Array.isArray(value)) {
|
|
496
|
+
obj[key] = value;
|
|
497
|
+
return true;
|
|
498
|
+
}
|
|
499
|
+
});
|
|
500
|
+
|
|
501
|
+
// node/utils/getGitTimestamp.ts
|
|
502
|
+
import { spawn } from "cross-spawn";
|
|
503
|
+
function getGitTimestamp(file, type = "updated") {
|
|
504
|
+
return new Promise((resolve15, _reject) => {
|
|
505
|
+
const params = ["log"];
|
|
506
|
+
if (type === "updated")
|
|
507
|
+
params.push("-1");
|
|
508
|
+
params.push('--pretty="%ci"', file);
|
|
509
|
+
if (type === "created")
|
|
510
|
+
params.push("|", "tail", "-1");
|
|
511
|
+
const child = spawn("git", params);
|
|
512
|
+
let output = "";
|
|
513
|
+
child.stdout.on("data", (d) => output += String(d));
|
|
514
|
+
child.on("close", () => {
|
|
515
|
+
resolve15(+new Date(output));
|
|
516
|
+
});
|
|
517
|
+
child.on("error", () => {
|
|
518
|
+
resolve15(0);
|
|
519
|
+
});
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
// node/constants/index.ts
|
|
524
|
+
var EXCERPT_SEPARATOR = "<!-- more -->";
|
|
525
|
+
var EXTERNAL_URL_RE = /^https?:/i;
|
|
526
|
+
var PATHNAME_PROTOCOL_RE = /^pathname:\/\//;
|
|
527
|
+
var ALL_ROUTE = "/:all(.*)*";
|
|
528
|
+
var customElements = /* @__PURE__ */ new Set([
|
|
529
|
+
// katex
|
|
530
|
+
"annotation",
|
|
531
|
+
"math",
|
|
532
|
+
"menclose",
|
|
533
|
+
"mfrac",
|
|
534
|
+
"mglyph",
|
|
535
|
+
"mi",
|
|
536
|
+
"mlabeledtr",
|
|
537
|
+
"mn",
|
|
538
|
+
"mo",
|
|
539
|
+
"mover",
|
|
540
|
+
"mpadded",
|
|
541
|
+
"mphantom",
|
|
542
|
+
"mroot",
|
|
543
|
+
"mrow",
|
|
544
|
+
"mspace",
|
|
545
|
+
"msqrt",
|
|
546
|
+
"mstyle",
|
|
547
|
+
"msub",
|
|
548
|
+
"msubsup",
|
|
549
|
+
"msup",
|
|
550
|
+
"mtable",
|
|
551
|
+
"mtd",
|
|
552
|
+
"mtext",
|
|
553
|
+
"mtr",
|
|
554
|
+
"munder",
|
|
555
|
+
"munderover",
|
|
556
|
+
"semantics"
|
|
557
|
+
]);
|
|
558
|
+
var defaultViteConfig = {
|
|
559
|
+
css: {
|
|
560
|
+
preprocessorOptions: {
|
|
561
|
+
scss: {
|
|
562
|
+
api: "modern-compiler"
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
};
|
|
567
|
+
|
|
568
|
+
// node/utils/helper.ts
|
|
569
|
+
function isExternal(str) {
|
|
570
|
+
return EXTERNAL_URL_RE.test(str);
|
|
571
|
+
}
|
|
572
|
+
function isPath(name) {
|
|
573
|
+
return name.startsWith("/") || /^\.\.?[/\\]/.test(name);
|
|
574
|
+
}
|
|
575
|
+
function transformObject(obj) {
|
|
576
|
+
return `JSON.parse(${JSON.stringify(JSON.stringify(obj))})`;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
// node/utils/resolve.ts
|
|
580
|
+
import { ensurePrefix, slash } from "@antfu/utils";
|
|
581
|
+
import consola6 from "consola";
|
|
582
|
+
import { resolvePath } from "mlly";
|
|
583
|
+
import { resolveGlobal } from "resolve-global";
|
|
584
|
+
var isInstalledGlobally = {};
|
|
585
|
+
async function resolveImportUrl(id) {
|
|
586
|
+
return toAtFS(await resolveImportPath(id, true));
|
|
587
|
+
}
|
|
588
|
+
function toAtFS(path17) {
|
|
589
|
+
return `/@fs${ensurePrefix("/", slash(path17))}`;
|
|
590
|
+
}
|
|
591
|
+
async function resolveImportPath(importName, ensure = false) {
|
|
592
|
+
try {
|
|
593
|
+
return await resolvePath(importName, {
|
|
594
|
+
url: import.meta.url
|
|
595
|
+
});
|
|
596
|
+
} catch (error) {
|
|
597
|
+
consola6.log(error);
|
|
598
|
+
}
|
|
599
|
+
if (isInstalledGlobally.value) {
|
|
600
|
+
try {
|
|
601
|
+
return resolveGlobal(importName);
|
|
602
|
+
} catch {
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
if (ensure)
|
|
606
|
+
throw new Error(`Failed to resolve package ${importName}`);
|
|
607
|
+
else
|
|
608
|
+
consola6.warn(`Failed to resolve package ${importName}`);
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
// node/utils/addons.ts
|
|
612
|
+
import process3 from "node:process";
|
|
613
|
+
import { colors as colors5 } from "consola/utils";
|
|
614
|
+
import defu2 from "defu";
|
|
615
|
+
import fs4 from "fs-extra";
|
|
616
|
+
import ora2 from "ora";
|
|
617
|
+
import { resolve as resolve3 } from "pathe";
|
|
618
|
+
|
|
619
|
+
// node/utils/root.ts
|
|
620
|
+
import { dirname } from "node:path";
|
|
621
|
+
import fs3 from "fs-extra";
|
|
622
|
+
import { resolve as resolve2 } from "pathe";
|
|
623
|
+
async function getModuleRoot(name, entry) {
|
|
624
|
+
if (!name)
|
|
625
|
+
return "";
|
|
626
|
+
if (isPath(name)) {
|
|
627
|
+
if (entry) {
|
|
628
|
+
const isFile = fs3.lstatSync(entry).isFile();
|
|
629
|
+
return resolve2(isFile ? dirname(entry) : entry, name);
|
|
630
|
+
} else {
|
|
631
|
+
throw new Error(`entry is required when ${name} is path`);
|
|
632
|
+
}
|
|
633
|
+
} else {
|
|
634
|
+
return resolve2(dirname(await resolveImportPath(`${name}/package.json`) || ""));
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
// node/utils/addons.ts
|
|
639
|
+
async function parseAddons(addons, userRoot2 = process3.cwd()) {
|
|
640
|
+
const spinner = ora2(`Resolve ${colors5.cyan("addons")} from ${colors5.dim(userRoot2)}`).start();
|
|
641
|
+
const resolvers = {};
|
|
642
|
+
const mergeResolver = (resolver) => {
|
|
643
|
+
if (resolver)
|
|
644
|
+
resolvers[resolver.name] = defu2(resolvers[resolver.name] || {}, resolver);
|
|
645
|
+
};
|
|
646
|
+
if (Array.isArray(addons)) {
|
|
647
|
+
for (const addon of addons) {
|
|
648
|
+
if (typeof addon === "string") {
|
|
649
|
+
mergeResolver(await readAddonModule(addon, { cwd: userRoot2 }));
|
|
650
|
+
continue;
|
|
651
|
+
}
|
|
652
|
+
if (typeof addon === "object")
|
|
653
|
+
mergeResolver(defu2(await readAddonModule(addon.name, { cwd: userRoot2 }), addon || {}));
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
spinner.succeed();
|
|
657
|
+
const resolvedAddons = Object.values(resolvers).filter((item) => item.enable);
|
|
658
|
+
resolvedAddons.forEach((addon, i) => {
|
|
659
|
+
console.log(` ${i === resolvedAddons.length - 1 ? "\u2514\u2500" : "\u251C\u2500"} ${colors5.yellow(addon.name)} ${colors5.blue(`v${addon.pkg?.version}`)}${addon.global ? colors5.cyan(" (global)") : ""} ${colors5.dim(addon.pkg.homepage || addon.pkg.repository?.url || addon.pkg.repository || "")}`);
|
|
660
|
+
});
|
|
661
|
+
return resolvedAddons;
|
|
662
|
+
}
|
|
663
|
+
async function readAddonModule(name, options = {}) {
|
|
664
|
+
const root = await getAddonRoot(name, options.cwd || process3.cwd());
|
|
665
|
+
const packageJSONPath = resolve3(root, "./package.json");
|
|
666
|
+
if (!await fs4.exists(packageJSONPath)) {
|
|
667
|
+
logger.error(`No addon named ${name} found`);
|
|
668
|
+
return;
|
|
669
|
+
}
|
|
670
|
+
const packageJSON = await fs4.readJSON(packageJSONPath);
|
|
671
|
+
const resolver = {
|
|
672
|
+
enable: true,
|
|
673
|
+
name: packageJSON.name,
|
|
674
|
+
global: !!packageJSON.global,
|
|
675
|
+
root,
|
|
676
|
+
options: {},
|
|
677
|
+
props: {},
|
|
678
|
+
pkg: packageJSON
|
|
679
|
+
};
|
|
680
|
+
return resolver;
|
|
681
|
+
}
|
|
682
|
+
async function getAddonRoot(name, entry) {
|
|
683
|
+
const addonModule = name.startsWith("valaxy-addon") || name.startsWith(".") ? name : `valaxy-addon-${name}`;
|
|
684
|
+
return await getModuleRoot(addonModule, entry);
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
// node/utils/clientRedirects.ts
|
|
688
|
+
import { writeFile } from "node:fs/promises";
|
|
689
|
+
import { ensureFile } from "fs-extra";
|
|
690
|
+
function handleRoute(route) {
|
|
691
|
+
if (route === "/")
|
|
692
|
+
return "/index";
|
|
693
|
+
if (route.endsWith("/"))
|
|
694
|
+
return route.slice(0, -1);
|
|
695
|
+
return route;
|
|
696
|
+
}
|
|
697
|
+
function collectRedirects(redirectRules) {
|
|
698
|
+
if (!redirectRules)
|
|
699
|
+
return [];
|
|
700
|
+
const redirects = [];
|
|
701
|
+
for (const rule of redirectRules) {
|
|
702
|
+
if (Array.isArray(rule.from)) {
|
|
703
|
+
for (const from of rule.from) {
|
|
704
|
+
redirects.push({
|
|
705
|
+
from: handleRoute(from),
|
|
706
|
+
to: handleRoute(rule.to)
|
|
707
|
+
});
|
|
708
|
+
}
|
|
709
|
+
} else {
|
|
710
|
+
redirects.push({
|
|
711
|
+
from: handleRoute(rule.from),
|
|
712
|
+
to: handleRoute(rule.to)
|
|
713
|
+
});
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
return redirects;
|
|
717
|
+
}
|
|
718
|
+
async function writeRedirectFiles(route, filePath) {
|
|
719
|
+
await ensureFile(filePath);
|
|
720
|
+
await writeFile(filePath, `
|
|
721
|
+
<!DOCTYPE html>
|
|
722
|
+
<html lang="en">
|
|
723
|
+
<head>
|
|
724
|
+
<meta charset="UTF-8">
|
|
725
|
+
<meta http-equiv="refresh" content="0; url=${route}">
|
|
726
|
+
<link rel="canonical" href="${route}">
|
|
727
|
+
</head>
|
|
728
|
+
<script>
|
|
729
|
+
window.location.href = '${route}' + window.location.search + window.location.hash
|
|
730
|
+
</script>
|
|
731
|
+
</html>
|
|
732
|
+
`);
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
// node/utils/theme.ts
|
|
736
|
+
async function getThemeRoot(name, entry) {
|
|
737
|
+
const themeModule = name.startsWith("valaxy-theme") || name.startsWith(".") ? name : `valaxy-theme-${name}`;
|
|
738
|
+
return await getModuleRoot(themeModule, entry);
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
// node/options.ts
|
|
742
|
+
var debug = _debug("valaxy:options");
|
|
743
|
+
async function processSiteConfig(options) {
|
|
744
|
+
const { config, themeRoot, theme } = options;
|
|
745
|
+
const siteConfig = config.siteConfig;
|
|
746
|
+
siteConfig.url = ensureSuffix("/", siteConfig.url || "");
|
|
747
|
+
siteConfig.cdn.prefix = ensureSuffix("/", siteConfig.cdn.prefix || "");
|
|
748
|
+
const themePkgPath = resolve4(themeRoot, "package.json");
|
|
749
|
+
try {
|
|
750
|
+
config.themeConfig.pkg = await fs5.readJson(themePkgPath, "utf-8");
|
|
751
|
+
} catch (e) {
|
|
752
|
+
console.error(`valaxy-theme-${theme} doesn't have package.json`);
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
async function processValaxyOptions(valaxyOptions, valaxyConfig) {
|
|
756
|
+
const { clientRoot, themeRoot, userRoot: userRoot2 } = valaxyOptions;
|
|
757
|
+
const addons = await parseAddons(valaxyConfig.addons || [], valaxyOptions.userRoot);
|
|
758
|
+
const addonsValaxyConfig = await resolveAddonsConfig(addons, valaxyOptions);
|
|
759
|
+
valaxyConfig = mergeValaxyConfig(valaxyConfig, addonsValaxyConfig);
|
|
760
|
+
const rollupOptions = getRollupOptions(valaxyOptions);
|
|
761
|
+
defaultValaxyConfig.vite.build.rollupOptions = rollupOptions;
|
|
762
|
+
const config = replaceArrMerge(valaxyConfig, defaultValaxyConfig);
|
|
763
|
+
valaxyOptions.config = {
|
|
764
|
+
...config,
|
|
765
|
+
runtimeConfig: {
|
|
766
|
+
addons: {},
|
|
767
|
+
redirects: {
|
|
768
|
+
useVueRouter: true,
|
|
769
|
+
redirectRoutes: []
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
};
|
|
773
|
+
valaxyOptions.addons = addons;
|
|
774
|
+
addons.forEach((addon) => {
|
|
775
|
+
valaxyOptions.config.runtimeConfig.addons[addon.name] = addon;
|
|
776
|
+
});
|
|
777
|
+
const addonRoots = addons.map(({ root }) => root);
|
|
778
|
+
const addonNames = addons.map(({ name }) => name);
|
|
779
|
+
valaxyOptions.addonRoots = addonRoots;
|
|
780
|
+
valaxyOptions.roots = uniq([clientRoot, themeRoot, ...addonRoots, userRoot2]);
|
|
781
|
+
const external = valaxyOptions.config.vite?.build?.rollupOptions?.external || [];
|
|
782
|
+
valaxyOptions.config.vite.build.rollupOptions.external = external.filter((name) => !addonNames.includes(name));
|
|
783
|
+
await processSiteConfig(valaxyOptions);
|
|
784
|
+
return valaxyOptions;
|
|
785
|
+
}
|
|
786
|
+
async function resolveOptions(options = { userRoot: process4.cwd() }, mode = "dev") {
|
|
787
|
+
const pkgRoot = dirname2(await resolveImportPath("valaxy/package.json", true));
|
|
788
|
+
const clientRoot = resolve4(pkgRoot, "client");
|
|
789
|
+
const userRoot2 = resolve4(options.userRoot || process4.cwd());
|
|
790
|
+
consola7.start(`Resolve ${colors6.magenta("valaxy")} config ...`);
|
|
791
|
+
const [resolvedValaxy, resolvedSite, resolvedTheme, pages] = await Promise.all([
|
|
792
|
+
resolveValaxyConfig(options),
|
|
793
|
+
resolveSiteConfig(options.userRoot),
|
|
794
|
+
// resolveThemeConfig(options),
|
|
795
|
+
resolveThemeConfigFromRoot(options.userRoot),
|
|
796
|
+
fg(["**.md"], {
|
|
797
|
+
cwd: resolve4(userRoot2, "pages"),
|
|
798
|
+
ignore: ["**/node_modules"]
|
|
799
|
+
})
|
|
800
|
+
]);
|
|
801
|
+
let { config: userValaxyConfig, configFile, theme } = resolvedValaxy;
|
|
802
|
+
const themeRoot = await getThemeRoot(theme, options.userRoot);
|
|
803
|
+
const { siteConfig, siteConfigFile } = resolvedSite;
|
|
804
|
+
const { config: themeConfig, configFile: themeConfigFile } = resolvedTheme;
|
|
805
|
+
const redirects = collectRedirects(siteConfig.redirects?.rules);
|
|
806
|
+
userValaxyConfig = replaceArrMerge({ siteConfig }, { themeConfig }, userValaxyConfig);
|
|
807
|
+
let valaxyOptions = {
|
|
808
|
+
mode,
|
|
809
|
+
pkgRoot,
|
|
810
|
+
tempDir: resolve4(userRoot2, ".valaxy"),
|
|
811
|
+
clientRoot,
|
|
812
|
+
userRoot: userRoot2,
|
|
813
|
+
themeRoot,
|
|
814
|
+
addonRoots: [],
|
|
815
|
+
roots: [],
|
|
816
|
+
theme,
|
|
817
|
+
config: {
|
|
818
|
+
...userValaxyConfig,
|
|
819
|
+
runtimeConfig: {
|
|
820
|
+
addons: {},
|
|
821
|
+
redirects: {
|
|
822
|
+
useVueRouter: true,
|
|
823
|
+
redirectRoutes: []
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
},
|
|
827
|
+
configFile: configFile || "",
|
|
828
|
+
siteConfigFile: siteConfigFile || "",
|
|
829
|
+
themeConfigFile: themeConfigFile || "",
|
|
830
|
+
pages: pages.sort(),
|
|
831
|
+
addons: [],
|
|
832
|
+
redirects,
|
|
833
|
+
env: {
|
|
834
|
+
id: "",
|
|
835
|
+
links: []
|
|
836
|
+
}
|
|
837
|
+
};
|
|
838
|
+
debug(valaxyOptions);
|
|
839
|
+
const themeValaxyConfig = await resolveThemeValaxyConfig(valaxyOptions);
|
|
840
|
+
const valaxyConfig = mergeValaxyConfig(userValaxyConfig, themeValaxyConfig);
|
|
841
|
+
valaxyOptions = await processValaxyOptions(valaxyOptions, valaxyConfig);
|
|
842
|
+
fs5.ensureDirSync(valaxyOptions.tempDir);
|
|
843
|
+
return valaxyOptions;
|
|
844
|
+
}
|
|
845
|
+
async function resolveThemeValaxyConfig(options) {
|
|
846
|
+
const endCount = countPerformanceTime();
|
|
847
|
+
const { config: themeValaxyConfig } = await resolveValaxyConfigFromRoot(options.themeRoot, options);
|
|
848
|
+
const duration = endCount();
|
|
849
|
+
if (themeValaxyConfig)
|
|
850
|
+
consola7.success(`Resolve ${colors6.cyan("valaxy.config.ts")} from ${colors6.blue(`theme(${options.theme})`)} ${colors6.yellow(duration)}`);
|
|
851
|
+
return themeValaxyConfig;
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
// node/plugins/markdown/transform/matter.ts
|
|
855
|
+
import yaml, { CORE_SCHEMA } from "js-yaml";
|
|
856
|
+
var matterOptions = {
|
|
857
|
+
excerpt_separator: EXCERPT_SEPARATOR,
|
|
858
|
+
engines: {
|
|
859
|
+
yaml: {
|
|
860
|
+
// Use the CORE_SCHEMA with more basic support to manually handle time (#409)
|
|
861
|
+
parse: (str) => yaml.load(str, { schema: CORE_SCHEMA }),
|
|
862
|
+
stringify: (data) => yaml.dump(data)
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
};
|
|
866
|
+
|
|
867
|
+
// node/utils/env.ts
|
|
868
|
+
import path3 from "node:path";
|
|
869
|
+
import process5 from "node:process";
|
|
870
|
+
import consola8 from "consola";
|
|
871
|
+
import fs6 from "fs-extra";
|
|
872
|
+
function isProd() {
|
|
873
|
+
return process5.env.NODE_ENV === "production";
|
|
874
|
+
}
|
|
875
|
+
function setEnv(env = "development") {
|
|
876
|
+
process5.env.NODE_ENV = env;
|
|
877
|
+
consola8.level = isProd() ? 2 : 3;
|
|
878
|
+
logger.level = consola8.level;
|
|
879
|
+
}
|
|
880
|
+
function setEnvProd() {
|
|
881
|
+
return setEnv("production");
|
|
882
|
+
}
|
|
883
|
+
function setTimezone(timezone) {
|
|
884
|
+
process5.env.TZ = timezone;
|
|
885
|
+
}
|
|
886
|
+
async function isPagesDirExist(root) {
|
|
887
|
+
const exist = await fs6.exists(path3.resolve(root, "pages"));
|
|
888
|
+
if (!exist)
|
|
889
|
+
logger.error(`No pages directory found in ${root}`);
|
|
890
|
+
return exist;
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
// node/modules/fuse.ts
|
|
894
|
+
async function generateFuseList(options) {
|
|
895
|
+
consola9.start(`Generate List for Fuse Search by (${colors7.cyan("fuse.js")}) ...`);
|
|
896
|
+
const files = await fg2(`${options.userRoot}/pages/posts/**/*.md`);
|
|
897
|
+
const posts = [];
|
|
898
|
+
for await (const i of files) {
|
|
899
|
+
const raw = fs7.readFileSync(i, "utf-8");
|
|
900
|
+
const { data, excerpt, content } = matter(raw, matterOptions);
|
|
901
|
+
const fmData = data;
|
|
902
|
+
if (fmData.draft) {
|
|
903
|
+
consola9.warn(`Ignore draft post: ${colors7.dim(i)}`);
|
|
904
|
+
continue;
|
|
905
|
+
}
|
|
906
|
+
if (fmData.hide)
|
|
907
|
+
continue;
|
|
908
|
+
if (fmData.password)
|
|
909
|
+
continue;
|
|
910
|
+
const extendKeys = options.config.fuse?.extendKeys || [];
|
|
911
|
+
const relativeLink = i.replace(`${options.userRoot}/pages`, "");
|
|
912
|
+
const link = i.endsWith("index.md") ? relativeLink.replace(/\/index\.md$/, "") : relativeLink.replace(/\.md$/, "");
|
|
913
|
+
const fuseListItem = {
|
|
914
|
+
title: fmData.title || "",
|
|
915
|
+
tags: (typeof fmData.tags === "string" ? [fmData.tags] : fmData.tags) || [],
|
|
916
|
+
categories: (typeof fmData.categories === "string" ? [fmData.categories] : fmData.categories) || [],
|
|
917
|
+
author: options.config.siteConfig.author.name,
|
|
918
|
+
excerpt: excerpt || content.slice(0, 100),
|
|
919
|
+
// encode for chinese url
|
|
920
|
+
link: encodeURI(link)
|
|
921
|
+
};
|
|
922
|
+
if (options.config.siteConfig.fuse.options.keys?.includes("content")) {
|
|
923
|
+
fuseListItem.content = content;
|
|
924
|
+
}
|
|
925
|
+
extendKeys.forEach((key) => {
|
|
926
|
+
fuseListItem[key] = fmData[key] || "";
|
|
927
|
+
});
|
|
928
|
+
posts.push(fuseListItem);
|
|
929
|
+
}
|
|
930
|
+
return posts;
|
|
931
|
+
}
|
|
932
|
+
async function execFuse(options) {
|
|
933
|
+
consola9.info("Start generate fuse list...");
|
|
934
|
+
const fuseList = await generateFuseList(options);
|
|
935
|
+
await fs7.ensureDir("./dist");
|
|
936
|
+
const publicFolder = path4.resolve(options.userRoot, "public");
|
|
937
|
+
const publicFuseFile = path4.resolve(publicFolder, options.config.siteConfig.fuse.dataPath);
|
|
938
|
+
const publicRelativeFile = path4.join("public", options.config.siteConfig.fuse.dataPath);
|
|
939
|
+
await fs7.ensureFile(publicFuseFile);
|
|
940
|
+
fs7.writeJSONSync(publicFuseFile, fuseList);
|
|
941
|
+
consola9.success(`Generate fuse list in ${colors7.dim(publicFolder)}`);
|
|
942
|
+
const distFolder = path4.resolve(options.userRoot, "dist");
|
|
943
|
+
const distFuseFile = path4.resolve(distFolder, options.config.siteConfig.fuse.dataPath);
|
|
944
|
+
await fs7.ensureDir(distFolder);
|
|
945
|
+
fs7.writeJSONSync(distFuseFile, fuseList);
|
|
946
|
+
consola9.success(`Generate fuse list in ${colors7.dim(distFolder)}`);
|
|
947
|
+
try {
|
|
948
|
+
const gitignorePath = path4.resolve(options.userRoot, ".gitignore");
|
|
949
|
+
const gitignore = await fs7.readFile(gitignorePath, "utf-8");
|
|
950
|
+
const ignorePath = publicRelativeFile.replace(/\\/g, "/");
|
|
951
|
+
if (!gitignore.includes(ignorePath)) {
|
|
952
|
+
await fs7.appendFile(gitignorePath, `
|
|
953
|
+
# valaxy fuse
|
|
954
|
+
${ignorePath}
|
|
955
|
+
`);
|
|
956
|
+
consola9.success(`Add ${colors7.dim(ignorePath)} to ${colors7.dim(".gitignore")}`);
|
|
957
|
+
}
|
|
958
|
+
} catch {
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
function registerFuseCommand(cli2) {
|
|
962
|
+
cli2.command(
|
|
963
|
+
"fuse [root]",
|
|
964
|
+
"generate fuse list for search",
|
|
965
|
+
(args) => commonOptions(args).strict().help(),
|
|
966
|
+
async ({ root }) => {
|
|
967
|
+
setEnvProd();
|
|
968
|
+
const options = await resolveOptions({ userRoot: root }, "build");
|
|
969
|
+
await execFuse(options);
|
|
970
|
+
}
|
|
971
|
+
);
|
|
972
|
+
}
|
|
973
|
+
var fuseModule = defineValaxyModule({
|
|
974
|
+
extendCli(cli2) {
|
|
975
|
+
registerFuseCommand(cli2);
|
|
976
|
+
},
|
|
977
|
+
setup(node) {
|
|
978
|
+
node.hook("build:before", async () => {
|
|
979
|
+
await execFuse(node.options);
|
|
980
|
+
});
|
|
981
|
+
}
|
|
982
|
+
});
|
|
983
|
+
|
|
984
|
+
// node/modules/rss/utils.ts
|
|
985
|
+
import { readFile } from "node:fs/promises";
|
|
986
|
+
import { dirname as dirname3, join, resolve as resolve5 } from "node:path";
|
|
987
|
+
import { ensurePrefix as ensurePrefix2 } from "@antfu/utils";
|
|
988
|
+
import consola10 from "consola";
|
|
989
|
+
import { colors as colors8 } from "consola/utils";
|
|
990
|
+
import dayjs from "dayjs";
|
|
991
|
+
import fg3 from "fast-glob";
|
|
992
|
+
import { Feed } from "feed";
|
|
993
|
+
import fs9 from "fs-extra";
|
|
994
|
+
import matter2 from "gray-matter";
|
|
995
|
+
import MarkdownIt from "markdown-it";
|
|
996
|
+
import ora3 from "ora";
|
|
997
|
+
import { getBorderCharacters, table } from "table";
|
|
998
|
+
|
|
999
|
+
// node/utils/date.ts
|
|
1000
|
+
import fs8 from "fs-extra";
|
|
1001
|
+
async function getCreatedTime(file) {
|
|
1002
|
+
return await getGitTimestamp(file, "created") || (await fs8.stat(file)).ctime;
|
|
1003
|
+
}
|
|
1004
|
+
async function getUpdatedTime(file) {
|
|
1005
|
+
return await getGitTimestamp(file, "created") || (await fs8.stat(file)).mtime;
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
// node/modules/rss/utils.ts
|
|
1009
|
+
var markdown = MarkdownIt({
|
|
1010
|
+
html: true,
|
|
1011
|
+
breaks: true,
|
|
1012
|
+
linkify: true
|
|
1013
|
+
});
|
|
1014
|
+
async function build(options) {
|
|
1015
|
+
const s = ora3("RSS Generating ...").start();
|
|
1016
|
+
const { config } = options;
|
|
1017
|
+
const siteConfig = config.siteConfig;
|
|
1018
|
+
if (!siteConfig.url || siteConfig.url === "/") {
|
|
1019
|
+
consola10.error("You must set `url` (like `https://example.com`) in `site.config.ts` to generate rss.");
|
|
1020
|
+
return;
|
|
1021
|
+
}
|
|
1022
|
+
const siteUrl = siteConfig.url;
|
|
1023
|
+
const author = {
|
|
1024
|
+
name: siteConfig.author?.name,
|
|
1025
|
+
email: siteConfig.author?.email,
|
|
1026
|
+
link: siteConfig.author?.link
|
|
1027
|
+
};
|
|
1028
|
+
const ccVersion = siteConfig.license?.type === "zero" ? "1.0" : "4.0";
|
|
1029
|
+
const feedNameMap = {
|
|
1030
|
+
atom: siteConfig.feed?.name ? `${siteConfig.feed?.name}.atom` : "atom.xml",
|
|
1031
|
+
json: `${siteConfig.feed?.name || "feed"}.json`,
|
|
1032
|
+
rss: `${siteConfig.feed?.name || "feed"}.xml`
|
|
1033
|
+
};
|
|
1034
|
+
const feedOptions = {
|
|
1035
|
+
title: siteConfig.title || "Valaxy Blog",
|
|
1036
|
+
description: siteConfig.description,
|
|
1037
|
+
id: siteUrl || "valaxy",
|
|
1038
|
+
link: siteUrl,
|
|
1039
|
+
copyright: `CC ${siteConfig.license?.type?.toUpperCase()} ${ccVersion} ${(/* @__PURE__ */ new Date()).getFullYear()} \xA9 ${siteConfig.author?.name}`,
|
|
1040
|
+
feedLinks: {}
|
|
1041
|
+
};
|
|
1042
|
+
Object.keys(feedNameMap).forEach((key) => {
|
|
1043
|
+
feedOptions.feedLinks[key] = `${siteUrl}${feedNameMap[key]}`;
|
|
1044
|
+
});
|
|
1045
|
+
const DOMAIN = siteConfig.url.slice(0, -1);
|
|
1046
|
+
const files = await fg3(`${options.userRoot}/pages/posts/**/*.md`);
|
|
1047
|
+
const posts = await getPosts({
|
|
1048
|
+
author,
|
|
1049
|
+
files,
|
|
1050
|
+
DOMAIN
|
|
1051
|
+
}, options);
|
|
1052
|
+
if (!posts)
|
|
1053
|
+
return;
|
|
1054
|
+
const authorAvatar = siteConfig.author?.avatar || "/favicon.svg";
|
|
1055
|
+
feedOptions.author = author;
|
|
1056
|
+
feedOptions.image = isExternal(authorAvatar) ? siteConfig.author?.avatar : `${DOMAIN}${ensurePrefix2("/", authorAvatar)}`;
|
|
1057
|
+
feedOptions.favicon = `${DOMAIN}${siteConfig.feed?.favicon || siteConfig.favicon}`;
|
|
1058
|
+
s.succeed("RSS Generated.");
|
|
1059
|
+
await writeFeed(feedOptions, posts, options, feedNameMap);
|
|
1060
|
+
}
|
|
1061
|
+
async function getPosts(params, options) {
|
|
1062
|
+
const { config } = options;
|
|
1063
|
+
const siteConfig = config.siteConfig;
|
|
1064
|
+
const lang = siteConfig.lang || "en";
|
|
1065
|
+
const { files, author, DOMAIN } = params;
|
|
1066
|
+
const readFilePromises = files.map(async (i) => {
|
|
1067
|
+
const raw = await readFile(i, "utf-8");
|
|
1068
|
+
const { data, content, excerpt } = matter2(raw, matterOptions);
|
|
1069
|
+
return { data, content, excerpt, path: i };
|
|
1070
|
+
});
|
|
1071
|
+
const draftPosts = [];
|
|
1072
|
+
const rawPosts = await Promise.all(readFilePromises);
|
|
1073
|
+
const filteredPosts = rawPosts.filter((p) => {
|
|
1074
|
+
const { data } = p;
|
|
1075
|
+
if (data.password)
|
|
1076
|
+
return false;
|
|
1077
|
+
if (data.draft) {
|
|
1078
|
+
draftPosts.push(p);
|
|
1079
|
+
return false;
|
|
1080
|
+
}
|
|
1081
|
+
if (data.hide)
|
|
1082
|
+
return false;
|
|
1083
|
+
return true;
|
|
1084
|
+
});
|
|
1085
|
+
const posts = [];
|
|
1086
|
+
for (const rawPost of filteredPosts) {
|
|
1087
|
+
const { data, path: path17, content, excerpt } = rawPost;
|
|
1088
|
+
if (!data.date)
|
|
1089
|
+
data.date = await getCreatedTime(path17);
|
|
1090
|
+
if (siteConfig.lastUpdated) {
|
|
1091
|
+
if (!data.updated)
|
|
1092
|
+
data.updated = await getUpdatedTime(path17);
|
|
1093
|
+
}
|
|
1094
|
+
const fullText = options.config.modules.rss.fullText;
|
|
1095
|
+
const rssContent = fullText ? content : excerpt || content.slice(0, 100);
|
|
1096
|
+
const html = markdown.render(rssContent).replace('src="/', `src="${DOMAIN}/`);
|
|
1097
|
+
if (data.image?.startsWith("/"))
|
|
1098
|
+
data.image = DOMAIN + data.image;
|
|
1099
|
+
const link = DOMAIN + path17.replace(`${options.userRoot}/pages`, "").replace(/\.md$/, "");
|
|
1100
|
+
const tip = `<br/><p>${lang === "zh-CN" ? `\u8BBF\u95EE <a href="${link}" target="_blank">${link}</a> ${fullText ? "\u67E5\u770B\u539F\u6587" : "\u9605\u8BFB\u5168\u6587"}\u3002` : `Visit <a href="${link}" target="_blank">${link}</a> to ${fullText ? "view original article" : "read more"}.`}</p>`;
|
|
1101
|
+
posts.push({
|
|
1102
|
+
title: "",
|
|
1103
|
+
...data,
|
|
1104
|
+
date: new Date(data.date),
|
|
1105
|
+
published: new Date(data.updated || data.date),
|
|
1106
|
+
content: html + tip,
|
|
1107
|
+
author: [author],
|
|
1108
|
+
id: data.id?.toString() || "",
|
|
1109
|
+
link
|
|
1110
|
+
});
|
|
1111
|
+
}
|
|
1112
|
+
posts.sort((a, b) => +new Date(b.published || b.date) - +new Date(a.published || a.date));
|
|
1113
|
+
return posts;
|
|
1114
|
+
}
|
|
1115
|
+
async function writeFeed(feedOptions, posts, options, feedNameMap) {
|
|
1116
|
+
const feed = new Feed(feedOptions);
|
|
1117
|
+
posts.forEach((item) => feed.addItem(item));
|
|
1118
|
+
await fs9.ensureDir(dirname3(`./dist/${feedNameMap.atom}`));
|
|
1119
|
+
const path17 = resolve5(options.userRoot, "./dist");
|
|
1120
|
+
const publicFolder = resolve5(options.userRoot, "public");
|
|
1121
|
+
const { config } = options;
|
|
1122
|
+
const siteConfig = config.siteConfig;
|
|
1123
|
+
const now = dayjs().format("YYYY-MM-DD HH:mm:ss zzz");
|
|
1124
|
+
const tableData = [
|
|
1125
|
+
[`${colors8.yellow("RSS Feed Files")} \u{1F4E1} ${colors8.dim(now)}`, "", ""],
|
|
1126
|
+
[colors8.bold("Site Url"), "", colors8.cyan(siteConfig.url)],
|
|
1127
|
+
["Type", "Folder", "Path"]
|
|
1128
|
+
];
|
|
1129
|
+
const types = ["rss", "atom", "json"];
|
|
1130
|
+
for (const type of types) {
|
|
1131
|
+
let data = "";
|
|
1132
|
+
const distFeedPath = `${path17}/${feedNameMap[type]}`;
|
|
1133
|
+
if (type === "rss")
|
|
1134
|
+
data = feed.rss2();
|
|
1135
|
+
else if (type === "atom")
|
|
1136
|
+
data = feed.atom1();
|
|
1137
|
+
else if (type === "json")
|
|
1138
|
+
data = feed.json1();
|
|
1139
|
+
await fs9.writeFile(distFeedPath, data, "utf-8");
|
|
1140
|
+
consola10.debug(`[${colors8.cyan(type)}] dist: ${colors8.dim(distFeedPath)}`);
|
|
1141
|
+
tableData.push([colors8.cyan(type), colors8.yellow("dist"), colors8.dim(distFeedPath)]);
|
|
1142
|
+
const publicFeedPath = resolve5(publicFolder, feedNameMap[type]);
|
|
1143
|
+
const publicRelativeFile = join("public", feedNameMap[type]);
|
|
1144
|
+
await fs9.writeFile(publicFeedPath, data, "utf-8");
|
|
1145
|
+
consola10.debug(`[${colors8.cyan(type)}] public: ${colors8.dim(publicFeedPath)}`);
|
|
1146
|
+
tableData.push(["", colors8.green("public"), colors8.dim(publicFeedPath)]);
|
|
1147
|
+
try {
|
|
1148
|
+
const gitignorePath = resolve5(options.userRoot, ".gitignore");
|
|
1149
|
+
const gitignore = await fs9.readFile(gitignorePath, "utf-8");
|
|
1150
|
+
const ignorePath = publicRelativeFile.replace(/\\/g, "/");
|
|
1151
|
+
if (!gitignore.includes(ignorePath)) {
|
|
1152
|
+
await fs9.appendFile(gitignorePath, `
|
|
1153
|
+
# valaxy rss
|
|
1154
|
+
${ignorePath}
|
|
1155
|
+
`);
|
|
1156
|
+
consola10.success(`Add ${colors8.dim(ignorePath)} to ${colors8.dim(".gitignore")}`);
|
|
1157
|
+
}
|
|
1158
|
+
} catch {
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
console.log(table(tableData, {
|
|
1162
|
+
columns: [
|
|
1163
|
+
{ alignment: "center" },
|
|
1164
|
+
{ alignment: "right" },
|
|
1165
|
+
{ alignment: "left" }
|
|
1166
|
+
],
|
|
1167
|
+
spanningCells: [
|
|
1168
|
+
{ col: 0, row: 0, colSpan: 3 },
|
|
1169
|
+
{ col: 0, row: 1, colSpan: 2 },
|
|
1170
|
+
{ col: 0, row: 3, rowSpan: 2, verticalAlignment: "middle" },
|
|
1171
|
+
{ col: 0, row: 5, rowSpan: 2, verticalAlignment: "middle" },
|
|
1172
|
+
{ col: 0, row: 7, rowSpan: 2, verticalAlignment: "middle" }
|
|
1173
|
+
],
|
|
1174
|
+
border: getBorderCharacters("norc")
|
|
1175
|
+
}));
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
// node/modules/rss/index.ts
|
|
1179
|
+
var rssModule = defineValaxyModule({
|
|
1180
|
+
/**
|
|
1181
|
+
* valaxy rss
|
|
1182
|
+
* @param cli
|
|
1183
|
+
*/
|
|
1184
|
+
extendCli(cli2) {
|
|
1185
|
+
cli2.command(
|
|
1186
|
+
"rss [root]",
|
|
1187
|
+
"generate rss feed",
|
|
1188
|
+
(args) => commonOptions(args).strict().help(),
|
|
1189
|
+
async ({ root }) => {
|
|
1190
|
+
setEnvProd();
|
|
1191
|
+
const options = await resolveOptions({ userRoot: root }, "build");
|
|
1192
|
+
await build(options);
|
|
1193
|
+
}
|
|
1194
|
+
);
|
|
1195
|
+
},
|
|
1196
|
+
setup(node) {
|
|
1197
|
+
node.hook("build:after", async () => {
|
|
1198
|
+
console.log();
|
|
1199
|
+
await build(node.options);
|
|
1200
|
+
});
|
|
1201
|
+
}
|
|
1202
|
+
});
|
|
1203
|
+
|
|
1204
|
+
// node/cli/build.ts
|
|
1205
|
+
import path13 from "node:path";
|
|
1206
|
+
import process9 from "node:process";
|
|
1207
|
+
import consola16 from "consola";
|
|
1208
|
+
import { colors as colors15 } from "consola/utils";
|
|
1209
|
+
import { mergeConfig as mergeConfig4 } from "vite";
|
|
1210
|
+
|
|
1211
|
+
// node/build.ts
|
|
1212
|
+
import { join as join8, resolve as resolve13 } from "node:path";
|
|
1213
|
+
import consola14 from "consola";
|
|
1214
|
+
import { colors as colors12 } from "consola/utils";
|
|
1215
|
+
import fs21 from "fs-extra";
|
|
1216
|
+
import { mergeConfig as mergeViteConfig2, build as viteBuild } from "vite";
|
|
1217
|
+
import generateSitemap from "vite-ssg-sitemap";
|
|
1218
|
+
import { build as viteSsgBuild } from "vite-ssg/node";
|
|
1219
|
+
|
|
1220
|
+
// node/plugins/preset.ts
|
|
1221
|
+
import VueI18n from "@intlify/unplugin-vue-i18n/vite";
|
|
1222
|
+
import UnheadVite from "@unhead/addons/vite";
|
|
1223
|
+
import Vue from "@vitejs/plugin-vue";
|
|
1224
|
+
import consola13 from "consola";
|
|
1225
|
+
import { resolve as resolve12 } from "pathe";
|
|
1226
|
+
import Components from "unplugin-vue-components/vite";
|
|
1227
|
+
import Layouts from "vite-plugin-vue-layouts";
|
|
1228
|
+
|
|
1229
|
+
// node/plugins/extendConfig.ts
|
|
1230
|
+
import { dirname as dirname4, join as join3, resolve as resolve6 } from "node:path";
|
|
1231
|
+
import { uniq as uniq3 } from "@antfu/utils";
|
|
1232
|
+
import { mergeConfig as mergeConfig2, searchForWorkspaceRoot } from "vite";
|
|
1233
|
+
|
|
1234
|
+
// node/common.ts
|
|
1235
|
+
import { join as join2 } from "node:path";
|
|
1236
|
+
import { uniq as uniq2 } from "@antfu/utils";
|
|
1237
|
+
import fs10 from "fs-extra";
|
|
1238
|
+
import { loadConfigFromFile as loadConfigFromFile2, mergeConfig } from "vite";
|
|
1239
|
+
async function mergeViteConfigs({ userRoot: userRoot2, themeRoot }, command) {
|
|
1240
|
+
const configEnv = {
|
|
1241
|
+
mode: "development",
|
|
1242
|
+
command
|
|
1243
|
+
};
|
|
1244
|
+
let resolvedConfig = {};
|
|
1245
|
+
const files = uniq2([themeRoot, userRoot2]).map((i) => join2(i, "vite.config.ts"));
|
|
1246
|
+
const loadViteConfigPromiseArr = files.map(async (file) => {
|
|
1247
|
+
if (!await fs10.exists(file))
|
|
1248
|
+
return;
|
|
1249
|
+
return loadConfigFromFile2(configEnv, file);
|
|
1250
|
+
});
|
|
1251
|
+
const viteConfigs = await Promise.all(loadViteConfigPromiseArr);
|
|
1252
|
+
for (const viteConfig of viteConfigs) {
|
|
1253
|
+
if (!viteConfig?.config)
|
|
1254
|
+
continue;
|
|
1255
|
+
resolvedConfig = mergeConfig(resolvedConfig, viteConfig.config);
|
|
1256
|
+
}
|
|
1257
|
+
return resolvedConfig;
|
|
1258
|
+
}
|
|
1259
|
+
async function getIndexHtml({ clientRoot, themeRoot, userRoot: userRoot2, config }, rawHtml) {
|
|
1260
|
+
let main = rawHtml;
|
|
1261
|
+
let head = "";
|
|
1262
|
+
let body = "";
|
|
1263
|
+
if (config.siteConfig.favicon)
|
|
1264
|
+
head += `<link rel="icon" href="${config.siteConfig.favicon}">`;
|
|
1265
|
+
const roots = [userRoot2, themeRoot];
|
|
1266
|
+
if (config.siteConfig.mode === "auto") {
|
|
1267
|
+
head += `
|
|
1268
|
+
<script>
|
|
1269
|
+
;(function () {
|
|
1270
|
+
const prefersDark =
|
|
1271
|
+
window.matchMedia &&
|
|
1272
|
+
window.matchMedia('(prefers-color-scheme: dark)').matches
|
|
1273
|
+
const setting = localStorage.getItem('vueuse-color-scheme') || 'auto'
|
|
1274
|
+
if (setting === 'dark' || (prefersDark && setting !== 'light'))
|
|
1275
|
+
document.documentElement.classList.toggle('dark', true)
|
|
1276
|
+
})()
|
|
1277
|
+
</script>
|
|
1278
|
+
`;
|
|
1279
|
+
head += `<style type="text/css">
|
|
1280
|
+
:root { color-scheme: light dark; --va-c-bg: #fff; }
|
|
1281
|
+
html.dark { --va-c-bg: #000; }
|
|
1282
|
+
html { background-color: var(--va-c-bg); }
|
|
1283
|
+
</style>`;
|
|
1284
|
+
}
|
|
1285
|
+
if (config.siteConfig.lang) {
|
|
1286
|
+
head += `
|
|
1287
|
+
<script>
|
|
1288
|
+
const locale = localStorage.getItem('valaxy-locale') || '${config.siteConfig.lang}';
|
|
1289
|
+
document.documentElement.setAttribute('lang', locale);
|
|
1290
|
+
</script>
|
|
1291
|
+
`;
|
|
1292
|
+
}
|
|
1293
|
+
for (const root of roots) {
|
|
1294
|
+
const path17 = join2(root, "index.html");
|
|
1295
|
+
if (!fs10.existsSync(path17))
|
|
1296
|
+
continue;
|
|
1297
|
+
const indexHtml = await fs10.readFile(path17, "utf-8");
|
|
1298
|
+
head += `
|
|
1299
|
+
${(indexHtml.match(/<head>([\s\S]*?)<\/head>/i)?.[1] || "").trim()}`;
|
|
1300
|
+
body += `
|
|
1301
|
+
${(indexHtml.match(/<body>([\s\S]*?)<\/body>/i)?.[1] || "").trim()}`;
|
|
1302
|
+
}
|
|
1303
|
+
main = main.replace("__ENTRY__", toAtFS(join2(clientRoot, "main.ts"))).replace("<!-- head -->", head).replace("<!-- body -->", body);
|
|
1304
|
+
return main;
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1307
|
+
// node/plugins/extendConfig.ts
|
|
1308
|
+
var clientDeps = [
|
|
1309
|
+
// https://cn.vite.dev/guide/dep-pre-bundling.html#the-why
|
|
1310
|
+
"dayjs",
|
|
1311
|
+
"dayjs/locale/en",
|
|
1312
|
+
"dayjs/locale/zh-cn",
|
|
1313
|
+
"dayjs/plugin/relativeTime",
|
|
1314
|
+
"dayjs/plugin/timezone",
|
|
1315
|
+
"dayjs/plugin/utc",
|
|
1316
|
+
"@unhead/schema-org",
|
|
1317
|
+
"@unhead/vue",
|
|
1318
|
+
"defu",
|
|
1319
|
+
"katex",
|
|
1320
|
+
"nprogress",
|
|
1321
|
+
"unocss",
|
|
1322
|
+
// vue
|
|
1323
|
+
"vue",
|
|
1324
|
+
"vue-router",
|
|
1325
|
+
"unplugin-vue-router/data-loaders/basic",
|
|
1326
|
+
"vue-i18n",
|
|
1327
|
+
// dev
|
|
1328
|
+
"@vue/devtools-api",
|
|
1329
|
+
// will may be addons
|
|
1330
|
+
"fuse.js",
|
|
1331
|
+
"medium-zoom",
|
|
1332
|
+
"vanilla-lazyload",
|
|
1333
|
+
"valaxy > @vueuse/integrations/useFuse"
|
|
1334
|
+
];
|
|
1335
|
+
var EXCLUDE = [
|
|
1336
|
+
"@docsearch/css",
|
|
1337
|
+
"@docsearch/js",
|
|
1338
|
+
// exclude for @waline/client/dist/component(use @vueuse/core) import
|
|
1339
|
+
"@vueuse/core",
|
|
1340
|
+
"@vueuse/shared",
|
|
1341
|
+
"@unocss/reset",
|
|
1342
|
+
"unocss",
|
|
1343
|
+
// addon, todo add externals for addon
|
|
1344
|
+
// main field error
|
|
1345
|
+
"meting",
|
|
1346
|
+
// internal
|
|
1347
|
+
"valaxy",
|
|
1348
|
+
"/@valaxyjs/config",
|
|
1349
|
+
"/@valaxyjs/context",
|
|
1350
|
+
"/@valaxyjs/addons",
|
|
1351
|
+
"/@valaxyjs/locales",
|
|
1352
|
+
"/@valaxyjs/styles"
|
|
1353
|
+
];
|
|
1354
|
+
function createConfigPlugin(options) {
|
|
1355
|
+
const addonDeps = options.addons.map((i) => Object.keys(i.pkg.dependencies || {})).flat();
|
|
1356
|
+
const includedDeps = uniq3([
|
|
1357
|
+
...clientDeps,
|
|
1358
|
+
// remove theme deps, for primevue parse entry
|
|
1359
|
+
// ...themeDeps,
|
|
1360
|
+
// addon deps
|
|
1361
|
+
...addonDeps
|
|
1362
|
+
]).filter((i) => !EXCLUDE.includes(i));
|
|
1363
|
+
return {
|
|
1364
|
+
name: "valaxy:site",
|
|
1365
|
+
// before devtools
|
|
1366
|
+
enforce: "pre",
|
|
1367
|
+
async config(config) {
|
|
1368
|
+
const injection = {
|
|
1369
|
+
// root: options.userRoot,
|
|
1370
|
+
// can not transform valaxy/client/*.ts when use userRoot
|
|
1371
|
+
root: options.clientRoot,
|
|
1372
|
+
// cacheDir: join(options.userRoot, 'node_modules/.vite'),
|
|
1373
|
+
cacheDir: join3(options.userRoot, "node_modules/.valaxy/cache"),
|
|
1374
|
+
publicDir: join3(options.userRoot, "public"),
|
|
1375
|
+
define: getDefine(options),
|
|
1376
|
+
resolve: {
|
|
1377
|
+
alias: await getAlias(options),
|
|
1378
|
+
dedupe: ["vue"]
|
|
1379
|
+
},
|
|
1380
|
+
optimizeDeps: {
|
|
1381
|
+
// do not entry node file
|
|
1382
|
+
entries: [resolve6(options.clientRoot, "main.ts")],
|
|
1383
|
+
// must need it
|
|
1384
|
+
include: includedDeps,
|
|
1385
|
+
exclude: EXCLUDE
|
|
1386
|
+
},
|
|
1387
|
+
server: {
|
|
1388
|
+
fs: {
|
|
1389
|
+
allow: uniq3([
|
|
1390
|
+
searchForWorkspaceRoot(options.clientRoot),
|
|
1391
|
+
searchForWorkspaceRoot(options.themeRoot),
|
|
1392
|
+
searchForWorkspaceRoot(options.userRoot),
|
|
1393
|
+
dirname4(await resolveImportPath("katex/package.json", true))
|
|
1394
|
+
])
|
|
1395
|
+
}
|
|
1396
|
+
}
|
|
1397
|
+
};
|
|
1398
|
+
if (isInstalledGlobally) {
|
|
1399
|
+
injection.resolve.alias.vue = `${resolveImportPath("vue/dist/vue.esm-browser.js", true)}`;
|
|
1400
|
+
}
|
|
1401
|
+
return mergeConfig2(config, injection);
|
|
1402
|
+
},
|
|
1403
|
+
async transformIndexHtml(html) {
|
|
1404
|
+
html = await getIndexHtml(options, html);
|
|
1405
|
+
return {
|
|
1406
|
+
html,
|
|
1407
|
+
tags: []
|
|
1408
|
+
};
|
|
1409
|
+
}
|
|
1410
|
+
};
|
|
1411
|
+
}
|
|
1412
|
+
function getDefine(_options) {
|
|
1413
|
+
return {
|
|
1414
|
+
__VUE_PROD_DEVTOOLS__: false,
|
|
1415
|
+
__INTLIFY_PROD_DEVTOOLS__: false
|
|
1416
|
+
};
|
|
1417
|
+
}
|
|
1418
|
+
async function getAlias(options) {
|
|
1419
|
+
const alias = [
|
|
1420
|
+
{ find: "~/", replacement: `${toAtFS(options.userRoot)}/` },
|
|
1421
|
+
{ find: "valaxy/client/", replacement: `${toAtFS(options.clientRoot)}/` },
|
|
1422
|
+
{ find: "valaxy/package.json", replacement: toAtFS(resolve6(options.clientRoot, "../package.json")) },
|
|
1423
|
+
{ find: /^valaxy$/, replacement: toAtFS(resolve6(options.clientRoot, "index.ts")) },
|
|
1424
|
+
{ find: "@valaxyjs/client/", replacement: `${toAtFS(options.clientRoot)}/` },
|
|
1425
|
+
// virtual module alias
|
|
1426
|
+
{
|
|
1427
|
+
find: /^#valaxy\/(.*)/,
|
|
1428
|
+
replacement: "/@valaxyjs/$1"
|
|
1429
|
+
},
|
|
1430
|
+
// import theme
|
|
1431
|
+
{ find: "virtual:valaxy-theme", replacement: `${toAtFS(options.themeRoot)}/client/index.ts` },
|
|
1432
|
+
{ find: `valaxy-theme-${options.theme}/client`, replacement: `${toAtFS(resolve6(options.themeRoot))}/client/index.ts` },
|
|
1433
|
+
{ find: `valaxy-theme-${options.theme}/`, replacement: `${toAtFS(resolve6(options.themeRoot))}/` },
|
|
1434
|
+
{ find: `valaxy-theme-${options.theme}`, replacement: `${toAtFS(resolve6(options.themeRoot))}/client/index.ts` }
|
|
1435
|
+
];
|
|
1436
|
+
if (options.config.siteConfig.encrypt.enable) {
|
|
1437
|
+
alias.push(
|
|
1438
|
+
{ find: /^vue$/, replacement: await resolveImportPath("vue/dist/vue.esm-bundler.js", true) }
|
|
1439
|
+
);
|
|
1440
|
+
}
|
|
1441
|
+
options.addons.forEach((addon) => {
|
|
1442
|
+
alias.push({
|
|
1443
|
+
find: `${addon.name}/client/`,
|
|
1444
|
+
replacement: `${toAtFS(`${resolve6(addon.root)}`)}/client/`
|
|
1445
|
+
});
|
|
1446
|
+
alias.push({
|
|
1447
|
+
find: `${addon.name}/App.vue`,
|
|
1448
|
+
replacement: `${toAtFS(resolve6(addon.root))}/App.vue`
|
|
1449
|
+
});
|
|
1450
|
+
alias.push({
|
|
1451
|
+
find: addon.name,
|
|
1452
|
+
replacement: `${toAtFS(resolve6(addon.root))}/client/index.ts`
|
|
1453
|
+
});
|
|
1454
|
+
});
|
|
1455
|
+
alias.push({
|
|
1456
|
+
find: /^valaxy-addon-(.*)$/,
|
|
1457
|
+
replacement: toAtFS(resolve6(options.clientRoot, "./addons/index.ts"))
|
|
1458
|
+
});
|
|
1459
|
+
return alias;
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1462
|
+
// node/plugins/markdown/index.ts
|
|
1463
|
+
import { createMarkdownItAsync } from "markdown-it-async";
|
|
1464
|
+
|
|
1465
|
+
// node/plugins/markdown/plugins/highlight.ts
|
|
1466
|
+
import {
|
|
1467
|
+
transformerCompactLineOptions,
|
|
1468
|
+
transformerNotationDiff,
|
|
1469
|
+
transformerNotationErrorLevel,
|
|
1470
|
+
transformerNotationFocus,
|
|
1471
|
+
transformerNotationHighlight
|
|
1472
|
+
} from "@shikijs/transformers";
|
|
1473
|
+
import { colors as colors9 } from "consola/utils";
|
|
1474
|
+
|
|
1475
|
+
// ../../node_modules/.pnpm/nanoid@5.1.3/node_modules/nanoid/index.js
|
|
1476
|
+
import { webcrypto as crypto } from "node:crypto";
|
|
1477
|
+
|
|
1478
|
+
// ../../node_modules/.pnpm/nanoid@5.1.3/node_modules/nanoid/url-alphabet/index.js
|
|
1479
|
+
var urlAlphabet = "useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";
|
|
1480
|
+
|
|
1481
|
+
// ../../node_modules/.pnpm/nanoid@5.1.3/node_modules/nanoid/index.js
|
|
1482
|
+
var POOL_SIZE_MULTIPLIER = 128;
|
|
1483
|
+
var pool;
|
|
1484
|
+
var poolOffset;
|
|
1485
|
+
function fillPool(bytes) {
|
|
1486
|
+
if (!pool || pool.length < bytes) {
|
|
1487
|
+
pool = Buffer.allocUnsafe(bytes * POOL_SIZE_MULTIPLIER);
|
|
1488
|
+
crypto.getRandomValues(pool);
|
|
1489
|
+
poolOffset = 0;
|
|
1490
|
+
} else if (poolOffset + bytes > pool.length) {
|
|
1491
|
+
crypto.getRandomValues(pool);
|
|
1492
|
+
poolOffset = 0;
|
|
1493
|
+
}
|
|
1494
|
+
poolOffset += bytes;
|
|
1495
|
+
}
|
|
1496
|
+
function random(bytes) {
|
|
1497
|
+
fillPool(bytes |= 0);
|
|
1498
|
+
return pool.subarray(poolOffset - bytes, poolOffset);
|
|
1499
|
+
}
|
|
1500
|
+
function customRandom(alphabet, defaultSize, getRandom) {
|
|
1501
|
+
let mask = (2 << 31 - Math.clz32(alphabet.length - 1 | 1)) - 1;
|
|
1502
|
+
let step = Math.ceil(1.6 * mask * defaultSize / alphabet.length);
|
|
1503
|
+
return (size = defaultSize) => {
|
|
1504
|
+
let id = "";
|
|
1505
|
+
while (true) {
|
|
1506
|
+
let bytes = getRandom(step);
|
|
1507
|
+
let i = step;
|
|
1508
|
+
while (i--) {
|
|
1509
|
+
id += alphabet[bytes[i] & mask] || "";
|
|
1510
|
+
if (id.length >= size) return id;
|
|
1511
|
+
}
|
|
1512
|
+
}
|
|
1513
|
+
};
|
|
1514
|
+
}
|
|
1515
|
+
function customAlphabet(alphabet, size = 21) {
|
|
1516
|
+
return customRandom(alphabet, size, random);
|
|
1517
|
+
}
|
|
1518
|
+
function nanoid(size = 21) {
|
|
1519
|
+
fillPool(size |= 0);
|
|
1520
|
+
let id = "";
|
|
1521
|
+
for (let i = poolOffset - size; i < poolOffset; i++) {
|
|
1522
|
+
id += urlAlphabet[pool[i] & 63];
|
|
1523
|
+
}
|
|
1524
|
+
return id;
|
|
1525
|
+
}
|
|
1526
|
+
|
|
1527
|
+
// node/plugins/markdown/plugins/highlight.ts
|
|
1528
|
+
import {
|
|
1529
|
+
addClassToHast,
|
|
1530
|
+
createHighlighter,
|
|
1531
|
+
isSpecialLang
|
|
1532
|
+
} from "shiki";
|
|
1533
|
+
var resolveLangSync = createSyncFn(
|
|
1534
|
+
__require.resolve("valaxy/dist/node/worker_shikiResolveLang.js")
|
|
1535
|
+
);
|
|
1536
|
+
var nanoid2 = customAlphabet("abcdefghijklmnopqrstuvwxyz", 10);
|
|
1537
|
+
function attrsToLines(attrs) {
|
|
1538
|
+
attrs = attrs.replace(/^(?:\[.*?\])?.*?([\d,-]+).*/, "$1").trim();
|
|
1539
|
+
const result = [];
|
|
1540
|
+
if (!attrs)
|
|
1541
|
+
return [];
|
|
1542
|
+
attrs.split(",").map((v) => v.split("-").map((v2) => Number.parseInt(v2, 10))).forEach(([start, end]) => {
|
|
1543
|
+
if (start && end) {
|
|
1544
|
+
result.push(
|
|
1545
|
+
...Array.from({ length: end - start + 1 }, (_, i) => start + i)
|
|
1546
|
+
);
|
|
1547
|
+
} else {
|
|
1548
|
+
result.push(start);
|
|
1549
|
+
}
|
|
1550
|
+
});
|
|
1551
|
+
return result.map((v) => ({
|
|
1552
|
+
line: v,
|
|
1553
|
+
classes: ["highlighted"]
|
|
1554
|
+
}));
|
|
1555
|
+
}
|
|
1556
|
+
async function highlight(theme, options, logger2 = console) {
|
|
1557
|
+
const {
|
|
1558
|
+
defaultHighlightLang: defaultLang = "txt",
|
|
1559
|
+
codeTransformers: userTransformers = []
|
|
1560
|
+
} = options;
|
|
1561
|
+
const highlighter = await createHighlighter({
|
|
1562
|
+
themes: typeof theme === "object" && "light" in theme && "dark" in theme ? [theme.light, theme.dark] : [theme],
|
|
1563
|
+
langs: [
|
|
1564
|
+
// load long time, about 3s
|
|
1565
|
+
// ...Object.keys(bundledLanguages),
|
|
1566
|
+
...options.languages || [],
|
|
1567
|
+
...Object.values(options.languageAlias || {})
|
|
1568
|
+
],
|
|
1569
|
+
langAlias: options.languageAlias
|
|
1570
|
+
});
|
|
1571
|
+
function loadLanguage(name) {
|
|
1572
|
+
const lang = typeof name === "string" ? name : name.name;
|
|
1573
|
+
if (!isSpecialLang(lang) && !highlighter.getLoadedLanguages().includes(lang)) {
|
|
1574
|
+
const resolvedLang = resolveLangSync(lang);
|
|
1575
|
+
if (resolvedLang.length)
|
|
1576
|
+
highlighter.loadLanguageSync(resolvedLang);
|
|
1577
|
+
else return false;
|
|
1578
|
+
}
|
|
1579
|
+
return true;
|
|
1580
|
+
}
|
|
1581
|
+
const internal = highlighter.getInternalContext();
|
|
1582
|
+
const getLanguage = internal.getLanguage;
|
|
1583
|
+
internal.getLanguage = (name) => {
|
|
1584
|
+
loadLanguage(name);
|
|
1585
|
+
return getLanguage.call(internal, name);
|
|
1586
|
+
};
|
|
1587
|
+
await options?.shikiSetup?.(highlighter);
|
|
1588
|
+
const transformers = [
|
|
1589
|
+
transformerNotationDiff(),
|
|
1590
|
+
transformerNotationFocus({
|
|
1591
|
+
classActiveLine: "has-focus",
|
|
1592
|
+
classActivePre: "has-focused-lines"
|
|
1593
|
+
}),
|
|
1594
|
+
transformerNotationHighlight(),
|
|
1595
|
+
transformerNotationErrorLevel(),
|
|
1596
|
+
{
|
|
1597
|
+
name: "valaxy:add-class",
|
|
1598
|
+
pre(node) {
|
|
1599
|
+
addClassToHast(node, "vp-code");
|
|
1600
|
+
}
|
|
1601
|
+
},
|
|
1602
|
+
{
|
|
1603
|
+
name: "valaxy:clean-up",
|
|
1604
|
+
pre(node) {
|
|
1605
|
+
delete node.properties.tabindex;
|
|
1606
|
+
delete node.properties.style;
|
|
1607
|
+
}
|
|
1608
|
+
}
|
|
1609
|
+
];
|
|
1610
|
+
const vueRE = /-vue$/;
|
|
1611
|
+
const lineNoStartRE = /=(\d*)/;
|
|
1612
|
+
const lineNoRE = /:(no-)?line-numbers(=\d*)?$/;
|
|
1613
|
+
const mustacheRE = /\{\{.*?\}\}/g;
|
|
1614
|
+
return (str, lang, attrs) => {
|
|
1615
|
+
const vPre = vueRE.test(lang) ? "" : "v-pre";
|
|
1616
|
+
lang = lang.replace(lineNoStartRE, "").replace(lineNoRE, "").replace(vueRE, "").toLowerCase() || defaultLang;
|
|
1617
|
+
if (!loadLanguage(lang)) {
|
|
1618
|
+
logger2.warn(
|
|
1619
|
+
colors9.yellow(
|
|
1620
|
+
`
|
|
1621
|
+
The language '${lang}' is not loaded, falling back to '${defaultLang}' for syntax highlighting.`
|
|
1622
|
+
)
|
|
1623
|
+
);
|
|
1624
|
+
lang = defaultLang;
|
|
1625
|
+
}
|
|
1626
|
+
const lineOptions = attrsToLines(attrs);
|
|
1627
|
+
const mustaches = /* @__PURE__ */ new Map();
|
|
1628
|
+
const removeMustache = (s) => {
|
|
1629
|
+
if (vPre)
|
|
1630
|
+
return s;
|
|
1631
|
+
return s.replace(mustacheRE, (match) => {
|
|
1632
|
+
let marker = mustaches.get(match);
|
|
1633
|
+
if (!marker) {
|
|
1634
|
+
marker = nanoid2();
|
|
1635
|
+
mustaches.set(match, marker);
|
|
1636
|
+
}
|
|
1637
|
+
return marker;
|
|
1638
|
+
});
|
|
1639
|
+
};
|
|
1640
|
+
const restoreMustache = (s) => {
|
|
1641
|
+
mustaches.forEach((marker, match) => {
|
|
1642
|
+
s = s.replaceAll(marker, match);
|
|
1643
|
+
});
|
|
1644
|
+
return s;
|
|
1645
|
+
};
|
|
1646
|
+
str = removeMustache(str).trimEnd();
|
|
1647
|
+
const highlighted = highlighter.codeToHtml(str, {
|
|
1648
|
+
lang,
|
|
1649
|
+
transformers: [
|
|
1650
|
+
...transformers,
|
|
1651
|
+
transformerCompactLineOptions(lineOptions),
|
|
1652
|
+
{
|
|
1653
|
+
name: "valaxy:v-pre",
|
|
1654
|
+
pre(node) {
|
|
1655
|
+
if (vPre)
|
|
1656
|
+
node.properties["v-pre"] = "";
|
|
1657
|
+
}
|
|
1658
|
+
},
|
|
1659
|
+
{
|
|
1660
|
+
name: "valaxy:empty-line",
|
|
1661
|
+
code(hast) {
|
|
1662
|
+
hast.children.forEach((span) => {
|
|
1663
|
+
if (span.type === "element" && span.tagName === "span" && Array.isArray(span.properties.class) && span.properties.class.includes("line") && span.children.length === 0) {
|
|
1664
|
+
span.children.push({
|
|
1665
|
+
type: "element",
|
|
1666
|
+
tagName: "wbr",
|
|
1667
|
+
properties: {},
|
|
1668
|
+
children: []
|
|
1669
|
+
});
|
|
1670
|
+
}
|
|
1671
|
+
});
|
|
1672
|
+
}
|
|
1673
|
+
},
|
|
1674
|
+
...userTransformers
|
|
1675
|
+
],
|
|
1676
|
+
meta: {
|
|
1677
|
+
__raw: attrs
|
|
1678
|
+
},
|
|
1679
|
+
...typeof theme === "object" && "light" in theme && "dark" in theme ? { themes: theme, defaultColor: false } : { theme }
|
|
1680
|
+
});
|
|
1681
|
+
return restoreMustache(highlighted);
|
|
1682
|
+
};
|
|
1683
|
+
}
|
|
1684
|
+
|
|
1685
|
+
// ../../node_modules/.pnpm/@mdit-vue+shared@2.1.3/node_modules/@mdit-vue/shared/dist/index.mjs
|
|
1686
|
+
var htmlEscapeMap = {
|
|
1687
|
+
"&": "&",
|
|
1688
|
+
"<": "<",
|
|
1689
|
+
">": ">",
|
|
1690
|
+
"'": "'",
|
|
1691
|
+
'"': """
|
|
1692
|
+
};
|
|
1693
|
+
var htmlEscapeRegexp = /[&<>'"]/g;
|
|
1694
|
+
var htmlEscape = (str) => str.replace(
|
|
1695
|
+
htmlEscapeRegexp,
|
|
1696
|
+
(char) => htmlEscapeMap[char]
|
|
1697
|
+
);
|
|
1698
|
+
var resolveTitleFromToken = (token, { shouldAllowHtml, shouldEscapeText }) => {
|
|
1699
|
+
const children = token.children ?? [];
|
|
1700
|
+
const titleTokenTypes = ["text", "emoji", "code_inline"];
|
|
1701
|
+
if (shouldAllowHtml) {
|
|
1702
|
+
titleTokenTypes.push("html_inline");
|
|
1703
|
+
}
|
|
1704
|
+
const titleTokens = children.filter(
|
|
1705
|
+
(item) => titleTokenTypes.includes(item.type) && // filter permalink symbol that generated by markdown-it-anchor
|
|
1706
|
+
!item.meta?.isPermalinkSymbol
|
|
1707
|
+
);
|
|
1708
|
+
return titleTokens.reduce((result, item) => {
|
|
1709
|
+
if (shouldEscapeText) {
|
|
1710
|
+
if (item.type === "code_inline" || item.type === "text") {
|
|
1711
|
+
return `${result}${htmlEscape(item.content)}`;
|
|
1712
|
+
}
|
|
1713
|
+
}
|
|
1714
|
+
return `${result}${item.content}`;
|
|
1715
|
+
}, "").trim();
|
|
1716
|
+
};
|
|
1717
|
+
var resolveHeadersFromTokens = (tokens, {
|
|
1718
|
+
level,
|
|
1719
|
+
shouldAllowHtml,
|
|
1720
|
+
shouldAllowNested,
|
|
1721
|
+
shouldEscapeText,
|
|
1722
|
+
slugify: slugify2,
|
|
1723
|
+
format
|
|
1724
|
+
}) => {
|
|
1725
|
+
const headers = [];
|
|
1726
|
+
const stack = [];
|
|
1727
|
+
const push = (header) => {
|
|
1728
|
+
while (stack.length !== 0 && header.level <= stack[0].level) {
|
|
1729
|
+
stack.shift();
|
|
1730
|
+
}
|
|
1731
|
+
if (stack.length === 0) {
|
|
1732
|
+
headers.push(header);
|
|
1733
|
+
stack.push(header);
|
|
1734
|
+
} else {
|
|
1735
|
+
stack[0].children.push(header);
|
|
1736
|
+
stack.unshift(header);
|
|
1737
|
+
}
|
|
1738
|
+
};
|
|
1739
|
+
for (let i = 0; i < tokens.length; i += 1) {
|
|
1740
|
+
const token = tokens[i];
|
|
1741
|
+
if (token.type !== "heading_open") {
|
|
1742
|
+
continue;
|
|
1743
|
+
}
|
|
1744
|
+
if (token.level !== 0 && !shouldAllowNested) {
|
|
1745
|
+
continue;
|
|
1746
|
+
}
|
|
1747
|
+
const headerLevel = Number.parseInt(token.tag.slice(1), 10);
|
|
1748
|
+
if (!level.includes(headerLevel)) {
|
|
1749
|
+
continue;
|
|
1750
|
+
}
|
|
1751
|
+
const nextToken = tokens[i + 1];
|
|
1752
|
+
if (!nextToken) {
|
|
1753
|
+
continue;
|
|
1754
|
+
}
|
|
1755
|
+
const title = resolveTitleFromToken(nextToken, {
|
|
1756
|
+
shouldAllowHtml,
|
|
1757
|
+
shouldEscapeText
|
|
1758
|
+
});
|
|
1759
|
+
const slug = token.attrGet("id") ?? slugify2(title);
|
|
1760
|
+
push({
|
|
1761
|
+
level: headerLevel,
|
|
1762
|
+
title: format?.(title) ?? title,
|
|
1763
|
+
slug,
|
|
1764
|
+
link: `#${slug}`,
|
|
1765
|
+
children: []
|
|
1766
|
+
});
|
|
1767
|
+
}
|
|
1768
|
+
return headers;
|
|
1769
|
+
};
|
|
1770
|
+
var rControl = /[\u0000-\u001f]/g;
|
|
1771
|
+
var rSpecial = /[\s~`!@#$%^&*()\-_+=[\]{}|\\;:"'“”‘’<>,.?/]+/g;
|
|
1772
|
+
var rCombining = /[\u0300-\u036F]/g;
|
|
1773
|
+
var slugify = (str) => str.normalize("NFKD").replace(rCombining, "").replace(rControl, "").replace(rSpecial, "-").replace(/-{2,}/g, "-").replace(/^-+|-+$/g, "").replace(/^(\d)/, "_$1").toLowerCase();
|
|
1774
|
+
|
|
1775
|
+
// ../../node_modules/.pnpm/@mdit-vue+plugin-headers@2.1.3/node_modules/@mdit-vue/plugin-headers/dist/index.mjs
|
|
1776
|
+
var headersPlugin = (md, {
|
|
1777
|
+
level = [2, 3],
|
|
1778
|
+
shouldAllowNested = false,
|
|
1779
|
+
slugify: slugify$1 = slugify,
|
|
1780
|
+
format
|
|
1781
|
+
} = {}) => {
|
|
1782
|
+
const render2 = md.renderer.render.bind(md.renderer);
|
|
1783
|
+
md.renderer.render = (tokens, options, env) => {
|
|
1784
|
+
env.headers = resolveHeadersFromTokens(tokens, {
|
|
1785
|
+
level,
|
|
1786
|
+
shouldAllowHtml: false,
|
|
1787
|
+
shouldAllowNested,
|
|
1788
|
+
shouldEscapeText: false,
|
|
1789
|
+
slugify: slugify$1,
|
|
1790
|
+
format
|
|
1791
|
+
});
|
|
1792
|
+
return render2(tokens, options, env);
|
|
1793
|
+
};
|
|
1794
|
+
};
|
|
1795
|
+
|
|
1796
|
+
// ../../node_modules/.pnpm/@mdit-vue+plugin-sfc@2.1.3/node_modules/@mdit-vue/plugin-sfc/dist/index.mjs
|
|
1797
|
+
var TAG_NAME_SCRIPT = "script";
|
|
1798
|
+
var TAG_NAME_STYLE = "style";
|
|
1799
|
+
var TAG_NAME_TEMPLATE = "template";
|
|
1800
|
+
var SCRIPT_SETUP_TAG_OPEN_REGEXP = /^<script\s+.*?\bsetup\b.*?>$/is;
|
|
1801
|
+
var createSfcRegexp = ({
|
|
1802
|
+
customBlocks
|
|
1803
|
+
}) => {
|
|
1804
|
+
const sfcTags = Array.from(
|
|
1805
|
+
/* @__PURE__ */ new Set([TAG_NAME_SCRIPT, TAG_NAME_STYLE, ...customBlocks])
|
|
1806
|
+
).join("|");
|
|
1807
|
+
return new RegExp(
|
|
1808
|
+
`^\\s*(?<content>(?<tagOpen><(?<type>${sfcTags})\\s?.*?>)(?<contentStripped>.*)(?<tagClose><\\/\\k<type>\\s*>))\\s*$`,
|
|
1809
|
+
"is"
|
|
1810
|
+
);
|
|
1811
|
+
};
|
|
1812
|
+
var sfcPlugin = (md, { customBlocks = [] } = {}) => {
|
|
1813
|
+
const sfcRegexp = createSfcRegexp({ customBlocks });
|
|
1814
|
+
const render2 = md.render.bind(md);
|
|
1815
|
+
md.render = (src, env = {}) => {
|
|
1816
|
+
env.sfcBlocks = {
|
|
1817
|
+
template: null,
|
|
1818
|
+
script: null,
|
|
1819
|
+
scriptSetup: null,
|
|
1820
|
+
scripts: [],
|
|
1821
|
+
styles: [],
|
|
1822
|
+
customBlocks: []
|
|
1823
|
+
};
|
|
1824
|
+
const rendered = render2(src, env);
|
|
1825
|
+
env.sfcBlocks.template = {
|
|
1826
|
+
type: TAG_NAME_TEMPLATE,
|
|
1827
|
+
content: `<${TAG_NAME_TEMPLATE}>${rendered}</${TAG_NAME_TEMPLATE}>`,
|
|
1828
|
+
contentStripped: rendered,
|
|
1829
|
+
tagOpen: `<${TAG_NAME_TEMPLATE}>`,
|
|
1830
|
+
tagClose: `</${TAG_NAME_TEMPLATE}>`
|
|
1831
|
+
};
|
|
1832
|
+
return rendered;
|
|
1833
|
+
};
|
|
1834
|
+
const htmlBlockRule = md.renderer.rules.html_block;
|
|
1835
|
+
md.renderer.rules.html_block = (tokens, idx, options, env, self) => {
|
|
1836
|
+
if (!env.sfcBlocks) {
|
|
1837
|
+
return htmlBlockRule(tokens, idx, options, env, self);
|
|
1838
|
+
}
|
|
1839
|
+
const token = tokens[idx];
|
|
1840
|
+
const content = token.content;
|
|
1841
|
+
const match = content.match(sfcRegexp);
|
|
1842
|
+
if (!match) {
|
|
1843
|
+
return htmlBlockRule(tokens, idx, options, env, self);
|
|
1844
|
+
}
|
|
1845
|
+
const sfcBlock = match.groups;
|
|
1846
|
+
if (sfcBlock.type === TAG_NAME_SCRIPT) {
|
|
1847
|
+
env.sfcBlocks.scripts.push(sfcBlock);
|
|
1848
|
+
if (SCRIPT_SETUP_TAG_OPEN_REGEXP.test(sfcBlock.tagOpen)) {
|
|
1849
|
+
env.sfcBlocks.scriptSetup = sfcBlock;
|
|
1850
|
+
} else {
|
|
1851
|
+
env.sfcBlocks.script = sfcBlock;
|
|
1852
|
+
}
|
|
1853
|
+
} else if (sfcBlock.type === TAG_NAME_STYLE) {
|
|
1854
|
+
env.sfcBlocks.styles.push(sfcBlock);
|
|
1855
|
+
} else {
|
|
1856
|
+
env.sfcBlocks.customBlocks.push(sfcBlock);
|
|
1857
|
+
}
|
|
1858
|
+
return "";
|
|
1859
|
+
};
|
|
1860
|
+
};
|
|
1861
|
+
|
|
1862
|
+
// ../../node_modules/.pnpm/@mdit-vue+plugin-title@2.1.3/node_modules/@mdit-vue/plugin-title/dist/index.mjs
|
|
1863
|
+
var titlePlugin = (md) => {
|
|
1864
|
+
const render2 = md.renderer.render.bind(md.renderer);
|
|
1865
|
+
md.renderer.render = (tokens, options, env) => {
|
|
1866
|
+
const tokenIdx = tokens.findIndex((token) => token.tag === "h1");
|
|
1867
|
+
env.title = tokenIdx > -1 ? resolveTitleFromToken(tokens[tokenIdx + 1], {
|
|
1868
|
+
shouldAllowHtml: false,
|
|
1869
|
+
shouldEscapeText: false
|
|
1870
|
+
}) : "";
|
|
1871
|
+
return render2(tokens, options, env);
|
|
1872
|
+
};
|
|
1873
|
+
};
|
|
1874
|
+
|
|
1875
|
+
// ../../node_modules/.pnpm/@mdit-vue+plugin-toc@2.1.3/node_modules/@mdit-vue/plugin-toc/dist/index.mjs
|
|
1876
|
+
var createRenderHeaders = ({
|
|
1877
|
+
listTag,
|
|
1878
|
+
listClass,
|
|
1879
|
+
itemClass,
|
|
1880
|
+
linkTag,
|
|
1881
|
+
linkClass
|
|
1882
|
+
}) => {
|
|
1883
|
+
const listTagString = htmlEscape(listTag);
|
|
1884
|
+
const listClassString = listClass ? ` class="${htmlEscape(listClass)}"` : "";
|
|
1885
|
+
const itemTagString = "li";
|
|
1886
|
+
const itemClassString = itemClass ? ` class="${htmlEscape(itemClass)}"` : "";
|
|
1887
|
+
const linkTagString = htmlEscape(linkTag);
|
|
1888
|
+
const linkClassString = linkClass ? ` class="${htmlEscape(linkClass)}"` : "";
|
|
1889
|
+
const linkTo = (link) => linkTag === "router-link" ? ` to="${link}"` : ` href="${link}"`;
|
|
1890
|
+
const renderHeaders = (headers) => `<${listTagString}${listClassString}>${headers.map(
|
|
1891
|
+
(header) => `<${itemTagString}${itemClassString}><${linkTagString}${linkClassString}${linkTo(header.link)}>${header.title}</${linkTagString}>${header.children.length > 0 ? renderHeaders(header.children) : ""}</${itemTagString}>`
|
|
1892
|
+
).join("")}</${listTagString}>`;
|
|
1893
|
+
return renderHeaders;
|
|
1894
|
+
};
|
|
1895
|
+
var createTocBlockRule = ({
|
|
1896
|
+
pattern,
|
|
1897
|
+
containerTag,
|
|
1898
|
+
containerClass
|
|
1899
|
+
}) => (state, startLine, endLine, silent) => {
|
|
1900
|
+
if (state.sCount[startLine] - state.blkIndent >= 4) {
|
|
1901
|
+
return false;
|
|
1902
|
+
}
|
|
1903
|
+
const pos = state.bMarks[startLine] + state.tShift[startLine];
|
|
1904
|
+
const max = state.eMarks[startLine];
|
|
1905
|
+
const lineFirstToken = state.src.slice(pos, max).split(" ")[0];
|
|
1906
|
+
if (!pattern.test(lineFirstToken))
|
|
1907
|
+
return false;
|
|
1908
|
+
if (silent)
|
|
1909
|
+
return true;
|
|
1910
|
+
state.line = startLine + 1;
|
|
1911
|
+
const tokenOpen = state.push("toc_open", containerTag, 1);
|
|
1912
|
+
tokenOpen.markup = "";
|
|
1913
|
+
tokenOpen.map = [startLine, state.line];
|
|
1914
|
+
if (containerClass) {
|
|
1915
|
+
tokenOpen.attrSet("class", containerClass);
|
|
1916
|
+
}
|
|
1917
|
+
const tokenBody = state.push("toc_body", "", 0);
|
|
1918
|
+
tokenBody.markup = lineFirstToken;
|
|
1919
|
+
tokenBody.map = [startLine, state.line];
|
|
1920
|
+
tokenBody.hidden = true;
|
|
1921
|
+
const tokenClose = state.push("toc_close", containerTag, -1);
|
|
1922
|
+
tokenClose.markup = "";
|
|
1923
|
+
tokenBody.map = [startLine, state.line];
|
|
1924
|
+
return true;
|
|
1925
|
+
};
|
|
1926
|
+
var tocPlugin = (md, {
|
|
1927
|
+
pattern = /^\[\[toc\]\]$/i,
|
|
1928
|
+
slugify: slugify$1 = slugify,
|
|
1929
|
+
format,
|
|
1930
|
+
level = [2, 3],
|
|
1931
|
+
shouldAllowNested = false,
|
|
1932
|
+
containerTag = "nav",
|
|
1933
|
+
containerClass = "table-of-contents",
|
|
1934
|
+
listTag = "ul",
|
|
1935
|
+
listClass = "",
|
|
1936
|
+
itemClass = "",
|
|
1937
|
+
linkTag = "a",
|
|
1938
|
+
linkClass = ""
|
|
1939
|
+
} = {}) => {
|
|
1940
|
+
md.block.ruler.before(
|
|
1941
|
+
"heading",
|
|
1942
|
+
"toc",
|
|
1943
|
+
createTocBlockRule({
|
|
1944
|
+
pattern,
|
|
1945
|
+
containerTag,
|
|
1946
|
+
containerClass
|
|
1947
|
+
}),
|
|
1948
|
+
{
|
|
1949
|
+
alt: ["paragraph", "reference", "blockquote"]
|
|
1950
|
+
}
|
|
1951
|
+
);
|
|
1952
|
+
const renderHeaders = createRenderHeaders({
|
|
1953
|
+
listTag,
|
|
1954
|
+
listClass,
|
|
1955
|
+
itemClass,
|
|
1956
|
+
linkTag,
|
|
1957
|
+
linkClass
|
|
1958
|
+
});
|
|
1959
|
+
md.renderer.rules.toc_body = (tokens) => renderHeaders(
|
|
1960
|
+
resolveHeadersFromTokens(tokens, {
|
|
1961
|
+
level,
|
|
1962
|
+
shouldAllowHtml: true,
|
|
1963
|
+
shouldAllowNested,
|
|
1964
|
+
shouldEscapeText: true,
|
|
1965
|
+
slugify: slugify$1,
|
|
1966
|
+
format
|
|
1967
|
+
})
|
|
1968
|
+
);
|
|
1969
|
+
};
|
|
1970
|
+
|
|
1971
|
+
// node/plugins/markdown/setup.ts
|
|
1972
|
+
import { cssI18nContainer } from "css-i18n";
|
|
1973
|
+
import anchorPlugin from "markdown-it-anchor";
|
|
1974
|
+
import attrsPlugin from "markdown-it-attrs";
|
|
1975
|
+
import { full as emojiPlugin } from "markdown-it-emoji";
|
|
1976
|
+
import footnotePlugin from "markdown-it-footnote";
|
|
1977
|
+
import imageFigures from "markdown-it-image-figures";
|
|
1978
|
+
import TaskLists from "markdown-it-task-lists";
|
|
1979
|
+
|
|
1980
|
+
// node/plugins/markdown/plugins/link.ts
|
|
1981
|
+
import { URL as URL2 } from "node:url";
|
|
1982
|
+
var indexRE = /(^|.*\/)index.md(.*)$/i;
|
|
1983
|
+
function linkPlugin(md, externalAttrs, base) {
|
|
1984
|
+
md.renderer.rules.link_open = (tokens, idx, options, env, self) => {
|
|
1985
|
+
const token = tokens[idx];
|
|
1986
|
+
const hrefIndex = token.attrIndex("href");
|
|
1987
|
+
if (hrefIndex >= 0) {
|
|
1988
|
+
const hrefAttr = token.attrs[hrefIndex];
|
|
1989
|
+
const url = hrefAttr[1];
|
|
1990
|
+
const isExternal2 = EXTERNAL_URL_RE.test(url);
|
|
1991
|
+
if (isExternal2) {
|
|
1992
|
+
Object.entries(externalAttrs).forEach(([key, val]) => {
|
|
1993
|
+
token.attrSet(key, val);
|
|
1994
|
+
});
|
|
1995
|
+
hrefAttr[1] = url.replace(PATHNAME_PROTOCOL_RE, "");
|
|
1996
|
+
} else if (
|
|
1997
|
+
// internal anchor links
|
|
1998
|
+
!url.startsWith("#") && !url.startsWith("mailto:") && !/\.(?!html|md)\w+($|\?)/i.test(url)
|
|
1999
|
+
) {
|
|
2000
|
+
normalizeHref(hrefAttr, env);
|
|
2001
|
+
}
|
|
2002
|
+
hrefAttr[1] = hrefAttr[1].replace(/\bimport\.meta/g, "import%2Emeta").replace(/\bprocess\.env/g, "process%2Eenv");
|
|
2003
|
+
}
|
|
2004
|
+
return self.renderToken(tokens, idx, options);
|
|
2005
|
+
};
|
|
2006
|
+
function normalizeHref(hrefAttr, env) {
|
|
2007
|
+
let url = hrefAttr[1];
|
|
2008
|
+
const indexMatch = url.match(indexRE);
|
|
2009
|
+
if (indexMatch) {
|
|
2010
|
+
const [, path17, hash] = indexMatch;
|
|
2011
|
+
url = path17 + hash;
|
|
2012
|
+
} else {
|
|
2013
|
+
let cleanUrl = url.replace(/[?#].*$/, "");
|
|
2014
|
+
if (cleanUrl.endsWith(".md")) {
|
|
2015
|
+
cleanUrl = cleanUrl.replace(
|
|
2016
|
+
/\.md$/,
|
|
2017
|
+
env.cleanUrls === "disabled" ? ".html" : ""
|
|
2018
|
+
);
|
|
2019
|
+
}
|
|
2020
|
+
if (env.cleanUrls === "disabled" && !cleanUrl.endsWith(".html") && !cleanUrl.endsWith("/")) {
|
|
2021
|
+
cleanUrl += ".html";
|
|
2022
|
+
}
|
|
2023
|
+
const parsed = new URL2(url, "http://a.com");
|
|
2024
|
+
url = cleanUrl + parsed.search + parsed.hash;
|
|
2025
|
+
}
|
|
2026
|
+
if (!url.startsWith("/") && !/^\.\//.test(url))
|
|
2027
|
+
url = `./${url}`;
|
|
2028
|
+
pushLink(url.replace(/\.html$/, ""), env);
|
|
2029
|
+
if (url.startsWith("/"))
|
|
2030
|
+
url = `${base}${url}`.replace(/\/+/g, "/");
|
|
2031
|
+
hrefAttr[1] = decodeURI(url);
|
|
2032
|
+
}
|
|
2033
|
+
function pushLink(link, env) {
|
|
2034
|
+
const links = env.links || (env.links = []);
|
|
2035
|
+
links.push(link);
|
|
2036
|
+
}
|
|
2037
|
+
}
|
|
2038
|
+
|
|
2039
|
+
// node/plugins/markdown/plugins/markdown-it/container.ts
|
|
2040
|
+
import container from "markdown-it-container";
|
|
2041
|
+
|
|
2042
|
+
// node/plugins/markdown/plugins/markdown-it/preWrapper.ts
|
|
2043
|
+
function extractLang(info) {
|
|
2044
|
+
return info.trim().replace(/=(\d*)/, "").replace(/:(no-)?line-numbers(\{| |$|=\d*).*/, "").replace(/(-vue|\{| ).*$/, "").replace(/^vue-html$/, "template").replace(/^ansi$/, "");
|
|
2045
|
+
}
|
|
2046
|
+
function getAdaptiveThemeMarker(options) {
|
|
2047
|
+
return options.hasSingleTheme ? "" : " vp-adaptive-theme";
|
|
2048
|
+
}
|
|
2049
|
+
function extractTitle(info, html = false) {
|
|
2050
|
+
if (html) {
|
|
2051
|
+
return info.replace(/<!--[\s\S]*?-->/g, "").match(/data-title="(.*?)"/)?.[1] || "";
|
|
2052
|
+
}
|
|
2053
|
+
return info.match(/\[(.*)\]/)?.[1] || extractLang(info) || "txt";
|
|
2054
|
+
}
|
|
2055
|
+
function getCodeHeightLimitStyle(options, env) {
|
|
2056
|
+
const codeHeightLimit = env.frontmatter?.codeHeightLimit || options?.siteConfig?.codeHeightLimit;
|
|
2057
|
+
if (codeHeightLimit === void 0 || codeHeightLimit <= 0)
|
|
2058
|
+
return "";
|
|
2059
|
+
return `style="max-height: ${codeHeightLimit}px;"`;
|
|
2060
|
+
}
|
|
2061
|
+
function preWrapperPlugin(md, options) {
|
|
2062
|
+
const fence = md.renderer.rules.fence;
|
|
2063
|
+
md.renderer.rules.fence = (...args) => {
|
|
2064
|
+
const [tokens, idx, _, env] = args;
|
|
2065
|
+
const token = tokens[idx];
|
|
2066
|
+
token.info = token.info.replace(/\[.*\]/, "");
|
|
2067
|
+
const lang = extractLang(token.info);
|
|
2068
|
+
const rawCode = fence(...args);
|
|
2069
|
+
return `
|
|
2070
|
+
<div ${getCodeHeightLimitStyle(options, env)} class="language-${lang}${getAdaptiveThemeMarker(options)}${// eslint-disable-next-line regexp/no-unused-capturing-group
|
|
2071
|
+
/ active( |$)/.test(token.info) ? " active" : ""}">
|
|
2072
|
+
<button title="Copy Code" class="copy"></button><span class="lang">${lang}</span>${rawCode}<button class="collapse"></button>
|
|
2073
|
+
</div>`;
|
|
2074
|
+
};
|
|
2075
|
+
}
|
|
2076
|
+
|
|
2077
|
+
// node/plugins/markdown/plugins/markdown-it/container.ts
|
|
2078
|
+
function createContainer(classes, { icon, color, text: defaultTitle, langs } = {}) {
|
|
2079
|
+
return [
|
|
2080
|
+
container,
|
|
2081
|
+
classes,
|
|
2082
|
+
{
|
|
2083
|
+
render(tokens, idx) {
|
|
2084
|
+
const token = tokens[idx];
|
|
2085
|
+
const info = token.info.trim().slice(classes.length).trim();
|
|
2086
|
+
if (token.nesting === 1) {
|
|
2087
|
+
if (classes === "details") {
|
|
2088
|
+
return `<details class="${classes} custom-block">${`<summary>${info}</summary>`}
|
|
2089
|
+
`;
|
|
2090
|
+
}
|
|
2091
|
+
let iconTag = "";
|
|
2092
|
+
if (icon)
|
|
2093
|
+
iconTag = `<i class="icon ${icon}" ${color ? `style="color: ${color}"` : ""}></i>`;
|
|
2094
|
+
let title = `<span lang="en">${info || defaultTitle}</span>`;
|
|
2095
|
+
if (langs) {
|
|
2096
|
+
Object.keys(langs).forEach((lang) => {
|
|
2097
|
+
title += `<span lang="${lang}">${info || langs[lang]}</span>`;
|
|
2098
|
+
});
|
|
2099
|
+
}
|
|
2100
|
+
return `<div class="${classes} custom-block"><p class="custom-block-title">${iconTag}${title}</p>
|
|
2101
|
+
`;
|
|
2102
|
+
} else {
|
|
2103
|
+
return classes === "details" ? "</details>\n" : "</div>\n";
|
|
2104
|
+
}
|
|
2105
|
+
}
|
|
2106
|
+
}
|
|
2107
|
+
];
|
|
2108
|
+
}
|
|
2109
|
+
var defaultBlocksOptions = {
|
|
2110
|
+
tip: {
|
|
2111
|
+
text: "TIP",
|
|
2112
|
+
langs: {
|
|
2113
|
+
"zh-CN": "\u63D0\u793A"
|
|
2114
|
+
}
|
|
2115
|
+
},
|
|
2116
|
+
warning: {
|
|
2117
|
+
text: "WARNING",
|
|
2118
|
+
langs: {
|
|
2119
|
+
"zh-CN": "\u6CE8\u610F"
|
|
2120
|
+
}
|
|
2121
|
+
},
|
|
2122
|
+
danger: {
|
|
2123
|
+
text: "DANGER",
|
|
2124
|
+
langs: {
|
|
2125
|
+
"zh-CN": "\u8B66\u544A"
|
|
2126
|
+
}
|
|
2127
|
+
},
|
|
2128
|
+
info: {
|
|
2129
|
+
text: "INFO",
|
|
2130
|
+
langs: {
|
|
2131
|
+
"zh-CN": "\u4FE1\u606F"
|
|
2132
|
+
}
|
|
2133
|
+
},
|
|
2134
|
+
details: {
|
|
2135
|
+
text: "Details",
|
|
2136
|
+
langs: {
|
|
2137
|
+
"zh-CN": "\u8BE6\u60C5"
|
|
2138
|
+
}
|
|
2139
|
+
}
|
|
2140
|
+
};
|
|
2141
|
+
function containerPlugin(md, options, containerOptions = {}) {
|
|
2142
|
+
Object.keys(defaultBlocksOptions).forEach((optionKey) => {
|
|
2143
|
+
const option = {
|
|
2144
|
+
...defaultBlocksOptions[optionKey],
|
|
2145
|
+
...containerOptions[optionKey] || {}
|
|
2146
|
+
};
|
|
2147
|
+
md.use(...createContainer(optionKey, option));
|
|
2148
|
+
});
|
|
2149
|
+
md.use(...createCodeGroup(options));
|
|
2150
|
+
const languages = ["zh-CN", "en"];
|
|
2151
|
+
languages.forEach((lang) => {
|
|
2152
|
+
md.use(container, lang, {
|
|
2153
|
+
render: (tokens, idx) => tokens[idx].nesting === 1 ? `<div lang="${lang}">
|
|
2154
|
+
` : "</div>\n"
|
|
2155
|
+
});
|
|
2156
|
+
});
|
|
2157
|
+
}
|
|
2158
|
+
function createCodeGroup(options) {
|
|
2159
|
+
return [
|
|
2160
|
+
container,
|
|
2161
|
+
"code-group",
|
|
2162
|
+
{
|
|
2163
|
+
render(tokens, idx) {
|
|
2164
|
+
if (tokens[idx].nesting === 1) {
|
|
2165
|
+
const name = nanoid(5);
|
|
2166
|
+
let tabs = "";
|
|
2167
|
+
let checked = 'checked="checked"';
|
|
2168
|
+
for (let i = idx + 1; !(tokens[i].nesting === -1 && tokens[i].type === "container_code-group_close"); ++i) {
|
|
2169
|
+
const isHtml = tokens[i].type === "html_block";
|
|
2170
|
+
if (tokens[i].type === "fence" && tokens[i].tag === "code" || isHtml) {
|
|
2171
|
+
const title = extractTitle(
|
|
2172
|
+
isHtml ? tokens[i].content : tokens[i].info,
|
|
2173
|
+
isHtml
|
|
2174
|
+
);
|
|
2175
|
+
if (title) {
|
|
2176
|
+
const id = nanoid(7);
|
|
2177
|
+
tabs += `<input type="radio" name="group-${name}" id="tab-${id}" ${checked}><label for="tab-${id}">${title}</label>`;
|
|
2178
|
+
if (checked && !isHtml)
|
|
2179
|
+
tokens[i].info += " active";
|
|
2180
|
+
checked = "";
|
|
2181
|
+
}
|
|
2182
|
+
}
|
|
2183
|
+
}
|
|
2184
|
+
return `<div class="vp-code-group${getAdaptiveThemeMarker(
|
|
2185
|
+
options
|
|
2186
|
+
)}"><div class="tabs">${tabs}</div><div class="blocks">
|
|
2187
|
+
`;
|
|
2188
|
+
}
|
|
2189
|
+
return `</div></div>
|
|
2190
|
+
`;
|
|
2191
|
+
}
|
|
2192
|
+
}
|
|
2193
|
+
];
|
|
2194
|
+
}
|
|
2195
|
+
|
|
2196
|
+
// node/plugins/markdown/plugins/markdown-it/footnoteTooltip.ts
|
|
2197
|
+
function footnoteTooltipPlugin(md) {
|
|
2198
|
+
const originalFootnoteRef = md.renderer.rules.footnote_ref;
|
|
2199
|
+
const originalFootnoteOpen = md.renderer.rules.footnote_open;
|
|
2200
|
+
const originalFootnoteClose = md.renderer.rules.footnote_close;
|
|
2201
|
+
const originalFootnoteAnchor = md.renderer.rules.footnote_anchor;
|
|
2202
|
+
md.renderer.rules.footnote_ref = function(tokens, idx, options, env, self) {
|
|
2203
|
+
const originalCode = originalFootnoteRef(tokens, idx, options, env, self);
|
|
2204
|
+
const href = originalCode.match(/href="(.*?)"/)[0];
|
|
2205
|
+
const id = originalCode.match(/id="(.*?)"/)[0];
|
|
2206
|
+
return `<ValaxyFootnoteRef ${href} ${id}>${originalCode}</ValaxyFootnoteRef>`;
|
|
2207
|
+
};
|
|
2208
|
+
md.renderer.rules.footnote_open = function(tokens, idx, options, env, self) {
|
|
2209
|
+
const originalOpen = originalFootnoteOpen(tokens, idx, options, env, self);
|
|
2210
|
+
const id = originalOpen.match(/id="(.*?)"/)[0];
|
|
2211
|
+
return `<ValaxyFootnoteItem ${id}>${originalOpen}<ValaxyFootnoteContent>`;
|
|
2212
|
+
};
|
|
2213
|
+
md.renderer.rules.footnote_close = function(tokens, idx, options, env, self) {
|
|
2214
|
+
const originalClose = originalFootnoteClose(tokens, idx, options, env, self);
|
|
2215
|
+
return `</ValaxyFootnoteContent>${originalClose}</ValaxyFootnoteItem>`;
|
|
2216
|
+
};
|
|
2217
|
+
md.renderer.rules.footnote_anchor = function(tokens, idx, options, env, self) {
|
|
2218
|
+
const originalCode = originalFootnoteAnchor(tokens, idx, options, env, self);
|
|
2219
|
+
const href = originalCode.match(/href="(.*?)"/)[0];
|
|
2220
|
+
return `<ValaxyFootnoteAnchor ${href}>${originalCode}</ValaxyFootnoteAnchor>`;
|
|
2221
|
+
};
|
|
2222
|
+
}
|
|
2223
|
+
|
|
2224
|
+
// node/plugins/markdown/plugins/markdown-it/highlightLines.ts
|
|
2225
|
+
var RE = /\{([\d,-]+)\}/;
|
|
2226
|
+
function highlightLinePlugin(md) {
|
|
2227
|
+
const fence = md.renderer.rules.fence;
|
|
2228
|
+
md.renderer.rules.fence = (...args) => {
|
|
2229
|
+
const [tokens, idx] = args;
|
|
2230
|
+
const token = tokens[idx];
|
|
2231
|
+
const attr = token.attrs && token.attrs[0];
|
|
2232
|
+
let lines = null;
|
|
2233
|
+
if (!attr) {
|
|
2234
|
+
const rawInfo = token.info;
|
|
2235
|
+
if (!rawInfo || !RE.test(rawInfo))
|
|
2236
|
+
return fence(...args);
|
|
2237
|
+
const langName = rawInfo.replace(RE, "").trim();
|
|
2238
|
+
token.info = langName;
|
|
2239
|
+
lines = RE.exec(rawInfo)[1];
|
|
2240
|
+
}
|
|
2241
|
+
if (!lines) {
|
|
2242
|
+
lines = attr[0];
|
|
2243
|
+
if (!lines || !/[\d,-]+/.test(lines))
|
|
2244
|
+
return fence(...args);
|
|
2245
|
+
}
|
|
2246
|
+
token.info += ` ${lines}`;
|
|
2247
|
+
return fence(...args);
|
|
2248
|
+
};
|
|
2249
|
+
}
|
|
2250
|
+
|
|
2251
|
+
// node/plugins/markdown/plugins/markdown-it/katex.ts
|
|
2252
|
+
import katex from "katex";
|
|
2253
|
+
function isValidDelim(state, pos) {
|
|
2254
|
+
const max = state.posMax;
|
|
2255
|
+
let can_open = true;
|
|
2256
|
+
let can_close = true;
|
|
2257
|
+
const prevChar = pos > 0 ? state.src.charCodeAt(pos - 1) : -1;
|
|
2258
|
+
const nextChar = pos + 1 <= max ? state.src.charCodeAt(pos + 1) : -1;
|
|
2259
|
+
if (prevChar === 32 || prevChar === 9 || /* \t */
|
|
2260
|
+
nextChar >= 48 && nextChar <= 57) {
|
|
2261
|
+
can_close = false;
|
|
2262
|
+
}
|
|
2263
|
+
if (nextChar === 32 || nextChar === 9)
|
|
2264
|
+
can_open = false;
|
|
2265
|
+
return {
|
|
2266
|
+
can_open,
|
|
2267
|
+
can_close
|
|
2268
|
+
};
|
|
2269
|
+
}
|
|
2270
|
+
function math_inline(state, silent) {
|
|
2271
|
+
let match, token, res, pos;
|
|
2272
|
+
if (state.src[state.pos] !== "$")
|
|
2273
|
+
return false;
|
|
2274
|
+
res = isValidDelim(state, state.pos);
|
|
2275
|
+
if (!res.can_open) {
|
|
2276
|
+
if (!silent)
|
|
2277
|
+
state.pending += "$";
|
|
2278
|
+
state.pos += 1;
|
|
2279
|
+
return true;
|
|
2280
|
+
}
|
|
2281
|
+
const start = state.pos + 1;
|
|
2282
|
+
match = start;
|
|
2283
|
+
while ((match = state.src.indexOf("$", match)) !== -1) {
|
|
2284
|
+
pos = match - 1;
|
|
2285
|
+
while (state.src[pos] === "\\") pos -= 1;
|
|
2286
|
+
if ((match - pos) % 2 === 1)
|
|
2287
|
+
break;
|
|
2288
|
+
match += 1;
|
|
2289
|
+
}
|
|
2290
|
+
if (match === -1) {
|
|
2291
|
+
if (!silent)
|
|
2292
|
+
state.pending += "$";
|
|
2293
|
+
state.pos = start;
|
|
2294
|
+
return true;
|
|
2295
|
+
}
|
|
2296
|
+
if (match - start === 0) {
|
|
2297
|
+
if (!silent)
|
|
2298
|
+
state.pending += "$$";
|
|
2299
|
+
state.pos = start + 1;
|
|
2300
|
+
return true;
|
|
2301
|
+
}
|
|
2302
|
+
res = isValidDelim(state, match);
|
|
2303
|
+
if (!res.can_close) {
|
|
2304
|
+
if (!silent)
|
|
2305
|
+
state.pending += "$";
|
|
2306
|
+
state.pos = start;
|
|
2307
|
+
return true;
|
|
2308
|
+
}
|
|
2309
|
+
if (!silent) {
|
|
2310
|
+
token = state.push("math_inline", "math", 0);
|
|
2311
|
+
token.markup = "$";
|
|
2312
|
+
token.content = state.src.slice(start, match);
|
|
2313
|
+
}
|
|
2314
|
+
state.pos = match + 1;
|
|
2315
|
+
return true;
|
|
2316
|
+
}
|
|
2317
|
+
function math_block(state, start, end, silent) {
|
|
2318
|
+
let firstLine;
|
|
2319
|
+
let lastLine;
|
|
2320
|
+
let next;
|
|
2321
|
+
let lastPos;
|
|
2322
|
+
let found = false;
|
|
2323
|
+
let pos = state.bMarks[start] + state.tShift[start];
|
|
2324
|
+
let max = state.eMarks[start];
|
|
2325
|
+
if (pos + 2 > max)
|
|
2326
|
+
return false;
|
|
2327
|
+
if (state.src.slice(pos, pos + 2) !== "$$")
|
|
2328
|
+
return false;
|
|
2329
|
+
pos += 2;
|
|
2330
|
+
firstLine = state.src.slice(pos, max);
|
|
2331
|
+
if (silent)
|
|
2332
|
+
return true;
|
|
2333
|
+
if (firstLine.trim().slice(-2) === "$$") {
|
|
2334
|
+
firstLine = firstLine.trim().slice(0, -2);
|
|
2335
|
+
found = true;
|
|
2336
|
+
}
|
|
2337
|
+
for (next = start; !found; ) {
|
|
2338
|
+
next++;
|
|
2339
|
+
if (next >= end)
|
|
2340
|
+
break;
|
|
2341
|
+
pos = state.bMarks[next] + state.tShift[next];
|
|
2342
|
+
max = state.eMarks[next];
|
|
2343
|
+
if (pos < max && state.tShift[next] < state.blkIndent) {
|
|
2344
|
+
break;
|
|
2345
|
+
}
|
|
2346
|
+
if (state.src.slice(pos, max).trim().slice(-2) === "$$") {
|
|
2347
|
+
lastPos = state.src.slice(0, max).lastIndexOf("$$");
|
|
2348
|
+
lastLine = state.src.slice(pos, lastPos);
|
|
2349
|
+
found = true;
|
|
2350
|
+
}
|
|
2351
|
+
}
|
|
2352
|
+
state.line = next + 1;
|
|
2353
|
+
const token = state.push("math_block", "math", 0);
|
|
2354
|
+
token.block = true;
|
|
2355
|
+
token.content = (firstLine && firstLine.trim() ? `${firstLine}
|
|
2356
|
+
` : "") + state.getLines(start + 1, next, state.tShift[start], true) + (lastLine && lastLine.trim() ? lastLine : "");
|
|
2357
|
+
token.map = [start, state.line];
|
|
2358
|
+
token.markup = "$$";
|
|
2359
|
+
return true;
|
|
2360
|
+
}
|
|
2361
|
+
function math_plugin(md, options) {
|
|
2362
|
+
options = options || {};
|
|
2363
|
+
const katexInline = function(latex) {
|
|
2364
|
+
options.displayMode = false;
|
|
2365
|
+
try {
|
|
2366
|
+
return katex.renderToString(latex, options);
|
|
2367
|
+
} catch (error) {
|
|
2368
|
+
if (options.throwOnError)
|
|
2369
|
+
console.warn(error);
|
|
2370
|
+
return latex;
|
|
2371
|
+
}
|
|
2372
|
+
};
|
|
2373
|
+
const inlineRenderer = function(tokens, idx) {
|
|
2374
|
+
return katexInline(tokens[idx].content);
|
|
2375
|
+
};
|
|
2376
|
+
const katexBlock = function(latex) {
|
|
2377
|
+
options.displayMode = true;
|
|
2378
|
+
try {
|
|
2379
|
+
return `<p>${katex.renderToString(latex, options)}</p>`;
|
|
2380
|
+
} catch (error) {
|
|
2381
|
+
if (options.throwOnError)
|
|
2382
|
+
console.warn(error);
|
|
2383
|
+
return latex;
|
|
2384
|
+
}
|
|
2385
|
+
};
|
|
2386
|
+
const blockRenderer = function(tokens, idx) {
|
|
2387
|
+
return `${katexBlock(tokens[idx].content)}
|
|
2388
|
+
`;
|
|
2389
|
+
};
|
|
2390
|
+
md.inline.ruler.after("escape", "math_inline", math_inline);
|
|
2391
|
+
md.block.ruler.after("blockquote", "math_block", math_block, {
|
|
2392
|
+
alt: ["paragraph", "reference", "blockquote", "list"]
|
|
2393
|
+
});
|
|
2394
|
+
md.renderer.rules.math_inline = inlineRenderer;
|
|
2395
|
+
md.renderer.rules.math_block = blockRenderer;
|
|
2396
|
+
}
|
|
2397
|
+
|
|
2398
|
+
// node/plugins/markdown/plugins/markdown-it/lineNumbers.ts
|
|
2399
|
+
function lineNumberPlugin(md, enable = false) {
|
|
2400
|
+
const fence = md.renderer.rules.fence;
|
|
2401
|
+
md.renderer.rules.fence = (...args) => {
|
|
2402
|
+
const rawCode = fence(...args);
|
|
2403
|
+
const [tokens, idx] = args;
|
|
2404
|
+
const info = tokens[idx].info;
|
|
2405
|
+
if (
|
|
2406
|
+
// eslint-disable-next-line regexp/no-unused-capturing-group
|
|
2407
|
+
!enable && !/:line-numbers($| |=)/.test(info) || enable && /:no-line-numbers($| )/.test(info)
|
|
2408
|
+
) {
|
|
2409
|
+
return rawCode;
|
|
2410
|
+
}
|
|
2411
|
+
let startLineNumber = 1;
|
|
2412
|
+
const matchStartLineNumber = info.match(/=(\d*)/);
|
|
2413
|
+
if (matchStartLineNumber && matchStartLineNumber[1])
|
|
2414
|
+
startLineNumber = Number.parseInt(matchStartLineNumber[1]);
|
|
2415
|
+
const code = rawCode.slice(
|
|
2416
|
+
rawCode.indexOf("<code>"),
|
|
2417
|
+
rawCode.indexOf("</code>")
|
|
2418
|
+
);
|
|
2419
|
+
const lines = code.split("\n");
|
|
2420
|
+
const lineNumbersCode = [...Array.from({ length: lines.length })].map(
|
|
2421
|
+
(_, index) => `<span class="line-number">${index + startLineNumber}</span><br>`
|
|
2422
|
+
).join("");
|
|
2423
|
+
const lineNumbersWrapperCode = `<div class="line-numbers-wrapper" aria-hidden="true">${lineNumbersCode}</div>`;
|
|
2424
|
+
const finalCode = rawCode.replace(/<\/div>$/, `${lineNumbersWrapperCode}</div>`).replace(/"(language-[^"]*)"/, '"$1 line-numbers-mode"');
|
|
2425
|
+
return finalCode;
|
|
2426
|
+
};
|
|
2427
|
+
}
|
|
2428
|
+
|
|
2429
|
+
// node/plugins/markdown/plugins/markdown-it/snippet.ts
|
|
2430
|
+
import fs11 from "fs-extra";
|
|
2431
|
+
import path5 from "pathe";
|
|
2432
|
+
var rawPathRegexp = /^(.+?(?:\.([a-z0-9]+))?)(#[\w-]+)?(?: ?\{(\d+(?:[,-]\d+)*)? ?(\S+)?\})? ?(?:\[(.+)\])?$/;
|
|
2433
|
+
function rawPathToToken(rawPath) {
|
|
2434
|
+
const [
|
|
2435
|
+
filepath = "",
|
|
2436
|
+
extension = "",
|
|
2437
|
+
region = "",
|
|
2438
|
+
lines = "",
|
|
2439
|
+
lang = "",
|
|
2440
|
+
rawTitle = ""
|
|
2441
|
+
] = (rawPathRegexp.exec(rawPath) || []).slice(1);
|
|
2442
|
+
const title = rawTitle || filepath.split("/").pop() || "";
|
|
2443
|
+
return { filepath, extension, region, lines, lang, title };
|
|
2444
|
+
}
|
|
2445
|
+
function dedent(text) {
|
|
2446
|
+
const lines = text.split("\n");
|
|
2447
|
+
const minIndentLength = lines.reduce((acc, line) => {
|
|
2448
|
+
for (let i = 0; i < line.length; i++) {
|
|
2449
|
+
if (line[i] !== " " && line[i] !== " ")
|
|
2450
|
+
return Math.min(i, acc);
|
|
2451
|
+
}
|
|
2452
|
+
return acc;
|
|
2453
|
+
}, Number.POSITIVE_INFINITY);
|
|
2454
|
+
if (minIndentLength < Number.POSITIVE_INFINITY)
|
|
2455
|
+
return lines.map((x) => x.slice(minIndentLength)).join("\n");
|
|
2456
|
+
return text;
|
|
2457
|
+
}
|
|
2458
|
+
function testLine(line, regexp, regionName, end = false) {
|
|
2459
|
+
const [full, tag, name] = regexp.exec(line.trim()) || [];
|
|
2460
|
+
return full && tag && name === regionName && tag.match(end ? /^[Ee]nd ?[rR]egion$/ : /^[rR]egion$/);
|
|
2461
|
+
}
|
|
2462
|
+
function findRegion(lines, regionName) {
|
|
2463
|
+
const regionRegexps = [
|
|
2464
|
+
/^\/\/ ?#?((?:end)?region) ([\w*-]+)$/,
|
|
2465
|
+
// javascript, typescript, java
|
|
2466
|
+
/^\/\* ?#((?:end)?region) ([\w*-]+) ?\*\/$/,
|
|
2467
|
+
// css, less, scss
|
|
2468
|
+
/^#pragma ((?:end)?region) ([\w*-]+)$/,
|
|
2469
|
+
// C, C++
|
|
2470
|
+
/^<!-- #?((?:end)?region) ([\w*-]+) -->$/,
|
|
2471
|
+
// HTML, markdown
|
|
2472
|
+
/^#(End Region) ([\w*-]+)$/,
|
|
2473
|
+
// Visual Basic
|
|
2474
|
+
/^::#(endregion) ([\w*-]+)$/,
|
|
2475
|
+
// Bat
|
|
2476
|
+
/^# ?((?:end)?region) ([\w*-]+)$/
|
|
2477
|
+
// C#, PHP, Powershell, Python, perl & misc
|
|
2478
|
+
];
|
|
2479
|
+
let regexp = null;
|
|
2480
|
+
let start = -1;
|
|
2481
|
+
for (const [lineId, line] of lines.entries()) {
|
|
2482
|
+
if (regexp === null) {
|
|
2483
|
+
for (const reg of regionRegexps) {
|
|
2484
|
+
if (testLine(line, reg, regionName)) {
|
|
2485
|
+
start = lineId + 1;
|
|
2486
|
+
regexp = reg;
|
|
2487
|
+
break;
|
|
2488
|
+
}
|
|
2489
|
+
}
|
|
2490
|
+
} else if (testLine(line, regexp, regionName, true)) {
|
|
2491
|
+
return { start, end: lineId, regexp };
|
|
2492
|
+
}
|
|
2493
|
+
}
|
|
2494
|
+
return null;
|
|
2495
|
+
}
|
|
2496
|
+
function snippetPlugin(md, srcDir) {
|
|
2497
|
+
const parser = (state, startLine, endLine, silent) => {
|
|
2498
|
+
const CH = "<".charCodeAt(0);
|
|
2499
|
+
const pos = state.bMarks[startLine] + state.tShift[startLine];
|
|
2500
|
+
const max = state.eMarks[startLine];
|
|
2501
|
+
if (state.sCount[startLine] - state.blkIndent >= 4)
|
|
2502
|
+
return false;
|
|
2503
|
+
for (let i = 0; i < 3; ++i) {
|
|
2504
|
+
const ch = state.src.charCodeAt(pos + i);
|
|
2505
|
+
if (ch !== CH || pos + i >= max)
|
|
2506
|
+
return false;
|
|
2507
|
+
}
|
|
2508
|
+
if (silent)
|
|
2509
|
+
return true;
|
|
2510
|
+
const start = pos + 3;
|
|
2511
|
+
const end = state.skipSpacesBack(max, pos);
|
|
2512
|
+
const rawPath = state.src.slice(start, end).trim().replace(/^@/, srcDir).trim();
|
|
2513
|
+
const { filepath, extension, region, lines, lang, title } = rawPathToToken(rawPath);
|
|
2514
|
+
state.line = startLine + 1;
|
|
2515
|
+
const token = state.push("fence", "code", 0);
|
|
2516
|
+
token.info = `${lang || extension}${lines ? `{${lines}}` : ""}${title ? `[${title}]` : ""}`;
|
|
2517
|
+
const { realPath, path: _path } = state.env;
|
|
2518
|
+
const resolvedPath = path5.resolve(path5.dirname(realPath ?? _path), filepath);
|
|
2519
|
+
token.src = [resolvedPath, region.slice(1)];
|
|
2520
|
+
token.markup = "```";
|
|
2521
|
+
token.map = [startLine, startLine + 1];
|
|
2522
|
+
return true;
|
|
2523
|
+
};
|
|
2524
|
+
const fence = md.renderer.rules.fence;
|
|
2525
|
+
md.renderer.rules.fence = (...args) => {
|
|
2526
|
+
const [tokens, idx, , { includes }] = args;
|
|
2527
|
+
const token = tokens[idx];
|
|
2528
|
+
const [src, regionName] = token.src ?? [];
|
|
2529
|
+
if (!src)
|
|
2530
|
+
return fence(...args);
|
|
2531
|
+
if (includes)
|
|
2532
|
+
includes.push(src);
|
|
2533
|
+
const isAFile = fs11.statSync(src).isFile();
|
|
2534
|
+
if (!fs11.existsSync(src) || !isAFile) {
|
|
2535
|
+
token.content = isAFile ? `Code snippet path not found: ${src}` : `Invalid code snippet option`;
|
|
2536
|
+
token.info = "";
|
|
2537
|
+
return fence(...args);
|
|
2538
|
+
}
|
|
2539
|
+
let content = fs11.readFileSync(src, "utf8");
|
|
2540
|
+
if (regionName) {
|
|
2541
|
+
const lines = content.split(/\r?\n/);
|
|
2542
|
+
const region = findRegion(lines, regionName);
|
|
2543
|
+
if (region) {
|
|
2544
|
+
content = dedent(
|
|
2545
|
+
lines.slice(region.start, region.end).filter((line) => !region.regexp.test(line.trim())).join("\n")
|
|
2546
|
+
);
|
|
2547
|
+
}
|
|
2548
|
+
}
|
|
2549
|
+
token.content = content;
|
|
2550
|
+
return fence(...args);
|
|
2551
|
+
};
|
|
2552
|
+
md.block.ruler.before("fence", "snippet", parser);
|
|
2553
|
+
}
|
|
2554
|
+
|
|
2555
|
+
// node/plugins/markdown/setup.ts
|
|
2556
|
+
var defaultCodeTheme = { light: "github-light", dark: "github-dark" };
|
|
2557
|
+
async function setupMarkdownPlugins(md, options, base = "/") {
|
|
2558
|
+
const mdOptions = options?.config.markdown || {};
|
|
2559
|
+
const theme = mdOptions.theme ?? defaultCodeTheme;
|
|
2560
|
+
const hasSingleTheme = typeof theme === "string" || "name" in theme;
|
|
2561
|
+
const siteConfig = options?.config.siteConfig || {};
|
|
2562
|
+
if (mdOptions.preConfig)
|
|
2563
|
+
mdOptions.preConfig(md);
|
|
2564
|
+
md.use(highlightLinePlugin).use(preWrapperPlugin, { theme, siteConfig }).use(snippetPlugin, options?.userRoot).use(containerPlugin, {
|
|
2565
|
+
hasSingleTheme
|
|
2566
|
+
}, {
|
|
2567
|
+
...mdOptions.blocks,
|
|
2568
|
+
...mdOptions?.container
|
|
2569
|
+
}).use(cssI18nContainer, {
|
|
2570
|
+
languages: options?.config.siteConfig.languages
|
|
2571
|
+
}).use(
|
|
2572
|
+
linkPlugin,
|
|
2573
|
+
{
|
|
2574
|
+
target: "_blank",
|
|
2575
|
+
rel: "noreferrer",
|
|
2576
|
+
...mdOptions.externalLinks
|
|
2577
|
+
},
|
|
2578
|
+
base
|
|
2579
|
+
);
|
|
2580
|
+
md.use(lineNumberPlugin, mdOptions.lineNumbers);
|
|
2581
|
+
if (!mdOptions.attrs?.disable)
|
|
2582
|
+
md.use(attrsPlugin, mdOptions.attrs);
|
|
2583
|
+
md.use(emojiPlugin).use(footnotePlugin).use(footnoteTooltipPlugin);
|
|
2584
|
+
md.use(anchorPlugin, {
|
|
2585
|
+
slugify,
|
|
2586
|
+
permalink: anchorPlugin.permalink.linkInsideHeader({
|
|
2587
|
+
symbol: "​",
|
|
2588
|
+
renderAttrs: (slug, state) => {
|
|
2589
|
+
const idx = state.tokens.findIndex((token) => {
|
|
2590
|
+
const attrs = token.attrs;
|
|
2591
|
+
const id = attrs?.find((attr) => attr[0] === "id");
|
|
2592
|
+
return id && slug === id[1];
|
|
2593
|
+
});
|
|
2594
|
+
const title = state.tokens[idx + 1].content;
|
|
2595
|
+
return {
|
|
2596
|
+
"aria-label": `Permalink to "${title}"`
|
|
2597
|
+
};
|
|
2598
|
+
}
|
|
2599
|
+
}),
|
|
2600
|
+
...mdOptions.anchor
|
|
2601
|
+
});
|
|
2602
|
+
md.use(headersPlugin, {
|
|
2603
|
+
slugify,
|
|
2604
|
+
...typeof mdOptions.headers === "boolean" ? void 0 : mdOptions.headers
|
|
2605
|
+
}).use(sfcPlugin, {
|
|
2606
|
+
...mdOptions.sfc
|
|
2607
|
+
}).use(titlePlugin).use(tocPlugin, {
|
|
2608
|
+
...mdOptions.toc
|
|
2609
|
+
});
|
|
2610
|
+
md.use(math_plugin, mdOptions.katex);
|
|
2611
|
+
const vanillaLazyload = options?.config.siteConfig.vanillaLazyload || { enable: false };
|
|
2612
|
+
md.use(imageFigures, {
|
|
2613
|
+
figcaption: true,
|
|
2614
|
+
// default web performance recommended settings
|
|
2615
|
+
lazy: true,
|
|
2616
|
+
async: true,
|
|
2617
|
+
// removeSrc and classes are required by vanilla-lazyload
|
|
2618
|
+
...vanillaLazyload.enable ? {
|
|
2619
|
+
lazy: true,
|
|
2620
|
+
async: true,
|
|
2621
|
+
classes: "lazy"
|
|
2622
|
+
// when removeSrc, vite can not handle relative path
|
|
2623
|
+
// removeSrc in useVanillaLazyload onMounted
|
|
2624
|
+
// removeSrc: true,
|
|
2625
|
+
} : {},
|
|
2626
|
+
...mdOptions.imageFigures
|
|
2627
|
+
});
|
|
2628
|
+
md.use(TaskLists);
|
|
2629
|
+
if (options?.config.groupIcons) {
|
|
2630
|
+
const { groupIconMdPlugin } = await import("vitepress-plugin-group-icons");
|
|
2631
|
+
md.use(groupIconMdPlugin, {
|
|
2632
|
+
titleBar: { includeSnippet: true }
|
|
2633
|
+
});
|
|
2634
|
+
}
|
|
2635
|
+
if (mdOptions.config)
|
|
2636
|
+
mdOptions.config(md);
|
|
2637
|
+
return md;
|
|
2638
|
+
}
|
|
2639
|
+
|
|
2640
|
+
// node/plugins/markdown/transform/index.ts
|
|
2641
|
+
import Markdown from "unplugin-vue-markdown/vite";
|
|
2642
|
+
|
|
2643
|
+
// node/plugins/markdown/transform/include.ts
|
|
2644
|
+
import { slash as slash2 } from "@antfu/utils";
|
|
2645
|
+
import path7 from "pathe";
|
|
2646
|
+
|
|
2647
|
+
// node/plugins/markdown/utils/html.ts
|
|
2648
|
+
import process6 from "node:process";
|
|
2649
|
+
var KNOWN_EXTENSIONS = /* @__PURE__ */ new Set();
|
|
2650
|
+
function treatAsHtml(filename) {
|
|
2651
|
+
if (KNOWN_EXTENSIONS.size === 0) {
|
|
2652
|
+
const extraExts = typeof process6 === "object" && process6.env.VITE_EXTRA_EXTENSIONS || process6.env?.VITE_EXTRA_EXTENSIONS || "";
|
|
2653
|
+
`3g2,3gp,aac,ai,apng,au,avif,bin,bmp,cer,class,conf,crl,css,csv,dll,doc,eps,epub,exe,gif,gz,ics,ief,jar,jpe,jpeg,jpg,js,json,jsonld,m4a,man,mid,midi,mjs,mov,mp2,mp3,mp4,mpe,mpeg,mpg,mpp,oga,ogg,ogv,ogx,opus,otf,p10,p7c,p7m,p7s,pdf,png,ps,qt,roff,rtf,rtx,ser,svg,t,tif,tiff,tr,ts,tsv,ttf,txt,vtt,wav,weba,webm,webp,woff,woff2,xhtml,xml,yaml,yml,zip${extraExts && typeof extraExts === "string" ? `,${extraExts}` : ""}`.split(",").forEach((ext2) => KNOWN_EXTENSIONS.add(ext2));
|
|
2654
|
+
}
|
|
2655
|
+
const ext = filename.split(".").pop();
|
|
2656
|
+
return ext == null || !KNOWN_EXTENSIONS.has(ext.toLowerCase());
|
|
2657
|
+
}
|
|
2658
|
+
|
|
2659
|
+
// node/plugins/markdown/utils/processInclude.ts
|
|
2660
|
+
import path6 from "node:path";
|
|
2661
|
+
import fs12 from "fs-extra";
|
|
2662
|
+
function processIncludes(srcDir, src, file) {
|
|
2663
|
+
const includesRE = /<!--\s*@include:\s*(.*?)\s*-->/g;
|
|
2664
|
+
const rangeRE = /\{(\d*),(\d*)\}$/;
|
|
2665
|
+
return src.replace(includesRE, (m, m1) => {
|
|
2666
|
+
if (!m1.length)
|
|
2667
|
+
return m;
|
|
2668
|
+
const range = m1.match(rangeRE);
|
|
2669
|
+
range && (m1 = m1.slice(0, -range[0].length));
|
|
2670
|
+
const atPresent = m1[0] === "@";
|
|
2671
|
+
try {
|
|
2672
|
+
const includePath = atPresent ? path6.join(srcDir, m1.slice(m1[1] === "/" ? 2 : 1)) : path6.join(path6.dirname(file), m1);
|
|
2673
|
+
let content = fs12.readFileSync(includePath, "utf-8");
|
|
2674
|
+
if (range) {
|
|
2675
|
+
const [, startLine, endLine] = range;
|
|
2676
|
+
const lines = content.split(/\r?\n/);
|
|
2677
|
+
content = lines.slice(
|
|
2678
|
+
startLine ? Number.parseInt(startLine, 10) - 1 : void 0,
|
|
2679
|
+
endLine ? Number.parseInt(endLine, 10) : void 0
|
|
2680
|
+
).join("\n");
|
|
2681
|
+
}
|
|
2682
|
+
content = `<!-- @included: ${m1} -->
|
|
2683
|
+
${content}`;
|
|
2684
|
+
return processIncludes(srcDir, content, includePath);
|
|
2685
|
+
} catch (error) {
|
|
2686
|
+
return m;
|
|
2687
|
+
}
|
|
2688
|
+
});
|
|
2689
|
+
}
|
|
2690
|
+
|
|
2691
|
+
// node/plugins/markdown/transform/include.ts
|
|
2692
|
+
var includedRE = /<!--\s*@included:\s*(.*?)\s*-->/g;
|
|
2693
|
+
function createTransformIncludes(options) {
|
|
2694
|
+
const srcDir = options.userRoot;
|
|
2695
|
+
return (code, id) => {
|
|
2696
|
+
const fileOrig = id;
|
|
2697
|
+
return processIncludes(srcDir, code, fileOrig);
|
|
2698
|
+
};
|
|
2699
|
+
}
|
|
2700
|
+
function resolveTransformIncludes(code, id, options) {
|
|
2701
|
+
const includes = [];
|
|
2702
|
+
const dir = path7.dirname(id);
|
|
2703
|
+
code = code.replace(includedRE, (m, m1) => {
|
|
2704
|
+
const atPresent = m1.startsWith("@");
|
|
2705
|
+
const includePath = atPresent ? path7.resolve(options.userRoot, m1.slice(m1[1] === "/" ? 2 : 1)) : path7.join(dir, m1);
|
|
2706
|
+
includes.push(slash2(includePath));
|
|
2707
|
+
return "";
|
|
2708
|
+
});
|
|
2709
|
+
return {
|
|
2710
|
+
code,
|
|
2711
|
+
includes
|
|
2712
|
+
};
|
|
2713
|
+
}
|
|
2714
|
+
|
|
2715
|
+
// node/plugins/markdown/transform/mermaid.ts
|
|
2716
|
+
import * as base64 from "js-base64";
|
|
2717
|
+
function transformMermaid(md) {
|
|
2718
|
+
md = md.replace(/^````txt\n```mermaid/gm, "````txt\n\\`\\`\\`mermaid");
|
|
2719
|
+
md = md.replace(/^```mermaid\s*?(\{.*?\})?\n([\s\S]+?)\n```/gm, (full, options = "", code = "") => {
|
|
2720
|
+
code = code.trim();
|
|
2721
|
+
options = options.trim() || "{}";
|
|
2722
|
+
const encoded = base64.encode(code, true);
|
|
2723
|
+
return `<ValaxyMermaid :code="'${encoded}'" v-bind="${options}" />`;
|
|
2724
|
+
});
|
|
2725
|
+
md = md.replace(/^````txt\n\\`\\`\\`mermaid/gm, "````txt\n```mermaid");
|
|
2726
|
+
return md;
|
|
2727
|
+
}
|
|
2728
|
+
|
|
2729
|
+
// node/plugins/markdown/transform/index.ts
|
|
2730
|
+
async function createMarkdownPlugin(options) {
|
|
2731
|
+
const mdOptions = options?.config.markdown || {};
|
|
2732
|
+
const theme = mdOptions.theme ?? defaultCodeTheme;
|
|
2733
|
+
const transformIncludes = createTransformIncludes(options);
|
|
2734
|
+
const mdItHighlight = await highlight(theme, mdOptions);
|
|
2735
|
+
return Markdown({
|
|
2736
|
+
include: [/\.md$/],
|
|
2737
|
+
wrapperClasses: "",
|
|
2738
|
+
// headEnabled: false,
|
|
2739
|
+
frontmatter: true,
|
|
2740
|
+
exportFrontmatter: false,
|
|
2741
|
+
frontmatterOptions: { grayMatterOptions: matterOptions },
|
|
2742
|
+
// v-pre
|
|
2743
|
+
escapeCodeTagInterpolation: true,
|
|
2744
|
+
markdownItOptions: {
|
|
2745
|
+
quotes: `""''`,
|
|
2746
|
+
html: true,
|
|
2747
|
+
xhtmlOut: true,
|
|
2748
|
+
linkify: true,
|
|
2749
|
+
highlight: mdItHighlight,
|
|
2750
|
+
...mdOptions?.markdownItOptions
|
|
2751
|
+
},
|
|
2752
|
+
async markdownItSetup(mdIt) {
|
|
2753
|
+
mdIt.linkify.set({ fuzzyLink: false });
|
|
2754
|
+
await setupMarkdownPlugins(mdIt, options);
|
|
2755
|
+
options?.config.markdown?.markdownItSetup?.(mdIt);
|
|
2756
|
+
function initEnv(md) {
|
|
2757
|
+
md.core.ruler.push("valaxy_md_env", (state) => {
|
|
2758
|
+
options.env = state.env;
|
|
2759
|
+
});
|
|
2760
|
+
}
|
|
2761
|
+
mdIt.use(initEnv);
|
|
2762
|
+
},
|
|
2763
|
+
transforms: {
|
|
2764
|
+
before(code, id) {
|
|
2765
|
+
code = transformMermaid(code);
|
|
2766
|
+
code = transformIncludes(code, id);
|
|
2767
|
+
return code;
|
|
2768
|
+
}
|
|
2769
|
+
},
|
|
2770
|
+
...mdOptions
|
|
2771
|
+
});
|
|
2772
|
+
}
|
|
2773
|
+
|
|
2774
|
+
// node/plugins/patchTransform.ts
|
|
2775
|
+
import { objectEntries } from "@antfu/utils";
|
|
2776
|
+
function createFixPlugins(options) {
|
|
2777
|
+
const define = objectEntries(getDefine(options));
|
|
2778
|
+
return [
|
|
2779
|
+
{
|
|
2780
|
+
name: "valaxy:flags",
|
|
2781
|
+
enforce: "pre",
|
|
2782
|
+
transform(code, id) {
|
|
2783
|
+
if (id.match(/\.vue($|\?)/)) {
|
|
2784
|
+
const original = code;
|
|
2785
|
+
define.forEach(([from, to]) => {
|
|
2786
|
+
code = code.replace(new RegExp(from, "g"), to);
|
|
2787
|
+
});
|
|
2788
|
+
if (original !== code)
|
|
2789
|
+
return code;
|
|
2790
|
+
}
|
|
2791
|
+
}
|
|
2792
|
+
}
|
|
2793
|
+
];
|
|
2794
|
+
}
|
|
2795
|
+
|
|
2796
|
+
// node/plugins/setupClient.ts
|
|
2797
|
+
import { existsSync } from "node:fs";
|
|
2798
|
+
import { join as join4, resolve as resolve7 } from "node:path";
|
|
2799
|
+
import { slash as slash3, uniq as uniq4 } from "@antfu/utils";
|
|
2800
|
+
function createClientSetupPlugin({ clientRoot, themeRoot, userRoot: userRoot2 }) {
|
|
2801
|
+
const setupEntry = slash3(resolve7(clientRoot, "setup"));
|
|
2802
|
+
return {
|
|
2803
|
+
name: "valaxy:setup",
|
|
2804
|
+
enforce: "pre",
|
|
2805
|
+
async transform(code, id) {
|
|
2806
|
+
if (id.startsWith(setupEntry)) {
|
|
2807
|
+
const name = id.slice(setupEntry.length + 1).replace(/\?.*$/, "");
|
|
2808
|
+
const imports = [];
|
|
2809
|
+
const injections = [];
|
|
2810
|
+
const setups = uniq4([
|
|
2811
|
+
themeRoot,
|
|
2812
|
+
userRoot2
|
|
2813
|
+
]).map((i) => join4(i, "setup", name));
|
|
2814
|
+
setups.forEach((path17, idx) => {
|
|
2815
|
+
if (!existsSync(path17))
|
|
2816
|
+
return;
|
|
2817
|
+
imports.push(`import __n${idx} from '${toAtFS(path17)}'`);
|
|
2818
|
+
let fn = `__n${idx}`;
|
|
2819
|
+
if (/\binjection_return\b/.test(code))
|
|
2820
|
+
fn = `injection_return = ${fn}`;
|
|
2821
|
+
if (/\binjection_arg\b/.test(code))
|
|
2822
|
+
fn += "(injection_arg)";
|
|
2823
|
+
else
|
|
2824
|
+
fn += "()";
|
|
2825
|
+
injections.push(
|
|
2826
|
+
`// ${path17}`,
|
|
2827
|
+
fn
|
|
2828
|
+
);
|
|
2829
|
+
});
|
|
2830
|
+
code = code.replace("/* __imports__ */", imports.join("\n"));
|
|
2831
|
+
code = code.replace("/* __injections__ */", injections.join("\n"));
|
|
2832
|
+
return code;
|
|
2833
|
+
}
|
|
2834
|
+
return null;
|
|
2835
|
+
}
|
|
2836
|
+
};
|
|
2837
|
+
}
|
|
2838
|
+
|
|
2839
|
+
// node/plugins/unocss.ts
|
|
2840
|
+
import { resolve as resolve9 } from "node:path";
|
|
2841
|
+
import defu3 from "defu";
|
|
2842
|
+
import fs14 from "fs-extra";
|
|
2843
|
+
import { createJiti as createJiti3 } from "jiti";
|
|
2844
|
+
import {
|
|
2845
|
+
presetAttributify,
|
|
2846
|
+
presetIcons,
|
|
2847
|
+
presetTypography,
|
|
2848
|
+
presetUno,
|
|
2849
|
+
transformerDirectives,
|
|
2850
|
+
transformerVariantGroup
|
|
2851
|
+
} from "unocss";
|
|
2852
|
+
|
|
2853
|
+
// node/plugins/setupNode.ts
|
|
2854
|
+
import { resolve as resolve8 } from "node:path";
|
|
2855
|
+
import { isObject } from "@antfu/utils";
|
|
2856
|
+
import fs13 from "fs-extra";
|
|
2857
|
+
import { createJiti as createJiti2 } from "jiti";
|
|
2858
|
+
var jiti2 = createJiti2(import.meta.url);
|
|
2859
|
+
function deepMerge(a, b, rootPath = "") {
|
|
2860
|
+
a = { ...a };
|
|
2861
|
+
Object.keys(b).forEach((key) => {
|
|
2862
|
+
if (isObject(a[key]))
|
|
2863
|
+
a[key] = deepMerge(a[key], b[key], rootPath ? `${rootPath}.${key}` : key);
|
|
2864
|
+
else if (Array.isArray(a[key]))
|
|
2865
|
+
a[key] = [...a[key], ...b[key]];
|
|
2866
|
+
else
|
|
2867
|
+
a[key] = b[key];
|
|
2868
|
+
});
|
|
2869
|
+
return a;
|
|
2870
|
+
}
|
|
2871
|
+
async function loadSetups(roots, name, arg, initial, merge = true) {
|
|
2872
|
+
let returns = initial;
|
|
2873
|
+
for (const root of roots) {
|
|
2874
|
+
const path17 = resolve8(root, "setup", name);
|
|
2875
|
+
if (fs13.existsSync(path17)) {
|
|
2876
|
+
const setup = await jiti2.import(path17, { default: true });
|
|
2877
|
+
const result = await setup(arg);
|
|
2878
|
+
if (result !== null) {
|
|
2879
|
+
returns = merge ? deepMerge(returns, result) : result;
|
|
2880
|
+
}
|
|
2881
|
+
}
|
|
2882
|
+
}
|
|
2883
|
+
return returns;
|
|
2884
|
+
}
|
|
2885
|
+
|
|
2886
|
+
// node/plugins/unocss.ts
|
|
2887
|
+
var jiti3 = createJiti3(import.meta.url);
|
|
2888
|
+
async function createSafelist(options) {
|
|
2889
|
+
const { config } = options;
|
|
2890
|
+
const safeIcons = [
|
|
2891
|
+
"i-ri-clipboard-line",
|
|
2892
|
+
"i-ri-archive-line",
|
|
2893
|
+
"i-ri-folder-2-line",
|
|
2894
|
+
"i-ri-price-tag-3-line",
|
|
2895
|
+
"i-ri-cloud-line"
|
|
2896
|
+
];
|
|
2897
|
+
const safelist = [
|
|
2898
|
+
"animate-fade-in",
|
|
2899
|
+
"m-auto",
|
|
2900
|
+
"text-left",
|
|
2901
|
+
"rotate-y-180",
|
|
2902
|
+
...safeIcons,
|
|
2903
|
+
...options.config.unocss?.safelist ?? []
|
|
2904
|
+
];
|
|
2905
|
+
if (options.mode === "dev") {
|
|
2906
|
+
const { safelist: devtoolsSafelist = [] } = await import("@valaxyjs/devtools");
|
|
2907
|
+
safelist.push(
|
|
2908
|
+
...devtoolsSafelist
|
|
2909
|
+
);
|
|
2910
|
+
}
|
|
2911
|
+
const siteConfig = config.siteConfig;
|
|
2912
|
+
if (config.markdown?.blocks) {
|
|
2913
|
+
const blocks = config.markdown.blocks;
|
|
2914
|
+
Object.entries(blocks).forEach(([_key, block]) => {
|
|
2915
|
+
if (block.icon)
|
|
2916
|
+
safelist.push(block.icon);
|
|
2917
|
+
});
|
|
2918
|
+
}
|
|
2919
|
+
if (siteConfig.social?.length)
|
|
2920
|
+
siteConfig.social.forEach((item) => safelist.push(item?.icon || ""));
|
|
2921
|
+
const methods = siteConfig.sponsor?.methods || [];
|
|
2922
|
+
if (methods.length)
|
|
2923
|
+
methods.forEach((item) => safelist.push(item?.icon || ""));
|
|
2924
|
+
return safelist;
|
|
2925
|
+
}
|
|
2926
|
+
async function createUnocssConfig(options) {
|
|
2927
|
+
const { config: pluginOptions } = options;
|
|
2928
|
+
const unocssConfig = {
|
|
2929
|
+
shortcuts: [
|
|
2930
|
+
["flex-center", "flex items-center justify-center"],
|
|
2931
|
+
["inline-flex-center", "inline-flex items-center justify-center"],
|
|
2932
|
+
["btn", "px-4 py-1 rounded inline-block bg-$va-c-primary text-white cursor-pointer transition hover:bg-$va-c-primary-light disabled:cursor-default disabled:bg-gray-600 disabled:opacity-50"],
|
|
2933
|
+
["va-card", "shadow hover:shadow-lg bg-$va-c-bg-light"]
|
|
2934
|
+
],
|
|
2935
|
+
presets: [
|
|
2936
|
+
presetUno(pluginOptions.unocssPresets?.uno),
|
|
2937
|
+
presetAttributify(pluginOptions.unocssPresets?.attributify),
|
|
2938
|
+
presetIcons({
|
|
2939
|
+
scale: 1.2,
|
|
2940
|
+
// warn: true,
|
|
2941
|
+
...pluginOptions.unocssPresets?.icons
|
|
2942
|
+
}),
|
|
2943
|
+
presetTypography(pluginOptions.unocssPresets?.typography)
|
|
2944
|
+
// web fonts is so big, so we disable it, let the user decide
|
|
2945
|
+
// presetWebFonts({
|
|
2946
|
+
// fonts: {
|
|
2947
|
+
// serif: [
|
|
2948
|
+
// {
|
|
2949
|
+
// name: 'Noto Serif SC',
|
|
2950
|
+
// weights: [900],
|
|
2951
|
+
// },
|
|
2952
|
+
// ],
|
|
2953
|
+
// },
|
|
2954
|
+
// }),
|
|
2955
|
+
],
|
|
2956
|
+
rules: [
|
|
2957
|
+
// more see 'valaxy/client/styles/global/helper.scss'
|
|
2958
|
+
["font-serif", {
|
|
2959
|
+
"font-family": "var(--va-font-serif)"
|
|
2960
|
+
}],
|
|
2961
|
+
["font-sans", {
|
|
2962
|
+
"font-family": "var(--va-font-sans)"
|
|
2963
|
+
}],
|
|
2964
|
+
["font-mono", {
|
|
2965
|
+
"font-family": "var(--va-font-mono)"
|
|
2966
|
+
}]
|
|
2967
|
+
],
|
|
2968
|
+
transformers: [
|
|
2969
|
+
transformerDirectives(),
|
|
2970
|
+
transformerVariantGroup()
|
|
2971
|
+
],
|
|
2972
|
+
safelist: await createSafelist(options)
|
|
2973
|
+
};
|
|
2974
|
+
return unocssConfig;
|
|
2975
|
+
}
|
|
2976
|
+
async function createUnocssPlugin(options) {
|
|
2977
|
+
const UnoCSS = await import("unocss/vite").then((r) => r.default);
|
|
2978
|
+
const { unocss: unoOptions } = options.config;
|
|
2979
|
+
const defaultConfig = await createUnocssConfig(options);
|
|
2980
|
+
const { themeRoot, clientRoot, roots } = options;
|
|
2981
|
+
const unoConfigFiles = ["uno.config.ts", "unocss.config.ts"];
|
|
2982
|
+
const configFiles = [];
|
|
2983
|
+
const dirs = [themeRoot, clientRoot];
|
|
2984
|
+
dirs.forEach(
|
|
2985
|
+
(dir) => unoConfigFiles.forEach(
|
|
2986
|
+
(file) => configFiles.push(resolve9(dir, file))
|
|
2987
|
+
)
|
|
2988
|
+
);
|
|
2989
|
+
let config = {};
|
|
2990
|
+
const configDeps = [];
|
|
2991
|
+
for (const configFile of configFiles) {
|
|
2992
|
+
if (await fs14.exists(configFile)) {
|
|
2993
|
+
const uConfig = await jiti3.import(configFile, { default: true });
|
|
2994
|
+
config = defu3(config, uConfig);
|
|
2995
|
+
configDeps.push(configFile);
|
|
2996
|
+
}
|
|
2997
|
+
}
|
|
2998
|
+
config = await loadSetups(roots, "unocss.ts", {}, config, true);
|
|
2999
|
+
return UnoCSS({
|
|
3000
|
+
configDeps,
|
|
3001
|
+
configFile: false,
|
|
3002
|
+
...defu3(unoOptions || {}, config, defaultConfig)
|
|
3003
|
+
});
|
|
3004
|
+
}
|
|
3005
|
+
|
|
3006
|
+
// node/plugins/valaxy/index.ts
|
|
3007
|
+
import consola12 from "consola";
|
|
3008
|
+
import { colors as colors11 } from "consola/utils";
|
|
3009
|
+
import fs19 from "fs-extra";
|
|
3010
|
+
import { join as join7, relative, resolve as resolve10 } from "pathe";
|
|
3011
|
+
|
|
3012
|
+
// node/virtual/addons.ts
|
|
3013
|
+
import fs15 from "fs-extra";
|
|
3014
|
+
import pascalCase from "pascalcase";
|
|
3015
|
+
import { join as join5 } from "pathe";
|
|
3016
|
+
var templateAddons = {
|
|
3017
|
+
id: "/@valaxyjs/addons",
|
|
3018
|
+
async getContent(options) {
|
|
3019
|
+
const globalAddonComponents = options.addons.filter((v) => v.global).filter((v) => fs15.existsSync(join5(v.root, "./App.vue")));
|
|
3020
|
+
const spliceImportName = (str) => `Addon${pascalCase(str)}App`;
|
|
3021
|
+
const imports = globalAddonComponents.map((addon) => `import ${spliceImportName(addon.name)} from "${addon.name}/App.vue"`).join("\n");
|
|
3022
|
+
const components = globalAddonComponents.map((addon) => `{ component: ${spliceImportName(addon.name)}, props: ${JSON.stringify(addon.props)} }`).join(",");
|
|
3023
|
+
return `${imports}
|
|
3024
|
+
export default [${components}]`;
|
|
3025
|
+
}
|
|
3026
|
+
};
|
|
3027
|
+
|
|
3028
|
+
// node/virtual/config.ts
|
|
3029
|
+
var templateConfig = {
|
|
3030
|
+
id: "/@valaxyjs/config",
|
|
3031
|
+
async getContent(options) {
|
|
3032
|
+
const routes = options.redirects.map((redirect) => {
|
|
3033
|
+
return {
|
|
3034
|
+
path: redirect.from,
|
|
3035
|
+
redirect: redirect.to
|
|
3036
|
+
};
|
|
3037
|
+
});
|
|
3038
|
+
options.config.runtimeConfig.redirects = {
|
|
3039
|
+
useVueRouter: isProd() ? options.config.siteConfig.redirects.useVueRouter : true,
|
|
3040
|
+
redirectRoutes: routes
|
|
3041
|
+
};
|
|
3042
|
+
return `export default ${JSON.stringify(JSON.stringify(options.config))}`;
|
|
3043
|
+
}
|
|
3044
|
+
};
|
|
3045
|
+
|
|
3046
|
+
// node/virtual/locales.ts
|
|
3047
|
+
import fs16 from "fs-extra";
|
|
3048
|
+
var templateLocales = {
|
|
3049
|
+
id: "/@valaxyjs/locales",
|
|
3050
|
+
async getContent({ roots }) {
|
|
3051
|
+
const imports = [
|
|
3052
|
+
'import { createDefu } from "defu"',
|
|
3053
|
+
'const messages = { "zh-CN": {}, en: {} }',
|
|
3054
|
+
`
|
|
3055
|
+
const replaceArrMerge = createDefu((obj, key, value) => {
|
|
3056
|
+
if (key && obj[key] && Array.isArray(obj[key]) && Array.isArray(value)) {
|
|
3057
|
+
obj[key] = value
|
|
3058
|
+
return true
|
|
3059
|
+
}
|
|
3060
|
+
})
|
|
3061
|
+
`
|
|
3062
|
+
];
|
|
3063
|
+
const languages = ["zh-CN", "en"];
|
|
3064
|
+
roots.forEach((root, i) => {
|
|
3065
|
+
languages.forEach((lang) => {
|
|
3066
|
+
const langYml = `${root}/locales/${lang}.yml`;
|
|
3067
|
+
if (fs16.existsSync(langYml) && fs16.readFileSync(langYml, "utf-8")) {
|
|
3068
|
+
const varName = lang.replace("-", "") + i;
|
|
3069
|
+
imports.unshift(`import ${varName} from "${toAtFS(langYml)}"`);
|
|
3070
|
+
imports.push(`messages['${lang}'] = replaceArrMerge(${varName}, messages['${lang}'])`);
|
|
3071
|
+
}
|
|
3072
|
+
});
|
|
3073
|
+
});
|
|
3074
|
+
imports.push("export default messages");
|
|
3075
|
+
return imports.join("\n");
|
|
3076
|
+
}
|
|
3077
|
+
};
|
|
3078
|
+
|
|
3079
|
+
// node/virtual/styles.ts
|
|
3080
|
+
import { existsSync as existsSync2 } from "node:fs";
|
|
3081
|
+
import { join as join6 } from "node:path";
|
|
3082
|
+
var templateStyles = {
|
|
3083
|
+
id: "/@valaxyjs/styles",
|
|
3084
|
+
async getContent({ clientRoot, roots, config }) {
|
|
3085
|
+
function resolveUrlOfClient(name) {
|
|
3086
|
+
return toAtFS(join6(clientRoot, name));
|
|
3087
|
+
}
|
|
3088
|
+
const imports = [];
|
|
3089
|
+
if (config.features?.katex) {
|
|
3090
|
+
imports.push(`import "${await resolveImportUrl("katex/dist/katex.min.css")}"`);
|
|
3091
|
+
imports.push(`import "${resolveUrlOfClient("styles/third/katex.scss")}"`);
|
|
3092
|
+
}
|
|
3093
|
+
for (const root of roots) {
|
|
3094
|
+
const styles = [
|
|
3095
|
+
join6(root, "styles", "index.ts"),
|
|
3096
|
+
join6(root, "styles", "index.css"),
|
|
3097
|
+
join6(root, "styles", "index.scss")
|
|
3098
|
+
];
|
|
3099
|
+
for (const style of styles) {
|
|
3100
|
+
if (existsSync2(style)) {
|
|
3101
|
+
imports.push(`import "${toAtFS(style)}"`);
|
|
3102
|
+
continue;
|
|
3103
|
+
}
|
|
3104
|
+
}
|
|
3105
|
+
}
|
|
3106
|
+
imports.unshift(`import "${await resolveImportUrl("@unocss/reset/tailwind-compat.css")}"`);
|
|
3107
|
+
return imports.join("\n");
|
|
3108
|
+
}
|
|
3109
|
+
};
|
|
3110
|
+
|
|
3111
|
+
// node/virtual/index.ts
|
|
3112
|
+
var templates = [
|
|
3113
|
+
templateAddons,
|
|
3114
|
+
templateConfig,
|
|
3115
|
+
templateLocales,
|
|
3116
|
+
templateStyles
|
|
3117
|
+
];
|
|
3118
|
+
|
|
3119
|
+
// node/plugins/markdown/markdownToVue.ts
|
|
3120
|
+
import _debug2 from "debug";
|
|
3121
|
+
import { LRUCache } from "lru-cache";
|
|
3122
|
+
import path11 from "pathe";
|
|
3123
|
+
|
|
3124
|
+
// node/plugins/markdown/transform/code-block.ts
|
|
3125
|
+
function handleCodeHeightLimit(mainContentMd, options, codeHeightLimit) {
|
|
3126
|
+
if (typeof codeHeightLimit !== "number" || codeHeightLimit <= 0)
|
|
3127
|
+
return mainContentMd;
|
|
3128
|
+
const siteConfigLimit = options.config.siteConfig.codeHeightLimit;
|
|
3129
|
+
mainContentMd = mainContentMd.replaceAll(/<div.+class="language-\w+">/g, (matchStr) => {
|
|
3130
|
+
if (siteConfigLimit !== void 0 && siteConfigLimit > 0)
|
|
3131
|
+
matchStr = matchStr.replace(/\d+/, codeHeightLimit.toString());
|
|
3132
|
+
else matchStr = `${matchStr.slice(0, 5)}style="max-height: ${codeHeightLimit}px;"${matchStr.slice(5)}`;
|
|
3133
|
+
return matchStr;
|
|
3134
|
+
});
|
|
3135
|
+
return mainContentMd;
|
|
3136
|
+
}
|
|
3137
|
+
function createTransformCodeBlock(options) {
|
|
3138
|
+
return (code) => {
|
|
3139
|
+
const { frontmatter = {} } = options.env;
|
|
3140
|
+
return handleCodeHeightLimit(code, options, frontmatter.codeHeightLimit);
|
|
3141
|
+
};
|
|
3142
|
+
}
|
|
3143
|
+
|
|
3144
|
+
// node/plugins/markdown/transform/dead-links.ts
|
|
3145
|
+
import { slash as slash4 } from "@antfu/utils";
|
|
3146
|
+
import fs17 from "fs-extra";
|
|
3147
|
+
import path8 from "pathe";
|
|
3148
|
+
function createScanDeadLinks(options) {
|
|
3149
|
+
const srcDir = path8.resolve(options.userRoot, "pages");
|
|
3150
|
+
const { ignoreDeadLinks } = options.config;
|
|
3151
|
+
const publicDir = options.config.vite?.publicDir || "public";
|
|
3152
|
+
return (code, id) => {
|
|
3153
|
+
const { links = [] } = options.env;
|
|
3154
|
+
const fileOrig = id;
|
|
3155
|
+
const file = id;
|
|
3156
|
+
const deadLinks = [];
|
|
3157
|
+
const recordDeadLink = (url) => {
|
|
3158
|
+
deadLinks.push({ url, file: path8.relative(srcDir, fileOrig) });
|
|
3159
|
+
};
|
|
3160
|
+
function shouldIgnoreDeadLink(url) {
|
|
3161
|
+
if (!ignoreDeadLinks)
|
|
3162
|
+
return false;
|
|
3163
|
+
if (ignoreDeadLinks === true)
|
|
3164
|
+
return true;
|
|
3165
|
+
if (ignoreDeadLinks === "localhostLinks")
|
|
3166
|
+
return url.replace(EXTERNAL_URL_RE, "").startsWith("//localhost");
|
|
3167
|
+
return ignoreDeadLinks.some((ignore) => {
|
|
3168
|
+
if (typeof ignore === "string")
|
|
3169
|
+
return url === ignore;
|
|
3170
|
+
if (ignore instanceof RegExp)
|
|
3171
|
+
return ignore.test(url);
|
|
3172
|
+
if (typeof ignore === "function")
|
|
3173
|
+
return ignore(url);
|
|
3174
|
+
return false;
|
|
3175
|
+
});
|
|
3176
|
+
}
|
|
3177
|
+
if (links) {
|
|
3178
|
+
const dir = path8.dirname(file);
|
|
3179
|
+
for (let url of links) {
|
|
3180
|
+
const { pathname } = new URL(url, "http://a.com");
|
|
3181
|
+
if (!treatAsHtml(pathname))
|
|
3182
|
+
continue;
|
|
3183
|
+
url = url.replace(/[?#].*$/, "").replace(/\.(html|md)$/, "");
|
|
3184
|
+
if (url.endsWith("/"))
|
|
3185
|
+
url += `index`;
|
|
3186
|
+
const resolved = decodeURIComponent(
|
|
3187
|
+
slash4(
|
|
3188
|
+
url.startsWith("/") ? url.slice(1) : path8.relative(srcDir, path8.resolve(dir, url))
|
|
3189
|
+
)
|
|
3190
|
+
// /index => /
|
|
3191
|
+
).replace(/\/index$/, "");
|
|
3192
|
+
if (!options.pages.includes(resolved) && !fs17.existsSync(path8.resolve(dir, publicDir, `${resolved}.html`)) && !shouldIgnoreDeadLink(url)) {
|
|
3193
|
+
recordDeadLink(url);
|
|
3194
|
+
}
|
|
3195
|
+
}
|
|
3196
|
+
}
|
|
3197
|
+
return deadLinks;
|
|
3198
|
+
};
|
|
3199
|
+
}
|
|
3200
|
+
|
|
3201
|
+
// node/utils/encrypt.ts
|
|
3202
|
+
import { webcrypto as webcrypto2 } from "node:crypto";
|
|
3203
|
+
function getKeyMaterial(password) {
|
|
3204
|
+
const enc = new TextEncoder();
|
|
3205
|
+
return webcrypto2.subtle.importKey(
|
|
3206
|
+
"raw",
|
|
3207
|
+
enc.encode(password),
|
|
3208
|
+
"PBKDF2",
|
|
3209
|
+
false,
|
|
3210
|
+
["deriveBits", "deriveKey"]
|
|
3211
|
+
);
|
|
3212
|
+
}
|
|
3213
|
+
function getKey(keyMaterial, salt) {
|
|
3214
|
+
return webcrypto2.subtle.deriveKey(
|
|
3215
|
+
{
|
|
3216
|
+
name: "PBKDF2",
|
|
3217
|
+
salt,
|
|
3218
|
+
iterations: 1e5,
|
|
3219
|
+
hash: "SHA-256"
|
|
3220
|
+
},
|
|
3221
|
+
keyMaterial,
|
|
3222
|
+
{
|
|
3223
|
+
name: "AES-CBC",
|
|
3224
|
+
length: 256
|
|
3225
|
+
},
|
|
3226
|
+
true,
|
|
3227
|
+
["encrypt", "decrypt"]
|
|
3228
|
+
);
|
|
3229
|
+
}
|
|
3230
|
+
async function encryptContent(content, options) {
|
|
3231
|
+
const { password, iv, salt } = options;
|
|
3232
|
+
const keyMaterial = await getKeyMaterial(password);
|
|
3233
|
+
const key = await getKey(keyMaterial, salt);
|
|
3234
|
+
const enc = new TextEncoder();
|
|
3235
|
+
const ciphertextData = await webcrypto2.subtle.encrypt(
|
|
3236
|
+
{
|
|
3237
|
+
name: "AES-CBC",
|
|
3238
|
+
iv
|
|
3239
|
+
},
|
|
3240
|
+
key,
|
|
3241
|
+
enc.encode(content)
|
|
3242
|
+
);
|
|
3243
|
+
return String.fromCharCode(...new Uint8Array(ciphertextData));
|
|
3244
|
+
}
|
|
3245
|
+
|
|
3246
|
+
// node/plugins/markdown/transform/encrypt.ts
|
|
3247
|
+
function createTransformEncrypt(options) {
|
|
3248
|
+
const { config: { siteConfig: { encrypt } } } = options;
|
|
3249
|
+
return async (code, _id, pageData) => {
|
|
3250
|
+
const { frontmatter = {} } = pageData;
|
|
3251
|
+
if (encrypt.enable) {
|
|
3252
|
+
let getValaxyDecryptTemplate2 = function(options2) {
|
|
3253
|
+
return [
|
|
3254
|
+
"<ClientOnly>",
|
|
3255
|
+
`<ValaxyDecrypt :encrypted-content="${options2.encryptedContent}" hint="${options2.hint}" />`,
|
|
3256
|
+
"</ClientOnly>"
|
|
3257
|
+
].join("");
|
|
3258
|
+
};
|
|
3259
|
+
var getValaxyDecryptTemplate = getValaxyDecryptTemplate2;
|
|
3260
|
+
const encryptRegexp = /<!-- valaxy-encrypt-start:(?<password>\w+) -->(?<content>.*?)<!-- valaxy-encrypt-end -->/gs;
|
|
3261
|
+
const encryptCommentRegexp = /((<!-- valaxy-encrypt-start:\w+ -->)|(<!-- valaxy-encrypt-end -->))/g;
|
|
3262
|
+
if (frontmatter.password) {
|
|
3263
|
+
code = code.replaceAll(encryptCommentRegexp, "");
|
|
3264
|
+
} else {
|
|
3265
|
+
const partiallyEncryptedContents = [];
|
|
3266
|
+
for (const matchArr of code.matchAll(encryptRegexp)) {
|
|
3267
|
+
partiallyEncryptedContents.push(
|
|
3268
|
+
await encryptContent(matchArr.groups.content, {
|
|
3269
|
+
password: matchArr.groups.password,
|
|
3270
|
+
iv: encrypt.iv,
|
|
3271
|
+
salt: encrypt.salt
|
|
3272
|
+
})
|
|
3273
|
+
);
|
|
3274
|
+
}
|
|
3275
|
+
let i = 0;
|
|
3276
|
+
if (partiallyEncryptedContents.length) {
|
|
3277
|
+
frontmatter.partiallyEncryptedContents = partiallyEncryptedContents;
|
|
3278
|
+
code = code.replaceAll(encryptRegexp, () => {
|
|
3279
|
+
const partiallyEncryptedContents2 = `$partiallyEncryptedContents`;
|
|
3280
|
+
const content = `${partiallyEncryptedContents2}[${i++}]`;
|
|
3281
|
+
return getValaxyDecryptTemplate2({
|
|
3282
|
+
encryptedContent: content,
|
|
3283
|
+
hint: frontmatter.password_hint || ""
|
|
3284
|
+
});
|
|
3285
|
+
});
|
|
3286
|
+
}
|
|
3287
|
+
}
|
|
3288
|
+
if (frontmatter.password) {
|
|
3289
|
+
const templateStart = code.indexOf("<template>");
|
|
3290
|
+
const templateEnd = code.lastIndexOf("</template>");
|
|
3291
|
+
const content = code.slice(templateStart + 10, templateEnd);
|
|
3292
|
+
const encryptedContent = await encryptContent(content, {
|
|
3293
|
+
password: frontmatter.password,
|
|
3294
|
+
iv: encrypt.iv,
|
|
3295
|
+
salt: encrypt.salt
|
|
3296
|
+
});
|
|
3297
|
+
frontmatter.encryptedContent = encryptedContent;
|
|
3298
|
+
frontmatter.encrypt = true;
|
|
3299
|
+
delete frontmatter.password;
|
|
3300
|
+
const encryptedContentStr = "$encryptedContent";
|
|
3301
|
+
code = code.replace(content, getValaxyDecryptTemplate2({
|
|
3302
|
+
encryptedContent: encryptedContentStr,
|
|
3303
|
+
hint: frontmatter.password_hint
|
|
3304
|
+
}));
|
|
3305
|
+
const scriptSetupStart = code.lastIndexOf("<script setup>");
|
|
3306
|
+
const scriptSetupEnd = code.lastIndexOf("</script>");
|
|
3307
|
+
const scriptSetupContent = code.slice(scriptSetupStart + 14, scriptSetupEnd);
|
|
3308
|
+
code = code.replace(scriptSetupContent, "");
|
|
3309
|
+
}
|
|
3310
|
+
if (frontmatter.gallery_password) {
|
|
3311
|
+
const encryptedPhotos = await encryptContent(JSON.stringify(frontmatter.photos), {
|
|
3312
|
+
password: frontmatter.gallery_password,
|
|
3313
|
+
iv: encrypt.iv,
|
|
3314
|
+
salt: encrypt.salt
|
|
3315
|
+
});
|
|
3316
|
+
frontmatter.encryptedPhotos = encryptedPhotos;
|
|
3317
|
+
delete frontmatter.gallery_password;
|
|
3318
|
+
delete frontmatter.photos;
|
|
3319
|
+
}
|
|
3320
|
+
}
|
|
3321
|
+
return code;
|
|
3322
|
+
};
|
|
3323
|
+
}
|
|
3324
|
+
|
|
3325
|
+
// node/plugins/markdown/transform/footnoteTooltip.ts
|
|
3326
|
+
function transformFootnoteTooltip(code) {
|
|
3327
|
+
const footnoteContentMap = /* @__PURE__ */ new Map();
|
|
3328
|
+
return code.replace(/<ValaxyFootnoteItem id="(.*?)">(.*?)<\/ValaxyFootnoteItem>/gs, (_, id, content) => {
|
|
3329
|
+
const tooltipContent = content.match(/<ValaxyFootnoteContent>(.*?)<\/ValaxyFootnoteContent>/s)[1].replace(/<ValaxyFootnoteAnchor.*?>(.*?)<\/ValaxyFootnoteAnchor>/gs, "");
|
|
3330
|
+
const itemContent = content.replace(/<ValaxyFootnoteContent>(.*?)<\/ValaxyFootnoteContent>/gs, (_2, content2) => content2).replace(/<ValaxyFootnoteAnchor.*?>(.*?)<\/ValaxyFootnoteAnchor>/gs, (_2, anchor) => anchor);
|
|
3331
|
+
footnoteContentMap.set(id, tooltipContent);
|
|
3332
|
+
return itemContent;
|
|
3333
|
+
}).replace(/<ValaxyFootnoteRef href="#(.*?)".*?>(.*?)<\/ValaxyFootnoteRef>/gs, (_, href, content) => {
|
|
3334
|
+
return `<ValaxyFootnoteTooltip>${content}<template #popper>${footnoteContentMap.get(href)}</template></ValaxyFootnoteTooltip>`;
|
|
3335
|
+
});
|
|
3336
|
+
}
|
|
3337
|
+
|
|
3338
|
+
// node/plugins/markdown/transform/hexo.ts
|
|
3339
|
+
import consola11 from "consola";
|
|
3340
|
+
import { colors as colors10 } from "consola/utils";
|
|
3341
|
+
function transformHexoTags(code, id) {
|
|
3342
|
+
if (code.includes("{%") && code.includes("%}")) {
|
|
3343
|
+
consola11.error(
|
|
3344
|
+
`${`${id}
|
|
3345
|
+
`} Please ${colors10.red("remove")} ${colors10.cyan("{% %}")}, because it conflicts with ${colors10.yellow("markdown-it-attrs")}.`
|
|
3346
|
+
);
|
|
3347
|
+
}
|
|
3348
|
+
code.replace("{%", "{%");
|
|
3349
|
+
code.replace("%}", "%}");
|
|
3350
|
+
return code;
|
|
3351
|
+
}
|
|
3352
|
+
|
|
3353
|
+
// node/plugins/markdown/transform/markdown.ts
|
|
3354
|
+
import path9 from "node:path";
|
|
3355
|
+
import fs18 from "fs-extra";
|
|
3356
|
+
function genProvideCode(name, data) {
|
|
3357
|
+
return [
|
|
3358
|
+
`const $${name} = ${transformObject(data)}`,
|
|
3359
|
+
`route.meta.$${name} = $${name}`,
|
|
3360
|
+
`provide('valaxy:${name}', $${name})`
|
|
3361
|
+
];
|
|
3362
|
+
}
|
|
3363
|
+
var encryptedKeys = ["encryptedContent", "partiallyEncryptedContents", "encryptedPhotos"];
|
|
3364
|
+
function injectPageDataCode(pageData) {
|
|
3365
|
+
const vueContextImports = [
|
|
3366
|
+
`import { provide } from 'vue'`,
|
|
3367
|
+
`import { useRoute, useRouter } from 'vue-router'`,
|
|
3368
|
+
"const { data: pageData } = usePageData()",
|
|
3369
|
+
"const router = useRouter()",
|
|
3370
|
+
"const route = useRoute()",
|
|
3371
|
+
// $frontmatter contain runtime added data, will be deleted (for example, $frontmatter.partiallyEncryptedContents)
|
|
3372
|
+
`const $frontmatter = Object.assign(route.meta.frontmatter || {}, pageData.value?.frontmatter || {})
|
|
3373
|
+
route.meta.frontmatter = $frontmatter
|
|
3374
|
+
router.currentRoute.value.data = pageData.value
|
|
3375
|
+
|
|
3376
|
+
provide('valaxy:frontmatter', $frontmatter)
|
|
3377
|
+
`
|
|
3378
|
+
];
|
|
3379
|
+
for (const key of encryptedKeys) {
|
|
3380
|
+
if (pageData.frontmatter[key]) {
|
|
3381
|
+
vueContextImports.push(...genProvideCode(key, pageData.frontmatter[key]));
|
|
3382
|
+
}
|
|
3383
|
+
}
|
|
3384
|
+
return vueContextImports;
|
|
3385
|
+
}
|
|
3386
|
+
function createTransformMarkdown(options) {
|
|
3387
|
+
const loaderVuePath = path9.resolve(options.clientRoot, "templates", "loader.vue");
|
|
3388
|
+
const loaderVue = fs18.readFileSync(loaderVuePath, "utf-8");
|
|
3389
|
+
return (code, id, pageData) => {
|
|
3390
|
+
const isDev = options.mode === "dev";
|
|
3391
|
+
if (!isDev) {
|
|
3392
|
+
delete pageData.filePath;
|
|
3393
|
+
}
|
|
3394
|
+
const dataCode = injectPageDataCode(pageData);
|
|
3395
|
+
const imports = [
|
|
3396
|
+
...dataCode,
|
|
3397
|
+
isDev ? `globalThis.$pageData = pageData` : "",
|
|
3398
|
+
"globalThis.$frontmatter = $frontmatter"
|
|
3399
|
+
];
|
|
3400
|
+
encryptedKeys.forEach((key) => {
|
|
3401
|
+
delete pageData.frontmatter[key];
|
|
3402
|
+
});
|
|
3403
|
+
const pagePath = pageData.relativePath.slice("/pages".length - 1, -".md".length);
|
|
3404
|
+
const customDataLoader = loaderVue.replace("/relativePath", pagePath.endsWith("index") ? pagePath.replace(/\/index$/, "") : pagePath).replace("// custom basic loader", `return ${transformObject(pageData)}`);
|
|
3405
|
+
code = customDataLoader + code;
|
|
3406
|
+
const scriptSetupStart = code.indexOf("<script setup>");
|
|
3407
|
+
if (scriptSetupStart !== -1)
|
|
3408
|
+
code = code.slice(0, scriptSetupStart + "<script setup>".length) + imports.join("\n") + code.slice(scriptSetupStart + 14);
|
|
3409
|
+
else
|
|
3410
|
+
code = `<script setup>
|
|
3411
|
+
${imports.join("\n")}
|
|
3412
|
+
</script>
|
|
3413
|
+
${code}`;
|
|
3414
|
+
const injectA = code.indexOf("<template>") + "<template>".length;
|
|
3415
|
+
const injectB = code.lastIndexOf("</template>");
|
|
3416
|
+
let body = code.slice(injectA, injectB).trim();
|
|
3417
|
+
if (body.startsWith("<div>") && body.endsWith("</div>"))
|
|
3418
|
+
body = body.slice(5, -6);
|
|
3419
|
+
code = `${code.slice(0, injectA)}
|
|
3420
|
+
${getValaxyMain(body)}
|
|
3421
|
+
${code.slice(injectB)}`;
|
|
3422
|
+
return code;
|
|
3423
|
+
};
|
|
3424
|
+
}
|
|
3425
|
+
|
|
3426
|
+
// node/plugins/markdown/transform/page-data.ts
|
|
3427
|
+
import path10 from "pathe";
|
|
3428
|
+
function getHeadMetaContent(head, name) {
|
|
3429
|
+
if (!head || !head.length)
|
|
3430
|
+
return void 0;
|
|
3431
|
+
const meta = head.find(([tag, attrs = {}]) => {
|
|
3432
|
+
return tag === "meta" && attrs.name === name && attrs.content;
|
|
3433
|
+
});
|
|
3434
|
+
return meta && meta[1].content;
|
|
3435
|
+
}
|
|
3436
|
+
function inferDescription(frontmatter) {
|
|
3437
|
+
const { description, head } = frontmatter;
|
|
3438
|
+
if (description !== void 0)
|
|
3439
|
+
return description;
|
|
3440
|
+
return head && getHeadMetaContent(head, "description") || "";
|
|
3441
|
+
}
|
|
3442
|
+
async function generatePageData(code, id, options) {
|
|
3443
|
+
const { frontmatter = {} } = options.env;
|
|
3444
|
+
const relativePath = path10.relative(options.userRoot, id);
|
|
3445
|
+
const fm = JSON.parse(JSON.stringify(frontmatter));
|
|
3446
|
+
const pageData = {
|
|
3447
|
+
title: fm.title || options.env.title || "",
|
|
3448
|
+
titleTemplate: fm.titleTemplate,
|
|
3449
|
+
description: inferDescription(fm),
|
|
3450
|
+
frontmatter: fm,
|
|
3451
|
+
// not be used
|
|
3452
|
+
headers: options.env.headers || [],
|
|
3453
|
+
relativePath,
|
|
3454
|
+
filePath: id
|
|
3455
|
+
};
|
|
3456
|
+
pageData.lastUpdated = await getGitTimestamp(id);
|
|
3457
|
+
return pageData;
|
|
3458
|
+
}
|
|
3459
|
+
|
|
3460
|
+
// node/plugins/markdown/markdownToVue.ts
|
|
3461
|
+
var debug2 = _debug2("valaxy:md");
|
|
3462
|
+
var cache2 = new LRUCache({ max: 128 });
|
|
3463
|
+
function generateSlots() {
|
|
3464
|
+
const slots = [
|
|
3465
|
+
"main-header",
|
|
3466
|
+
"main-header-after",
|
|
3467
|
+
"main-nav",
|
|
3468
|
+
"main-content-before",
|
|
3469
|
+
"main-content",
|
|
3470
|
+
"main-content-after",
|
|
3471
|
+
"main-nav-before",
|
|
3472
|
+
"main-nav-after",
|
|
3473
|
+
"comment",
|
|
3474
|
+
"footer",
|
|
3475
|
+
"aside",
|
|
3476
|
+
"aside-custom"
|
|
3477
|
+
];
|
|
3478
|
+
const slotsText = slots.map((s) => `<template #${s}><slot name="${s}" /></template>`).join("");
|
|
3479
|
+
return slotsText;
|
|
3480
|
+
}
|
|
3481
|
+
function getValaxyMain(mainContentMd) {
|
|
3482
|
+
const pageComponent = "ValaxyMain";
|
|
3483
|
+
return `
|
|
3484
|
+
<${pageComponent} :frontmatter="$frontmatter">
|
|
3485
|
+
<template #main-content-md>${mainContentMd}</template>
|
|
3486
|
+
${generateSlots()}
|
|
3487
|
+
<slot />
|
|
3488
|
+
</${pageComponent}>
|
|
3489
|
+
`;
|
|
3490
|
+
}
|
|
3491
|
+
async function createMarkdownToVueRenderFn(options, _viteConfig) {
|
|
3492
|
+
options.pages = options.pages.map((p) => p.replace(/\.md$/, "").replace(/\/index$/, ""));
|
|
3493
|
+
const transformCodeBlock = createTransformCodeBlock(options);
|
|
3494
|
+
const transformMarkdown = createTransformMarkdown(options);
|
|
3495
|
+
const transformEncrypt = createTransformEncrypt(options);
|
|
3496
|
+
const scanDeadLinks = createScanDeadLinks(options);
|
|
3497
|
+
const srcDir = options.userRoot;
|
|
3498
|
+
const isBuild = options.mode === "build";
|
|
3499
|
+
return async (code, id) => {
|
|
3500
|
+
const file = id;
|
|
3501
|
+
const relativePath = path11.relative(srcDir, file);
|
|
3502
|
+
const deadLinks = scanDeadLinks(code, id);
|
|
3503
|
+
const cacheKey = JSON.stringify({ code, id });
|
|
3504
|
+
if (isBuild) {
|
|
3505
|
+
const cacheKey2 = JSON.stringify({ code, id });
|
|
3506
|
+
const cached = cache2.get(cacheKey2);
|
|
3507
|
+
if (cached) {
|
|
3508
|
+
debug2(`[cache hit] ${relativePath}`);
|
|
3509
|
+
return cached;
|
|
3510
|
+
}
|
|
3511
|
+
}
|
|
3512
|
+
const start = Date.now();
|
|
3513
|
+
const pageData = await generatePageData(code, id, options);
|
|
3514
|
+
code = transformHexoTags(code, id);
|
|
3515
|
+
const data = resolveTransformIncludes(code, id, options);
|
|
3516
|
+
const includes = data.includes;
|
|
3517
|
+
code = data.code;
|
|
3518
|
+
code = transformCodeBlock(code);
|
|
3519
|
+
code = await transformEncrypt(code, id, pageData);
|
|
3520
|
+
code = transformFootnoteTooltip(code);
|
|
3521
|
+
code = transformMarkdown(code, id, pageData);
|
|
3522
|
+
debug2(`[render] ${file} in ${Date.now() - start}ms.`);
|
|
3523
|
+
const result = {
|
|
3524
|
+
code,
|
|
3525
|
+
pageData,
|
|
3526
|
+
deadLinks,
|
|
3527
|
+
includes
|
|
3528
|
+
};
|
|
3529
|
+
if (isBuild)
|
|
3530
|
+
cache2.set(cacheKey, result);
|
|
3531
|
+
return result;
|
|
3532
|
+
};
|
|
3533
|
+
}
|
|
3534
|
+
|
|
3535
|
+
// node/plugins/valaxy/index.ts
|
|
3536
|
+
var nullVue = 'import { defineComponent } from "vue"; export default defineComponent({ render: () => null });';
|
|
3537
|
+
function generateAppVue(root) {
|
|
3538
|
+
const appVue = join7(root, "App.vue");
|
|
3539
|
+
if (!fs19.existsSync(appVue))
|
|
3540
|
+
return nullVue;
|
|
3541
|
+
const scripts = [
|
|
3542
|
+
`import AppVue from "${toAtFS(appVue)}"`,
|
|
3543
|
+
"export default AppVue"
|
|
3544
|
+
];
|
|
3545
|
+
return scripts.join("\n");
|
|
3546
|
+
}
|
|
3547
|
+
async function createValaxyLoader(options, serverOptions = {}) {
|
|
3548
|
+
let { config: valaxyConfig } = options;
|
|
3549
|
+
const valaxyPrefix2 = "/@valaxy";
|
|
3550
|
+
let hasDeadLinks = false;
|
|
3551
|
+
let markdownToVue;
|
|
3552
|
+
let viteConfig;
|
|
3553
|
+
return [
|
|
3554
|
+
{
|
|
3555
|
+
name: "valaxy:loader",
|
|
3556
|
+
enforce: "pre",
|
|
3557
|
+
async configResolved(resolvedConfig) {
|
|
3558
|
+
viteConfig = resolvedConfig;
|
|
3559
|
+
markdownToVue = await createMarkdownToVueRenderFn(
|
|
3560
|
+
options,
|
|
3561
|
+
viteConfig
|
|
3562
|
+
);
|
|
3563
|
+
},
|
|
3564
|
+
configureServer(server) {
|
|
3565
|
+
server.watcher.add([
|
|
3566
|
+
options.configFile,
|
|
3567
|
+
options.clientRoot,
|
|
3568
|
+
options.themeRoot,
|
|
3569
|
+
options.userRoot
|
|
3570
|
+
]);
|
|
3571
|
+
},
|
|
3572
|
+
resolveId(id) {
|
|
3573
|
+
if (id.startsWith(valaxyPrefix2))
|
|
3574
|
+
return id;
|
|
3575
|
+
return null;
|
|
3576
|
+
},
|
|
3577
|
+
async load(id) {
|
|
3578
|
+
const template = templates.find((t) => t.id === id);
|
|
3579
|
+
if (template) {
|
|
3580
|
+
return {
|
|
3581
|
+
code: await template.getContent.call(this, options),
|
|
3582
|
+
map: { mappings: "" }
|
|
3583
|
+
};
|
|
3584
|
+
}
|
|
3585
|
+
if (id === "/@valaxyjs/context") {
|
|
3586
|
+
return `export default ${JSON.stringify(JSON.stringify({
|
|
3587
|
+
userRoot: options.userRoot
|
|
3588
|
+
// clientRoot: options.clientRoot,
|
|
3589
|
+
}))}`;
|
|
3590
|
+
}
|
|
3591
|
+
if (id === "/@valaxyjs/AppVue")
|
|
3592
|
+
return generateAppVue(options.clientRoot);
|
|
3593
|
+
if (id === "/@valaxyjs/UserAppVue")
|
|
3594
|
+
return generateAppVue(options.userRoot);
|
|
3595
|
+
if (id === "/@valaxyjs/ThemeAppVue")
|
|
3596
|
+
return generateAppVue(options.themeRoot);
|
|
3597
|
+
if (id.startsWith(valaxyPrefix2)) {
|
|
3598
|
+
return {
|
|
3599
|
+
code: "",
|
|
3600
|
+
map: { mappings: "" }
|
|
3601
|
+
};
|
|
3602
|
+
}
|
|
3603
|
+
},
|
|
3604
|
+
async transform(code, id) {
|
|
3605
|
+
if (id.endsWith(".md")) {
|
|
3606
|
+
const { code: newCode, deadLinks, includes } = await markdownToVue(code, id);
|
|
3607
|
+
if (deadLinks.length) {
|
|
3608
|
+
hasDeadLinks = true;
|
|
3609
|
+
consola12.error(`Dead links found in ${id}`);
|
|
3610
|
+
consola12.error(deadLinks);
|
|
3611
|
+
}
|
|
3612
|
+
if (includes.length) {
|
|
3613
|
+
includes.forEach((i) => {
|
|
3614
|
+
this.addWatchFile(i);
|
|
3615
|
+
});
|
|
3616
|
+
}
|
|
3617
|
+
return newCode;
|
|
3618
|
+
}
|
|
3619
|
+
},
|
|
3620
|
+
renderStart() {
|
|
3621
|
+
if (hasDeadLinks && !(valaxyConfig.ignoreDeadLinks || valaxyConfig.build.ignoreDeadLinks))
|
|
3622
|
+
throw new Error("One or more pages contain dead links.");
|
|
3623
|
+
},
|
|
3624
|
+
/**
|
|
3625
|
+
* handle config hmr
|
|
3626
|
+
* @param ctx
|
|
3627
|
+
*/
|
|
3628
|
+
async handleHotUpdate(ctx) {
|
|
3629
|
+
const { file, server, read } = ctx;
|
|
3630
|
+
const reloadConfigAndEntries = (config) => {
|
|
3631
|
+
serverOptions.onConfigReload?.(config, options.config);
|
|
3632
|
+
Object.assign(options.config, config);
|
|
3633
|
+
valaxyConfig = config;
|
|
3634
|
+
const moduleIds = ["/@valaxyjs/config", "/@valaxyjs/context"];
|
|
3635
|
+
const moduleEntries = [
|
|
3636
|
+
...Array.from(moduleIds).map((id) => server.moduleGraph.getModuleById(id))
|
|
3637
|
+
].filter((item) => !!item);
|
|
3638
|
+
return moduleEntries;
|
|
3639
|
+
};
|
|
3640
|
+
const configFiles = [options.configFile];
|
|
3641
|
+
if (configFiles.includes(file)) {
|
|
3642
|
+
const { config } = await resolveOptions({ userRoot: options.userRoot });
|
|
3643
|
+
return reloadConfigAndEntries(config);
|
|
3644
|
+
}
|
|
3645
|
+
if (file === options.siteConfigFile) {
|
|
3646
|
+
const { siteConfig } = await resolveSiteConfig(options.userRoot);
|
|
3647
|
+
valaxyConfig.siteConfig = replaceArrMerge(siteConfig, defaultSiteConfig);
|
|
3648
|
+
return reloadConfigAndEntries(valaxyConfig);
|
|
3649
|
+
}
|
|
3650
|
+
if (file === options.themeConfigFile) {
|
|
3651
|
+
const { themeConfig } = await resolveUserThemeConfig(options);
|
|
3652
|
+
const pkg = valaxyConfig.themeConfig.pkg;
|
|
3653
|
+
themeConfig.pkg = pkg;
|
|
3654
|
+
valaxyConfig.themeConfig = themeConfig;
|
|
3655
|
+
return reloadConfigAndEntries(valaxyConfig);
|
|
3656
|
+
}
|
|
3657
|
+
if (file === resolve10(options.themeRoot, "valaxy.config.ts")) {
|
|
3658
|
+
const themeValaxyConfig = await resolveThemeValaxyConfig(options);
|
|
3659
|
+
const valaxyConfig2 = mergeValaxyConfig(options.config, themeValaxyConfig);
|
|
3660
|
+
const { config } = await processValaxyOptions(options, valaxyConfig2);
|
|
3661
|
+
return reloadConfigAndEntries(config);
|
|
3662
|
+
}
|
|
3663
|
+
if (file.endsWith(".md")) {
|
|
3664
|
+
const endCount = countPerformanceTime();
|
|
3665
|
+
const content = await read();
|
|
3666
|
+
const { code, pageData } = await markdownToVue(content, file);
|
|
3667
|
+
const path17 = `/${relative(`${options.userRoot}/pages`, file)}`;
|
|
3668
|
+
const payload = {
|
|
3669
|
+
path: path17,
|
|
3670
|
+
pageData
|
|
3671
|
+
};
|
|
3672
|
+
server.hot.send({
|
|
3673
|
+
type: "custom",
|
|
3674
|
+
event: "valaxy:pageData",
|
|
3675
|
+
data: payload
|
|
3676
|
+
});
|
|
3677
|
+
vLogger.success(`${colors11.yellow("[HMR]")} ${file} ${colors11.dim(`updated in ${endCount()}`)}`);
|
|
3678
|
+
ctx.read = () => code;
|
|
3679
|
+
}
|
|
3680
|
+
}
|
|
3681
|
+
}
|
|
3682
|
+
// {
|
|
3683
|
+
// // we need post encrypt html
|
|
3684
|
+
// name: 'valaxy:encrypt:post',
|
|
3685
|
+
// enforce: 'pre',
|
|
3686
|
+
// async transform(code, id) {
|
|
3687
|
+
// if (id.endsWith('.md'))
|
|
3688
|
+
// code = await transformEncrypt(code, id)
|
|
3689
|
+
// return code
|
|
3690
|
+
// },
|
|
3691
|
+
// },
|
|
3692
|
+
];
|
|
3693
|
+
}
|
|
3694
|
+
|
|
3695
|
+
// node/plugins/vueRouter.ts
|
|
3696
|
+
import fs20 from "fs-extra";
|
|
3697
|
+
import matter3 from "gray-matter";
|
|
3698
|
+
import { convert } from "html-to-text";
|
|
3699
|
+
import { MarkdownItAsync } from "markdown-it-async";
|
|
3700
|
+
import { resolve as resolve11 } from "pathe";
|
|
3701
|
+
import VueRouter from "unplugin-vue-router/vite";
|
|
3702
|
+
|
|
3703
|
+
// node/plugins/presets/statistics.ts
|
|
3704
|
+
import { existsSync as existsSync3, readFileSync } from "node:fs";
|
|
3705
|
+
function count(content) {
|
|
3706
|
+
const cn = (content.match(/[\u4E00-\u9FA5]/g) || []).length;
|
|
3707
|
+
const en = (content.replace(/[\u4E00-\u9FA5]/g, "").match(/[\w\u0392-\u03C9\u0400-\u04FF]+|[\u4E00-\u9FFF\u3400-\u4DBF\uF900-\uFAFF\u3040-\u309F\uAC00-\uD7AF\u0400-\u04FF]+|[\u00E4\u00C4\u00E5\u00C5\u00F6\u00D6]+/g) || []).length;
|
|
3708
|
+
return {
|
|
3709
|
+
cn,
|
|
3710
|
+
en
|
|
3711
|
+
};
|
|
3712
|
+
}
|
|
3713
|
+
function readTime({ cn, en }, options) {
|
|
3714
|
+
const readingTime = cn / (options.speed.cn || 300) + en / (options.speed.en || 100);
|
|
3715
|
+
return readingTime < 1 ? 1 : Math.ceil(readingTime);
|
|
3716
|
+
}
|
|
3717
|
+
function wordCount({ cn, en }) {
|
|
3718
|
+
const num = cn + en;
|
|
3719
|
+
if (num < 1e3)
|
|
3720
|
+
return num.toString();
|
|
3721
|
+
return `${Math.round(num / 100) / 10}k`;
|
|
3722
|
+
}
|
|
3723
|
+
function statistics(content, options) {
|
|
3724
|
+
const countData = count(content);
|
|
3725
|
+
return {
|
|
3726
|
+
countData,
|
|
3727
|
+
wordCount: wordCount(countData),
|
|
3728
|
+
readingTime: readTime(countData, options.readTime)
|
|
3729
|
+
};
|
|
3730
|
+
}
|
|
3731
|
+
function presetStatistics({
|
|
3732
|
+
route,
|
|
3733
|
+
options
|
|
3734
|
+
}) {
|
|
3735
|
+
const absolutePath = route.components.get("default") || "";
|
|
3736
|
+
if (existsSync3(absolutePath)) {
|
|
3737
|
+
const file = readFileSync(absolutePath, "utf-8");
|
|
3738
|
+
const { wordCount: wordCount2, readingTime } = statistics(file, {
|
|
3739
|
+
readTime: Object.assign({
|
|
3740
|
+
speed: {
|
|
3741
|
+
cn: 300,
|
|
3742
|
+
en: 100
|
|
3743
|
+
}
|
|
3744
|
+
}, options.readTime)
|
|
3745
|
+
});
|
|
3746
|
+
if (route.meta.frontmatter) {
|
|
3747
|
+
if (!route.meta.frontmatter.wordCount)
|
|
3748
|
+
route.meta.frontmatter.wordCount = wordCount2;
|
|
3749
|
+
if (!route.meta.frontmatter.readingTime)
|
|
3750
|
+
route.meta.frontmatter.readingTime = readingTime;
|
|
3751
|
+
}
|
|
3752
|
+
}
|
|
3753
|
+
}
|
|
3754
|
+
|
|
3755
|
+
// node/plugins/vueRouter.ts
|
|
3756
|
+
function getExcerptByType(excerpt = "", type = "html", mdIt) {
|
|
3757
|
+
switch (type) {
|
|
3758
|
+
case "ai":
|
|
3759
|
+
case "md":
|
|
3760
|
+
return excerpt;
|
|
3761
|
+
case "html":
|
|
3762
|
+
return mdIt.render(excerpt);
|
|
3763
|
+
case "text":
|
|
3764
|
+
return convert(mdIt.render(excerpt));
|
|
3765
|
+
default:
|
|
3766
|
+
return excerpt;
|
|
3767
|
+
}
|
|
3768
|
+
}
|
|
3769
|
+
async function createRouterPlugin(valaxyApp) {
|
|
3770
|
+
const { options } = valaxyApp;
|
|
3771
|
+
const { roots, config: valaxyConfig } = options;
|
|
3772
|
+
const mdIt = new MarkdownItAsync({ html: true });
|
|
3773
|
+
await setupMarkdownPlugins(mdIt, options);
|
|
3774
|
+
return VueRouter({
|
|
3775
|
+
extensions: [".vue", ".md"],
|
|
3776
|
+
routesFolder: roots.map((root) => `${root}/pages`),
|
|
3777
|
+
dts: resolve11(options.tempDir, "typed-router.d.ts"),
|
|
3778
|
+
...valaxyConfig.router,
|
|
3779
|
+
/**
|
|
3780
|
+
* @experimental See https://github.com/posva/unplugin-vue-router/issues/43
|
|
3781
|
+
* we need get frontmatter before route, so write it in extendRoute
|
|
3782
|
+
*/
|
|
3783
|
+
async extendRoute(route) {
|
|
3784
|
+
const defaultFrontmatter = JSON.parse(JSON.stringify(valaxyConfig.siteConfig.frontmatter)) || {};
|
|
3785
|
+
if (route.meta && route.meta.frontmatter) {
|
|
3786
|
+
const { frontmatter: _, otherMeta } = route.meta;
|
|
3787
|
+
route.meta = otherMeta;
|
|
3788
|
+
}
|
|
3789
|
+
route.addToMeta({
|
|
3790
|
+
frontmatter: defaultFrontmatter
|
|
3791
|
+
});
|
|
3792
|
+
if (route.fullPath === "/" || route.fullPath === "/page") {
|
|
3793
|
+
route.addToMeta({
|
|
3794
|
+
layout: "home"
|
|
3795
|
+
});
|
|
3796
|
+
}
|
|
3797
|
+
if (["/posts", "/posts/"].includes(route.fullPath)) {
|
|
3798
|
+
route.addToMeta({
|
|
3799
|
+
layout: "posts"
|
|
3800
|
+
});
|
|
3801
|
+
} else if (route.fullPath.startsWith("/posts/")) {
|
|
3802
|
+
if (route.children.length === 0) {
|
|
3803
|
+
route.addToMeta({
|
|
3804
|
+
layout: "post"
|
|
3805
|
+
});
|
|
3806
|
+
}
|
|
3807
|
+
}
|
|
3808
|
+
const path17 = route.components.get("default") || "";
|
|
3809
|
+
if (path17.endsWith(".md")) {
|
|
3810
|
+
const md = fs20.readFileSync(path17, "utf-8");
|
|
3811
|
+
const { data, excerpt, content } = matter3(md, matterOptions);
|
|
3812
|
+
const mdFm = data;
|
|
3813
|
+
const lastUpdated = options.config.siteConfig.lastUpdated;
|
|
3814
|
+
delete mdFm.password;
|
|
3815
|
+
if (mdFm.gallery_password) {
|
|
3816
|
+
delete mdFm.gallery_password;
|
|
3817
|
+
delete mdFm.photos;
|
|
3818
|
+
}
|
|
3819
|
+
if (!mdFm.date)
|
|
3820
|
+
mdFm.date = (await fs20.stat(path17)).mtime;
|
|
3821
|
+
if (lastUpdated) {
|
|
3822
|
+
if (!mdFm.updated)
|
|
3823
|
+
mdFm.updated = (await fs20.stat(path17)).ctime;
|
|
3824
|
+
}
|
|
3825
|
+
if (mdFm.from) {
|
|
3826
|
+
if (Array.isArray(mdFm.from)) {
|
|
3827
|
+
mdFm.from.forEach((from) => {
|
|
3828
|
+
options.redirects.push({
|
|
3829
|
+
from,
|
|
3830
|
+
to: route.fullPath
|
|
3831
|
+
});
|
|
3832
|
+
});
|
|
3833
|
+
} else {
|
|
3834
|
+
options.redirects.push({
|
|
3835
|
+
from: mdFm.from,
|
|
3836
|
+
to: route.fullPath
|
|
3837
|
+
});
|
|
3838
|
+
}
|
|
3839
|
+
}
|
|
3840
|
+
const excludeKeys = [
|
|
3841
|
+
"albums",
|
|
3842
|
+
"excerpt",
|
|
3843
|
+
"girls",
|
|
3844
|
+
"links",
|
|
3845
|
+
"photos"
|
|
3846
|
+
// @TODO defineBasicLoader for page
|
|
3847
|
+
// 'projects',
|
|
3848
|
+
];
|
|
3849
|
+
const routerFM = {
|
|
3850
|
+
...mdFm,
|
|
3851
|
+
// 主题有新的字段需要主动设置
|
|
3852
|
+
// @TODO 添加文档和配置项,或者反过来允许用户自行优化
|
|
3853
|
+
tags: typeof mdFm.tags === "string" ? [mdFm.tags] : mdFm.tags
|
|
3854
|
+
};
|
|
3855
|
+
excludeKeys.forEach((key) => {
|
|
3856
|
+
delete routerFM[key];
|
|
3857
|
+
});
|
|
3858
|
+
route.addToMeta({
|
|
3859
|
+
frontmatter: routerFM,
|
|
3860
|
+
excerpt: mdFm.excerpt || (excerpt ? getExcerptByType(excerpt, mdFm.excerpt_type || defaultFrontmatter.excerpt_type, mdIt) : "")
|
|
3861
|
+
});
|
|
3862
|
+
if (data.layout) {
|
|
3863
|
+
route.addToMeta({
|
|
3864
|
+
layout: data.layout
|
|
3865
|
+
});
|
|
3866
|
+
}
|
|
3867
|
+
if (!route.meta.frontmatter?.updated)
|
|
3868
|
+
route.meta.frontmatter.updated = mdFm.date;
|
|
3869
|
+
if (valaxyConfig.siteConfig.statistics.enable) {
|
|
3870
|
+
presetStatistics({
|
|
3871
|
+
options: valaxyConfig.siteConfig.statistics,
|
|
3872
|
+
route
|
|
3873
|
+
});
|
|
3874
|
+
}
|
|
3875
|
+
const ctx = {
|
|
3876
|
+
route,
|
|
3877
|
+
data,
|
|
3878
|
+
excerpt,
|
|
3879
|
+
content,
|
|
3880
|
+
path: path17
|
|
3881
|
+
};
|
|
3882
|
+
valaxyConfig.extendMd?.(ctx);
|
|
3883
|
+
}
|
|
3884
|
+
await valaxyApp.hooks.callHook("vue-router:extendRoute", route);
|
|
3885
|
+
return valaxyConfig.router?.extendRoute?.(route);
|
|
3886
|
+
}
|
|
3887
|
+
});
|
|
3888
|
+
}
|
|
3889
|
+
|
|
3890
|
+
// node/plugins/preset.ts
|
|
3891
|
+
async function ViteValaxyPlugins(valaxyApp, serverOptions = {}) {
|
|
3892
|
+
const { options } = valaxyApp;
|
|
3893
|
+
const { roots, config: valaxyConfig } = options;
|
|
3894
|
+
const MarkdownPlugin = await createMarkdownPlugin(options);
|
|
3895
|
+
const ValaxyLoader = await createValaxyLoader(options, serverOptions);
|
|
3896
|
+
const componentsDirs = roots.map((root) => `${root}/components`).concat(["src/components", "components"]);
|
|
3897
|
+
const plugins = [
|
|
3898
|
+
MarkdownPlugin,
|
|
3899
|
+
createConfigPlugin(options),
|
|
3900
|
+
createClientSetupPlugin(options),
|
|
3901
|
+
Vue({
|
|
3902
|
+
include: [/\.vue$/, /\.md$/],
|
|
3903
|
+
exclude: [],
|
|
3904
|
+
template: {
|
|
3905
|
+
compilerOptions: {
|
|
3906
|
+
isCustomElement: (tag) => {
|
|
3907
|
+
let is = customElements.has(tag);
|
|
3908
|
+
valaxyConfig.vue?.isCustomElement?.forEach((fn) => {
|
|
3909
|
+
is = is || fn(tag);
|
|
3910
|
+
});
|
|
3911
|
+
return is;
|
|
3912
|
+
}
|
|
3913
|
+
}
|
|
3914
|
+
},
|
|
3915
|
+
...valaxyConfig.vue
|
|
3916
|
+
}),
|
|
3917
|
+
ValaxyLoader,
|
|
3918
|
+
UnheadVite(),
|
|
3919
|
+
// https://github.com/posva/unplugin-vue-router
|
|
3920
|
+
await createRouterPlugin(valaxyApp),
|
|
3921
|
+
// https://github.com/JohnCampionJr/vite-plugin-vue-layouts
|
|
3922
|
+
Layouts({
|
|
3923
|
+
layoutsDirs: roots.map((root) => `${root}/layouts`),
|
|
3924
|
+
...valaxyConfig.layouts
|
|
3925
|
+
}),
|
|
3926
|
+
// https://github.com/antfu/unplugin-vue-components
|
|
3927
|
+
Components({
|
|
3928
|
+
extensions: ["vue", "md"],
|
|
3929
|
+
// allow auto import and register components used in markdown
|
|
3930
|
+
include: [/\.vue$/, /\.vue\?vue/, /\.md$/],
|
|
3931
|
+
/**
|
|
3932
|
+
* 默认排除 components/.exclude
|
|
3933
|
+
* `/[\\/]node_modules[\\/]/, ` 不要排除 node_modules/valaxy/client/components 下的组件
|
|
3934
|
+
*/
|
|
3935
|
+
exclude: [/[\\/]\.git[\\/]/, /[\\/]\.exclude[\\/]/],
|
|
3936
|
+
// allow override
|
|
3937
|
+
allowOverrides: true,
|
|
3938
|
+
/**
|
|
3939
|
+
* override: user -> theme -> client
|
|
3940
|
+
*
|
|
3941
|
+
* latter override former
|
|
3942
|
+
*/
|
|
3943
|
+
dirs: componentsDirs,
|
|
3944
|
+
dts: resolve12(options.tempDir, "components.d.ts"),
|
|
3945
|
+
...valaxyConfig.components
|
|
3946
|
+
}),
|
|
3947
|
+
// https://github.com/antfu/unocss
|
|
3948
|
+
// UnocssPlugin,
|
|
3949
|
+
await createUnocssPlugin(options),
|
|
3950
|
+
// ...MarkdownPlugin,
|
|
3951
|
+
// https://github.com/intlify/bundle-tools/tree/main/packages/unplugin-vue-i18n
|
|
3952
|
+
VueI18n({
|
|
3953
|
+
runtimeOnly: true,
|
|
3954
|
+
compositionOnly: true,
|
|
3955
|
+
fullInstall: true,
|
|
3956
|
+
include: roots.map((root) => `${root}/locales/**`)
|
|
3957
|
+
}),
|
|
3958
|
+
createFixPlugins(options)
|
|
3959
|
+
];
|
|
3960
|
+
if (valaxyConfig.groupIcons) {
|
|
3961
|
+
const { groupIconVitePlugin } = await import("vitepress-plugin-group-icons");
|
|
3962
|
+
plugins.push(
|
|
3963
|
+
groupIconVitePlugin({
|
|
3964
|
+
customIcon: {
|
|
3965
|
+
nodejs: "vscode-icons:file-type-node",
|
|
3966
|
+
playwright: "vscode-icons:file-type-playwright",
|
|
3967
|
+
typedoc: "vscode-icons:file-type-typedoc",
|
|
3968
|
+
eslint: "vscode-icons:file-type-eslint"
|
|
3969
|
+
},
|
|
3970
|
+
...valaxyConfig.groupIcons
|
|
3971
|
+
})
|
|
3972
|
+
);
|
|
3973
|
+
} else {
|
|
3974
|
+
const virtualCssId = "virtual:group-icons.css";
|
|
3975
|
+
const resolvedVirtualCssId = `\0${virtualCssId}`;
|
|
3976
|
+
plugins.push({
|
|
3977
|
+
name: "valaxy:virtual:group-icons.css",
|
|
3978
|
+
resolveId(id) {
|
|
3979
|
+
if (id === virtualCssId) {
|
|
3980
|
+
return resolvedVirtualCssId;
|
|
3981
|
+
}
|
|
3982
|
+
return void 0;
|
|
3983
|
+
},
|
|
3984
|
+
async load(id) {
|
|
3985
|
+
if (id === resolvedVirtualCssId) {
|
|
3986
|
+
return "";
|
|
3987
|
+
}
|
|
3988
|
+
return void 0;
|
|
3989
|
+
}
|
|
3990
|
+
});
|
|
3991
|
+
}
|
|
3992
|
+
if (valaxyConfig.visualizer) {
|
|
3993
|
+
try {
|
|
3994
|
+
const visualizer = (await import("rollup-plugin-visualizer")).visualizer;
|
|
3995
|
+
plugins.push(
|
|
3996
|
+
visualizer({
|
|
3997
|
+
open: true,
|
|
3998
|
+
gzipSize: true,
|
|
3999
|
+
...valaxyConfig.visualizer
|
|
4000
|
+
})
|
|
4001
|
+
);
|
|
4002
|
+
} catch (e) {
|
|
4003
|
+
console.error(e);
|
|
4004
|
+
consola13.error("Failed to load rollup-plugin-visualizer");
|
|
4005
|
+
consola13.error("Please install `rollup-plugin-visualizer` to enable the feature");
|
|
4006
|
+
console.log();
|
|
4007
|
+
consola13.info("pnpm add -D rollup-plugin-visualizer");
|
|
4008
|
+
console.log();
|
|
4009
|
+
}
|
|
4010
|
+
}
|
|
4011
|
+
return plugins;
|
|
4012
|
+
}
|
|
4013
|
+
|
|
4014
|
+
// node/build.ts
|
|
4015
|
+
async function build2(valaxyApp, viteConfig = defaultViteConfig) {
|
|
4016
|
+
const inlineConfig = mergeViteConfig2(viteConfig, {
|
|
4017
|
+
...defaultViteConfig,
|
|
4018
|
+
plugins: await ViteValaxyPlugins(valaxyApp)
|
|
4019
|
+
});
|
|
4020
|
+
await viteBuild(inlineConfig);
|
|
4021
|
+
}
|
|
4022
|
+
async function ssgBuild(valaxyApp, viteConfig = {}) {
|
|
4023
|
+
const { options } = valaxyApp;
|
|
4024
|
+
const defaultConfig = {
|
|
4025
|
+
...defaultViteConfig,
|
|
4026
|
+
plugins: await ViteValaxyPlugins(valaxyApp),
|
|
4027
|
+
ssr: {
|
|
4028
|
+
// TODO: workaround until they support native ESM
|
|
4029
|
+
noExternal: ["workbox-window", /vue-i18n/, "@vue/devtools-api"]
|
|
4030
|
+
}
|
|
4031
|
+
};
|
|
4032
|
+
defaultConfig.ssgOptions = {
|
|
4033
|
+
script: "async",
|
|
4034
|
+
formatting: "minify",
|
|
4035
|
+
beastiesOptions: {
|
|
4036
|
+
preload: "swap",
|
|
4037
|
+
// reduceInlineStyles: false,
|
|
4038
|
+
...options.config.beastiesOptions || {}
|
|
4039
|
+
},
|
|
4040
|
+
onFinished() {
|
|
4041
|
+
generateSitemap(
|
|
4042
|
+
{
|
|
4043
|
+
hostname: options.config.siteConfig.url
|
|
4044
|
+
}
|
|
4045
|
+
);
|
|
4046
|
+
}
|
|
4047
|
+
// dirStyle default it flat
|
|
4048
|
+
// dirStyle: 'nested',
|
|
4049
|
+
};
|
|
4050
|
+
if (options.config.build.ssgForPagination) {
|
|
4051
|
+
defaultConfig.ssgOptions.includedRoutes = (paths, _routes) => {
|
|
4052
|
+
const newPaths = paths;
|
|
4053
|
+
const posts = paths.filter((path17) => path17.startsWith("/posts/"));
|
|
4054
|
+
const pageNumber = Math.ceil(posts.length / options.config.siteConfig.pageSize);
|
|
4055
|
+
consola14.info(`Generate ${colors12.yellow(pageNumber)} pages for pagination.`);
|
|
4056
|
+
for (let i = 1; i <= pageNumber; i++)
|
|
4057
|
+
newPaths.push(`/page/${i}`);
|
|
4058
|
+
if (!options.config.vite?.ssgOptions?.includeAllRoutes)
|
|
4059
|
+
return newPaths.filter((path17) => !path17.split("/").some((p) => p.startsWith(":")));
|
|
4060
|
+
else
|
|
4061
|
+
return newPaths;
|
|
4062
|
+
};
|
|
4063
|
+
}
|
|
4064
|
+
const inlineConfig = mergeViteConfig2(defaultConfig, viteConfig);
|
|
4065
|
+
await viteSsgBuild({}, inlineConfig);
|
|
4066
|
+
}
|
|
4067
|
+
async function postProcessForSSG(options) {
|
|
4068
|
+
const { userRoot: userRoot2 } = options;
|
|
4069
|
+
const indexPath = resolve13(userRoot2, "dist/index.html");
|
|
4070
|
+
if (fs21.existsSync(indexPath)) {
|
|
4071
|
+
consola14.info("post process for ssg...");
|
|
4072
|
+
const indexFile = await fs21.readFile(indexPath, "utf-8");
|
|
4073
|
+
const htmlTag = "</html>";
|
|
4074
|
+
if (!indexFile.endsWith(htmlTag)) {
|
|
4075
|
+
consola14.warn("fix incomplete index.html...");
|
|
4076
|
+
const htmlTagStart = indexFile.lastIndexOf(htmlTag);
|
|
4077
|
+
await fs21.writeFile(indexPath, indexFile.slice(0, htmlTagStart + htmlTag.length), "utf-8");
|
|
4078
|
+
}
|
|
4079
|
+
}
|
|
4080
|
+
if (!options.config.siteConfig.redirects?.useVueRouter)
|
|
4081
|
+
await generateClientRedirects(options);
|
|
4082
|
+
}
|
|
4083
|
+
async function generateClientRedirects(options) {
|
|
4084
|
+
consola14.info("generate client redirects...");
|
|
4085
|
+
const outputPath = resolve13(options.userRoot, "dist");
|
|
4086
|
+
const redirectRules = collectRedirects(options.redirects);
|
|
4087
|
+
const task = redirectRules.map(async (rule) => {
|
|
4088
|
+
const fromPath = join8(outputPath, `${rule.from}.html`);
|
|
4089
|
+
const toPath = join8(outputPath, `${rule.to}.html`);
|
|
4090
|
+
const routeExist = await fs21.pathExists(toPath);
|
|
4091
|
+
if (!routeExist)
|
|
4092
|
+
throw new Error(`the route of '${rule.to}' not exists`);
|
|
4093
|
+
await writeRedirectFiles(rule.to, fromPath);
|
|
4094
|
+
});
|
|
4095
|
+
await Promise.all(task);
|
|
4096
|
+
}
|
|
4097
|
+
|
|
4098
|
+
// node/server.ts
|
|
4099
|
+
import process7 from "node:process";
|
|
4100
|
+
import { colors as colors13 } from "consola/utils";
|
|
4101
|
+
import { createServer as createViteServer, mergeConfig as mergeViteConfig3 } from "vite";
|
|
4102
|
+
function getServerInfoText(msg) {
|
|
4103
|
+
return `${valaxyPrefix} ${colors13.gray(msg)}`;
|
|
4104
|
+
}
|
|
4105
|
+
async function createServer(valaxyApp, viteConfig = {}, serverOptions = {}) {
|
|
4106
|
+
process7.env.EDITOR = process7.env.EDITOR || "code";
|
|
4107
|
+
const { options } = valaxyApp;
|
|
4108
|
+
const plugins = await ViteValaxyPlugins(valaxyApp, serverOptions);
|
|
4109
|
+
const enableDevtools = options.config.devtools;
|
|
4110
|
+
const vitePlugins = [
|
|
4111
|
+
...plugins
|
|
4112
|
+
];
|
|
4113
|
+
if (enableDevtools) {
|
|
4114
|
+
vitePlugins.push(
|
|
4115
|
+
(await import("vite-plugin-vue-devtools")).default(),
|
|
4116
|
+
(await import("@valaxyjs/devtools")).default({
|
|
4117
|
+
userRoot: options.userRoot
|
|
4118
|
+
})
|
|
4119
|
+
);
|
|
4120
|
+
}
|
|
4121
|
+
const mergedViteConfig = mergeViteConfig3(
|
|
4122
|
+
viteConfig,
|
|
4123
|
+
{
|
|
4124
|
+
plugins: vitePlugins
|
|
4125
|
+
}
|
|
4126
|
+
);
|
|
4127
|
+
const server = await createViteServer(mergedViteConfig);
|
|
4128
|
+
return server;
|
|
4129
|
+
}
|
|
4130
|
+
|
|
4131
|
+
// node/app/index.ts
|
|
4132
|
+
import { createHooks } from "hookable";
|
|
4133
|
+
var buildHooks = [
|
|
4134
|
+
"build:before",
|
|
4135
|
+
"build:after"
|
|
4136
|
+
];
|
|
4137
|
+
function createValaxyNode(options) {
|
|
4138
|
+
const hooks = createHooks();
|
|
4139
|
+
if (typeof options.config.hooks === "object") {
|
|
4140
|
+
Object.keys(options.config.hooks).forEach((name) => {
|
|
4141
|
+
const hookName = name;
|
|
4142
|
+
const hook = options.config.hooks[hookName];
|
|
4143
|
+
if (typeof hook !== "function")
|
|
4144
|
+
return;
|
|
4145
|
+
if (buildHooks.includes(hookName)) {
|
|
4146
|
+
if (options.mode === "build")
|
|
4147
|
+
hooks.hook(hookName, hook);
|
|
4148
|
+
} else {
|
|
4149
|
+
hooks.hook(hookName, hook);
|
|
4150
|
+
}
|
|
4151
|
+
});
|
|
4152
|
+
}
|
|
4153
|
+
const valaxyNode = {
|
|
4154
|
+
version,
|
|
4155
|
+
hooks,
|
|
4156
|
+
hook: hooks.hook,
|
|
4157
|
+
options
|
|
4158
|
+
};
|
|
4159
|
+
options.addons.forEach((addon) => {
|
|
4160
|
+
if (typeof addon.setup === "function")
|
|
4161
|
+
addon.setup(valaxyNode);
|
|
4162
|
+
});
|
|
4163
|
+
return valaxyNode;
|
|
4164
|
+
}
|
|
4165
|
+
|
|
4166
|
+
// node/cli/utils/cli.ts
|
|
4167
|
+
import os from "node:os";
|
|
4168
|
+
import path12 from "node:path";
|
|
4169
|
+
import process8 from "node:process";
|
|
4170
|
+
import * as readline from "node:readline";
|
|
4171
|
+
import consola15 from "consola";
|
|
4172
|
+
import { colors as colors14 } from "consola/utils";
|
|
4173
|
+
import ora4 from "ora";
|
|
4174
|
+
import { mergeConfig as mergeConfig3 } from "vite";
|
|
4175
|
+
|
|
4176
|
+
// node/env.ts
|
|
4177
|
+
var GLOBAL_STATE = {
|
|
4178
|
+
valaxyApp: void 0,
|
|
4179
|
+
server: void 0
|
|
4180
|
+
};
|
|
4181
|
+
|
|
4182
|
+
// node/cli/utils/cli.ts
|
|
4183
|
+
function printInfo(options, port, remote) {
|
|
4184
|
+
const themeVersion = colors14.blue(`v${options.config.themeConfig?.pkg?.version}`) || "unknown";
|
|
4185
|
+
console.log();
|
|
4186
|
+
console.log(` ${colors14.bold("\u{1F30C} Valaxy")} ${colors14.blue(`v${version}`)}`);
|
|
4187
|
+
console.log();
|
|
4188
|
+
console.log(`${colors14.dim(" \u{1FA90} theme ")} > ${options.theme ? colors14.green(options.theme) : colors14.gray("none")} (${themeVersion})`);
|
|
4189
|
+
console.log(` ${colors14.dim("\u{1F4C1}")} ${colors14.dim(path12.resolve(options.userRoot))}`);
|
|
4190
|
+
if (port) {
|
|
4191
|
+
console.log();
|
|
4192
|
+
console.log(`${colors14.dim(" Preview ")} > ${colors14.cyan(`http://localhost:${colors14.bold(port)}/`)}`);
|
|
4193
|
+
if (remote) {
|
|
4194
|
+
Object.values(os.networkInterfaces()).forEach(
|
|
4195
|
+
(v) => (v || []).filter((details) => details.family === "IPv4" && !details.address.includes("127.0.0.1")).forEach(({ address }) => {
|
|
4196
|
+
console.log(`${colors14.dim(" Network ")} > ${colors14.blue(`http://${address}:${colors14.bold(port)}/`)}`);
|
|
4197
|
+
})
|
|
4198
|
+
);
|
|
4199
|
+
}
|
|
4200
|
+
console.log();
|
|
4201
|
+
const restart = `${colors14.underline("r")}${colors14.dim("estart")}`;
|
|
4202
|
+
const edit = `${colors14.underline("e")}${colors14.dim("dit")}`;
|
|
4203
|
+
const open = `${colors14.underline("o")}${colors14.dim("pen")}`;
|
|
4204
|
+
const qr = `${colors14.underline("q")}${colors14.dim("r")}`;
|
|
4205
|
+
const divider = `${colors14.dim(" | ")}`;
|
|
4206
|
+
console.log(`${colors14.dim(" shortcuts ")} > ${restart}${divider}${open}${divider}${qr}${divider}${edit}`);
|
|
4207
|
+
}
|
|
4208
|
+
console.log();
|
|
4209
|
+
}
|
|
4210
|
+
var serverSpinner = ora4(`${valaxyPrefix} creating server ...`);
|
|
4211
|
+
async function initServer(valaxyApp, viteConfig) {
|
|
4212
|
+
if (GLOBAL_STATE.server) {
|
|
4213
|
+
vLogger.info("close server...");
|
|
4214
|
+
await GLOBAL_STATE.server.close();
|
|
4215
|
+
}
|
|
4216
|
+
const { options } = valaxyApp;
|
|
4217
|
+
serverSpinner.start();
|
|
4218
|
+
const viteConfigs = mergeConfig3(
|
|
4219
|
+
await mergeViteConfigs(options, "serve"),
|
|
4220
|
+
viteConfig
|
|
4221
|
+
);
|
|
4222
|
+
try {
|
|
4223
|
+
const server = await createServer(valaxyApp, viteConfigs, {
|
|
4224
|
+
async onConfigReload(newConfig, config, force = false) {
|
|
4225
|
+
if (force) {
|
|
4226
|
+
vLogger.info(`${colors14.yellow("force")} reload the server`);
|
|
4227
|
+
initServer(valaxyApp, viteConfig);
|
|
4228
|
+
}
|
|
4229
|
+
let reload = false;
|
|
4230
|
+
if (newConfig.theme !== config.theme)
|
|
4231
|
+
reload = true;
|
|
4232
|
+
if (reload)
|
|
4233
|
+
initServer(valaxyApp, viteConfig);
|
|
4234
|
+
}
|
|
4235
|
+
});
|
|
4236
|
+
await server.listen();
|
|
4237
|
+
serverSpinner.succeed(`${valaxyPrefix} ${colors14.green("server ready.")}`);
|
|
4238
|
+
GLOBAL_STATE.server = server;
|
|
4239
|
+
return server;
|
|
4240
|
+
} catch (e) {
|
|
4241
|
+
consola15.error("failed to start server. error:\n");
|
|
4242
|
+
console.error(e);
|
|
4243
|
+
process8.exit(1);
|
|
4244
|
+
}
|
|
4245
|
+
}
|
|
4246
|
+
function bindShortcut(SHORTCUTS) {
|
|
4247
|
+
process8.stdin.resume();
|
|
4248
|
+
process8.stdin.setEncoding("utf8");
|
|
4249
|
+
readline.emitKeypressEvents(process8.stdin);
|
|
4250
|
+
if (process8.stdin.isTTY)
|
|
4251
|
+
process8.stdin.setRawMode(true);
|
|
4252
|
+
process8.stdin.on("keypress", (str, key) => {
|
|
4253
|
+
if (key.ctrl && key.name === "c") {
|
|
4254
|
+
process8.exit();
|
|
4255
|
+
} else {
|
|
4256
|
+
const [sh] = SHORTCUTS.filter((item) => item.name === str);
|
|
4257
|
+
if (sh) {
|
|
4258
|
+
try {
|
|
4259
|
+
sh.action();
|
|
4260
|
+
} catch (err) {
|
|
4261
|
+
console.error(`Failed to execute shortcut ${sh.fullName}`, err);
|
|
4262
|
+
}
|
|
4263
|
+
}
|
|
4264
|
+
}
|
|
4265
|
+
});
|
|
4266
|
+
}
|
|
4267
|
+
if (import.meta.hot) {
|
|
4268
|
+
await import.meta.hot.data.stopping;
|
|
4269
|
+
let reload = async () => {
|
|
4270
|
+
consola15.info("HMR: Stop Server");
|
|
4271
|
+
await GLOBAL_STATE.server?.close();
|
|
4272
|
+
};
|
|
4273
|
+
import.meta.hot.on("vite:beforeFullReload", () => {
|
|
4274
|
+
const stopping = reload();
|
|
4275
|
+
reload = () => Promise.resolve();
|
|
4276
|
+
if (import.meta.hot)
|
|
4277
|
+
import.meta.hot.data.stopping = stopping;
|
|
4278
|
+
});
|
|
4279
|
+
}
|
|
4280
|
+
|
|
4281
|
+
// node/cli/build.ts
|
|
4282
|
+
async function execBuild({ ssg, root, output, log }) {
|
|
4283
|
+
setEnvProd();
|
|
4284
|
+
if (!isPagesDirExist(root))
|
|
4285
|
+
process9.exit(0);
|
|
4286
|
+
const userRoot2 = path13.resolve(root);
|
|
4287
|
+
const options = await resolveOptions({ userRoot: userRoot2 }, "build");
|
|
4288
|
+
setTimezone(options.config.siteConfig.timezone);
|
|
4289
|
+
printInfo(options);
|
|
4290
|
+
const valaxyApp = createValaxyNode(options);
|
|
4291
|
+
await callHookWithLog("options:resolved", valaxyApp);
|
|
4292
|
+
const modules2 = [];
|
|
4293
|
+
if (options.config.siteConfig.search.type === "fuse")
|
|
4294
|
+
modules2.push(fuseModule);
|
|
4295
|
+
if (options.config.modules.rss.enable)
|
|
4296
|
+
modules2.push(rssModule);
|
|
4297
|
+
setupModules(
|
|
4298
|
+
valaxyApp,
|
|
4299
|
+
modules2
|
|
4300
|
+
);
|
|
4301
|
+
const valaxyViteConfig = mergeConfig4(await mergeViteConfigs(options, "build"), options.config.vite || {});
|
|
4302
|
+
const viteConfig = mergeConfig4(
|
|
4303
|
+
valaxyViteConfig,
|
|
4304
|
+
{
|
|
4305
|
+
// avoid load userRoot/vite.config.ts repeatedly
|
|
4306
|
+
configFile: path13.resolve(options.clientRoot, "vite.config.ts"),
|
|
4307
|
+
build: {
|
|
4308
|
+
// make out dir empty, https://vitejs.dev/config/#build-emptyoutdir
|
|
4309
|
+
emptyOutDir: true,
|
|
4310
|
+
outDir: path13.resolve(options.userRoot, output)
|
|
4311
|
+
},
|
|
4312
|
+
logLevel: log
|
|
4313
|
+
}
|
|
4314
|
+
);
|
|
4315
|
+
await callHookWithLog("config:init", valaxyApp);
|
|
4316
|
+
await callHookWithLog("build:before", valaxyApp);
|
|
4317
|
+
consola16.box("\u{1F320} Start building...");
|
|
4318
|
+
try {
|
|
4319
|
+
if (ssg) {
|
|
4320
|
+
consola16.info(`use ${colors15.yellow("vite-ssg")} to do ssg build...`);
|
|
4321
|
+
try {
|
|
4322
|
+
await ssgBuild(valaxyApp, viteConfig);
|
|
4323
|
+
await postProcessForSSG(options);
|
|
4324
|
+
} catch (e) {
|
|
4325
|
+
consola16.error("[vite-ssg] An internal error occurred.");
|
|
4326
|
+
console.log(e);
|
|
4327
|
+
}
|
|
4328
|
+
} else {
|
|
4329
|
+
consola16.info("use vite do spa build...");
|
|
4330
|
+
await build2(valaxyApp, viteConfig);
|
|
4331
|
+
}
|
|
4332
|
+
} catch (e) {
|
|
4333
|
+
console.log(e);
|
|
4334
|
+
} finally {
|
|
4335
|
+
await callHookWithLog("build:after", valaxyApp);
|
|
4336
|
+
}
|
|
4337
|
+
}
|
|
4338
|
+
function registerBuildCommand(cli2) {
|
|
4339
|
+
cli2.command(
|
|
4340
|
+
"build [root]",
|
|
4341
|
+
"build your blog to static content",
|
|
4342
|
+
(args) => commonOptions(args).option("ssg", {
|
|
4343
|
+
alias: "s",
|
|
4344
|
+
type: "boolean",
|
|
4345
|
+
// https://github.com/antfu/vite-ssg/pull/219
|
|
4346
|
+
// to be true, when vite-ssg export build
|
|
4347
|
+
default: false,
|
|
4348
|
+
describe: "static site generate"
|
|
4349
|
+
}).option("output", {
|
|
4350
|
+
alias: "o",
|
|
4351
|
+
type: "string",
|
|
4352
|
+
default: "dist",
|
|
4353
|
+
describe: "output dir"
|
|
4354
|
+
}).option("log", {
|
|
4355
|
+
default: "warn",
|
|
4356
|
+
type: "string",
|
|
4357
|
+
choices: ["error", "warn", "info", "silent"],
|
|
4358
|
+
describe: "log level"
|
|
4359
|
+
}).strict().help(),
|
|
4360
|
+
async ({ ssg, root, output, log }) => {
|
|
4361
|
+
await execBuild({ ssg, root, output, log });
|
|
4362
|
+
}
|
|
4363
|
+
);
|
|
4364
|
+
}
|
|
4365
|
+
|
|
4366
|
+
// node/cli/clean.ts
|
|
4367
|
+
import path14 from "node:path";
|
|
4368
|
+
import process10 from "node:process";
|
|
4369
|
+
import consola17 from "consola";
|
|
4370
|
+
import fs22 from "fs-extra";
|
|
4371
|
+
|
|
4372
|
+
// node/cli/utils/fs.ts
|
|
4373
|
+
import { access } from "node:fs/promises";
|
|
4374
|
+
async function exists(path17) {
|
|
4375
|
+
try {
|
|
4376
|
+
await access(path17);
|
|
4377
|
+
return true;
|
|
4378
|
+
} catch (e) {
|
|
4379
|
+
return false;
|
|
4380
|
+
}
|
|
4381
|
+
}
|
|
4382
|
+
|
|
4383
|
+
// node/cli/clean.ts
|
|
4384
|
+
async function cleanDist() {
|
|
4385
|
+
const distDir = path14.join(process10.cwd(), "dist");
|
|
4386
|
+
const cacheDir = path14.join(process10.cwd(), ".valaxy");
|
|
4387
|
+
consola17.box("\u{1F9F9} Starting clean...");
|
|
4388
|
+
if (await exists(distDir)) {
|
|
4389
|
+
consola17.info("dist directory exists, removing...");
|
|
4390
|
+
try {
|
|
4391
|
+
await fs22.rm(distDir, { recursive: true, force: true });
|
|
4392
|
+
consola17.success("dist directory has been successfully removed.");
|
|
4393
|
+
} catch (error) {
|
|
4394
|
+
consola17.error("Failed to remove dist directory.");
|
|
4395
|
+
consola17.error(error);
|
|
4396
|
+
}
|
|
4397
|
+
} else {
|
|
4398
|
+
consola17.info("No dist directory found, nothing to clean.");
|
|
4399
|
+
}
|
|
4400
|
+
if (await exists(cacheDir)) {
|
|
4401
|
+
consola17.info(".valaxy cache directory exists, removing...");
|
|
4402
|
+
try {
|
|
4403
|
+
await fs22.rm(cacheDir, { recursive: true, force: true });
|
|
4404
|
+
consola17.success(".valaxy cache directory has been successfully removed.");
|
|
4405
|
+
} catch (error) {
|
|
4406
|
+
consola17.error("Failed to remove .valaxy cache directory.");
|
|
4407
|
+
consola17.error(error);
|
|
4408
|
+
}
|
|
4409
|
+
} else {
|
|
4410
|
+
consola17.info("No .valaxy cache directory found, nothing to clean.");
|
|
4411
|
+
}
|
|
4412
|
+
}
|
|
4413
|
+
function registerCleanCommand(cli2) {
|
|
4414
|
+
cli2.command(
|
|
4415
|
+
"clean",
|
|
4416
|
+
"Clean the dist folder and cache",
|
|
4417
|
+
() => {
|
|
4418
|
+
},
|
|
4419
|
+
async () => {
|
|
4420
|
+
await cleanDist();
|
|
4421
|
+
}
|
|
4422
|
+
);
|
|
4423
|
+
}
|
|
4424
|
+
|
|
4425
|
+
// node/cli/debug.ts
|
|
4426
|
+
import consola18 from "consola";
|
|
4427
|
+
function registerDebugCommand(cli2) {
|
|
4428
|
+
cli2.command("debug", "Debug your blog", async () => {
|
|
4429
|
+
consola18.info("\u63D0\u95EE\u524D\u8BF7\u643A\u5E26\u4EE5\u4E0B\u4FE1\u606F\uFF1A");
|
|
4430
|
+
});
|
|
4431
|
+
}
|
|
4432
|
+
|
|
4433
|
+
// node/cli/deploy.ts
|
|
4434
|
+
import process11 from "node:process";
|
|
4435
|
+
import { confirm, intro, outro, select } from "@clack/prompts";
|
|
4436
|
+
function registerDeployCommand(cli2) {
|
|
4437
|
+
cli2.command("deploy", "deploy your blog to the cloud", async () => {
|
|
4438
|
+
intro("Deploying Your Blog");
|
|
4439
|
+
const shouldBuild = await confirm({
|
|
4440
|
+
message: "Do you want to build your blog before deploying?"
|
|
4441
|
+
});
|
|
4442
|
+
if (shouldBuild) {
|
|
4443
|
+
await execBuild({ ssg: true, root: process11.cwd(), output: "dist", log: "info" });
|
|
4444
|
+
}
|
|
4445
|
+
const deployType = await select({
|
|
4446
|
+
message: "Where do you want to deploy?",
|
|
4447
|
+
options: [
|
|
4448
|
+
{ label: "GitHub Pages", value: "gh-pages", hint: "You need install `gh-pages` dependencies." },
|
|
4449
|
+
{ label: "Your Own Server", value: "server" }
|
|
4450
|
+
]
|
|
4451
|
+
});
|
|
4452
|
+
if (deployType === "gh-pages") {
|
|
4453
|
+
let isGhPagesInstalled = false;
|
|
4454
|
+
try {
|
|
4455
|
+
await import("gh-pages");
|
|
4456
|
+
isGhPagesInstalled = true;
|
|
4457
|
+
} catch (e) {
|
|
4458
|
+
console.error(e);
|
|
4459
|
+
const installGhPages = await confirm({
|
|
4460
|
+
message: "Do you want to install `gh-pages` now?"
|
|
4461
|
+
});
|
|
4462
|
+
if (installGhPages) {
|
|
4463
|
+
await import("@antfu/install-pkg").then((i) => i.installPackage("gh-pages", { dev: true }));
|
|
4464
|
+
isGhPagesInstalled = true;
|
|
4465
|
+
} else {
|
|
4466
|
+
outro("Please install `gh-pages` before deploying to GitHub Pages.");
|
|
4467
|
+
}
|
|
4468
|
+
}
|
|
4469
|
+
if (isGhPagesInstalled) {
|
|
4470
|
+
const { publish } = await import("gh-pages");
|
|
4471
|
+
await publish("dist", {
|
|
4472
|
+
branch: "gh-pages",
|
|
4473
|
+
message: "chore: deploy by valaxy"
|
|
4474
|
+
});
|
|
4475
|
+
outro("Done!");
|
|
4476
|
+
}
|
|
4477
|
+
}
|
|
4478
|
+
});
|
|
4479
|
+
}
|
|
4480
|
+
|
|
4481
|
+
// node/cli/dev.ts
|
|
4482
|
+
import { exec } from "node:child_process";
|
|
4483
|
+
import os2 from "node:os";
|
|
4484
|
+
import path15 from "node:path";
|
|
4485
|
+
import process12 from "node:process";
|
|
4486
|
+
import qrcode from "qrcode";
|
|
4487
|
+
import { mergeConfig as mergeConfig5 } from "vite";
|
|
4488
|
+
|
|
4489
|
+
// node/utils/net.ts
|
|
4490
|
+
import net from "node:net";
|
|
4491
|
+
async function findFreePort(start) {
|
|
4492
|
+
if (await isPortFree(start))
|
|
4493
|
+
return start;
|
|
4494
|
+
return await findFreePort(start + 1);
|
|
4495
|
+
}
|
|
4496
|
+
function isPortFree(port) {
|
|
4497
|
+
return new Promise((resolve15) => {
|
|
4498
|
+
const server = net.createServer((socket) => {
|
|
4499
|
+
socket.write("Echo server\r\n");
|
|
4500
|
+
socket.pipe(socket);
|
|
4501
|
+
});
|
|
4502
|
+
server.listen(port, "0.0.0.0");
|
|
4503
|
+
server.on("error", () => {
|
|
4504
|
+
resolve15(false);
|
|
4505
|
+
});
|
|
4506
|
+
server.on("listening", () => {
|
|
4507
|
+
server.close();
|
|
4508
|
+
resolve15(true);
|
|
4509
|
+
});
|
|
4510
|
+
});
|
|
4511
|
+
}
|
|
4512
|
+
|
|
4513
|
+
// node/cli/dev.ts
|
|
4514
|
+
async function startValaxyDev({
|
|
4515
|
+
root = process12.cwd(),
|
|
4516
|
+
port,
|
|
4517
|
+
remote,
|
|
4518
|
+
log,
|
|
4519
|
+
open
|
|
4520
|
+
}) {
|
|
4521
|
+
setEnv();
|
|
4522
|
+
if (!isPagesDirExist(root))
|
|
4523
|
+
process12.exit(0);
|
|
4524
|
+
port = port || await findFreePort(4859);
|
|
4525
|
+
const resolvedOptions = await resolveOptions({ userRoot: root });
|
|
4526
|
+
setTimezone(resolvedOptions.config.siteConfig.timezone);
|
|
4527
|
+
const valaxyApp = createValaxyNode(resolvedOptions);
|
|
4528
|
+
GLOBAL_STATE.valaxyApp = valaxyApp;
|
|
4529
|
+
const viteConfig = mergeConfig5({
|
|
4530
|
+
// initial vite config
|
|
4531
|
+
...defaultViteConfig,
|
|
4532
|
+
// avoid load userRoot/vite.config.ts repeatedly
|
|
4533
|
+
configFile: path15.resolve(resolvedOptions.clientRoot, "vite.config.ts"),
|
|
4534
|
+
server: {
|
|
4535
|
+
watch: {
|
|
4536
|
+
// watch theme updated
|
|
4537
|
+
ignored: [`!${resolvedOptions.themeRoot}/**`, `${resolvedOptions.userRoot}/**.md`]
|
|
4538
|
+
},
|
|
4539
|
+
port,
|
|
4540
|
+
strictPort: true,
|
|
4541
|
+
open,
|
|
4542
|
+
host: remote ? "0.0.0.0" : "localhost"
|
|
4543
|
+
},
|
|
4544
|
+
logLevel: log
|
|
4545
|
+
}, resolvedOptions.config.vite || {});
|
|
4546
|
+
await initServer(valaxyApp, viteConfig);
|
|
4547
|
+
printInfo(resolvedOptions, port, remote);
|
|
4548
|
+
const SHORTCUTS = [
|
|
4549
|
+
{
|
|
4550
|
+
name: "r",
|
|
4551
|
+
fullName: "restart",
|
|
4552
|
+
async action() {
|
|
4553
|
+
await initServer(valaxyApp, viteConfig);
|
|
4554
|
+
printInfo(resolvedOptions, port, remote);
|
|
4555
|
+
}
|
|
4556
|
+
},
|
|
4557
|
+
{
|
|
4558
|
+
name: "o",
|
|
4559
|
+
fullName: "open",
|
|
4560
|
+
async action() {
|
|
4561
|
+
const { default: openBrowser } = await import("open");
|
|
4562
|
+
openBrowser(`http://localhost:${port}`);
|
|
4563
|
+
}
|
|
4564
|
+
},
|
|
4565
|
+
{
|
|
4566
|
+
name: "q",
|
|
4567
|
+
fullName: "qr",
|
|
4568
|
+
action() {
|
|
4569
|
+
const addresses = Object.values(os2.networkInterfaces()).flat().filter((details) => details?.family === "IPv4" && !details.address.includes("127.0.0.1"));
|
|
4570
|
+
const remoteUrl = `http://${addresses[0]?.address || "localhost"}:${port}`;
|
|
4571
|
+
qrcode.toString(remoteUrl, { type: "terminal" }, (err, qrCode) => {
|
|
4572
|
+
if (err)
|
|
4573
|
+
throw err;
|
|
4574
|
+
console.log(qrCode);
|
|
4575
|
+
});
|
|
4576
|
+
}
|
|
4577
|
+
},
|
|
4578
|
+
{
|
|
4579
|
+
name: "e",
|
|
4580
|
+
fullName: "edit",
|
|
4581
|
+
action() {
|
|
4582
|
+
exec(`code "${root}"`);
|
|
4583
|
+
}
|
|
4584
|
+
}
|
|
4585
|
+
];
|
|
4586
|
+
bindShortcut(SHORTCUTS);
|
|
4587
|
+
}
|
|
4588
|
+
function registerDevCommand(cli2) {
|
|
4589
|
+
cli2.command(
|
|
4590
|
+
"* [root]",
|
|
4591
|
+
"Start a local server for Valaxy",
|
|
4592
|
+
(args) => commonOptions(args).option("port", {
|
|
4593
|
+
alias: "p",
|
|
4594
|
+
type: "number",
|
|
4595
|
+
describe: "port"
|
|
4596
|
+
}).option("open", {
|
|
4597
|
+
alias: "o",
|
|
4598
|
+
default: false,
|
|
4599
|
+
type: "boolean",
|
|
4600
|
+
describe: "open in browser"
|
|
4601
|
+
}).option("remote", {
|
|
4602
|
+
default: true,
|
|
4603
|
+
type: "boolean",
|
|
4604
|
+
describe: "listen public host and enable remote control"
|
|
4605
|
+
}).option("log", {
|
|
4606
|
+
default: "info",
|
|
4607
|
+
type: "string",
|
|
4608
|
+
choices: ["error", "warn", "info", "silent"],
|
|
4609
|
+
describe: "log level"
|
|
4610
|
+
}).strict().help(),
|
|
4611
|
+
async ({ root, port, open, remote, log }) => {
|
|
4612
|
+
startValaxyDev({
|
|
4613
|
+
root,
|
|
4614
|
+
open,
|
|
4615
|
+
port,
|
|
4616
|
+
remote,
|
|
4617
|
+
log
|
|
4618
|
+
});
|
|
4619
|
+
}
|
|
4620
|
+
);
|
|
4621
|
+
}
|
|
4622
|
+
|
|
4623
|
+
// node/cli/utils/post.ts
|
|
4624
|
+
import { writeFile as writeFile2 } from "node:fs/promises";
|
|
4625
|
+
import { join as join9, resolve as resolve14 } from "node:path";
|
|
4626
|
+
import { ensureSuffix as ensureSuffix2 } from "@antfu/utils";
|
|
4627
|
+
import { consola as consola19 } from "consola";
|
|
4628
|
+
import { colors as colors16 } from "consola/utils";
|
|
4629
|
+
import dayjs2 from "dayjs";
|
|
4630
|
+
import { render } from "ejs";
|
|
4631
|
+
|
|
4632
|
+
// node/cli/utils/constants.ts
|
|
4633
|
+
import process13 from "node:process";
|
|
4634
|
+
var userRoot = process13.cwd();
|
|
4635
|
+
var defaultPostTemplate = `---
|
|
4636
|
+
layout: <%=layout%>
|
|
4637
|
+
title: <%=title%>
|
|
4638
|
+
date: <%=date%>
|
|
4639
|
+
---
|
|
4640
|
+
`;
|
|
4641
|
+
|
|
4642
|
+
// node/cli/utils/scaffold.ts
|
|
4643
|
+
import { readFile as readFile2 } from "node:fs/promises";
|
|
4644
|
+
import path16 from "node:path";
|
|
4645
|
+
async function getTemplate(layout) {
|
|
4646
|
+
const { clientRoot, themeRoot } = await resolveOptions({ userRoot });
|
|
4647
|
+
const roots = [userRoot, themeRoot, clientRoot];
|
|
4648
|
+
for (const root of roots) {
|
|
4649
|
+
const scaffoldPath = path16.resolve(root, "scaffolds", `${layout}.md`);
|
|
4650
|
+
if (await exists(scaffoldPath))
|
|
4651
|
+
return readFile2(scaffoldPath, "utf-8");
|
|
4652
|
+
}
|
|
4653
|
+
return false;
|
|
4654
|
+
}
|
|
4655
|
+
|
|
4656
|
+
// node/cli/utils/post.ts
|
|
4657
|
+
async function create(data) {
|
|
4658
|
+
const pagesPath = resolve14(userRoot, "pages");
|
|
4659
|
+
const {
|
|
4660
|
+
path: path17,
|
|
4661
|
+
title
|
|
4662
|
+
} = data;
|
|
4663
|
+
const postPath = path17 || join9("posts", title);
|
|
4664
|
+
let counter = 0;
|
|
4665
|
+
while (true) {
|
|
4666
|
+
let destinationPath = resolve14(pagesPath, postPath);
|
|
4667
|
+
if (counter)
|
|
4668
|
+
destinationPath = `${destinationPath}-${counter}`;
|
|
4669
|
+
destinationPath = ensureSuffix2(".md", destinationPath);
|
|
4670
|
+
if (!await exists(destinationPath)) {
|
|
4671
|
+
const content = await genLayoutTemplate(data);
|
|
4672
|
+
try {
|
|
4673
|
+
await writeFile2(destinationPath, content, "utf-8");
|
|
4674
|
+
consola19.success(`[valaxy new]: successfully generated file ${colors16.magenta(destinationPath)}`);
|
|
4675
|
+
} catch (e) {
|
|
4676
|
+
console.log(e);
|
|
4677
|
+
consola19.error(`[valaxy new]: failed to write file ${destinationPath}`);
|
|
4678
|
+
consola19.warn(`You should run ${colors16.green("valaxy new")} in your valaxy project root directory.`);
|
|
4679
|
+
}
|
|
4680
|
+
return destinationPath;
|
|
4681
|
+
}
|
|
4682
|
+
counter++;
|
|
4683
|
+
}
|
|
4684
|
+
}
|
|
4685
|
+
async function genLayoutTemplate({
|
|
4686
|
+
date,
|
|
4687
|
+
title,
|
|
4688
|
+
layout = "post"
|
|
4689
|
+
}) {
|
|
4690
|
+
let template = await getTemplate(layout);
|
|
4691
|
+
if (!template)
|
|
4692
|
+
template = defaultPostTemplate;
|
|
4693
|
+
const dateFormat = "YYYY-MM-DD HH:mm:ss";
|
|
4694
|
+
return render(template, { title, layout, date: date ? dayjs2().format(dateFormat) : "" });
|
|
4695
|
+
}
|
|
4696
|
+
|
|
4697
|
+
// node/cli/new.ts
|
|
4698
|
+
function registerNewCommand(cli2) {
|
|
4699
|
+
cli2.command(
|
|
4700
|
+
"new <title>",
|
|
4701
|
+
"Draft a new post",
|
|
4702
|
+
(args) => {
|
|
4703
|
+
args.usage("$0 <title> -p [path] -l [layout]").positional("title", {
|
|
4704
|
+
describe: "The title of the new post",
|
|
4705
|
+
required: true
|
|
4706
|
+
}).option("path", {
|
|
4707
|
+
alias: "p",
|
|
4708
|
+
type: "string",
|
|
4709
|
+
describe: "the path to generate new post. Customize the path of post to generate"
|
|
4710
|
+
}).option("layout", {
|
|
4711
|
+
alias: "l",
|
|
4712
|
+
type: "string",
|
|
4713
|
+
default: "post"
|
|
4714
|
+
}).option("date", {
|
|
4715
|
+
alias: "d",
|
|
4716
|
+
type: "boolean",
|
|
4717
|
+
default: true,
|
|
4718
|
+
describe: "Generate post with the current date"
|
|
4719
|
+
}).strict().help();
|
|
4720
|
+
},
|
|
4721
|
+
async ({ title, path: path17, date, layout }) => {
|
|
4722
|
+
await create({
|
|
4723
|
+
title,
|
|
4724
|
+
date,
|
|
4725
|
+
layout,
|
|
4726
|
+
path: path17
|
|
4727
|
+
});
|
|
4728
|
+
}
|
|
4729
|
+
);
|
|
4730
|
+
}
|
|
4731
|
+
|
|
4732
|
+
// node/cli/index.ts
|
|
4733
|
+
var cli = yargs(hideBin(process14.argv)).scriptName("valaxy").usage("$0 [args]").version(version).showHelpOnFail(false).alias("h", "help").alias("v", "version");
|
|
4734
|
+
registerDevCommand(cli);
|
|
4735
|
+
registerBuildCommand(cli);
|
|
4736
|
+
registerNewCommand(cli);
|
|
4737
|
+
registerCleanCommand(cli);
|
|
4738
|
+
registerDeployCommand(cli);
|
|
4739
|
+
registerDebugCommand(cli);
|
|
4740
|
+
cli.help();
|
|
4741
|
+
var modules = [
|
|
4742
|
+
fuseModule,
|
|
4743
|
+
rssModule
|
|
4744
|
+
];
|
|
4745
|
+
modules.forEach((module) => {
|
|
4746
|
+
module.extendCli?.(cli);
|
|
4747
|
+
});
|
|
4748
|
+
function run() {
|
|
4749
|
+
cli.parse();
|
|
4750
|
+
}
|
|
4751
|
+
|
|
4752
|
+
export {
|
|
4753
|
+
EXCERPT_SEPARATOR,
|
|
4754
|
+
EXTERNAL_URL_RE,
|
|
4755
|
+
PATHNAME_PROTOCOL_RE,
|
|
4756
|
+
ALL_ROUTE,
|
|
4757
|
+
customElements,
|
|
4758
|
+
defaultViteConfig,
|
|
4759
|
+
getGitTimestamp,
|
|
4760
|
+
isExternal,
|
|
4761
|
+
isPath,
|
|
4762
|
+
transformObject,
|
|
4763
|
+
isInstalledGlobally,
|
|
4764
|
+
resolveImportUrl,
|
|
4765
|
+
toAtFS,
|
|
4766
|
+
resolveImportPath,
|
|
4767
|
+
mergeViteConfigs,
|
|
4768
|
+
getIndexHtml,
|
|
4769
|
+
loadConfig,
|
|
4770
|
+
loadConfigFromFile,
|
|
4771
|
+
defaultSiteConfig,
|
|
4772
|
+
defineSiteConfig,
|
|
4773
|
+
resolveSiteConfigFromRoot,
|
|
4774
|
+
resolveSiteConfig,
|
|
4775
|
+
defaultValaxyConfig,
|
|
4776
|
+
defineValaxyConfig,
|
|
4777
|
+
defineConfig,
|
|
4778
|
+
resolveValaxyConfigFromRoot,
|
|
4779
|
+
mergeValaxyConfig,
|
|
4780
|
+
resolveValaxyConfig,
|
|
4781
|
+
defineValaxyAddon,
|
|
4782
|
+
defineAddon,
|
|
4783
|
+
resolveAddonsConfig,
|
|
4784
|
+
resolveThemeConfigFromRoot,
|
|
4785
|
+
resolveUserThemeConfig,
|
|
4786
|
+
defineValaxyTheme,
|
|
4787
|
+
defineTheme,
|
|
4788
|
+
defineUnoSetup,
|
|
4789
|
+
processValaxyOptions,
|
|
4790
|
+
resolveOptions,
|
|
4791
|
+
resolveThemeValaxyConfig,
|
|
4792
|
+
createValaxyLoader,
|
|
4793
|
+
ViteValaxyPlugins,
|
|
4794
|
+
build2 as build,
|
|
4795
|
+
ssgBuild,
|
|
4796
|
+
postProcessForSSG,
|
|
4797
|
+
generateClientRedirects,
|
|
4798
|
+
getServerInfoText,
|
|
4799
|
+
createServer,
|
|
4800
|
+
startValaxyDev,
|
|
4801
|
+
registerDevCommand,
|
|
4802
|
+
cli,
|
|
4803
|
+
run
|
|
4804
|
+
};
|
|
4805
|
+
/*! Bundled license information:
|
|
4806
|
+
|
|
4807
|
+
@mdit-vue/shared/dist/index.mjs:
|
|
4808
|
+
(* istanbul ignore if -- @preserve *)
|
|
4809
|
+
|
|
4810
|
+
@mdit-vue/plugin-sfc/dist/index.mjs:
|
|
4811
|
+
(* istanbul ignore if -- @preserve *)
|
|
4812
|
+
*/
|