@slidev/cli 0.49.2 → 0.49.4

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.
@@ -2,9 +2,9 @@ import {
2
2
  ViteSlidevPlugin,
3
3
  getIndexHtml,
4
4
  mergeViteConfigs
5
- } from "./chunk-PMIYMR2F.mjs";
5
+ } from "./chunk-UUONTUWJ.mjs";
6
6
  import "./chunk-LOUKLO2C.mjs";
7
- import "./chunk-ALXAQLRA.mjs";
7
+ import "./chunk-RG2EEPCO.mjs";
8
8
  import "./chunk-BXO7ZPPU.mjs";
9
9
 
10
10
  // node/commands/build.ts
@@ -63,7 +63,7 @@ async function build(options, viteConfig = {}, args) {
63
63
  await fs.writeFile(redirectsPath, `${config.base}* ${config.base}index.html 200
64
64
  `, "utf-8");
65
65
  if ([true, "true", "auto"].includes(options.data.config.download)) {
66
- const { exportSlides, getExportOptions } = await import("./export-D7UWWRHH.mjs");
66
+ const { exportSlides, getExportOptions } = await import("./export-Q4LURPEZ.mjs");
67
67
  const port = 12445;
68
68
  const app = connect();
69
69
  const server = http.createServer(app);
@@ -2,12 +2,12 @@ import {
2
2
  ViteSlidevPlugin,
3
3
  mergeViteConfigs,
4
4
  version
5
- } from "./chunk-PMIYMR2F.mjs";
5
+ } from "./chunk-UUONTUWJ.mjs";
6
6
  import {
7
7
  createResolver,
8
8
  getRoots,
9
9
  resolveEntry
10
- } from "./chunk-ALXAQLRA.mjs";
10
+ } from "./chunk-RG2EEPCO.mjs";
11
11
 
12
12
  // node/commands/server.ts
13
13
  import { join } from "node:path";
@@ -53,7 +53,7 @@ async function findGlobalPkgRoot(name, ensure = false) {
53
53
  throw new Error(`Failed to resolve global package "${name}"`);
54
54
  }
55
55
  async function resolveEntry(entryRaw) {
56
- if (!fs.existsSync(entryRaw) && !entryRaw.endsWith(".md") && !/[\/\\]/.test(entryRaw))
56
+ if (!fs.existsSync(entryRaw) && !entryRaw.endsWith(".md") && !/[/\\]/.test(entryRaw))
57
57
  entryRaw += ".md";
58
58
  const entry = resolve(entryRaw);
59
59
  if (!fs.existsSync(entry)) {
@@ -6,7 +6,7 @@ import {
6
6
  resolveImportPath,
7
7
  resolveImportUrl,
8
8
  toAtFS
9
- } from "./chunk-ALXAQLRA.mjs";
9
+ } from "./chunk-RG2EEPCO.mjs";
10
10
  import {
11
11
  __commonJS,
12
12
  __toESM
@@ -7143,7 +7143,7 @@ var require_dist = __commonJS({
7143
7143
  });
7144
7144
 
7145
7145
  // package.json
7146
- var version = "0.49.2";
7146
+ var version = "0.49.4";
7147
7147
 
7148
7148
  // node/commands/shared.ts
7149
7149
  import { existsSync, promises as fs } from "node:fs";
@@ -7256,9 +7256,9 @@ async function getIndexHtml({ entry, clientRoot, roots, data }) {
7256
7256
  continue;
7257
7257
  const index = await fs.readFile(path3, "utf-8");
7258
7258
  head += `
7259
- ${(index.match(/<head>([\s\S]*?)<\/head>/im)?.[1] || "").trim()}`;
7259
+ ${(index.match(/<head>([\s\S]*?)<\/head>/i)?.[1] || "").trim()}`;
7260
7260
  body += `
7261
- ${(index.match(/<body>([\s\S]*?)<\/body>/im)?.[1] || "").trim()}`;
7261
+ ${(index.match(/<body>([\s\S]*?)<\/body>/i)?.[1] || "").trim()}`;
7262
7262
  }
7263
7263
  if (data.features.tweet)
7264
7264
  body += '\n<script async src="https://platform.twitter.com/widgets.js"></script>';
@@ -7484,7 +7484,7 @@ function createConfigPlugin(options) {
7484
7484
  options.userWorkspaceRoot,
7485
7485
  options.clientRoot,
7486
7486
  // Special case for PNPM global installation
7487
- isInstalledGlobally.value ? slash2(options.cliRoot).replace(/\/\.pnpm\/.*$/ig, "") : options.cliRoot,
7487
+ isInstalledGlobally.value ? slash2(options.cliRoot).replace(/\/\.pnpm\/.*$/gi, "") : options.cliRoot,
7488
7488
  ...options.roots
7489
7489
  ])
7490
7490
  }
@@ -8013,8 +8013,8 @@ var templates = [
8013
8013
  ];
8014
8014
 
