valaxy 0.28.0 → 0.28.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  import 'node:process';
2
2
  import 'yargs';
3
3
  import 'yargs/helpers';
4
- export { c as cli, I as registerDevCommand, W as run, Z as startValaxyDev } from '../../shared/valaxy.DQ6HsU2J.mjs';
4
+ export { c as cli, I as registerDevCommand, W as run, Z as startValaxyDev } from '../../shared/valaxy.DFTOADvQ.mjs';
5
5
  import 'node:os';
6
6
  import 'node:path';
7
7
  import 'consola';
@@ -29,6 +29,7 @@ import 'feed';
29
29
  import 'markdown-it';
30
30
  import 'table';
31
31
  import 'hookable';
32
+ import 'node:fs';
32
33
  import 'node:child_process';
33
34
  import 'node:v8';
34
35
  import 'vite-ssg-sitemap';
@@ -57,7 +58,6 @@ import 'p-map';
57
58
  import 'node:buffer';
58
59
  import 'minisearch';
59
60
  import 'lru-cache';
60
- import 'node:fs';
61
61
  import 'jiti';
62
62
  import 'unocss';
63
63
  import 'pascalcase';
@@ -1,7 +1,7 @@
1
1
  import { ViteSSGOptions } from 'vite-ssg';
2
2
  import * as vite from 'vite';
3
3
  import { UserConfig, InlineConfig, ViteDevServer, PluginOption, Plugin } from 'vite';
4
- import { D as DefaultTheme, R as RuntimeConfig, a as RedirectItem, V as ValaxyConfig, P as PartialDeep, b as ValaxyAddon, S as SiteConfig, U as UserSiteConfig } from '../shared/valaxy.6MW2qn5T.mjs';
4
+ import { S as SiteConfig, D as DefaultTheme, R as RuntimeConfig, a as RedirectItem, V as ValaxyConfig, P as PartialDeep, b as ValaxyAddon, U as UserSiteConfig } from '../shared/valaxy.6MW2qn5T.mjs';
5
5
  import Vue from '@vitejs/plugin-vue';
6
6
  import { Hookable } from 'hookable';
7
7
  import { PluginVisualizerOptions } from 'rollup-plugin-visualizer';
