@slidev/cli 52.8.0 → 52.9.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,5 +1,5 @@
1
- import { t as resolveViteConfigs } from "./shared-OlAiAU1s.mjs";
2
- import "./resolver-Dl3RCceV.mjs";
1
+ import { t as resolveViteConfigs } from "./shared-D3BW4vqA.mjs";
2
+ import "./resolver-Du-CxvL9.mjs";
3
3
  import fs from "node:fs/promises";
4
4
  import { join, resolve } from "node:path";
5
5
  import { build as build$1 } from "vite";
@@ -45,7 +45,7 @@ async function build(options, viteConfig = {}, args) {
45
45
  dev: true
46
46
  }));
47
47
  server.listen(port);
48
- const { exportSlides } = await import("./export-dSJYnjas.mjs");
48
+ const { exportSlides } = await import("./export-snweM1-1.mjs");
49
49
  const tempDir = resolve(outDir, "temp");
50
50
  await fs.mkdir(tempDir, { recursive: true });
51
51
  await exportSlides({
@@ -86,7 +86,7 @@ async function build(options, viteConfig = {}, args) {
86
86
  "true",
87
87
  "auto"
88
88
  ].includes(options.data.config.download)) {
89
- const { exportSlides, getExportOptions } = await import("./export-dSJYnjas.mjs");
89
+ const { exportSlides, getExportOptions } = await import("./export-snweM1-1.mjs");
90
90
  const port = 12445;
91
91
  const app = connect();
92
92
  const server = http.createServer(app);
package/dist/cli.mjs CHANGED
@@ -1,6 +1,6 @@
1
- import { a as loadSetups, c as resolveTheme, d as version, i as resolveOptions, l as resolveAddons, o as parser, s as getThemeMeta, u as updateFrontmatterPatch } from "./shared-OlAiAU1s.mjs";
2
- import { i as resolveEntry, n as getRoots, r as isInstalledGlobally } from "./resolver-Dl3RCceV.mjs";
3
- import { t as createServer } from "./serve-DiGMRooB.mjs";
1
+ import { a as loadSetups, c as resolveTheme, d as version, i as resolveOptions, l as resolveAddons, o as parser, s as getThemeMeta, u as updateFrontmatterPatch } from "./shared-D3BW4vqA.mjs";
2
+ import { i as resolveEntry, n as getRoots, r as isInstalledGlobally } from "./resolver-Du-CxvL9.mjs";
3
+ import { t as createServer } from "./serve-BrA39NVM.mjs";
4
4
  import { exec } from "node:child_process";
5
5
  import fs from "node:fs/promises";
6
6
  import os from "node:os";
@@ -292,7 +292,7 @@ cli.command("build [entry..]", "Build hostable SPA", (args) => exportOptions(com
292
292
  describe: "enable the inspect plugin for debugging"
293
293
  }).strict().help(), async (args) => {
294
294
  const { entry, theme, base, download, out, inspect } = args;
295
- const { build } = await import("./build-Co9SDEv9.mjs");
295
+ const { build } = await import("./build-C0y4MWcQ.mjs");
296
296
  for (const entryFile of entry) {
297
297
  const options = await resolveOptions({
298
298
  entry: entryFile,
@@ -355,7 +355,7 @@ cli.command("theme [subcommand]", "Theme related operations", (command) => {
355
355
  });
356
356
  cli.command("export [entry..]", "Export slides to PDF", (args) => exportOptions(commonOptions(args)).strict().help(), async (args) => {
357
357
  const { entry, theme } = args;
358
- const { exportSlides, getExportOptions } = await import("./export-dSJYnjas.mjs");
358
+ const { exportSlides, getExportOptions } = await import("./export-snweM1-1.mjs");
359
359
  const port = await getPort(12445);
360
360
  let warned = false;
361
361
  for (const entryFile of entry) {
@@ -402,7 +402,7 @@ cli.command("export-notes [entry..]", "Export slide notes to PDF", (args) => arg
402
402
  type: "number",
403
403
  describe: "wait for the specified ms before exporting"
404
404
  }).strict().help(), async ({ entry, output, timeout, wait }) => {
405
- const { exportNotes } = await import("./export-dSJYnjas.mjs");
405
+ const { exportNotes } = await import("./export-snweM1-1.mjs");
406
406
  const port = await getPort(12445);
407
407
  for (const entryFile of entry) {
408
408
  const options = await resolveOptions({ entry: entryFile }, "export");
@@ -1,4 +1,4 @@
1
- import { n as getRoots } from "./resolver-Dl3RCceV.mjs";
1
+ import { n as getRoots } from "./resolver-Du-CxvL9.mjs";
2
2
  import fs from "node:fs/promises";
3
3
  import path, { dirname, relative } from "node:path";
4
4
  import process from "node:process";
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { i as resolveOptions, n as ViteSlidevPlugin, o as parser, r as createDataUtils } from "./shared-OlAiAU1s.mjs";
2
- import "./resolver-Dl3RCceV.mjs";
3
- import { t as createServer } from "./serve-DiGMRooB.mjs";
1
+ import { i as resolveOptions, n as ViteSlidevPlugin, o as parser, r as createDataUtils } from "./shared-D3BW4vqA.mjs";
2
+ import "./resolver-Du-CxvL9.mjs";
3
+ import { t as createServer } from "./serve-BrA39NVM.mjs";
4
4
 
5
5
  export { ViteSlidevPlugin, createDataUtils, createServer, parser, resolveOptions };
@@ -1,12 +1,13 @@
1
+ import { copyFile, readFile } from "node:fs/promises";
1
2
  import { dirname, join, relative, resolve } from "node:path";
2
3
  import process from "node:process";
3
4
  import { underline, yellow } from "ansis";
4
- import * as fs$1 from "node:fs";
5
+ import { existsSync } from "node:fs";
5
6
  import { fileURLToPath } from "node:url";
6
- import { ensurePrefix, slash } from "@antfu/utils";
7
- import { resolvePath } from "mlly";
8
7
  import { parseNi, run } from "@antfu/ni";
8
+ import { ensurePrefix, slash } from "@antfu/utils";
9
9
  import globalDirs from "global-directory";
10
+ import { resolvePath } from "mlly";
10
11
  import prompts from "prompts";
11
12
  import { resolveGlobal } from "resolve-global";
12
13
  import { findClosestPkgJsonPath, findDepPkgJsonPath } from "vitefu";
@@ -39,23 +40,29 @@ async function findPkgRoot(dep, parent, ensure = false) {
39
40
  return path$1;
40
41
  }
41
42
  async function findGlobalPkgRoot(name, ensure = false) {
43
+ const localPath = await findDepPkgJsonPath(name, cliRoot);
44
+ if (localPath) return dirname(localPath);
42
45
  const yarnPath = join(globalDirs.yarn.packages, name);
43
- if (fs$1.existsSync(`${yarnPath}/package.json`)) return yarnPath;
46
+ if (existsSync(`${yarnPath}/package.json`)) return yarnPath;
44
47
  const npmPath = join(globalDirs.npm.packages, name);
45
- if (fs$1.existsSync(`${npmPath}/package.json`)) return npmPath;
48
+ if (existsSync(`${npmPath}/package.json`)) return npmPath;
46
49
  if (ensure) throw new Error(`Failed to resolve global package "${name}"`);
47
50
  }
48
51
  async function resolveEntry(entryRaw) {
49
- if (!fs$1.existsSync(entryRaw) && !entryRaw.endsWith(".md") && !/[/\\]/.test(entryRaw)) entryRaw += ".md";
52
+ if (!existsSync(entryRaw) && !entryRaw.endsWith(".md") && !/[/\\]/.test(entryRaw)) entryRaw += ".md";
50
53
  const entry = resolve(entryRaw);
51
- if (!fs$1.existsSync(entry)) {
54
+ if (!existsSync(entry)) {
55
+ if (!process.stdin.isTTY) {
56
+ console.error(`Entry file "${entry}" does not exist and cannot prompt for confirmation`);
57
+ process.exit(1);
58
+ }
52
59
  const { create } = await prompts({
53
60
  name: "create",
54
61
  type: "confirm",
55
62
  initial: "Y",
56
63
  message: `Entry file ${yellow(`"${entry}"`)} does not exist, do you want to create it?`
57
64
  });
58
- if (create) fs$1.copyFileSync(resolve(cliRoot, "template.md"), entry);
65
+ if (create) await copyFile(resolve(cliRoot, "template.md"), entry);
59
66
  else process.exit(0);
60
67
  }
61
68
  return slash(entry);
@@ -65,6 +72,10 @@ async function resolveEntry(entryRaw) {
65
72
  */
66
73
  function createResolver(type, officials) {
67
74
  async function promptForInstallation(pkgName) {
75
+ if (!process.stdin.isTTY) {
76
+ console.error(`The ${type} "${pkgName}" was not found and cannot prompt for installation`);
77
+ process.exit(1);
78
+ }
68
79
  const { confirm } = await prompts({
69
80
  name: "confirm",
70
81
  initial: "Y",
@@ -81,16 +92,9 @@ function createResolver(type, officials) {
81
92
  if (name[0] === "/") return [name, name];
82
93
  if (name.startsWith("@/")) return [name, resolve(userRoot, name.slice(2))];
83
94
  if (name[0] === "." || name[0] !== "@" && name.includes("/")) return [name, resolve(dirname(importer), name)];
84
- if (name.startsWith(`@slidev/${type}-`) || name.startsWith(`slidev-${type}-`)) {
85
- if (!await findPkgRoot(name, importer)) await promptForInstallation(name);
86
- return [name, await findPkgRoot(name, importer, true)];
87
- }
88
95
  {
89
- const possiblePkgNames = [
90
- `@slidev/${type}-${name}`,
91
- `slidev-${type}-${name}`,
92
- name
93
- ];
96
+ const possiblePkgNames = [name];
97
+ if (!name.includes("/") && !name.startsWith("@")) possiblePkgNames.push(`@slidev/${type}-${name}`, `slidev-${type}-${name}`);
94
98
  for (const pkgName$1 of possiblePkgNames) {
95
99
  const pkgRoot = await findPkgRoot(pkgName$1, importer);
96
100
  if (pkgRoot) return [pkgName$1, pkgRoot];
@@ -101,29 +105,25 @@ function createResolver(type, officials) {
101
105
  return [pkgName, await findPkgRoot(pkgName, importer, true)];
102
106
  };
103
107
  }
104
- function getUserPkgJson(userRoot) {
108
+ async function getUserPkgJson(userRoot) {
105
109
  const path$1 = resolve(userRoot, "package.json");
106
- if (fs$1.existsSync(path$1)) return JSON.parse(fs$1.readFileSync(path$1, "utf-8"));
110
+ if (existsSync(path$1)) return JSON.parse(await readFile(path$1, "utf-8"));
107
111
  return {};
108
112
  }
109
- function hasWorkspacePackageJSON(root) {
113
+ async function hasWorkspacePackageJSON(root) {
110
114
  const path$1 = join(root, "package.json");
111
- try {
112
- fs$1.accessSync(path$1, fs$1.constants.R_OK);
113
- } catch {
114
- return false;
115
- }
116
- return !!(JSON.parse(fs$1.readFileSync(path$1, "utf-8")) || {}).workspaces;
115
+ if (!existsSync(path$1)) return false;
116
+ return !!(JSON.parse(await readFile(path$1, "utf-8")) || {}).workspaces;
117
117
  }
118
118
  function hasRootFile(root) {
119
- return ["pnpm-workspace.yaml"].some((file) => fs$1.existsSync(join(root, file)));
119
+ return ["pnpm-workspace.yaml"].some((file) => existsSync(join(root, file)));
120
120
  }
121
121
  /**
122
122
  * Search up for the nearest workspace root
123
123
  */
124
- function searchForWorkspaceRoot(current, root = current) {
124
+ async function searchForWorkspaceRoot(current, root = current) {
125
125
  if (hasRootFile(current)) return current;
126
- if (hasWorkspacePackageJSON(current)) return current;
126
+ if (await hasWorkspacePackageJSON(current)) return current;
127
127
  const dir = dirname(current);
128
128
  if (!dir || dir === current) return root;
129
129
  return searchForWorkspaceRoot(dir, root);
@@ -140,11 +140,27 @@ async function getRoots(entry) {
140
140
  cliRoot,
141
141
  clientRoot,
142
142
  userRoot,
143
- userPkgJson: getUserPkgJson(closestPkgRoot),
144
- userWorkspaceRoot: searchForWorkspaceRoot(closestPkgRoot)
143
+ userPkgJson: await getUserPkgJson(closestPkgRoot),
144
+ userWorkspaceRoot: await searchForWorkspaceRoot(closestPkgRoot)
145
145
  };
146
146
  return rootsInfo;
147
147
  }
148
+ function resolveSourceFiles(roots, subpath, extensions = [
149
+ ".mjs",
150
+ ".js",
151
+ ".mts",
152
+ ".ts"
153
+ ]) {
154
+ const results = [];
155
+ for (const root of roots) for (const ext of extensions) {
156
+ const fullPath = join(root, subpath + ext);
157
+ if (existsSync(fullPath)) {
158
+ results.push(fullPath);
159
+ break;
160
+ }
161
+ }
162
+ return results;
163
+ }
148
164
 
149
165
  //#endregion
150
- export { resolveImportPath as a, resolveEntry as i, getRoots as n, resolveImportUrl as o, isInstalledGlobally as r, toAtFS as s, createResolver as t };
166
+ export { resolveImportPath as a, toAtFS as c, resolveEntry as i, getRoots as n, resolveImportUrl as o, isInstalledGlobally as r, resolveSourceFiles as s, createResolver as t };
@@ -1,4 +1,4 @@
1
- import { t as resolveViteConfigs } from "./shared-OlAiAU1s.mjs";
1
+ import { t as resolveViteConfigs } from "./shared-D3BW4vqA.mjs";
2
2
  import { join } from "node:path";
3
3
  import process from "node:process";
4
4
  import { createServer } from "vite";
@@ -1,39 +1,41 @@
1
- import { a as resolveImportPath, i as resolveEntry, n as getRoots, o as resolveImportUrl, r as isInstalledGlobally, s as toAtFS, t as createResolver } from "./resolver-Dl3RCceV.mjs";
1
+ import { a as resolveImportPath, c as toAtFS, i as resolveEntry, n as getRoots, o as resolveImportUrl, r as isInstalledGlobally, s as resolveSourceFiles, t as createResolver } from "./resolver-Du-CxvL9.mjs";
2
2
  import { builtinModules } from "node:module";
3
3
  import fs, { readFile } from "node:fs/promises";
4
4
  import path, { basename, dirname, join, resolve } from "node:path";
5
5
  import { bold, gray, red, white, yellow } from "ansis";
6
6
  import equal from "fast-deep-equal";
7
7
  import { loadConfigFromFile, mergeConfig } from "vite";
8
- import fs$1, { existsSync, readFileSync } from "node:fs";
9
8
  import MarkdownIt from "markdown-it";
9
+ import fs$1, { existsSync } from "node:fs";
10
10
  import { fileURLToPath, pathToFileURL } from "node:url";
11
+ import { isString, isTruthy, notNullish, objectEntries, objectMap, range, slash, uniq } from "@antfu/utils";
12
+ import { createResolve } from "mlly";
13
+ import { findDepPkgJsonPath } from "vitefu";
11
14
  import { createJiti } from "jiti";
12
15
  import YAML from "yaml";
13
- import { isString, isTruthy, notNullish, objectEntries, objectMap, range, slash, uniq } from "@antfu/utils";
14
16
  import IconsResolver from "unplugin-icons/resolver";
15
17
  import Components from "unplugin-vue-components/vite";
16
- import { createResolve } from "mlly";
17
- import { findDepPkgJsonPath } from "vitefu";
18
18
  import Icons from "unplugin-icons/vite";
19
19
  import * as parser from "@slidev/parser/fs";
20
- import Debug from "debug";
21
20
  import fg from "fast-glob";
21
+ import { createDebug } from "obug";
22
22
  import pm from "picomatch";
23
23
  import { satisfies } from "semver";
24
24
  import { escapeHtml } from "markdown-it/lib/common/utils.mjs";
25
25
  import { createHead, extractUnheadInputFromHtml, transformHtmlTemplate } from "unhead/server";
26
- import { bundledLanguages, createHighlighter } from "shiki";
26
+ import { createSingletonShorthands, createdBundledHighlighter } from "shiki/core";
27
+ import { createJavaScriptRegexEngine } from "shiki/engine/javascript";
28
+ import { bundledLanguages, bundledThemes } from "shiki";
27
29
  import katex from "katex";
28
30
  import MagicString from "magic-string-stack";
29
31
  import Markdown from "unplugin-vue-markdown/vite";
30
32
  import Token from "markdown-it/lib/token.mjs";
31
33
  import MarkdownItFootnote from "markdown-it-footnote";
32
34
  import MarkdownItMdc from "markdown-it-mdc";
33
- import { fromHighlighter } from "@shikijs/markdown-it/core";
35
+ import { fromAsyncCodeToHtml } from "@shikijs/markdown-it/async";
34
36
  import { SourceMapConsumer } from "source-map-js";
35
37
  import lz from "lz-string";
36
- import { codeToKeyedTokens } from "shiki-magic-move/core";
38
+ import { toKeyedTokens } from "shiki-magic-move/core";
37
39
  import { encode } from "plantuml-encoder";
38
40
  import ServerRef from "vite-plugin-vue-server-ref";
39
41
  import UnoCSS from "unocss/vite";
@@ -42,7 +44,7 @@ import Vue from "@vitejs/plugin-vue";
42
44
  import VueJsx from "@vitejs/plugin-vue-jsx";
43
45
 
44
46
  //#region package.json
45
- var version = "52.8.0";
47
+ var version = "52.9.1";
46
48
 
47
49
  //#endregion
48
50
  //#region node/syntax/markdown-it/markdown-it-link.ts
@@ -252,7 +254,8 @@ const INCLUDE_GLOBAL = [
252
254
  "prettier",
253
255
  "recordrtc",
254
256
  "typescript",
255
- "yaml"
257
+ "yaml",
258
+ "pptxgenjs"
256
259
  ];
257
260
  const INCLUDE_LOCAL = INCLUDE_GLOBAL.map((i) => `@slidev/cli > @slidev/client > ${i}`);
258
261
  const EXCLUDE_GLOBAL = [
@@ -444,7 +447,7 @@ function createLayoutWrapperPlugin({ data, utils }) {
444
447
  const [, no, type] = match;
445
448
  if (type !== "md") return;
446
449
  const index = +no - 1;
447
- const layouts = utils.getLayouts();
450
+ const layouts = await utils.getLayouts();
448
451
  let layoutName = (data.slides[index]?.frontmatter?.layout ?? data.slides[0]?.frontmatter?.defaults?.layout) || (index === 0 ? "cover" : "default");
449
452
  if (!layouts[layoutName]) {
450
453
  console.error(red(`\nUnknown layout "${bold(layoutName)}".${yellow(" Available layouts are:")}`) + Object.keys(layouts).map((i, idx) => (idx % 3 === 0 ? "\n " : "") + gray(i.padEnd(15, " "))).join(" "));
@@ -520,13 +523,13 @@ function toAttrValue(unsafe) {
520
523
  return JSON.stringify(escapeHtml(String(unsafe)));
521
524
  }
522
525
  async function setupIndexHtml({ mode, entry, clientRoot, userRoot, roots, data, base }) {
523
- let main = readFileSync(join(clientRoot, "index.html"), "utf-8");
526
+ let main = await readFile(join(clientRoot, "index.html"), "utf-8");
524
527
  let body = "";
525
528
  const inputs = [];
526
529
  for (const root of roots) {
527
530
  const path$1 = join(root, "index.html");
528
531
  if (!existsSync(path$1)) continue;
529
- const html = readFileSync(path$1, "utf-8");
532
+ const html = await readFile(path$1, "utf-8");
530
533
  if (root === userRoot && html.includes("<!DOCTYPE")) {
531
534
  console.error(yellow(`[Slidev] Ignored provided index.html with doctype declaration. (${white(path$1)})`));
532
535
  console.error(yellow("This file may be generated by Slidev, please remove it from your project."));
@@ -629,8 +632,13 @@ async function setupIndexHtml({ mode, entry, clientRoot, userRoot, roots, data,
629
632
  }
630
633
  ].filter((x) => x.content)
631
634
  }, ...inputs] });
632
- const baseInDev = mode === "dev" && base ? base.slice(0, -1) : "";
633
- main = main.replace("__ENTRY__", baseInDev + encodeURI(toAtFS(join(clientRoot, "main.ts")))).replace("<!-- body -->", body);
635
+ const mainUrl = toAtFS(join(clientRoot, "main.ts"));
636
+ if (mode === "build") main = main.replace("__ENTRY__", mainUrl);
637
+ else {
638
+ const basePrefix = base ? base.slice(0, -1) : "";
639
+ main = main.replace("__ENTRY__", encodeURI(basePrefix + mainUrl));
640
+ }
641
+ main = main.replace("<!-- body -->", body);
634
642
  return await transformHtmlTemplate(unhead, main);
635
643
  }
636
644
 
@@ -658,16 +666,8 @@ async function setupKatex(roots) {
658
666
  }
659
667
 
660
668
  //#endregion
661
- //#region node/setups/shiki.ts
662
- let cachedRoots;
663
- let cachedShiki;
664
- async function setupShiki(roots) {
665
- if (cachedRoots === roots) return cachedShiki;
666
- cachedShiki?.shiki.dispose();
667
- const options = await loadSetups(roots, "shiki.ts", [{ async loadTheme(path$1) {
668
- console.warn("[slidev] `loadTheme` in `setup/shiki.ts` is deprecated. Pass directly the theme name it's supported by Shiki. For custom themes, load it manually via `JSON.parse(fs.readFileSync(path, 'utf-8'))` and pass the raw JSON object instead.");
669
- return JSON.parse(await fs.readFile(path$1, "utf-8"));
670
- } }]);
669
+ //#region ../client/setup/shiki-options.ts
670
+ function resolveShikiOptions(options) {
671
671
  const mergedOptions = Object.assign({}, ...options);
672
672
  if ("theme" in mergedOptions && "themes" in mergedOptions) delete mergedOptions.theme;
673
673
  if (mergedOptions.theme && typeof mergedOptions.theme !== "string" && !mergedOptions.theme.name && !mergedOptions.theme.tokenColors) {
@@ -679,21 +679,89 @@ async function setupShiki(roots) {
679
679
  light: "vitesse-light"
680
680
  };
681
681
  if (mergedOptions.themes) mergedOptions.defaultColor = false;
682
- const shiki = await createHighlighter({
683
- ...mergedOptions,
684
- langs: mergedOptions.langs ?? Object.keys(bundledLanguages),
685
- themes: "themes" in mergedOptions ? Object.values(mergedOptions.themes) : [mergedOptions.theme]
682
+ const themeOption = extractThemeName(mergedOptions.theme) || extractThemeNames(mergedOptions.themes || {});
683
+ const themeNames = typeof themeOption === "string" ? [themeOption] : Object.values(themeOption);
684
+ const themeInput = Object.assign({}, bundledThemes);
685
+ if (typeof mergedOptions.theme === "object" && mergedOptions.theme?.name) themeInput[mergedOptions.theme.name] = mergedOptions.theme;
686
+ if (mergedOptions.themes) {
687
+ for (const theme of Object.values(mergedOptions.themes)) if (typeof theme === "object" && theme?.name) themeInput[theme.name] = theme;
688
+ }
689
+ const languageNames = new Set([
690
+ "markdown",
691
+ "vue",
692
+ "javascript",
693
+ "typescript",
694
+ "html",
695
+ "css"
696
+ ]);
697
+ const languageInput = Object.assign({}, bundledLanguages);
698
+ for (const option of options) {
699
+ const langs = option?.langs;
700
+ if (langs == null) continue;
701
+ if (Array.isArray(langs)) for (const lang of langs.flat()) if (typeof lang === "function") console.error(red("[slidev] `langs` option returned by setup/shiki.ts cannot be an array containing functions. Please use the record format (`{ [name]: () => {...} }`) instead."));
702
+ else if (typeof lang === "string") languageNames.add(lang);
703
+ else if (lang.name) {
704
+ languageNames.add(lang.name);
705
+ languageInput[lang.name] = lang;
706
+ for (const alias of lang.aliases || []) {
707
+ languageNames.add(alias);
708
+ languageInput[alias] = lang;
709
+ }
710
+ } else console.error(red("[slidev] Invalid lang option in shiki setup:"), lang);
711
+ else if (typeof langs === "object") {
712
+ for (const name of Object.keys(langs)) languageNames.add(name);
713
+ Object.assign(languageInput, langs);
714
+ } else console.error(red("[slidev] Invalid langs option in shiki setup:"), langs);
715
+ }
716
+ return {
717
+ options: mergedOptions,
718
+ themeOption,
719
+ themeNames,
720
+ themeInput,
721
+ languageNames,
722
+ languageInput
723
+ };
724
+ }
725
+ function extractThemeName(theme) {
726
+ if (!theme) return void 0;
727
+ if (typeof theme === "string") return theme;
728
+ if (!theme.name) console.warn(yellow("[slidev] Theme"), theme, yellow("does not have a name, which may cause issues."));
729
+ return theme.name;
730
+ }
731
+ function extractThemeNames(themes) {
732
+ if (!themes) return {};
733
+ return objectMap(themes, (key, theme) => {
734
+ const name = extractThemeName(theme);
735
+ if (!name) return void 0;
736
+ return [key, name];
737
+ });
738
+ }
739
+
740
+ //#endregion
741
+ //#region node/setups/shiki.ts
742
+ let cachedRoots;
743
+ let cachedShiki;
744
+ async function setupShiki(roots) {
745
+ if (cachedRoots === roots) return cachedShiki;
746
+ const { options, languageInput, themeInput } = resolveShikiOptions(await loadSetups(roots, "shiki.ts", [{ async loadTheme(path$1) {
747
+ console.warn("[slidev] `loadTheme` in `setup/shiki.ts` is deprecated. Pass directly the theme name it's supported by Shiki. For custom themes, load it manually via `JSON.parse(fs.readFileSync(path, 'utf-8'))` and pass the raw JSON object instead.");
748
+ return JSON.parse(await fs.readFile(path$1, "utf-8"));
749
+ } }]));
750
+ const createHighlighter = createdBundledHighlighter({
751
+ engine: createJavaScriptRegexEngine,
752
+ langs: languageInput,
753
+ themes: themeInput
686
754
  });
687
755
  cachedRoots = roots;
688
756
  return cachedShiki = {
689
- shiki,
690
- shikiOptions: mergedOptions
757
+ shiki: createSingletonShorthands(createHighlighter),
758
+ shikiOptions: options
691
759
  };
692
760
  }
693
761
 
694
762
  //#endregion
695
763
  //#region node/options.ts
696
- const debug = Debug("slidev:options");
764
+ const debug = createDebug("slidev:options");
697
765
  async function resolveOptions(entryOptions, mode) {
698
766
  const entry = await resolveEntry(entryOptions.entry);
699
767
  const rootsInfo = await getRoots(entry);
@@ -748,7 +816,7 @@ async function resolveOptions(entryOptions, mode) {
748
816
  async function createDataUtils(resolved) {
749
817
  const monacoTypesIgnorePackagesMatches = (resolved.data.config.monacoTypesIgnorePackages || []).map((i) => pm.makeRe(i));
750
818
  let _layouts_cache_time = 0;
751
- let _layouts_cache = {};
819
+ let _layouts_cache = null;
752
820
  return {
753
821
  ...await setupShiki(resolved.roots),
754
822
  katexOptions: await setupKatex(resolved.roots),
@@ -758,22 +826,22 @@ async function createDataUtils(resolved) {
758
826
  isMonacoTypesIgnored: (pkg) => monacoTypesIgnorePackagesMatches.some((i) => i.test(pkg)),
759
827
  getLayouts: () => {
760
828
  const now = Date.now();
761
- if (now - _layouts_cache_time < 2e3) return _layouts_cache;
762
- const layouts = {};
763
- for (const root of [resolved.clientRoot, ...resolved.roots]) {
764
- const layoutPaths = fg.sync("layouts/**/*.{vue,ts}", {
829
+ if (_layouts_cache && now - _layouts_cache_time < 2e3) return _layouts_cache;
830
+ _layouts_cache_time = now;
831
+ return _layouts_cache = worker();
832
+ async function worker() {
833
+ const layouts = {};
834
+ const layoutPaths = await Promise.all([resolved.clientRoot, ...resolved.roots].map((root) => fg("layouts/**/*.{vue,js,mjs,ts,mts}", {
765
835
  cwd: root,
766
836
  absolute: true,
767
837
  suppressErrors: true
768
- });
769
- for (const layoutPath of layoutPaths) {
838
+ })));
839
+ for (const layoutPath of layoutPaths.flat(1)) {
770
840
  const layoutName = path.basename(layoutPath).replace(/\.\w+$/, "");
771
841
  layouts[layoutName] = layoutPath;
772
842
  }
843
+ return layouts;
773
844
  }
774
- _layouts_cache_time = now;
775
- _layouts_cache = layouts;
776
- return layouts;
777
845
  }
778
846
  };
779
847
  }
@@ -799,6 +867,60 @@ function getDefine(options) {
799
867
  }, (v, k) => [v, JSON.stringify(k)]);
800
868
  }
801
869
 
870
+ //#endregion
871
+ //#region node/syntax/transform/utils.ts
872
+ function normalizeRangeStr(rangeStr = "") {
873
+ return !rangeStr.trim() ? [] : rangeStr.trim().split(/\|/g).map((i) => i.trim());
874
+ }
875
+ function getCodeBlocks(md) {
876
+ const codeblocks = Array.from(md.matchAll(/^```[\s\S]*?^```/gm)).map((m) => {
877
+ const start = m.index;
878
+ const end = m.index + m[0].length;
879
+ return [
880
+ start,
881
+ end,
882
+ md.slice(0, start).match(/\n/g)?.length || 0,
883
+ md.slice(0, end).match(/\n/g)?.length || 0
884
+ ];
885
+ });
886
+ return {
887
+ codeblocks,
888
+ isInsideCodeblocks(idx) {
889
+ return codeblocks.some(([s, e]) => s <= idx && idx <= e);
890
+ },
891
+ isLineInsideCodeblocks(line) {
892
+ return codeblocks.some(([, , s, e]) => s <= line && line <= e);
893
+ }
894
+ };
895
+ }
896
+ function getCommentBlocks(md) {
897
+ const commentBlocks = Array.from(md.matchAll(/<!--[\s\S]*?-->/g)).map((m) => {
898
+ const start = m.index;
899
+ const end = m.index + m[0].length;
900
+ return [
901
+ start,
902
+ end,
903
+ md.slice(0, start).match(/\n/g)?.length || 0,
904
+ md.slice(0, end).match(/\n/g)?.length || 0
905
+ ];
906
+ });
907
+ return {
908
+ commentBlocks,
909
+ isInsideCommentBlocks(idx) {
910
+ return commentBlocks.some(([s, e]) => s <= idx && idx <= e);
911
+ },
912
+ isLineInsideCommentBlocks(line) {
913
+ return commentBlocks.some(([, , s, e]) => s <= line && line <= e);
914
+ }
915
+ };
916
+ }
917
+ /**
918
+ * Escape `{{` in code block to prevent Vue interpret it, #99, #1316
919
+ */
920
+ function escapeVueInCode(md) {
921
+ return md.replace(/\{\{/g, "&lbrace;&lbrace;");
922
+ }
923
+
802
924
  //#endregion
803
925
  //#region node/syntax/markdown-it/markdown-it-katex.ts
804
926
  function isValidDelim(state, pos) {
@@ -896,7 +1018,7 @@ function MarkdownItKatex(md, options) {
896
1018
  const katexInline = function(latex) {
897
1019
  options.displayMode = false;
898
1020
  try {
899
- return katex.renderToString(latex, options);
1021
+ return escapeVueInCode(katex.renderToString(latex, options));
900
1022
  } catch (error) {
901
1023
  if (options.throwOnError) console.warn(error);
902
1024
  return latex;
@@ -908,7 +1030,7 @@ function MarkdownItKatex(md, options) {
908
1030
  const katexBlock = function(latex) {
909
1031
  options.displayMode = true;
910
1032
  try {
911
- return `<p>${katex.renderToString(latex, options)}</p>`;
1033
+ return `<p>${escapeVueInCode(katex.renderToString(latex, options))}</p>`;
912
1034
  } catch (error) {
913
1035
  if (options.throwOnError) console.warn(error);
914
1036
  return latex;
@@ -1013,9 +1135,9 @@ const templateGlobalLayers = {
1013
1135
  //#region node/virtual/layouts.ts
1014
1136
  const templateLayouts = {
1015
1137
  id: "/@slidev/layouts",
1016
- getContent({ utils }) {
1138
+ async getContent({ utils }) {
1017
1139
  const imports = [];
1018
- const layouts = objectMap(utils.getLayouts(), (k, v) => {
1140
+ const layouts = objectMap(await utils.getLayouts(), (k, v) => {
1019
1141
  imports.push(`import __layout_${k} from "${toAtFS(v)}"`);
1020
1142
  return [k, `__layout_${k}`];
1021
1143
  });
@@ -1104,15 +1226,7 @@ function createSetupTemplate(name) {
1104
1226
  return {
1105
1227
  id: `/@slidev/setups/${name}`,
1106
1228
  getContent({ roots }) {
1107
- const setups = roots.flatMap((i) => {
1108
- const path$1 = join(i, "setup", name);
1109
- return [
1110
- ".ts",
1111
- ".mts",
1112
- ".js",
1113
- ".mjs"
1114
- ].map((ext) => path$1 + ext);
1115
- }).filter((i) => existsSync(i));
1229
+ const setups = resolveSourceFiles(roots, `setup/${name}`);
1116
1230
  const imports = [];
1117
1231
  setups.forEach((path$1, idx) => {
1118
1232
  imports.push(`import __n${idx} from '${toAtFS(path$1)}'`);
@@ -1135,51 +1249,15 @@ const setupModules = [
1135
1249
  ];
1136
1250
  const templateSetups = setupModules.map(createSetupTemplate);
1137
1251
 
1138
- //#endregion
1139
- //#region node/virtual/shiki.ts
1140
- const templateShiki = {
1141
- id: "/@slidev/shiki",
1142
- getContent: async ({ utils }) => {
1143
- const options = utils.shikiOptions;
1144
- const langs = await resolveLangs(options.langs || [
1145
- "markdown",
1146
- "vue",
1147
- "javascript",
1148
- "typescript",
1149
- "html",
1150
- "css"
1151
- ]);
1152
- const resolvedThemeOptions = "themes" in options ? { themes: Object.fromEntries(await Promise.all(Object.entries(options.themes).map(async ([name, value]) => [name, await resolveTheme$1(value)]))) } : { theme: await resolveTheme$1(options.theme || "vitesse-dark") };
1153
- const themes = resolvedThemeOptions.themes ? Object.values(resolvedThemeOptions.themes) : [resolvedThemeOptions.theme];
1154
- const themeOptionsNames = resolvedThemeOptions.themes ? { themes: Object.fromEntries(Object.entries(resolvedThemeOptions.themes).map(([name, value]) => [name, typeof value === "string" ? value : value.name])) } : { theme: typeof resolvedThemeOptions.theme === "string" ? resolvedThemeOptions.theme : resolvedThemeOptions.theme.name };
1155
- async function normalizeGetter(p) {
1156
- const r = typeof p === "function" ? p() : p;
1157
- return r.default || r;
1158
- }
1159
- async function resolveLangs(langs$1) {
1160
- return uniq((await Promise.all(langs$1.map((lang) => normalizeGetter(lang)))).flat());
1161
- }
1162
- async function resolveTheme$1(theme) {
1163
- return typeof theme === "string" ? theme : await normalizeGetter(theme);
1164
- }
1165
- const langsInit = await Promise.all(langs.map(async (lang) => typeof lang === "string" ? `import('${await resolveImportUrl(`shiki/langs/${lang}.mjs`)}')` : JSON.stringify(lang)));
1166
- const themesInit = await Promise.all(themes.map(async (theme) => typeof theme === "string" ? `import('${await resolveImportUrl(`shiki/themes/${theme}.mjs`)}')` : JSON.stringify(theme)));
1167
- const langNames = langs.flatMap((lang) => typeof lang === "string" ? lang : lang.name);
1168
- const lines = [];
1169
- lines.push(`import { createHighlighterCore } from "${await resolveImportUrl("shiki/core")}"`, `import { createJavaScriptRegexEngine } from "${await resolveImportUrl("@shikijs/engine-javascript")}"`, `export { shikiToMonaco } from "${await resolveImportUrl("@shikijs/monaco")}"`, `export const languages = ${JSON.stringify(langNames)}`, `export const themes = ${JSON.stringify(themeOptionsNames.themes || themeOptionsNames.theme)}`, "export const shiki = createHighlighterCore({", ` themes: [${themesInit.join(",")}],`, ` langs: [${langsInit.join(",")}],`, ` engine: createJavaScriptRegexEngine(),`, "})", "let highlight", "export async function getHighlighter() {", " if (highlight) return highlight", " const highlighter = await shiki", " highlight = (code, lang, options) => highlighter.codeToHtml(code, {", " lang,", ` theme: ${JSON.stringify(themeOptionsNames.theme)},`, ` themes: ${JSON.stringify(themeOptionsNames.themes)},`, " defaultColor: false,", " ...options,", " })", " return highlight", "}");
1170
- return lines.join("\n");
1171
- }
1172
- };
1173
-
1174
1252
  //#endregion
1175
1253
  //#region node/virtual/slides.ts
1176
1254
  const VIRTUAL_SLIDE_PREFIX = "/@slidev/slides/";
1177
1255
  const templateSlides = {
1178
1256
  id: "/@slidev/slides",
1179
- getContent({ data, utils }) {
1257
+ async getContent({ data, utils }) {
1180
1258
  const statements = [
1181
1259
  `import { defineAsyncComponent, shallowRef } from 'vue'`,
1182
- `import SlideError from '${utils.getLayouts().error}'`,
1260
+ `import SlideError from '${(await utils.getLayouts()).error}'`,
1183
1261
  `import SlideLoading from '@slidev/client/internals/SlideLoading.vue'`,
1184
1262
  `const componentsCache = new Array(${data.slides.length})`,
1185
1263
  `const getAsyncComponent = (idx, loader) => defineAsyncComponent({`,
@@ -1265,7 +1343,6 @@ const templateTitleRenderer = {
1265
1343
  //#endregion
1266
1344
  //#region node/virtual/index.ts
1267
1345
  const templates = [
1268
- templateShiki,
1269
1346
  templateMonacoTypes,
1270
1347
  templateMonacoRunDeps,
1271
1348
  templateConfigs,
@@ -1472,10 +1549,8 @@ function createSlidesLoader(options, serverOptions) {
1472
1549
  "import { computed, reactive, shallowReactive } from \"vue\"",
1473
1550
  `export const frontmatterData = ${JSON.stringify(fontmatter)}`,
1474
1551
  "if (import.meta.hot) {",
1475
- " const firstLoad = !import.meta.hot.data.frontmatter",
1476
1552
  " import.meta.hot.data.frontmatter ??= reactive(frontmatterData)",
1477
1553
  " import.meta.hot.accept(({ frontmatterData: update }) => {",
1478
- " if (firstLoad) return",
1479
1554
  " const frontmatter = import.meta.hot.data.frontmatter",
1480
1555
  " Object.keys(frontmatter).forEach(key => {",
1481
1556
  " if (!(key in update)) delete frontmatter[key]",
@@ -1649,69 +1724,29 @@ function MarkdownItEscapeInlineCode(md) {
1649
1724
  };
1650
1725
  }
1651
1726
 
1652
- //#endregion
1653
- //#region node/syntax/transform/utils.ts
1654
- function normalizeRangeStr(rangeStr = "") {
1655
- return !rangeStr.trim() ? [] : rangeStr.trim().split(/\|/g).map((i) => i.trim());
1656
- }
1657
- function getCodeBlocks(md) {
1658
- const codeblocks = Array.from(md.matchAll(/^```[\s\S]*?^```/gm)).map((m) => {
1659
- const start = m.index;
1660
- const end = m.index + m[0].length;
1661
- return [
1662
- start,
1663
- end,
1664
- md.slice(0, start).match(/\n/g)?.length || 0,
1665
- md.slice(0, end).match(/\n/g)?.length || 0
1666
- ];
1667
- });
1668
- return {
1669
- codeblocks,
1670
- isInsideCodeblocks(idx) {
1671
- return codeblocks.some(([s, e]) => s <= idx && idx <= e);
1672
- },
1673
- isLineInsideCodeblocks(line) {
1674
- return codeblocks.some(([, , s, e]) => s <= line && line <= e);
1675
- }
1676
- };
1677
- }
1678
- function getCommentBlocks(md) {
1679
- const commentBlocks = Array.from(md.matchAll(/<!--[\s\S]*?-->/g)).map((m) => {
1680
- const start = m.index;
1681
- const end = m.index + m[0].length;
1682
- return [
1683
- start,
1684
- end,
1685
- md.slice(0, start).match(/\n/g)?.length || 0,
1686
- md.slice(0, end).match(/\n/g)?.length || 0
1687
- ];
1688
- });
1689
- return {
1690
- commentBlocks,
1691
- isInsideCommentBlocks(idx) {
1692
- return commentBlocks.some(([s, e]) => s <= idx && idx <= e);
1693
- },
1694
- isLineInsideCommentBlocks(line) {
1695
- return commentBlocks.some(([, , s, e]) => s <= line && line <= e);
1696
- }
1697
- };
1698
- }
1699
- /**
1700
- * Escape `{{` in code block to prevent Vue interpret it, #99, #1316
1701
- */
1702
- function escapeVueInCode(md) {
1703
- return md.replace(/\{\{/g, "&lbrace;&lbrace;");
1704
- }
1705
-
1706
1727
  //#endregion
1707
1728
  //#region node/syntax/markdown-it/markdown-it-shiki.ts
1708
- async function MarkdownItShiki({ data: { config }, mode, utils }) {
1709
- const transformers = [
1710
- ...utils.shikiOptions.transformers || [],
1711
- (config.twoslash === true || config.twoslash === mode) && (await import("@shikijs/vitepress-twoslash")).transformerTwoslash({
1729
+ async function MarkdownItShiki({ data: { config }, mode, utils: { shiki, shikiOptions } }) {
1730
+ async function getTwoslashTransformer() {
1731
+ const [, , { transformerTwoslash }] = await Promise.all([
1732
+ shiki.codeToHast("", {
1733
+ lang: "js",
1734
+ ...shikiOptions
1735
+ }),
1736
+ shiki.codeToHast("", {
1737
+ lang: "ts",
1738
+ ...shikiOptions
1739
+ }),
1740
+ import("@shikijs/vitepress-twoslash")
1741
+ ]);
1742
+ return transformerTwoslash({
1712
1743
  explicitTrigger: true,
1713
1744
  twoslashOptions: { handbookOptions: { noErrorValidation: true } }
1714
- }),
1745
+ });
1746
+ }
1747
+ const transformers = [
1748
+ ...shikiOptions.transformers || [],
1749
+ (config.twoslash === true || config.twoslash === mode) && await getTwoslashTransformer(),
1715
1750
  {
1716
1751
  pre(pre) {
1717
1752
  this.addClassToHast(pre, "slidev-code");
@@ -1722,8 +1757,8 @@ async function MarkdownItShiki({ data: { config }, mode, utils }) {
1722
1757
  }
1723
1758
  }
1724
1759
  ].filter(isTruthy);
1725
- return fromHighlighter(utils.shiki, {
1726
- ...utils.shikiOptions,
1760
+ return fromAsyncCodeToHtml(shiki.codeToHtml, {
1761
+ ...shikiOptions,
1727
1762
  transformers
1728
1763
  });
1729
1764
  }
@@ -1873,28 +1908,51 @@ function transformKaTexWrapper(ctx) {
1873
1908
 
1874
1909
  //#endregion
1875
1910
  //#region node/syntax/transform/magic-move.ts
1876
- const reMagicMoveBlock = /^````(?:md|markdown) magic-move(?: *\[([^\]]*)\])?(?: *(\{[^}]*\}))? *([^ \n]*)\n([\s\S]+?)^````$/gm;
1911
+ const reMagicMoveBlock = /^````(?:md|markdown) magic-move(?: *\[([^\]]*)\])?(?: *(\{[^}]*\}))? *([^\n]*)\n([\s\S]+?)^````\s*?$/gm;
1877
1912
  function parseLineNumbersOption(options) {
1878
1913
  return /lines: *true/.test(options) ? true : /lines: *false/.test(options) ? false : void 0;
1879
1914
  }
1880
1915
  /**
1881
1916
  * Transform magic-move code blocks
1882
1917
  */
1883
- function transformMagicMove(ctx) {
1884
- ctx.s.replace(reMagicMoveBlock, (full, title = "", options = "{}", _attrs = "", body) => {
1885
- const matches = Array.from(body.matchAll(reCodeBlock));
1886
- if (!matches.length) throw new Error("Magic Move block must contain at least one code block");
1887
- const defaultLineNumbers = parseLineNumbersOption(options) ?? ctx.options.data.config.lineNumbers;
1888
- const ranges = matches.map((i) => normalizeRangeStr(i[3]));
1889
- const steps = matches.map((i) => {
1890
- const lineNumbers = parseLineNumbersOption(i[4]) ?? defaultLineNumbers;
1891
- return codeToKeyedTokens(ctx.options.utils.shiki, i[6].trimEnd(), {
1892
- ...ctx.options.utils.shikiOptions,
1893
- lang: i[1]
1894
- }, lineNumbers);
1895
- });
1896
- return `<ShikiMagicMove v-bind="${options}" steps-lz="${lz.compressToBase64(JSON.stringify(steps))}" :title='${JSON.stringify(title)}' :step-ranges='${JSON.stringify(ranges)}' />`;
1918
+ async function transformMagicMove(ctx) {
1919
+ const { codeToTokens } = ctx.options.utils.shiki;
1920
+ const replacements = [];
1921
+ ctx.s.replace(reMagicMoveBlock, (full, title = "", options = "{}", _attrs = "", body, start) => {
1922
+ const end = start + full.length;
1923
+ replacements.push([
1924
+ start,
1925
+ end,
1926
+ worker()
1927
+ ]);
1928
+ return "";
1929
+ async function worker() {
1930
+ const matches = Array.from(body.matchAll(reCodeBlock));
1931
+ if (!matches.length) throw new Error("Magic Move block must contain at least one code block");
1932
+ const defaultLineNumbers = parseLineNumbersOption(options) ?? ctx.options.data.config.lineNumbers;
1933
+ const ranges = matches.map((i) => normalizeRangeStr(i[3]));
1934
+ const steps = await Promise.all(matches.map(async (i) => {
1935
+ const lang = i[1];
1936
+ const lineNumbers = parseLineNumbersOption(i[4]) ?? defaultLineNumbers;
1937
+ const code = i[6].trimEnd();
1938
+ const options$1 = {
1939
+ ...ctx.options.utils.shikiOptions,
1940
+ lang
1941
+ };
1942
+ const { tokens, bg, fg: fg$1, rootStyle, themeName } = await codeToTokens(code, options$1);
1943
+ return {
1944
+ ...toKeyedTokens(code, tokens, JSON.stringify([lang, "themes" in options$1 ? options$1.themes : options$1.theme]), lineNumbers),
1945
+ bg,
1946
+ fg: fg$1,
1947
+ rootStyle,
1948
+ themeName,
1949
+ lang
1950
+ };
1951
+ }));
1952
+ return `<ShikiMagicMove v-bind="${options}" steps-lz="${lz.compressToBase64(JSON.stringify(steps))}" :title='${JSON.stringify(title)}' :step-ranges='${JSON.stringify(ranges)}' />`;
1953
+ }
1897
1954
  });
1955
+ for (const [start, end, content] of replacements) ctx.s.overwrite(start, end, await content);
1898
1956
  }
1899
1957
 
1900
1958
  //#endregion
@@ -2015,31 +2073,67 @@ function dedent(text) {
2015
2073
  if (minIndentLength < Number.POSITIVE_INFINITY) return lines.map((x) => x.slice(minIndentLength)).join("\n");
2016
2074
  return text;
2017
2075
  }
2076
+ const markers = [
2077
+ {
2078
+ start: /^\s*\/\/\s*#?region\b\s*(.*?)\s*$/,
2079
+ end: /^\s*\/\/\s*#?endregion\b\s*(.*?)\s*$/
2080
+ },
2081
+ {
2082
+ start: /^\s*<!--\s*#?region\b\s*(.*?)\s*-->/,
2083
+ end: /^\s*<!--\s*#?endregion\b\s*(.*?)\s*-->/
2084
+ },
2085
+ {
2086
+ start: /^\s*\/\*\s*#region\b\s*(.*?)\s*\*\//,
2087
+ end: /^\s*\/\*\s*#endregion\b\s*(.*?)\s*\*\//
2088
+ },
2089
+ {
2090
+ start: /^\s*#[rR]egion\b\s*(.*?)\s*$/,
2091
+ end: /^\s*#[eE]nd ?[rR]egion\b\s*(.*?)\s*$/
2092
+ },
2093
+ {
2094
+ start: /^\s*#\s*#?region\b\s*(.*?)\s*$/,
2095
+ end: /^\s*#\s*#?endregion\b\s*(.*?)\s*$/
2096
+ },
2097
+ {
2098
+ start: /^\s*(?:--|::|@?REM)\s*#region\b\s*(.*?)\s*$/,
2099
+ end: /^\s*(?:--|::|@?REM)\s*#endregion\b\s*(.*?)\s*$/
2100
+ },
2101
+ {
2102
+ start: /^\s*#pragma\s+region\b\s*(.*?)\s*$/,
2103
+ end: /^\s*#pragma\s+endregion\b\s*(.*?)\s*$/
2104
+ },
2105
+ {
2106
+ start: /^\s*\(\*\s*#region\b\s*(.*?)\s*\*\)/,
2107
+ end: /^\s*\(\*\s*#endregion\b\s*(.*?)\s*\*\)/
2108
+ }
2109
+ ];
2018
2110
  function findRegion(lines, regionName) {
2019
- const regionRegexps = [
2020
- [/^\/\/ ?#?region ([\w*-]+)$/, /^\/\/ ?#?endregion/],
2021
- [/^\/\* ?#region ([\w*-]+) ?\*\/$/, /^\/\* ?#endregion[\s\w*-]*\*\/$/],
2022
- [/^#pragma region ([\w*-]+)$/, /^#pragma endregion/],
2023
- [/^<!-- #?region ([\w*-]+) -->$/, /^<!-- #?region[\s\w*-]*-->$/],
2024
- [/^#Region ([\w*-]+)$/, /^#End Region/],
2025
- [/^::#region ([\w*-]+)$/, /^::#endregion/],
2026
- [/^# ?region ([\w*-]+)$/, /^# ?endregion/]
2027
- ];
2028
- let endReg = null;
2029
- let start = -1;
2030
- for (const [lineId, line] of lines.entries()) if (endReg === null) for (const [startReg, end] of regionRegexps) {
2031
- const match = line.trim().match(startReg);
2032
- if (match && match[1] === regionName) {
2033
- start = lineId + 1;
2034
- endReg = end;
2111
+ let chosen = null;
2112
+ for (let i = 0; i < lines.length; i++) {
2113
+ for (const re of markers) if (re.start.exec(lines[i])?.[1] === regionName) {
2114
+ chosen = {
2115
+ re,
2116
+ start: i + 1
2117
+ };
2035
2118
  break;
2036
2119
  }
2120
+ if (chosen) break;
2121
+ }
2122
+ if (!chosen) return null;
2123
+ let counter = 1;
2124
+ for (let i = chosen.start; i < lines.length; i++) {
2125
+ if (chosen.re.start.exec(lines[i])?.[1] === regionName) {
2126
+ counter++;
2127
+ continue;
2128
+ }
2129
+ const endRegion = chosen.re.end.exec(lines[i])?.[1];
2130
+ if (endRegion === regionName || endRegion === "") {
2131
+ if (--counter === 0) return {
2132
+ ...chosen,
2133
+ end: i
2134
+ };
2135
+ }
2037
2136
  }
2038
- else if (endReg.test(line.trim())) return {
2039
- start,
2040
- end: lineId,
2041
- regexp: endReg
2042
- };
2043
2137
  return null;
2044
2138
  }
2045
2139
  const reMonacoWrite = /^\{monaco-write\}/;
@@ -2068,7 +2162,7 @@ function transformSnippet({ s, slide, options }) {
2068
2162
  if (regionName) {
2069
2163
  const lines = content.split(/\r?\n/);
2070
2164
  const region = findRegion(lines, regionName.slice(1));
2071
- if (region) content = dedent(lines.slice(region.start, region.end).filter((line) => !region.regexp.test(line.trim())).join("\n"));
2165
+ if (region) content = dedent(lines.slice(region.start, region.end).filter((l) => !(region.re.start.test(l) || region.re.end.test(l))).join("\n"));
2072
2166
  }
2073
2167
  if (meta.match(reMonacoWrite)) {
2074
2168
  monacoWriterWhitelist.add(filepath);
@@ -2358,7 +2452,7 @@ async function setupUnocss({ clientRoot, roots, data, utils }) {
2358
2452
  {
2359
2453
  presets: [presetIcons({
2360
2454
  collectionsNodeResolvePath: utils.iconsResolvePath,
2361
- collections: { slidev: { logo: () => readFileSync(resolve(clientRoot, "assets/logo.svg"), "utf-8") } }
2455
+ collections: { slidev: { logo: () => readFile(resolve(clientRoot, "assets/logo.svg"), "utf-8") } }
2362
2456
  })],
2363
2457
  safelist: tokens
2364
2458
  },
@@ -2490,12 +2584,11 @@ async function resolveViteConfigs(options, baseConfig, overrideConfigs, command,
2490
2584
  mode: command === "build" ? "production" : "development",
2491
2585
  command
2492
2586
  };
2493
- const files = options.roots.map((i) => join(i, "vite.config.ts"));
2494
- for (const file of files) {
2495
- if (!existsSync(file)) continue;
2496
- const viteConfig = await loadConfigFromFile(configEnv, file);
2497
- if (!viteConfig?.config) continue;
2498
- baseConfig = mergeConfig(baseConfig, viteConfig.config);
2587
+ const files = resolveSourceFiles(options.roots, "vite.config");
2588
+ const configs = await Promise.all(files.map((file) => loadConfigFromFile(configEnv, file)));
2589
+ for (const config of configs) {
2590
+ if (!config?.config) continue;
2591
+ baseConfig = mergeConfig(baseConfig, config.config);
2499
2592
  }
2500
2593
  baseConfig = mergeConfig(baseConfig, overrideConfigs);
2501
2594
  baseConfig = mergeConfig(baseConfig, {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@slidev/cli",
3
3
  "type": "module",
4
- "version": "52.8.0",
4
+ "version": "52.9.1",
5
5
  "description": "Presentation slides for developers",
6
6
  "author": "Anthony Fu <anthonyfu117@hotmail.com>",
7
7
  "license": "MIT",
@@ -59,7 +59,6 @@
59
59
  "chokidar": "^4.0.3",
60
60
  "cli-progress": "^3.12.0",
61
61
  "connect": "^3.7.0",
62
- "debug": "^4.4.3",
63
62
  "fast-deep-equal": "^3.1.3",
64
63
  "fast-glob": "^3.3.3",
65
64
  "get-port-please": "^3.2.0",
@@ -77,6 +76,7 @@
77
76
  "markdown-it-mdc": "^0.2.6",
78
77
  "mlly": "^1.8.0",
79
78
  "monaco-editor": "^0.54.0",
79
+ "obug": "^2.0.0",
80
80
  "open": "^10.2.0",
81
81
  "pdf-lib": "^1.17.1",
82
82
  "picomatch": "^4.0.3",
@@ -109,9 +109,9 @@
109
109
  "vue": "^3.5.24",
110
110
  "yaml": "^2.8.1",
111
111
  "yargs": "^18.0.0",
112
- "@slidev/parser": "52.8.0",
113
- "@slidev/types": "52.8.0",
114
- "@slidev/client": "52.8.0"
112
+ "@slidev/client": "52.9.1",
113
+ "@slidev/parser": "52.9.1",
114
+ "@slidev/types": "52.9.1"
115
115
  },
116
116
  "devDependencies": {
117
117
  "@hedgedoc/markdown-it-plugins": "^2.1.4",