@slidev/cli 52.19.2 → 52.20.0

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.
@@ -262,6 +262,16 @@ function loadModule(absolutePath) {
262
262
  function stringifyMarkdownTokens(tokens) {
263
263
  return tokens.map((token) => token.children?.filter((t) => ["text", "code_inline"].includes(t.type) && !t.content.match(RE_WHITESPACE_ONLY)).map((t) => t.content.trim()).join(" ")).filter(Boolean).join(" ");
264
264
  }
265
+ const RE_WORD_CHARS_ONLY = /^[\w-]+$/;
266
+ const RE_REGEXP_CHARS = /[.*+?^${}()|[\]\\]/g;
267
+ function applyNotesAutoRuby(md, notesAutoRuby) {
268
+ const keys = Object.keys(notesAutoRuby).sort((a, b) => b.length - a.length).map((i) => RE_WORD_CHARS_ONLY.test(i) ? `\\b${i}\\b` : i.replace(RE_REGEXP_CHARS, "\\$&"));
269
+ if (!keys.length) return md;
270
+ return md.replace(new RegExp(`(${keys.join("|")})`, "g"), (match) => {
271
+ if (notesAutoRuby[match]) return `<ruby>${match}<rt>${notesAutoRuby[match]}</rt></ruby>`;
272
+ return match;
273
+ });
274
+ }
265
275
  function generateFontParams(options) {
266
276
  const weights = options.weights.flatMap((i) => options.italic ? [`0,${i}`, `1,${i}`] : [`${i}`]).sort().join(";");
267
277
  return options.webfonts.map((i) => `family=${i.replace(RE_QUOTED_STRING, "$1").replace(RE_WHITESPACE, "+")}:${options.italic ? "ital," : ""}wght@${weights}`).join("&");
@@ -712,7 +722,7 @@ function createLayoutWrapperPlugin({ data, utils }) {
712
722
  }
713
723
  //#endregion
714
724
  //#region package.json
715
- var version = "52.19.2";
725
+ var version = "52.20.0";
716
726
  //#endregion
717
727
  //#region node/integrations/addons.ts
718
728
  async function resolveAddons(addonsInConfig) {
@@ -1507,7 +1517,6 @@ const templates = [
1507
1517
  ];
1508
1518
  //#endregion
1509
1519
  //#region node/vite/loaders.ts
1510
- const RE_WORD_CHARS_ONLY = /^[\w-]+$/;
1511
1520
  function createSlidesLoader(options, serverOptions) {
1512
1521
  const { data, mode, utils, withoutNotes } = options;
1513
1522
  const notesMd = MarkdownExit({ html: true });
@@ -1547,12 +1556,17 @@ function createSlidesLoader(options, serverOptions) {
1547
1556
  if (!match) return next();
1548
1557
  const [, no] = match;
1549
1558
  const idx = Number.parseInt(no) - 1;
1559
+ const targetSlide = data.slides[idx];
1560
+ if (!targetSlide) {
1561
+ res.statusCode = 404;
1562
+ return res.end();
1563
+ }
1550
1564
  if (req.method === "GET") {
1551
- res.write(JSON.stringify(withRenderedNote(data.slides[idx])));
1565
+ res.write(JSON.stringify(withRenderedNote(targetSlide)));
1552
1566
  return res.end();
1553
1567
  } else if (req.method === "POST") {
1554
1568
  const body = await getBodyJson(req);
1555
- const slide = data.slides[idx];
1569
+ const slide = targetSlide;
1556
1570
  if (body.content && body.content !== slide.source.content) hmrSlidesIndexes.add(idx);
1557
1571
  if (body.content) slide.content = slide.source.content = body.content;
1558
1572
  if (body.frontmatterRaw != null) {
@@ -1754,19 +1768,11 @@ function createSlidesLoader(options, serverOptions) {
1754
1768
  if (withoutNotes) return "";
1755
1769
  let clickCount = 0;
1756
1770
  const notesAutoRuby = data.headmatter.notesAutoRuby || {};
1757
- let md = text.replace(/\[click(?::(\d+))?\]/gi, (_, count = 1) => {
1771
+ const md = text.replace(/\[click(?::(\d+))?\]/gi, (_, count = 1) => {
1758
1772
  clickCount += Number(count);
1759
1773
  return `<span class="slidev-note-click-mark" data-clicks="${clickCount}"></span>`;
1760
1774
  });
1761
- const keys = Object.keys(notesAutoRuby).sort((b, a) => b.length - a.length).map((i) => RE_WORD_CHARS_ONLY.test(i) ? `\\b${i}\\b` : i);
1762
- if (keys.length) {
1763
- const regex = new RegExp(`(${keys.join("|")})`, "g");
1764
- md = md.replace(regex, (match) => {
1765
- if (notesAutoRuby[match]) return `<ruby>${match}<rt>${notesAutoRuby[match]}</rt></ruby>`;
1766
- return match;
1767
- });
1768
- }
1769
- return notesMd.render(md);
1775
+ return notesMd.render(applyNotesAutoRuby(md, notesAutoRuby));
1770
1776
  }
1771
1777
  function withRenderedNote(data) {
1772
1778
  return {
@@ -2210,13 +2216,14 @@ function MarkdownItSnippet(md, { userRoot, userWorkspaceRoot, roots, data: { wat
2210
2216
  }
2211
2217
  const snippet = resolveSnippetImport(lineText, userRoot, slide, allowedRoots);
2212
2218
  if (!snippet) return false;
2213
- const { content, filepath, src } = snippet;
2219
+ const { content, src } = snippet;
2214
2220
  let { lang, meta } = snippet;
2215
2221
  if (meta.includes("{monaco-write}")) {
2216
- monacoWriterWhitelist.add(filepath);
2222
+ const writePath = slash(path.relative(userRoot, src));
2223
+ monacoWriterWhitelist.add(writePath);
2217
2224
  lang = lang.trim();
2218
2225
  meta = meta.replace("{monaco-write}", "").trim() || "{}";
2219
- const safeFilepath = JSON.stringify(filepath).slice(1, -1);
2226
+ const safeFilepath = JSON.stringify(writePath).slice(1, -1);
2220
2227
  const encoded = lz.compressToBase64(content);
2221
2228
  const token = state.push("html_block", "", 0);
2222
2229
  token.content = `<Monaco writable="${safeFilepath}" code-lz="${encoded}" lang="${lang}" v-bind="${meta}" />\n`;
@@ -1,5 +1,5 @@
1
1
  import { n as getRoots } from "./resolver-BIhhHpe7.mjs";
2
- import { i as createSlidevMcpServer, s as parser, u as version } from "./serve-CLfxiJWo.mjs";
2
+ import { i as createSlidevMcpServer, s as parser, u as version } from "./serve-BRH-KJ3L.mjs";
3
3
  import { StdioServerTransport } from "@modelcontextprotocol/server/stdio";
4
4
  //#region node/mcp/stdio.ts
5
5
  /**
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@slidev/cli",
3
3
  "type": "module",
4
- "version": "52.19.2",
4
+ "version": "52.20.0",
5
5
  "description": "Presentation slides for developers",
6
6
  "author": "Anthony Fu <anthonyfu117@hotmail.com>",
7
7
  "license": "MIT",
@@ -60,11 +60,11 @@
60
60
  "@shikijs/markdown-it": "^4.4.3",
61
61
  "@shikijs/twoslash": "^4.4.3",
62
62
  "@shikijs/vitepress-twoslash": "^4.4.3",
63
- "@slidev/client": "52.19.2",
64
- "@slidev/parser": "52.19.2",
65
- "@slidev/types": "52.19.2",
66
- "@unocss/extractor-mdc": "^66.10.3",
67
- "@unocss/reset": "^66.10.3",
63
+ "@slidev/client": "52.20.0",
64
+ "@slidev/parser": "52.20.0",
65
+ "@slidev/types": "52.20.0",
66
+ "@unocss/extractor-mdc": "^66.10.4",
67
+ "@unocss/reset": "^66.10.4",
68
68
  "@vitejs/plugin-vue": "^6.0.9",
69
69
  "@vitejs/plugin-vue-jsx": "^5.1.6",
70
70
  "ansis": "^4.4.0",
@@ -105,14 +105,14 @@
105
105
  "source-map-js": "^1.2.1",
106
106
  "typescript": "^6.0.3",
107
107
  "unhead": "^3.4.1",
108
- "unocss": "^66.10.3",
108
+ "unocss": "^66.10.4",
109
109
  "unplugin-icons": "^24.0.0",
110
110
  "unplugin-vue-components": "^32.1.0",
111
111
  "unplugin-vue-markdown": "^32.1.1",
112
112
  "untun": "^0.2.2",
113
113
  "uqr": "^0.1.3",
114
114
  "verkit": "^0.4.0",
115
- "vite": "~8.2.0",
115
+ "vite": "^8.3.0",
116
116
  "vite-plugin-inspect": "^12.0.2",
117
117
  "vite-plugin-remote-assets": "^2.1.0",
118
118
  "vite-plugin-static-copy": "^4.1.1",
@@ -126,7 +126,8 @@
126
126
  "devDependencies": {
127
127
  "@hedgedoc/markdown-it-plugins": "^2.1.4",
128
128
  "@types/picomatch": "^4.0.3",
129
- "@types/plantuml-encoder": "^1.4.2"
129
+ "@types/plantuml-encoder": "^1.4.2",
130
+ "jszip": "^3.10.1"
130
131
  },
131
132
  "scripts": {
132
133
  "build": "tsdown node/index.ts node/cli.ts",
@@ -65,7 +65,7 @@ Options:
65
65
  | Option | Default | Description |
66
66
  |--------|---------|-------------|
67
67
  | `--output` | - | Output filename |
68
- | `--format` | pdf | pdf / png / pptx / md |
68
+ | `--format` | pdf | pdf / png / pptx / pptx-editable / md |
69
69
  | `--timeout` | 30000 | Timeout per slide (ms) |
70
70
  | `--range` | - | Slide range (e.g., 1,4-7) |
71
71
  | `--dark` | false | Export dark mode |
@@ -30,9 +30,12 @@ slidev export --output my-slides.pdf
30
30
  ### PowerPoint Export
31
31
 
32
32
  ```bash
33
- slidev export --format pptx
33
+ slidev export --format pptx # each slide as an image
34
+ slidev export --format pptx-editable # native shapes, selectable text
34
35
  ```
35
36
 
37
+ `pptx-editable` measures the rendered slides and rebuilds them as PowerPoint shapes. SVG (including Mermaid), canvas, iframes, KaTeX formulas, gradients and CSS filters stay pictures, and any slide that cannot be rebuilt falls back to the image export on its own. Fonts are named, not embedded. `--per-slide` is not supported with it.
38
+
36
39
  ### PNG Export
37
40
 
38
41
  ```bash