@slidev/cli 52.19.1 → 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.1";
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,19 +1556,26 @@ 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
- if (body.frontmatterRaw != null) if (body.frontmatterRaw.trim() === "") slide.source.frontmatterDoc = slide.source.frontmatterStyle = void 0;
1559
- else {
1560
- const parsed = YAML.parseDocument(body.frontmatterRaw);
1561
- if (parsed.errors.length) console.error("ERROR when saving frontmatter", parsed.errors);
1562
- else slide.source.frontmatterDoc = parsed;
1572
+ if (body.frontmatterRaw != null) {
1573
+ if (body.frontmatterRaw.trim() === "") slide.source.frontmatterDoc = slide.source.frontmatterStyle = void 0;
1574
+ else {
1575
+ const parsed = YAML.parseDocument(body.frontmatterRaw);
1576
+ if (parsed.errors.length) console.error("ERROR when saving frontmatter", parsed.errors);
1577
+ else slide.source.frontmatterDoc = parsed;
1578
+ }
1563
1579
  }
1564
1580
  if (body.note != null) slide.note = slide.source.note = body.note;
1565
1581
  if (body.frontmatter) {
@@ -1752,19 +1768,11 @@ function createSlidesLoader(options, serverOptions) {
1752
1768
  if (withoutNotes) return "";
1753
1769
  let clickCount = 0;
1754
1770
  const notesAutoRuby = data.headmatter.notesAutoRuby || {};
1755
- let md = text.replace(/\[click(?::(\d+))?\]/gi, (_, count = 1) => {
1771
+ const md = text.replace(/\[click(?::(\d+))?\]/gi, (_, count = 1) => {
1756
1772
  clickCount += Number(count);
1757
1773
  return `<span class="slidev-note-click-mark" data-clicks="${clickCount}"></span>`;
1758
1774
  });
1759
- const keys = Object.keys(notesAutoRuby).sort((b, a) => b.length - a.length).map((i) => RE_WORD_CHARS_ONLY.test(i) ? `\\b${i}\\b` : i);
1760
- if (keys.length) {
1761
- const regex = new RegExp(`(${keys.join("|")})`, "g");
1762
- md = md.replace(regex, (match) => {
1763
- if (notesAutoRuby[match]) return `<ruby>${match}<rt>${notesAutoRuby[match]}</rt></ruby>`;
1764
- return match;
1765
- });
1766
- }
1767
- return notesMd.render(md);
1775
+ return notesMd.render(applyNotesAutoRuby(md, notesAutoRuby));
1768
1776
  }
1769
1777
  function withRenderedNote(data) {
1770
1778
  return {
@@ -1797,7 +1805,7 @@ async function setupTransformers(roots) {
1797
1805
  return result;
1798
1806
  }
1799
1807
  //#endregion
1800
- //#region ../../node_modules/.pnpm/@hedgedoc+markdown-it-plugins@2.1.4_patch_hash=49e14003b6caa0b7d164cbe71da573809d375bab_5d0803032f59b14bddf561c39219cd80/node_modules/@hedgedoc/markdown-it-plugins/dist/esm/image-size/specialCharacters.js
1808
+ //#region ../../node_modules/.pnpm/@hedgedoc+markdown-it-plugins@2.1.4_patch_hash=49e14003b6caa0b7d164cbe71da573809d375bab_18adf40ca8d248c8719aefb5f4dca995/node_modules/@hedgedoc/markdown-it-plugins/dist/esm/image-size/specialCharacters.js
1801
1809
  var SpecialCharacters;
1802
1810
  (function(SpecialCharacters) {
1803
1811
  SpecialCharacters[SpecialCharacters["EXCLAMATION_MARK"] = 33] = "EXCLAMATION_MARK";
@@ -1813,7 +1821,7 @@ var SpecialCharacters;
1813
1821
  SpecialCharacters[SpecialCharacters["CLOSING_PARENTHESIS"] = 41] = "CLOSING_PARENTHESIS";
1814
1822
  })(SpecialCharacters || (SpecialCharacters = {}));
1815
1823
  //#endregion
1816
- //#region ../../node_modules/.pnpm/markdown-it@14.3.0/node_modules/markdown-it/lib/token.mjs
1824
+ //#region ../../node_modules/.pnpm/markdown-it@14.3.2/node_modules/markdown-it/lib/token.mjs
1817
1825
  /**
1818
1826
  * class Token
1819
1827
  **/
@@ -1967,7 +1975,7 @@ Token.prototype.attrJoin = function attrJoin(name, value) {
1967
1975
  else this.attrs[idx][1] = this.attrs[idx][1] + " " + value;
1968
1976
  };
1969
1977
  //#endregion
1970
- //#region ../../node_modules/.pnpm/@hedgedoc+markdown-it-plugins@2.1.4_patch_hash=49e14003b6caa0b7d164cbe71da573809d375bab_5d0803032f59b14bddf561c39219cd80/node_modules/@hedgedoc/markdown-it-plugins/dist/esm/task-lists/index.js
1978
+ //#region ../../node_modules/.pnpm/@hedgedoc+markdown-it-plugins@2.1.4_patch_hash=49e14003b6caa0b7d164cbe71da573809d375bab_18adf40ca8d248c8719aefb5f4dca995/node_modules/@hedgedoc/markdown-it-plugins/dist/esm/task-lists/index.js
1971
1979
  const checkboxRegex = /^ *\[([\sx])] /i;
1972
1980
  function taskLists(md, options = {
1973
1981
  enabled: false,
@@ -2208,13 +2216,14 @@ function MarkdownItSnippet(md, { userRoot, userWorkspaceRoot, roots, data: { wat
2208
2216
  }
2209
2217
  const snippet = resolveSnippetImport(lineText, userRoot, slide, allowedRoots);
2210
2218
  if (!snippet) return false;
2211
- const { content, filepath, src } = snippet;
2219
+ const { content, src } = snippet;
2212
2220
  let { lang, meta } = snippet;
2213
2221
  if (meta.includes("{monaco-write}")) {
2214
- monacoWriterWhitelist.add(filepath);
2222
+ const writePath = slash(path.relative(userRoot, src));
2223
+ monacoWriterWhitelist.add(writePath);
2215
2224
  lang = lang.trim();
2216
2225
  meta = meta.replace("{monaco-write}", "").trim() || "{}";
2217
- const safeFilepath = JSON.stringify(filepath).slice(1, -1);
2226
+ const safeFilepath = JSON.stringify(writePath).slice(1, -1);
2218
2227
  const encoded = lz.compressToBase64(content);
2219
2228
  const token = state.push("html_block", "", 0);
2220
2229
  token.content = `<Monaco writable="${safeFilepath}" code-lz="${encoded}" lang="${lang}" v-bind="${meta}" />\n`;
@@ -2659,11 +2668,13 @@ async function applySlidePatch(data, no, patch) {
2659
2668
  const slide = resolveSlide(data, no);
2660
2669
  const source = slide.source;
2661
2670
  if (patch.content != null) source.content = patch.content;
2662
- if (patch.frontmatterRaw != null) if (patch.frontmatterRaw.trim() === "") source.frontmatterDoc = source.frontmatterStyle = void 0;
2663
- else {
2664
- const parsed = YAML.parseDocument(patch.frontmatterRaw);
2665
- if (parsed.errors.length) throw new Error(`Invalid YAML frontmatter: ${parsed.errors.map((e) => e.message).join("; ")}`);
2666
- source.frontmatterDoc = parsed;
2671
+ if (patch.frontmatterRaw != null) {
2672
+ if (patch.frontmatterRaw.trim() === "") source.frontmatterDoc = source.frontmatterStyle = void 0;
2673
+ else {
2674
+ const parsed = YAML.parseDocument(patch.frontmatterRaw);
2675
+ if (parsed.errors.length) throw new Error(`Invalid YAML frontmatter: ${parsed.errors.map((e) => e.message).join("; ")}`);
2676
+ source.frontmatterDoc = parsed;
2677
+ }
2667
2678
  }
2668
2679
  if (patch.note != null) source.note = patch.note;
2669
2680
  if (patch.frontmatter) updateFrontmatterPatch(source, patch.frontmatter);
@@ -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-DzftUF4M.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.1",
4
+ "version": "52.20.0",
5
5
  "description": "Presentation slides for developers",
6
6
  "author": "Anthony Fu <anthonyfu117@hotmail.com>",
7
7
  "license": "MIT",
@@ -50,7 +50,7 @@
50
50
  "@antfu/ni": "^30.5.0",
51
51
  "@antfu/utils": "^9.3.0",
52
52
  "@comark/markdown-it": "^0.3.4",
53
- "@iconify-json/carbon": "^1.2.25",
53
+ "@iconify-json/carbon": "^1.2.27",
54
54
  "@iconify-json/ph": "^1.2.2",
55
55
  "@iconify-json/svg-spinners": "^1.2.4",
56
56
  "@lillallol/outline-pdf": "^4.0.0",
@@ -60,11 +60,14 @@
60
60
  "@shikijs/markdown-it": "^4.4.3",
61
61
  "@shikijs/twoslash": "^4.4.3",
62
62
  "@shikijs/vitepress-twoslash": "^4.4.3",
63
- "@unocss/extractor-mdc": "^66.7.5",
64
- "@unocss/reset": "^66.7.5",
65
- "@vitejs/plugin-vue": "^6.0.8",
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
+ "@vitejs/plugin-vue": "^6.0.9",
66
69
  "@vitejs/plugin-vue-jsx": "^5.1.6",
67
- "ansis": "^4.3.1",
70
+ "ansis": "^4.4.0",
68
71
  "chokidar": "^5.0.0",
69
72
  "cli-progress": "^3.12.0",
70
73
  "connect": "^3.7.0",
@@ -75,21 +78,21 @@
75
78
  "htmlparser2": "^12.0.0",
76
79
  "is-installed-globally": "^1.0.0",
77
80
  "jiti": "^2.7.0",
78
- "katex": "^0.18.4",
81
+ "katex": "^0.18.7",
79
82
  "local-pkg": "^1.2.1",
80
83
  "lz-string": "^1.5.0",
81
- "magic-string": "^1.2.0",
84
+ "magic-string": "^1.4.1",
82
85
  "magic-string-stack": "^2.0.0",
83
- "markdown-exit": "^1.1.0-beta.2",
86
+ "markdown-exit": "^1.3.0",
84
87
  "markdown-it-footnote": "^4.0.0",
85
88
  "markdown-it-github-alerts": "^1.0.1",
86
89
  "mlly": "^1.8.2",
87
90
  "monaco-editor": "^0.56.0",
88
- "obug": "^2.1.4",
89
- "open": "^11.0.1",
91
+ "obug": "^3.0.0",
92
+ "open": "^11.0.4",
90
93
  "pathe": "^2.0.3",
91
94
  "pdf-lib": "^1.17.1",
92
- "picomatch": "^4.0.5",
95
+ "picomatch": "^4.0.7",
93
96
  "plantuml-encoder": "^1.4.0",
94
97
  "postcss-nested": "^8.0.1",
95
98
  "pptxgenjs": "^4.0.1",
@@ -101,32 +104,30 @@
101
104
  "sirv": "^3.0.2",
102
105
  "source-map-js": "^1.2.1",
103
106
  "typescript": "^6.0.3",
104
- "unhead": "^3.3.2",
105
- "unocss": "^66.7.5",
106
- "unplugin-icons": "^23.0.1",
107
+ "unhead": "^3.4.1",
108
+ "unocss": "^66.10.4",
109
+ "unplugin-icons": "^24.0.0",
107
110
  "unplugin-vue-components": "^32.1.0",
108
- "unplugin-vue-markdown": "^32.0.0",
111
+ "unplugin-vue-markdown": "^32.1.1",
109
112
  "untun": "^0.2.2",
110
113
  "uqr": "^0.1.3",
111
114
  "verkit": "^0.4.0",
112
- "vite": "^8.2.1",
115
+ "vite": "^8.3.0",
113
116
  "vite-plugin-inspect": "^12.0.2",
114
117
  "vite-plugin-remote-assets": "^2.1.0",
115
118
  "vite-plugin-static-copy": "^4.1.1",
116
119
  "vite-plugin-vue-server-ref": "^1.0.0",
117
120
  "vitefu": "^1.1.3",
118
- "vue": "^3.5.41",
119
- "yaml": "^2.9.0",
121
+ "vue": "^3.5.42",
122
+ "yaml": "^2.9.1",
120
123
  "yargs": "^18.1.0",
121
- "zod": "^4.4.3",
122
- "@slidev/client": "52.19.1",
123
- "@slidev/parser": "52.19.1",
124
- "@slidev/types": "52.19.1"
124
+ "zod": "^4.6.5"
125
125
  },
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 |
@@ -136,8 +136,11 @@ Props: `controls`, `autoplay`, `autoreset`, `poster`, `timestamp`
136
136
  ```md
137
137
  <Tweet id="1423789844234231808" />
138
138
  <Tweet id="1423789844234231808" :scale="0.8" />
139
+ <Tweet url="https://x.com/antfu7/status/1389604687502995457" />
139
140
  ```
140
141
 
142
+ Use either `id` or a full `x.com` or `twitter.com` post URL. When both are present, `id` takes precedence.
143
+
141
144
  ## Conditional
142
145
 
143
146
  ### LightOrDark
@@ -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