8015
8015
  // node/vite/loaders.ts
8016
- var regexId = /^\/\@slidev\/slide\/(\d+)\.(md|json)(?:\?import)?$/;
8017
- var regexIdQuery = /(\d+?)\.(md|json|frontmatter)$/;
8016
+ var regexId = /^\/@slidev\/slide\/(\d+)\.(md|json)(?:\?import)?$/;
8017
+ var regexIdQuery = /(\d+)\.(md|json|frontmatter)$/;
8018
8018
  var templateInjectionMarker = "/* @slidev-injection */";
8019
8019
  var templateImportContextUtils = `import {
8020
8020
  useSlideContext,
@@ -8388,7 +8388,7 @@ ${code.slice(injectB)}`;
8388
8388
  ${imports.join("\n")}
8389
8389
  `);
8390
8390
  } else if (matchScript && !matchScript[2]) {
8391
- const matchExport = code.match(/export\s+default\s+{/);
8391
+ const matchExport = code.match(/export\s+default\s+\{/);
8392
8392
  if (matchExport) {
8393
8393
  const exportIndex = (matchExport.index || 0) + matchExport[0].length;
8394
8394
  let component = code.slice(exportIndex);
@@ -8398,7 +8398,7 @@ ${imports.join("\n")}
8398
8398
  code = `${code.slice(0, scriptIndex)}${provideImport}${code.slice(scriptIndex)}`;
8399
8399
  let injectIndex = exportIndex + provideImport.length;
8400
8400
  let injectObject = "$slidev: { from: injectionSlidevContext },";
8401
- const matchInject = component.match(/.*inject\s*:\s*([\[{])/);
8401
+ const matchInject = component.match(/.*inject\s*:\s*([[{])/);
8402
8402
  if (matchInject) {
8403
8403
  injectIndex += (matchInject.index || 0) + matchInject[0].length;
8404
8404
  if (matchInject[1] === "[") {
@@ -8719,7 +8719,7 @@ function normalizeRangeStr(rangeStr = "") {
8719
8719
  return !rangeStr.trim() ? [] : rangeStr.trim().split(/\|/g).map((i) => i.trim());
8720
8720
  }
8721
8721
  function getCodeBlocks(md) {
8722
- const codeblocks = Array.from(md.matchAll(/^```[\s\S]*?^```/mg)).map((m) => {
8722
+ const codeblocks = Array.from(md.matchAll(/^```[\s\S]*?^```/gm)).map((m) => {
8723
8723
  const start = m.index;
8724
8724
  const end = m.index + m[0].length;
8725
8725
  const startLine = md.slice(0, start).match(/\n/g)?.length || 0;
@@ -8737,7 +8737,7 @@ function getCodeBlocks(md) {
8737
8737
  };
8738
8738
  }
8739
8739
  function escapeVueInCode(md) {
8740
- return md.replace(/{{/g, "&lbrace;&lbrace;");
8740
+ return md.replace(/\{\{/g, "&lbrace;&lbrace;");
8741
8741
  }
8742
8742
 
8743
8743
  // node/syntax/markdown-it/markdown-it-prism.ts
@@ -8882,7 +8882,7 @@ function markdownItVDrag(md, markdownTransformMap) {
8882
8882
  }
8883
8883
 
8884
8884
  // node/syntax/transform/code-wrapper.ts
8885
- var reCodeBlock = /^```([\w'-]+?)(?:\s*{([\d\w*,\|-]+)}\s*?({.*?})?(.*?))?\r?\n([\s\S]+?)^```$/mg;
8885
+ var reCodeBlock = /^```([\w'-]+)(?:\s*\{([\w*,|-]+)\}\s*?(\{[^}]*\})?([^\r\n]*))?\r?\n(\S[\s\S]*?)^```$/gm;
8886
8886
  function transformCodeWrapper(ctx) {
8887
8887
  ctx.s.replace(
8888
8888
  reCodeBlock,
@@ -8905,7 +8905,7 @@ ${code}
8905
8905
  // node/syntax/transform/magic-move.ts
8906
8906
  import { codeToKeyedTokens } from "shiki-magic-move/core";
8907
8907
  import lz from "lz-string";
8908
- var reMagicMoveBlock = /^````(?:md|markdown) magic-move(?:[ ]*(\{.*?\})?([^\n]*?))?\n([\s\S]+?)^````$/mg;
8908
+ var reMagicMoveBlock = /^````(?:md|markdown) magic-move(?: *(\{[^}]*\})?([^\n]*))?\n([\s\S]+?)^````$/gm;
8909
8909
  function transformMagicMove(shiki, shikiOptions) {
8910
8910
  return (ctx) => {
8911
8911
  ctx.s.replace(
@@ -8933,23 +8933,29 @@ function transformMagicMove(shiki, shikiOptions) {
8933
8933
  // node/syntax/transform/mermaid.ts
8934
8934
  import lz2 from "lz-string";
8935
8935
  function transformMermaid(ctx) {
8936
- ctx.s.replace(/^```mermaid\s*?({.*?})?\n([\s\S]+?)\n```/mg, (full, options = "", code = "") => {
8937
- code = code.trim();
8938
- options = options.trim() || "{}";
8939
- const encoded = lz2.compressToBase64(code);
8940
- return `<Mermaid code-lz="${encoded}" v-bind="${options}" />`;
8941
- });
8936
+ ctx.s.replace(
8937
+ /^```mermaid *(\{[^}]*\})?\n([\s\S]+?)\n```/gm,
8938
+ (full, options = "", code = "") => {
8939
+ code = code.trim();
8940
+ options = options.trim() || "{}";
8941
+ const encoded = lz2.compressToBase64(code);
8942
+ return `<Mermaid code-lz="${encoded}" v-bind="${options}" />`;
8943
+ }
8944
+ );
8942
8945
  }
8943
8946
 
8944
8947
  // node/syntax/transform/plant-uml.ts
8945
8948
  import { encode as encodePlantUml } from "plantuml-encoder";
8946
8949
  function transformPlantUml(ctx) {
8947
8950
  const server = ctx.options.data.config.plantUmlServer;
8948
- ctx.s.replace(/^```plantuml\s*?({.*?})?\n([\s\S]+?)\n```/mg, (full, options = "", content = "") => {
8949
- const code = encodePlantUml(content.trim());
8950
- options = options.trim() || "{}";
8951
- return `<PlantUml :code="'${code}'" :server="'${server}'" v-bind="${options}" />`;
8952
- });
8951
+ ctx.s.replace(
8952
+ /^```plantuml[^\n{}]*(\{[^}\n]*\})?\n([\s\S]+?)\n```/gm,
8953
+ (full, options = "", content = "") => {
8954
+ const code = encodePlantUml(content.trim());
8955
+ options = options.trim() || "{}";
8956
+ return `<PlantUml :code="'${code}'" :server="'${server}'" v-bind="${options}" />`;
8957
+ }
8958
+ );
8953
8959
  }
8954
8960
 
8955
8961
  // node/syntax/transform/snippet.ts
@@ -8983,9 +8989,9 @@ function findRegion(lines, regionName) {
8983
8989
  // C, C++
8984
8990
  /^<!-- #?((?:end)?region) ([\w*-]+) -->$/,
8985
8991
  // HTML, markdown
8986
- /^#((?:End )Region) ([\w*-]+)$/,
8992
+ /^#(End Region) ([\w*-]+)$/,
8987
8993
  // Visual Basic
8988
- /^::#((?:end)region) ([\w*-]+)$/,
8994
+ /^::#(endregion) ([\w*-]+)$/,
8989
8995
  // Bat
8990
8996
  /^# ?((?:end)?region) ([\w*-]+)$/
8991
8997
  // C#, PHP, Powershell, Python, perl & misc
@@ -9016,11 +9022,12 @@ function transformSnippet(ctx) {
9016
9022
  const slideInfo = data.slides[+slideId - 1];
9017
9023
  const dir = path2.dirname(slideInfo.source?.filepath ?? options.entry ?? options.userRoot);
9018
9024
  ctx.s.replace(
9019
- /^<<< *(.+?)(#[\w-]+)? *(?: (\S+?))? *(\{.*)?$/mg,
9025
+ // eslint-disable-next-line regexp/no-super-linear-backtracking
9026
+ /^<<<\s*(\S.*?)(#[\w-]+)?\s*(?:\s(\S+?))?\s*(\{.*)?$/gm,
9020
9027
  (full, filepath = "", regionName = "", lang = "", meta = "") => {
9021
9028
  const firstLine = `\`\`\`${lang || path2.extname(filepath).slice(1)} ${meta}`;
9022
9029
  const src = slash3(
9023
- /^\@[\/]/.test(filepath) ? path2.resolve(options.userRoot, filepath.slice(2)) : path2.resolve(dir, filepath)
9030
+ /^@\//.test(filepath) ? path2.resolve(options.userRoot, filepath.slice(2)) : path2.resolve(dir, filepath)
9024
9031
  );
9025
9032
  data.watchFiles.push(src);
9026
9033
  const isAFile = fs4.statSync(src).isFile();
@@ -9063,7 +9070,7 @@ function transformSlotSugar(ctx) {
9063
9070
  offset += line.length;
9064
9071
  if (codeBlocks.isInsideCodeblocks(offset))
9065
9072
  return;
9066
- const match = line.match(/^::\s*([\w\.\-\:]+)\s*::(\s*)?$/);
9073
+ const match = line.match(/^::\s*([\w.\-:]+)\s*::(\s*)$/);
9067
9074
  if (match) {
9068
9075
  ctx.s.overwrite(start, offset - match[2].length, `${prevSlot ? "\n\n</template>\n" : "\n"}<template v-slot:${match[1]}="slotProps">
9069
9076
  `);
@@ -9081,7 +9088,7 @@ function transformPageCSS(ctx) {
9081
9088
  return;
9082
9089
  const codeBlocks = getCodeBlocks(ctx.s.original);
9083
9090
  ctx.s.replace(
9084
- /(\n<style[^>]*?>)([\s\S]+?)(<\/style>)/g,
9091
+ /(\n<style[^>]*>)([\s\S]+?)(<\/style>)/g,
9085
9092
  (full, start, css, end, index) => {
9086
9093
  if (codeBlocks.isInsideCodeblocks(index))
9087
9094
  return full;
@@ -9098,11 +9105,11 @@ import lz3 from "lz-string";
9098
9105
  function transformMonaco(ctx) {
9099
9106
  const enabled = ctx.options.data.config.monaco === true || ctx.options.data.config.monaco === ctx.options.mode;
9100
9107
  if (!enabled) {
9101
- ctx.s.replace(/{monaco([\w:,-]*)}/g, "");
9108
+ ctx.s.replace(/\{monaco([\w:,-]*)\}/g, "");
9102
9109
  return;
9103
9110
  }
9104
9111
  ctx.s.replace(
9105
- /^```(\w+?)\s*{monaco-diff}\s*?({.*?})?\s*?\n([\s\S]+?)^~~~\s*?\n([\s\S]+?)^```/mg,
9112
+ /^```(\w+) *\{monaco-diff\} *(?:(\{[^\n}]*\}) *)?\n([\s\S]+?)^~~~ *\n([\s\S]+?)^```/gm,
9106
9113
  (full, lang = "ts", options = "{}", code, diff) => {
9107
9114
  lang = lang.trim();
9108
9115
  options = options.trim() || "{}";
@@ -9112,7 +9119,7 @@ function transformMonaco(ctx) {
9112
9119
  }
9113
9120
  );
9114
9121
  ctx.s.replace(
9115
- /^```(\w+?)\s*{monaco}\s*?({.*?})?\s*?\n([\s\S]+?)^```/mg,
9122
+ /^```(\w+) *\{monaco\} *(?:(\{[^}]*\}) *)?\n([\s\S]+?)^```/gm,
9116
9123
  (full, lang = "ts", options = "{}", code) => {
9117
9124
  lang = lang.trim();
9118
9125
  options = options.trim() || "{}";
@@ -9121,7 +9128,7 @@ function transformMonaco(ctx) {
9121
9128
  }
9122
9129
  );
9123
9130
  ctx.s.replace(
9124
- /^```(\w+?)\s*{monaco-run}\s*?({.*?})?\s*?\n([\s\S]+?)^```/mg,
9131
+ /^```(\w+) *\{monaco-run\} *(?:(\{[^}]*\}) *)?\n([\s\S]+?)^```/gm,
9125
9132
  (full, lang = "ts", options = "{}", code) => {
9126
9133
  lang = lang.trim();
9127
9134
  options = options.trim() || "{}";
@@ -9134,7 +9141,7 @@ function transformMonaco(ctx) {
9134
9141
  // node/syntax/transform/katex-wrapper.ts
9135
9142
  function transformKaTexWrapper(ctx) {
9136
9143
  ctx.s.replace(
9137
- /^\$\$(?:\s*{([\d\w*,\|-]+)}\s*?({.*?})?\s*?)?\n([\s\S]+?)^\$\$/mg,
9144
+ /^\$\$(?:\s*\{([\w*,|-]+)\}\s*?(?:(\{[^}]*\})\s*?)?)?\n(\S[\s\S]*?)^\$\$/gm,
9138
9145
  (full, rangeStr = "", options = "", code) => {
9139
9146
  const ranges = !rangeStr.trim() ? [] : rangeStr.trim().split(/\|/g).map((i) => i.trim());
9140
9147
  code = code.trimEnd();
@@ -9325,7 +9332,7 @@ function createMonacoTypesLoader({ userRoot }) {
9325
9332
  return null;
9326
9333
  },
9327
9334
  async load(id) {
9328
- const matchResolve = id.match(/^\/\@slidev-monaco-types\/resolve\?pkg=(.*?)(?:&importer=(.*))?$/);
9335
+ const matchResolve = id.match(/^\/@slidev-monaco-types\/resolve\?pkg=(.*?)(?:&importer=(.*))?$/);
9329
9336
  if (matchResolve) {
9330
9337
  const [_, pkg, importer = userRoot] = matchResolve;
9331
9338
  const resolvedDeps = resolvedDepsMap[importer] ??= /* @__PURE__ */ new Set();
@@ -9343,7 +9350,7 @@ function createMonacoTypesLoader({ userRoot }) {
9343
9350
  ...Object.keys(deps).map((dep) => `import "/@slidev-monaco-types/resolve?pkg=${dep}&importer=${slash5(root)}"`)
9344
9351
  ].join("\n");
9345
9352
  }
9346
- const matchLoad = id.match(/^\/\@slidev-monaco-types\/load\?root=(.*?)&name=(.*)$/);
9353
+ const matchLoad = id.match(/^\/@slidev-monaco-types\/load\?root=(.*?)&name=(.*)$/);
9347
9354
  if (matchLoad) {
9348
9355
  const [_, root, name] = matchLoad;
9349
9356
  const files = await fg4(
@@ -9478,7 +9485,7 @@ async function ViteSlidevPlugin(options, pluginOptions, serverOptions = {}) {
9478
9485
  rules: [
9479
9486
  ...r.DefaultRules,
9480
9487
  {
9481
- match: /\b(https?:\/\/image.unsplash\.com.*?)(?=[`'")\]])/ig,
9488
+ match: /\b(https?:\/\/image.unsplash\.com.*?)(?=[`'")\]])/gi,
9482
9489
  ext: ".png"
9483
9490
  }
9484
9491
  ],
package/dist/cli.mjs CHANGED
@@ -5,10 +5,10 @@ import {
5
5
  resolveAddons,
6
6
  resolveOptions,
7
7
  resolveTheme
8
- } from "./chunk-PUAFMPIH.mjs";
8
+ } from "./chunk-R4VWCFXW.mjs";
9
9
  import {
10
10
  version
11
- } from "./chunk-PMIYMR2F.mjs";
11
+ } from "./chunk-UUONTUWJ.mjs";
12
12
  import {
13
13
  loadSetups
14
14
  } from "./chunk-LOUKLO2C.mjs";
@@ -16,7 +16,7 @@ import {
16
16
  getRoots,
17
17
  isInstalledGlobally,
18
18
  resolveEntry
19
- } from "./chunk-ALXAQLRA.mjs";
19
+ } from "./chunk-RG2EEPCO.mjs";
20
20
  import "./chunk-BXO7ZPPU.mjs";
21
21
 
22
22
  // node/cli.ts
@@ -168,6 +168,11 @@ cli.command(
168
168
  restartServer();
169
169
  return false;
170
170
  }
171
+ if (newData.features.katex && !oldData.features.katex || newData.features.monaco && !oldData.features.monaco) {
172
+ console.log(yellow("\n restarting on feature change\n"));
173
+ restartServer();
174
+ return false;
175
+ }
171
176
  return newData;
172
177
  }
173
178
  }
@@ -304,11 +309,7 @@ ${dim(" Public IP: ")} ${blue(publicIp)}
304
309
  cli.command(
305
310
  "build [entry..]",
306
311
  "Build hostable SPA",
307
- (args) => exportOptions(commonOptions(args)).option("watch", {
308
- alias: "w",
309
- default: false,
310
- describe: "build watch"
311
- }).option("out", {
312
+ (args) => exportOptions(commonOptions(args)).option("out", {
312
313
  alias: "o",
313
314
  type: "string",
314
315
  default: "dist",
@@ -326,8 +327,8 @@ cli.command(
326
327
  describe: "enable the inspect plugin for debugging"
327
328
  }).strict().help(),
328
329
  async (args) => {
329
- const { entry, theme, watch, base, download, out, inspect } = args;
330
- const { build } = await import("./build-VHRT7T2N.mjs");
330
+ const { entry, theme, base, download, out, inspect } = args;
331
+ const { build } = await import("./build-6VAW6JNE.mjs");
331
332
  for (const entryFile of entry) {
332
333
  const options = await resolveOptions({ entry: entryFile, theme, inspect }, "build");
333
334
  if (download && !options.data.config.download)
@@ -338,7 +339,6 @@ cli.command(
338
339
  {
339
340
  base,
340
341
  build: {
341
- watch: watch ? {} : void 0,
342
342
  outDir: entry.length === 1 ? out : path.join(out, path.basename(entryFile, ".md"))
343
343
  }
344
344
  },
@@ -408,7 +408,7 @@ cli.command(
408
408
  (args) => exportOptions(commonOptions(args)).strict().help(),
409
409
  async (args) => {
410
410
  const { entry, theme } = args;
411
- const { exportSlides, getExportOptions } = await import("./export-D7UWWRHH.mjs");
411
+ const { exportSlides, getExportOptions } = await import("./export-Q4LURPEZ.mjs");
412
412
  const port = await getPort(12445);
413
413
  for (const entryFile of entry) {
414
414
  const options = await resolveOptions({ entry: entryFile, theme }, "export");
@@ -457,7 +457,7 @@ cli.command(
457
457
  timeout,
458
458
  wait
459
459
  }) => {
460
- const { exportNotes } = await import("./export-D7UWWRHH.mjs");
460
+ const { exportNotes } = await import("./export-Q4LURPEZ.mjs");
461
461
  const port = await getPort(12445);
462
462
  for (const entryFile of entry) {
463
463
  const options = await resolveOptions({ entry: entryFile }, "export");
@@ -501,7 +501,7 @@ function exportOptions(args) {
501
501
  describe: "path to the output"
502
502
  }).option("format", {
503
503
  type: "string",
504
- choices: ["pdf", "png", "md"],
504
+ choices: ["pdf", "png", "pptx", "md"],
505
505
  describe: "output format"
506
506
  }).option("timeout", {
507
507
  type: "number",
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getRoots
3
- } from "./chunk-ALXAQLRA.mjs";
3
+ } from "./chunk-RG2EEPCO.mjs";
4
4
  import "./chunk-BXO7ZPPU.mjs";
5
5
 
6
6
  // node/commands/export.ts
@@ -152,8 +152,7 @@ async function exportSlides({
152
152
  query.set("range", range);
153
153
  if (clicks)
154
154
  query.set("clicks", clicks);
155
- const path2 = `${no}?${query.toString()}`;
156
- const url = routerMode === "hash" ? `http://localhost:${port}${base}#${path2}` : `http://localhost:${port}${base}${path2}`;
155
+ const url = routerMode === "hash" ? `http://localhost:${port}${base}?${query}#${no}` : `http://localhost:${port}${base}${no}?${query}`;
157
156
  await page.goto(url, {
158
157
  waitUntil: "networkidle",
159
158
  timeout
@@ -226,15 +225,15 @@ async function exportSlides({
226
225
  return slideIndexes;
227
226
  }
228
227
  function getClicksFromUrl(url) {
229
- return url.match(/clicks=([1-9][0-9]*)/)?.[1];
228
+ return url.match(/clicks=([1-9]\d*)/)?.[1];
230
229
  }
231
- async function genPageWithClicks(fn, i, clicks) {
232
- await fn(i, clicks);
230
+ async function genPageWithClicks(fn, no, clicks) {
231
+ await fn(no, clicks);
233
232
  if (withClicks) {
234
233
  await page.keyboard.press("ArrowRight", { delay: 100 });
235
234
  const _clicks = getClicksFromUrl(page.url());
236
235
  if (_clicks && clicks !== _clicks)
237
- await genPageWithClicks(fn, i, _clicks);
236
+ await genPageWithClicks(fn, no, _clicks);
238
237
  }
239
238
  }
240
239
  async function genPagePdfPerSlide() {
@@ -298,50 +297,57 @@ async function exportSlides({
298
297
  pdfData = Buffer.from(await pdf.save());
299
298
  await fs.writeFile(output, pdfData);
300
299
  }
301
- async function genPagePngOnePiece() {
300
+ async function genPagePngOnePiece(writeToDisk) {
301
+ const result = [];
302
302
  await go("print");
303
303
  await fs.emptyDir(output);
304
- const slides2 = await page.locator(".print-slide-container");
305
- const count = await slides2.count();
304
+ const slideContainers = page.locator(".print-slide-container");
305
+ const count = await slideContainers.count();
306
306
  for (let i = 0; i < count; i++) {
307
307
  progress.update(i + 1);
308
- let id = await slides2.nth(i).getAttribute("id") || "";
309
- id = withClicks ? id : id.split("-")[0];
310
- const buffer = await slides2.nth(i).screenshot();
311
- await fs.writeFile(path.join(output, `${id}.png`), buffer);
308
+ const id = await slideContainers.nth(i).getAttribute("id") || "";
309
+ const slideNo = +id.split("-")[0];
310
+ const buffer = await slideContainers.nth(i).screenshot();
311
+ result.push({ slideIndex: slideNo - 1, buffer });
312
+ if (writeToDisk)
313
+ await fs.writeFile(path.join(output, `${withClicks ? id : slideNo}.png`), buffer);
312
314
  }
315
+ return result;
313
316
  }
314
- async function genPagePngPerSlide() {
315
- const genScreenshot = async (i, clicks) => {
316
- await go(i, clicks);
317
- await page.screenshot({
318
- omitBackground: false,
319
- path: path.join(
320
- output,
321
- `${i.toString().padStart(2, "0")}${clicks ? `-${clicks}` : ""}.png`
322
- )
323
- });
317
+ async function genPagePngPerSlide(writeToDisk) {
318
+ const result = [];
319
+ const genScreenshot = async (no, clicks) => {
320
+ await go(no, clicks);
321
+ const buffer = await page.screenshot();
322
+ result.push({ slideIndex: no - 1, buffer });
323
+ if (writeToDisk) {
324
+ await fs.writeFile(
325
+ path.join(output, `${no.toString().padStart(2, "0")}${clicks ? `-${clicks}` : ""}.png`),
326
+ buffer
327
+ );
328
+ }
324
329
  };
325
- for (const i of pages)
326
- await genPageWithClicks(genScreenshot, i);
330
+ for (const no of pages)
331
+ await genPageWithClicks(genScreenshot, no);
332
+ return result;
327
333
  }
328
334
  function genPagePdf() {
329
335
  if (!output.endsWith(".pdf"))
330
336
  output = `${output}.pdf`;
331
337
  return perSlide ? genPagePdfPerSlide() : genPagePdfOnePiece();
332
338
  }
333
- function genPagePng() {
334
- return perSlide ? genPagePngPerSlide() : genPagePngOnePiece();
339
+ function genPagePng(writeToDisk = true) {
340
+ return perSlide ? genPagePngPerSlide(writeToDisk) : genPagePngOnePiece(writeToDisk);
335
341
  }
336
- async function genPageMd(slides2) {
342
+ async function genPageMd() {
337
343
  const files = await fs.readdir(output);
338
344
  const mds = files.map((file, i, files2) => {
339
345
  const slideIndex = getSlideIndex(file);
340
- const mdImg = `![${slides2[slideIndex]?.title}](./${path.join(output, file)})
346
+ const mdImg = `![${slides[slideIndex]?.title}](./${path.join(output, file)})
341
347
 
342
348
  `;
343
- if ((i + 1 === files2.length || getSlideIndex(files2[i + 1]) !== slideIndex) && slides2[slideIndex]?.note)
344
- return `${mdImg}${slides2[slideIndex]?.note}
349
+ if ((i + 1 === files2.length || getSlideIndex(files2[i + 1]) !== slideIndex) && slides[slideIndex]?.note)
350
+ return `${mdImg}${slides[slideIndex]?.note}
345
351
 
346
352
  `;
347
353
  return mdImg;
@@ -350,6 +356,39 @@ async function exportSlides({
350
356
  output = `${output}.md`;
351
357
  await fs.writeFile(output, mds.join(""));
352
358
  }
359
+ async function genPagePptx(pngs) {
360
+ const { default: PptxGenJS } = await import("pptxgenjs");
361
+ const pptx = new PptxGenJS();
362
+ const layoutName = `${width}x${height}`;
363
+ pptx.defineLayout({
364
+ name: layoutName,
365
+ width: width / 96,
366
+ height: height / 96
367
+ });
368
+ pptx.layout = layoutName;
369
+ const titleSlide = slides[0];
370
+ pptx.author = titleSlide?.frontmatter?.author;
371
+ pptx.company = "Created using Slidev";
372
+ if (titleSlide?.title)
373
+ pptx.title = titleSlide?.title;
374
+ if (titleSlide?.frontmatter?.info)
375
+ pptx.subject = titleSlide?.frontmatter?.info;
376
+ pngs.forEach(({ slideIndex, buffer: buffer2 }) => {
377
+ const slide = pptx.addSlide();
378
+ slide.background = {
379
+ data: `data:image/png;base64,${buffer2.toString("base64")}`
380
+ };
381
+ const note = slides[slideIndex].note;
382
+ if (note)
383
+ slide.addNotes(note);
384
+ });
385
+ const buffer = await pptx.write({
386
+ outputType: "nodebuffer"
387
+ });
388
+ if (!output.endsWith(".pptx"))
389
+ output = `${output}.pptx`;
390
+ await fs.writeFile(output, buffer);
391
+ }
353
392
  function getSlideIndex(file) {
354
393
  const slideId = file.substring(0, file.indexOf(".")).split("-")[0];
355
394
  return Number(slideId) - 1;
@@ -386,7 +425,10 @@ async function exportSlides({
386
425
  await genPagePng();
387
426
  } else if (format === "md") {
388
427
  await genPagePng();
389
- await genPageMd(slides);
428
+ await genPageMd();
429
+ } else if (format === "pptx") {
430
+ const buffers = await genPagePng(false);
431
+ await genPagePptx(buffers);
390
432
  } else {
391
433
  throw new Error(`Unsupported exporting format "${format}"`);
392
434
  }
@@ -434,11 +476,11 @@ function getExportOptions(args, options, outDir, outFilename) {
434
476
  routerMode: options.data.config.routerMode,
435
477
  width: options.data.config.canvasWidth,
436
478
  height: Math.round(options.data.config.canvasWidth / options.data.config.aspectRatio),
437
- withClicks: withClicks || false,
479
+ withClicks: withClicks ?? format === "pptx",
438
480
  executablePath,
439
481
  withToc: withToc || false,
440
482
  perSlide: perSlide || false,
441
- scale: scale || 1
483
+ scale: scale || 2
442
484
  };
443
485
  }
444
486
  async function importPlaywright() {
package/dist/index.mjs CHANGED
@@ -2,12 +2,12 @@ import {
2
2
  createServer,
3
3
  parser,
4
4
  resolveOptions
5
- } from "./chunk-PUAFMPIH.mjs";
5
+ } from "./chunk-R4VWCFXW.mjs";
6
6
  import {
7
7
  ViteSlidevPlugin
8
- } from "./chunk-PMIYMR2F.mjs";
8
+ } from "./chunk-UUONTUWJ.mjs";
9
9
  import "./chunk-LOUKLO2C.mjs";
10
- import "./chunk-ALXAQLRA.mjs";
10
+ import "./chunk-RG2EEPCO.mjs";
11
11
  import "./chunk-BXO7ZPPU.mjs";
12
12
  export {
13
13
  ViteSlidevPlugin,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@slidev/cli",
3
- "version": "0.49.2",
3
+ "version": "0.49.4",
4
4
  "description": "Presentation slides for developers",
5
5
  "author": "antfu <anthonyfu117@hotmail.com>",
6
6
  "license": "MIT",
@@ -44,15 +44,15 @@
44
44
  "dependencies": {
45
45
  "@antfu/ni": "^0.21.12",
46
46
  "@antfu/utils": "^0.7.8",
47
- "@iconify-json/carbon": "^1.1.32",
47
+ "@iconify-json/carbon": "^1.1.34",
48
48
  "@iconify-json/ph": "^1.1.13",
49
49
  "@iconify-json/svg-spinners": "^1.1.2",
50
50
  "@lillallol/outline-pdf": "^4.0.0",
51
- "@shikijs/markdown-it": "^1.5.1",
52
- "@shikijs/twoslash": "^1.5.1",
53
- "@shikijs/vitepress-twoslash": "^1.5.1",
54
- "@unocss/extractor-mdc": "^0.60.0",
55
- "@unocss/reset": "^0.60.0",
51
+ "@shikijs/markdown-it": "^1.6.0",
52
+ "@shikijs/twoslash": "^1.6.0",
53
+ "@shikijs/vitepress-twoslash": "^1.6.0",
54
+ "@unocss/extractor-mdc": "^0.60.3",
55
+ "@unocss/reset": "^0.60.3",
56
56
  "@vitejs/plugin-vue": "^5.0.4",
57
57
  "@vitejs/plugin-vue-jsx": "^3.1.0",
58
58
  "chokidar": "^3.6.0",
@@ -78,23 +78,24 @@
78
78
  "markdown-it-footnote": "^4.0.0",
79
79
  "markdown-it-mdc": "^0.2.3",
80
80
  "mlly": "^1.7.0",
81
- "monaco-editor": "^0.48.0",
81
+ "monaco-editor": "^0.49.0",
82
82
  "open": "^10.1.0",
83
83
  "pdf-lib": "^1.17.1",
84
84
  "plantuml-encoder": "^1.4.0",
85
85
  "postcss-nested": "^6.0.1",
86
+ "pptxgenjs": "^3.12.0",
86
87
  "prismjs": "^1.29.0",
87
88
  "prompts": "^2.4.2",
88
89
  "public-ip": "^6.0.2",
89
90
  "resolve-from": "^5.0.0",
90
91
  "resolve-global": "^2.0.0",
91
92
  "semver": "^7.6.2",
92
- "shiki": "^1.5.1",
93
+ "shiki": "^1.6.0",
93
94
  "shiki-magic-move": "^0.4.2",
94
95
  "sirv": "^2.0.4",
95
96
  "source-map-js": "^1.2.0",
96
97
  "typescript": "^5.4.5",
97
- "unocss": "^0.60.0",
98
+ "unocss": "^0.60.3",
98
99
  "unplugin-icons": "^0.19.0",
99
100
  "unplugin-vue-components": "^0.27.0",
100
101
  "unplugin-vue-markdown": "^0.26.2",
@@ -103,14 +104,14 @@
103
104
  "vite": "^5.2.11",
104
105
  "vite-plugin-inspect": "^0.8.4",
105
106
  "vite-plugin-remote-assets": "^0.4.1",
106
- "vite-plugin-static-copy": "^1.0.4",
107
+ "vite-plugin-static-copy": "^1.0.5",
107
108
  "vite-plugin-vue-server-ref": "^0.4.2",
108
109
  "vitefu": "^0.2.5",
109
110
  "vue": "^3.4.27",
110
111
  "yargs": "^17.7.2",
111
- "@slidev/client": "0.49.2",
112
- "@slidev/parser": "0.49.2",
113
- "@slidev/types": "0.49.2"
112
+ "@slidev/client": "0.49.4",
113
+ "@slidev/types": "0.49.4",
114
+ "@slidev/parser": "0.49.4"
114
115
  },
115
116
  "devDependencies": {
116
117
  "@hedgedoc/markdown-it-plugins": "^2.1.4",
package/template.md CHANGED
@@ -56,7 +56,7 @@ Slidev is a slides maker and presenter designed for developers, consist of the f
56
56
  - 🧑‍💻 **Developer Friendly** - code highlighting, live coding with autocompletion
57
57
  - 🤹 **Interactive** - embedding Vue components to enhance your expressions
58
58
  - 🎥 **Recording** - built-in recording and camera view
59
- - 📤 **Portable** - export into PDF, PNGs, or even a hostable SPA
59
+ - 📤 **Portable** - export into PDF, PPTX, PNGs, or even a hostable SPA
60
60
  - 🛠 **Hackable** - anything possible on a webpage
61
61
 
62
62
  <br>