@@ -445,6 +445,14 @@ interface ValaxyHooks {
445
445
  'md:afterRender': (ctx: MdAfterRenderContext) => HookResult;
446
446
  'build:before': () => HookResult;
447
447
  'build:after': () => HookResult;
448
+ /**
449
+ * Called to compute statistics (word count, reading time) for a markdown route.
450
+ * Default implementation uses `presetStatistics`; addons/themes can hook to override.
451
+ */
452
+ 'statistics': (ctx: {
453
+ route: EditableTreeNode;
454
+ options: SiteConfig['statistics'];
455
+ }) => HookResult;
448
456
  /**
449
457
  * @experimental
450
458
  * Called before content loaders start fetching.
@@ -1,4 +1,4 @@
1
- export { A as ALL_ROUTE, E as EXCERPT_SEPARATOR, G as GLOBAL_STATE, P as PATHNAME_PROTOCOL_RE, V as ViteValaxyPlugins, b as build, c as cli, a as createServer, d as createValaxyPlugin, e as customElements, f as defaultSiteConfig, g as defaultValaxyConfig, h as defaultViteConfig, i as defineAddon, j as defineConfig, k as defineSiteConfig, l as defineTheme, m as defineValaxyAddon, n as defineValaxyConfig, o as defineValaxyTheme, p as encryptContent, q as generateClientRedirects, r as getGitTimestamp, s as getIndexHtml, t as getServerInfoText, u as isExternal, v as isInstalledGlobally, w as isKatexEnabled, x as isKatexPluginNeeded, y as isMathJaxEnabled, z as isPath, B as loadConfigFromFile, C as mergeValaxyConfig, D as mergeViteConfigs, F as postProcessForSSG, H as processValaxyOptions, I as registerDevCommand, J as resolveAddonsConfig, K as resolveImportPath, L as resolveImportUrl, M as resolveOptions, N as resolveSiteConfig, O as resolveSiteConfigFromRoot, Q as resolveThemeConfigFromRoot, R as resolveThemeValaxyConfig, S as resolveUserThemeConfig, T as resolveValaxyConfig, U as resolveValaxyConfigFromRoot, W as run, X as ssgBuild, Y as ssgBuildLegacy, Z as startValaxyDev, _ as toAtFS, $ as transformObject, a0 as version } from '../shared/valaxy.DQ6HsU2J.mjs';
1
+ export { A as ALL_ROUTE, E as EXCERPT_SEPARATOR, G as GLOBAL_STATE, P as PATHNAME_PROTOCOL_RE, V as ViteValaxyPlugins, b as build, c as cli, a as createServer, d as createValaxyPlugin, e as customElements, f as defaultSiteConfig, g as defaultValaxyConfig, h as defaultViteConfig, i as defineAddon, j as defineConfig, k as defineSiteConfig, l as defineTheme, m as defineValaxyAddon, n as defineValaxyConfig, o as defineValaxyTheme, p as encryptContent, q as generateClientRedirects, r as getGitTimestamp, s as getIndexHtml, t as getServerInfoText, u as isExternal, v as isInstalledGlobally, w as isKatexEnabled, x as isKatexPluginNeeded, y as isMathJaxEnabled, z as isPath, B as loadConfigFromFile, C as mergeValaxyConfig, D as mergeViteConfigs, F as postProcessForSSG, H as processValaxyOptions, I as registerDevCommand, J as resolveAddonsConfig, K as resolveImportPath, L as resolveImportUrl, M as resolveOptions, N as resolveSiteConfig, O as resolveSiteConfigFromRoot, Q as resolveThemeConfigFromRoot, R as resolveThemeValaxyConfig, S as resolveUserThemeConfig, T as resolveValaxyConfig, U as resolveValaxyConfigFromRoot, W as run, X as ssgBuild, Y as ssgBuildLegacy, Z as startValaxyDev, _ as toAtFS, $ as transformObject, a0 as version } from '../shared/valaxy.DFTOADvQ.mjs';
2
2
  import 'node:path';
3
3
  import 'fs-extra';
4
4
  import 'consola/utils';
@@ -29,6 +29,7 @@ import 'feed';
29
29
  import 'markdown-it';
30
30
  import 'table';
31
31
  import 'hookable';
32
+ import 'node:fs';
32
33
  import 'node:child_process';
33
34
  import 'node:v8';
34
35
  import 'vite-ssg-sitemap';
@@ -57,7 +58,6 @@ import 'p-map';
57
58
  import 'node:buffer';
58
59
  import 'minisearch';
59
60
  import 'lru-cache';
60
- import 'node:fs';
61
61
  import 'jiti';
62
62
  import 'unocss';
63
63
  import 'pascalcase';
@@ -28,6 +28,7 @@ import { Feed } from 'feed';
28
28
  import MarkdownIt from 'markdown-it';
29
29
  import { table, getBorderCharacters } from 'table';
30
30
  import { createHooks } from 'hookable';
31
+ import { existsSync, readFileSync } from 'node:fs';
31
32
  import { execFileSync, execSync, exec } from 'node:child_process';
32
33
  import v8 from 'node:v8';
33
34
  import generateSitemap from 'vite-ssg-sitemap';
@@ -56,14 +57,13 @@ import pMap from 'p-map';
56
57
  import { Buffer as Buffer$1 } from 'node:buffer';
57
58
  import MiniSearch from 'minisearch';
58
59
  import { LRUCache } from 'lru-cache';
59
- import { existsSync, readFileSync } from 'node:fs';
60
60
  import { createJiti } from 'jiti';
61
61
  import { transformerDirectives, transformerVariantGroup, presetWind4, presetAttributify, presetIcons, presetTypography } from 'unocss';
62
62
  import pascalCase from 'pascalcase';
63
63
  import { convert } from 'html-to-text';
64
64
  import VueRouter from 'vue-router/vite';
65
65
  import { renderSSRHead } from '@unhead/vue/server';
66
- import { intro, confirm, select, outro } from '@clack/prompts';
66
+ import { intro, confirm, isCancel, cancel, select, outro } from '@clack/prompts';
67
67
  import net from 'node:net';
68
68
  import * as readline from 'node:readline';
69
69
  import qrcode from 'qrcode';
@@ -1721,7 +1721,7 @@ async function setupMarkdownPlugins(md, options, base = "/") {
1721
1721
  return md;
1722
1722
  }
1723
1723
 
1724
- const version = "0.28.0";
1724
+ const version = "0.28.1";
1725
1725
 
1726
1726
  const GLOBAL_STATE = {
1727
1727
  valaxyApp: void 0,
@@ -3109,12 +3109,68 @@ function clearHtmlTags(str) {
3109
3109
  return str.replace(/<[^>]*>/g, "").replace(/\s+/g, " ");
3110
3110
  }
3111
3111
 
3112
+ function count(content) {
3113
+ const cn = (content.match(/[\u4E00-\u9FA5]/g) || []).length;
3114
+ 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;
3115
+ return {
3116
+ cn,
3117
+ en
3118
+ };
3119
+ }
3120
+ function readTime({ cn, en }, options) {
3121
+ const readingTime = cn / (options.speed.cn || 300) + en / (options.speed.en || 100);
3122
+ return readingTime < 1 ? 1 : Math.ceil(readingTime);
3123
+ }
3124
+ function wordCount({ cn, en }) {
3125
+ const num = cn + en;
3126
+ if (num < 1e3)
3127
+ return num.toString();
3128
+ return `${Math.round(num / 100) / 10}k`;
3129
+ }
3130
+ function statistics(content, options) {
3131
+ const countData = count(content);
3132
+ return {
3133
+ countData,
3134
+ wordCount: wordCount(countData),
3135
+ readingTime: readTime(countData, options.readTime)
3136
+ };
3137
+ }
3138
+ function presetStatistics({
3139
+ route,
3140
+ options
3141
+ }) {
3142
+ const absolutePath = route.components.get("default") || "";
3143
+ if (existsSync(absolutePath)) {
3144
+ const file = readFileSync(absolutePath, "utf-8");
3145
+ const { wordCount: wordCount2, readingTime } = statistics(file, {
3146
+ readTime: {
3147
+ ...options.readTime,
3148
+ speed: {
3149
+ cn: options.readTime?.speed?.cn || 300,
3150
+ en: options.readTime?.speed?.en || 100
3151
+ }
3152
+ }
3153
+ });
3154
+ const { frontmatter } = route.meta;
3155
+ if (frontmatter && typeof frontmatter === "object" && !Array.isArray(frontmatter)) {
3156
+ const fm = frontmatter;
3157
+ if (!fm.wordCount)
3158
+ fm.wordCount = wordCount2;
3159
+ if (!fm.readingTime)
3160
+ fm.readingTime = readingTime;
3161
+ }
3162
+ }
3163
+ }
3164
+
3112
3165
  const buildHooks = [
3113
3166
  "build:before",
3114
3167
  "build:after"
3115
3168
  ];
3116
3169
  function createValaxyNode(options) {
3117
3170
  const hooks = createHooks();
3171
+ hooks.hook("statistics", ({ route, options: statsOptions }) => {
3172
+ presetStatistics({ route, options: statsOptions });
3173
+ });
3118
3174
  if (typeof options.config.hooks === "object") {
3119
3175
  Object.keys(options.config.hooks).forEach((name) => {
3120
3176
  const hookName = name;
@@ -4302,59 +4358,6 @@ async function createValaxyPlugin(options, serverOptions = {}) {
4302
4358
  ];
4303
4359
  }
4304
4360
 
4305
- function count(content) {
4306
- const cn = (content.match(/[\u4E00-\u9FA5]/g) || []).length;
4307
- 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;
4308
- return {
4309
- cn,
4310
- en
4311
- };
4312
- }
4313
- function readTime({ cn, en }, options) {
4314
- const readingTime = cn / (options.speed.cn || 300) + en / (options.speed.en || 100);
4315
- return readingTime < 1 ? 1 : Math.ceil(readingTime);
4316
- }
4317
- function wordCount({ cn, en }) {
4318
- const num = cn + en;
4319
- if (num < 1e3)
4320
- return num.toString();
4321
- return `${Math.round(num / 100) / 10}k`;
4322
- }
4323
- function statistics(content, options) {
4324
- const countData = count(content);
4325
- return {
4326
- countData,
4327
- wordCount: wordCount(countData),
4328
- readingTime: readTime(countData, options.readTime)
4329
- };
4330
- }
4331
- function presetStatistics({
4332
- route,
4333
- options
4334
- }) {
4335
- const absolutePath = route.components.get("default") || "";
4336
- if (existsSync(absolutePath)) {
4337
- const file = readFileSync(absolutePath, "utf-8");
4338
- const { wordCount: wordCount2, readingTime } = statistics(file, {
4339
- readTime: {
4340
- ...options.readTime,
4341
- speed: {
4342
- cn: options.readTime?.speed?.cn || 300,
4343
- en: options.readTime?.speed?.en || 100
4344
- }
4345
- }
4346
- });
4347
- const { frontmatter } = route.meta;
4348
- if (frontmatter && typeof frontmatter === "object" && !Array.isArray(frontmatter)) {
4349
- const fm = frontmatter;
4350
- if (!fm.wordCount)
4351
- fm.wordCount = wordCount2;
4352
- if (!fm.readingTime)
4353
- fm.readingTime = readingTime;
4354
- }
4355
- }
4356
- }
4357
-
4358
4361
  async function getExcerptByType(excerpt = "", type = "html", mdIt) {
4359
4362
  switch (type) {
4360
4363
  case "ai":
@@ -4433,7 +4436,7 @@ async function createRouterPlugin(valaxyApp) {
4433
4436
  const md = await fs.readFile(path, "utf-8");
4434
4437
  const { data, excerpt, content } = matter(md, matterOptions);
4435
4438
  const mdFm = data;
4436
- const lastUpdated = options.config.siteConfig.lastUpdated;
4439
+ const lastUpdated = valaxyConfig.siteConfig.lastUpdated;
4437
4440
  delete mdFm.password;
4438
4441
  if (mdFm.gallery_password) {
4439
4442
  delete mdFm.gallery_password;
@@ -4471,8 +4474,7 @@ async function createRouterPlugin(valaxyApp) {
4471
4474
  ];
4472
4475
  const routerFM = {
4473
4476
  ...mdFm,
4474
- // 主题有新的字段需要主动设置
4475
- // @TODO 添加文档和配置项,或者反过来允许用户自行优化
4477
+ // Normalize tags: ensure always an array for consistent consumption
4476
4478
  tags: typeof mdFm.tags === "string" ? [mdFm.tags] : mdFm.tags,
4477
4479
  // set default updated to date if not present
4478
4480
  updated: mdFm.updated ?? mdFm.date
@@ -4497,7 +4499,7 @@ async function createRouterPlugin(valaxyApp) {
4497
4499
  });
4498
4500
  }
4499
4501
  if (valaxyConfig.siteConfig.statistics.enable) {
4500
- presetStatistics({
4502
+ await valaxyApp.hooks.callHook("statistics", {
4501
4503
  options: valaxyConfig.siteConfig.statistics,
4502
4504
  route
4503
4505
  });
@@ -6205,48 +6207,81 @@ function registerDebugCommand(cli) {
6205
6207
  }
6206
6208
 
6207
6209
  function registerDeployCommand(cli) {
6208
- cli.command("deploy", "deploy your blog to the cloud", async () => {
6209
- intro("Deploying Your Blog");
6210
- const shouldBuild = await confirm({
6211
- message: "Do you want to build your blog before deploying?"
6212
- });
6213
- if (shouldBuild) {
6214
- await execBuild({ ssg: true, ssgEngine: "valaxy", root: process.cwd(), output: "dist", log: "info" });
6215
- }
6216
- const deployType = await select({
6217
- message: "Where do you want to deploy?",
6218
- options: [
6219
- { label: "GitHub Pages", value: "gh-pages", hint: "You need install `gh-pages` dependencies." },
6220
- { label: "Your Own Server", value: "server" }
6221
- ]
6222
- });
6223
- if (deployType === "gh-pages") {
6224
- let isGhPagesInstalled = false;
6225
- try {
6226
- await import('gh-pages');
6227
- isGhPagesInstalled = true;
6228
- } catch (e) {
6229
- console.error(e);
6230
- const installGhPages = await confirm({
6231
- message: "Do you want to install `gh-pages` now?"
6232
- });
6233
- if (installGhPages) {
6234
- await import('@antfu/install-pkg').then((i) => i.installPackage("gh-pages", { dev: true }));
6210
+ cli.command(
6211
+ "deploy [root]",
6212
+ "deploy your blog to the cloud",
6213
+ (args) => commonOptions(args).option("type", {
6214
+ type: "string",
6215
+ choices: ["gh-pages", "remote"],
6216
+ describe: "deploy type, overrides `deploy.type` in config"
6217
+ }).option("output", {
6218
+ alias: "o",
6219
+ type: "string",
6220
+ default: "dist",
6221
+ describe: "output dir"
6222
+ }).strict().help(),
6223
+ async ({ root, type, output }) => {
6224
+ intro("Deploying Your Blog");
6225
+ const shouldBuild = await confirm({
6226
+ message: "Do you want to build your blog before deploying?"
6227
+ });
6228
+ if (isCancel(shouldBuild)) {
6229
+ cancel("Operation cancelled.");
6230
+ process.exit(0);
6231
+ }
6232
+ if (shouldBuild) {
6233
+ await execBuild({ ssg: true, ssgEngine: "valaxy", root, output, log: "info" });
6234
+ }
6235
+ const options = await resolveOptions({ userRoot: root }, "build");
6236
+ const configDeployType = type ?? options.config.deploy?.type;
6237
+ const deployType = configDeployType ?? await select({
6238
+ message: "Where do you want to deploy?",
6239
+ options: [
6240
+ { label: "GitHub Pages", value: "gh-pages", hint: "You need install `gh-pages` dependencies." },
6241
+ { label: "Your Own Server", value: "remote" }
6242
+ ]
6243
+ });
6244
+ if (isCancel(deployType)) {
6245
+ cancel("Operation cancelled.");
6246
+ process.exit(0);
6247
+ }
6248
+ if (deployType === "gh-pages") {
6249
+ let isGhPagesInstalled = false;
6250
+ try {
6251
+ await import('gh-pages');
6235
6252
  isGhPagesInstalled = true;
6236
- } else {
6237
- outro("Please install `gh-pages` before deploying to GitHub Pages.");
6253
+ } catch {
6254
+ const installGhPages = await confirm({
6255
+ message: "Do you want to install `gh-pages` now?"
6256
+ });
6257
+ if (isCancel(installGhPages)) {
6258
+ cancel("Operation cancelled.");
6259
+ process.exit(0);
6260
+ }
6261
+ if (installGhPages) {
6262
+ try {
6263
+ await import('@antfu/install-pkg').then((i) => i.installPackage("gh-pages", { dev: true }));
6264
+ isGhPagesInstalled = true;
6265
+ } catch (e) {
6266
+ consola.error("Failed to install `gh-pages`:", e);
6267
+ }
6268
+ } else {
6269
+ outro("Please install `gh-pages` before deploying to GitHub Pages.");
6270
+ }
6238
6271
  }
6239
- }
6240
- if (isGhPagesInstalled) {
6241
- const { publish } = await import('gh-pages');
6242
- await publish("dist", {
6243
- branch: "gh-pages",
6244
- message: "chore: deploy by valaxy"
6245
- });
6246
- outro("Done!");
6272
+ if (isGhPagesInstalled) {
6273
+ const { publish } = await import('gh-pages');
6274
+ await publish(output, {
6275
+ branch: "gh-pages",
6276
+ message: "chore: deploy by valaxy"
6277
+ });
6278
+ outro("Done!");
6279
+ }
6280
+ } else if (deployType === "remote") {
6281
+ outro("Remote deployment is not yet implemented.");
6247
6282
  }
6248
6283
  }
6249
- });
6284
+ );
6250
6285
  }
6251
6286
 
6252
6287
  async function findFreePort(start) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "valaxy",
3
3
  "type": "module",
4
- "version": "0.28.0",
4
+ "version": "0.28.1",
5
5
  "description": "📄 Vite & Vue powered static blog generator.",
6
6
  "author": {
7
7
  "email": "me@yunyoujun.cn",
@@ -139,8 +139,8 @@
139
139
  "vue-i18n": "^11.3.0",
140
140
  "vue-router": "^5.0.4",
141
141
  "yargs": "^18.0.0",
142
- "@valaxyjs/devtools": "0.28.0",
143
- "@valaxyjs/utils": "0.28.0"
142
+ "@valaxyjs/devtools": "0.28.1",
143
+ "@valaxyjs/utils": "0.28.1"
144
144
  },
145
145
  "devDependencies": {
146
146
  "@mdit-vue/plugin-component": "^3.0.2",