@slidev/cli 52.15.1 → 52.15.2

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 "./resolver-XedCEhxI.mjs";
2
- import { t as resolveViteConfigs } from "./shared-ClfjhvJo.mjs";
1
+ import "./resolver-BhqywfGz.mjs";
2
+ import { t as resolveViteConfigs } from "./shared-CmTSrQGO.mjs";
3
3
  import { join, resolve } from "node:path";
4
4
  import { build as build$1 } from "vite";
5
5
  import { existsSync } from "node:fs";
@@ -53,7 +53,7 @@ async function build(options, viteConfig = {}, args) {
53
53
  dev: true
54
54
  }));
55
55
  server.listen(port);
56
- const { exportSlides } = await import("./export-DA_9kPXd.mjs");
56
+ const { exportSlides } = await import("./export-C2XL3OpJ.mjs");
57
57
  const tempDir = resolve(outDir, "temp");
58
58
  await fs$1.mkdir(tempDir, { recursive: true });
59
59
  await exportSlides({
@@ -94,7 +94,7 @@ async function build(options, viteConfig = {}, args) {
94
94
  "true",
95
95
  "auto"
96
96
  ].includes(options.data.config.download)) {
97
- const { exportSlides, getExportOptions } = await import("./export-DA_9kPXd.mjs");
97
+ const { exportSlides, getExportOptions } = await import("./export-C2XL3OpJ.mjs");
98
98
  const port = 12445;
99
99
  const app = connect();
100
100
  const server = http.createServer(app);
package/dist/cli.mjs CHANGED
@@ -1,6 +1,6 @@
1
- import { i as resolveEntry, n as getRoots, r as isInstalledGlobally } from "./resolver-XedCEhxI.mjs";
2
- import { a as parser, c as resolveAddons, d as updateFrontmatterPatch, i as resolveOptions, l as version, o as getThemeMeta, s as resolveTheme, u as loadSetups } from "./shared-ClfjhvJo.mjs";
3
- import { t as createServer } from "./serve-CYSWeFFN.mjs";
1
+ import { i as resolveEntry, n as getRoots, r as isInstalledGlobally } from "./resolver-BhqywfGz.mjs";
2
+ import { a as parser, c as resolveAddons, d as updateFrontmatterPatch, i as resolveOptions, l as version, o as getThemeMeta, s as resolveTheme, u as loadSetups } from "./shared-CmTSrQGO.mjs";
3
+ import { t as createServer } from "./serve-CLoYUI-M.mjs";
4
4
  import path from "node:path";
5
5
  import process from "node:process";
6
6
  import fs from "node:fs/promises";
@@ -294,7 +294,7 @@ cli.command("build [entry..]", "Build hostable SPA", (args) => exportOptions(com
294
294
  describe: "enable the inspect plugin for debugging"
295
295
  }).strict().help(), async (args) => {
296
296
  const { entry, theme, base, download, out, inspect, "without-notes": withoutNotes, "router-mode": routerMode } = args;
297
- const { build } = await import("./build-yk6Ejluk.mjs");
297
+ const { build } = await import("./build-BZYW8gn1.mjs");
298
298
  for (const entryFile of entry) {
299
299
  const options = await resolveOptions({
300
300
  entry: entryFile,
@@ -359,7 +359,7 @@ cli.command("theme [subcommand]", "Theme related operations", (command) => {
359
359
  });
360
360
  cli.command("export [entry..]", "Export slides to PDF", (args) => exportOptions(commonOptions(args)).strict().help(), async (args) => {
361
361
  const { entry, theme } = args;
362
- const { exportSlides, getExportOptions } = await import("./export-DA_9kPXd.mjs");
362
+ const { exportSlides, getExportOptions } = await import("./export-C2XL3OpJ.mjs");
363
363
  const candidatePort = await getPort(12445);
364
364
  let warned = false;
365
365
  for (const entryFile of entry) {
@@ -411,7 +411,7 @@ cli.command("export-notes [entry..]", "Export slide notes to PDF", (args) => arg
411
411
  type: "number",
412
412
  describe: "wait for the specified ms before exporting"
413
413
  }).strict().help(), async ({ entry, output, timeout, wait }) => {
414
- const { exportNotes } = await import("./export-DA_9kPXd.mjs");
414
+ const { exportNotes } = await import("./export-C2XL3OpJ.mjs");
415
415
  const candidatePort = await getPort(12445);
416
416
  for (const entryFile of entry) {
417
417
  const options = await resolveOptions({ entry: entryFile }, "export");
@@ -1,4 +1,4 @@
1
- import { n as getRoots } from "./resolver-XedCEhxI.mjs";
1
+ import { n as getRoots } from "./resolver-BhqywfGz.mjs";
2
2
  import path, { dirname, relative } from "node:path";
3
3
  import process from "node:process";
4
4
  import fs from "node:fs/promises";
@@ -304,9 +304,9 @@ async function exportSlides({ port = 18724, total = 0, range: range$1, format =
304
304
  if (!output.endsWith(".pdf")) output = `${output}.pdf`;
305
305
  return perSlide ? genPagePdfPerSlide() : genPagePdfOnePiece();
306
306
  }
307
- async function genPagePng(writeToDisk) {
307
+ async function genPagePng(writeToDisk, cleanOutput = true) {
308
308
  if (writeToDisk) {
309
- await fs.rm(writeToDisk, {
309
+ if (cleanOutput) await fs.rm(writeToDisk, {
310
310
  force: true,
311
311
  recursive: true
312
312
  });
@@ -315,7 +315,7 @@ async function exportSlides({ port = 18724, total = 0, range: range$1, format =
315
315
  return perSlide ? genPagePngPerSlide(writeToDisk) : genPagePngOnePiece(writeToDisk);
316
316
  }
317
317
  async function genPageMd() {
318
- const pngs = await genPagePng(dirname(output));
318
+ const pngs = await genPagePng(dirname(output), false);
319
319
  const content = slides.filter(({ index }) => pages.includes(index + 1)).map(({ title, index, note }) => pngs.filter(({ slideIndex }) => slideIndex === index).map(({ filename }) => `![${title || index + 1}](./${filename})\n\n`).join("") + (note ? `${note.trim()}\n\n` : "")).join("---\n\n");
320
320
  await fs.writeFile(ensureSuffix(".md", output), content);
321
321
  }
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import "./resolver-XedCEhxI.mjs";
2
- import { a as parser, i as resolveOptions, n as ViteSlidevPlugin, r as createDataUtils } from "./shared-ClfjhvJo.mjs";
3
- import { t as createServer } from "./serve-CYSWeFFN.mjs";
1
+ import "./resolver-BhqywfGz.mjs";
2
+ import { a as parser, i as resolveOptions, n as ViteSlidevPlugin, r as createDataUtils } from "./shared-CmTSrQGO.mjs";
3
+ import { t as createServer } from "./serve-CLoYUI-M.mjs";
4
4
 
5
5
  export { ViteSlidevPlugin, createDataUtils, createServer, parser, resolveOptions };
@@ -14,6 +14,7 @@ import { findClosestPkgJsonPath, findDepPkgJsonPath } from "vitefu";
14
14
 
15
15
  //#region node/resolver.ts
16
16
  const RE_PATH_SEPARATOR = /[/\\]/;
17
+ const RE_SAFE_PKG_NAME = /^(?:@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/;
17
18
  const cliRoot = fileURLToPath(new URL("..", import.meta.url));
18
19
  const isInstalledGlobally = {};
19
20
  /**
@@ -93,6 +94,7 @@ function createResolver(type, officials) {
93
94
  if (name[0] === "/") return [name, name];
94
95
  if (name.startsWith("@/")) return [name, resolve(userRoot, name.slice(2))];
95
96
  if (name[0] === "." || name[0] !== "@" && name.includes("/")) return [name, resolve(dirname(importer), name)];
97
+ if (!RE_SAFE_PKG_NAME.test(name)) throw new Error(`Invalid ${type} name "${name}". Only valid npm package names are allowed.`);
96
98
  {
97
99
  const possiblePkgNames = [name];
98
100
  if (!name.includes("/") && !name.startsWith("@")) possiblePkgNames.unshift(`@slidev/${type}-${name}`, `slidev-${type}-${name}`);
@@ -1,4 +1,4 @@
1
- import { t as resolveViteConfigs } from "./shared-ClfjhvJo.mjs";
1
+ import { t as resolveViteConfigs } from "./shared-CmTSrQGO.mjs";
2
2
  import { join } from "node:path";
3
3
  import process from "node:process";
4
4
  import { createServer } from "vite";
@@ -1,9 +1,9 @@
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-XedCEhxI.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-BhqywfGz.mjs";
2
2
  import { builtinModules } from "node:module";
3
3
  import path, { basename, dirname, join, relative, resolve, win32 } from "node:path";
4
- import { loadConfigFromFile, mergeConfig } from "vite";
4
+ import { loadConfigFromFile, mergeConfig, parseSync } from "vite";
5
5
  import MarkdownExit from "markdown-exit";
6
- import fs, { existsSync } from "node:fs";
6
+ import fs, { existsSync, realpathSync } from "node:fs";
7
7
  import fs$1, { readFile } from "node:fs/promises";
8
8
  import { fileURLToPath, pathToFileURL } from "node:url";
9
9
  import { ensureSuffix, isString, isTruthy, notNullish, objectEntries, objectMap, range, slash, uniq } from "@antfu/utils";
@@ -473,6 +473,158 @@ function createIconsPlugin(options, pluginOptions) {
473
473
  });
474
474
  }
475
475
 
476
+ //#endregion
477
+ //#region node/virtual/deprecated.ts
478
+ /**
479
+ * Kept for backward compatibility, use #slidev/slides instead
480
+ *
481
+ * @deprecated
482
+ */
483
+ const templateLegacyRoutes = {
484
+ id: "/@slidev/routes",
485
+ getContent() {
486
+ return [`export { slides } from '#slidev/slides'`, `console.warn('[slidev] #slidev/routes is deprecated, use #slidev/slides instead')`].join("\n");
487
+ }
488
+ };
489
+ /**
490
+ * Kept for backward compatibility, use #slidev/title-renderer instead
491
+ *
492
+ * @deprecated
493
+ */
494
+ const templateLegacyTitles = {
495
+ id: "/@slidev/titles.md",
496
+ getContent() {
497
+ return `
498
+ <script setup lang="ts">
499
+ import TitleRenderer from '#slidev/title-renderer'
500
+ defineProps<{ no: number | string }>()
501
+ console.warn('/@slidev/titles.md is deprecated, import from #slidev/title-renderer instead')
502
+ <\/script>
503
+
504
+ <TitleRenderer :no="no" />
505
+ `;
506
+ }
507
+ };
508
+
509
+ //#endregion
510
+ //#region node/virtual/titles.ts
511
+ const templateTitleRendererMd = {
512
+ id: "/@slidev/title-renderer.md",
513
+ getContent({ data }) {
514
+ const lines = data.slides.map(({ title }, i) => `<template ${i === 0 ? "v-if" : "v-else-if"}="no === ${i + 1}">\n\n${title}\n\n</template>`);
515
+ lines.push(`<script setup lang="ts">`, `import { useSlideContext } from '@slidev/client/context.ts'`, `import { computed } from 'vue'`, `const props = defineProps<{ no?: number | string }>()`, `const { $page } = useSlideContext()`, `const no = computed(() => +(props.no ?? $page.value))`, `<\/script>`);
516
+ return lines.join("\n");
517
+ }
518
+ };
519
+ const templateTitleRenderer = {
520
+ id: "/@slidev/title-renderer",
521
+ async getContent() {
522
+ return "export { default } from \"/@slidev/title-renderer.md\"";
523
+ }
524
+ };
525
+
526
+ //#endregion
527
+ //#region node/vite/importGuard.ts
528
+ const virtualSlideMarkdownIds = new Set([templateTitleRendererMd.id, templateLegacyTitles.id]);
529
+ function createSlideImportGuardPlugin() {
530
+ let config;
531
+ let allowRoots = [];
532
+ return {
533
+ name: "slidev:slide-import-guard",
534
+ configResolved(resolved) {
535
+ config = resolved;
536
+ allowRoots = config.server.fs.allow.map(normalizeFsPath);
537
+ },
538
+ async transform(code, id$2) {
539
+ if (!isSlideMarkdownId(id$2) || !config?.server.fs.strict) return null;
540
+ const importer = filePathFromId(id$2) ?? id$2;
541
+ await Promise.all(extractImportSources(code, id$2).map(async ({ value, start }) => {
542
+ const resolved = await this.resolve(value, importer, { skipSelf: true });
543
+ if (!resolved || resolved.external) return;
544
+ const filePath = filePathFromId(resolved.id);
545
+ if (!filePath) return;
546
+ const normalized = normalizeFsPath(filePath);
547
+ if (isAllowedFile(normalized, allowRoots)) return;
548
+ if (isBareImport(value) && isDependencyFile(normalized)) return;
549
+ this.error(`[slidev] Import "${value}" from slide Markdown resolves outside of Vite server.fs.allow: ${normalized}`, start);
550
+ }));
551
+ return null;
552
+ }
553
+ };
554
+ }
555
+ function isSlideMarkdownId(id$2) {
556
+ const clean = cleanUrl$1(id$2);
557
+ return regexSlideSourceId.test(clean) || virtualSlideMarkdownIds.has(clean);
558
+ }
559
+ function filePathFromId(id$2) {
560
+ const clean = cleanUrl$1(id$2);
561
+ if (clean.startsWith("file://")) return fileURLToPath(clean);
562
+ if (clean.startsWith("/@fs/")) return clean.slice(4);
563
+ if (clean.startsWith("/@")) return null;
564
+ if (path.isAbsolute(clean)) return clean;
565
+ return null;
566
+ }
567
+ function isAllowedFile(filePath, allowRoots) {
568
+ return allowRoots.some((root) => isFileInRoot(root, filePath));
569
+ }
570
+ function extractImportSources(code, id$2) {
571
+ const result = parseSync(id$2, code);
572
+ const sources = [];
573
+ for (const item of result.module.staticImports) sources.push({
574
+ value: item.moduleRequest.value,
575
+ start: item.moduleRequest.start
576
+ });
577
+ for (const item of result.module.staticExports) for (const entry of item.entries) if (entry.moduleRequest) sources.push({
578
+ value: entry.moduleRequest.value,
579
+ start: entry.moduleRequest.start
580
+ });
581
+ for (const item of result.module.dynamicImports) {
582
+ const source = parseStringLiteral(code.slice(item.moduleRequest.start, item.moduleRequest.end));
583
+ if (source) sources.push({
584
+ value: source,
585
+ start: item.moduleRequest.start
586
+ });
587
+ }
588
+ return sources;
589
+ }
590
+ function cleanUrl$1(id$2) {
591
+ return id$2.replace(/[?#].*$/, "");
592
+ }
593
+ function normalizeFsPath(filePath) {
594
+ const absolute = path.resolve(filePath);
595
+ if (!existsSync(absolute)) return normalizeMissingFsPath(absolute);
596
+ return realpathSync.native(absolute);
597
+ }
598
+ function normalizeMissingFsPath(filePath) {
599
+ const dir = path.dirname(filePath);
600
+ if (dir === filePath) return filePath;
601
+ if (existsSync(dir)) return path.join(realpathSync.native(dir), path.basename(filePath));
602
+ return path.join(normalizeMissingFsPath(dir), path.basename(filePath));
603
+ }
604
+ function isFileInRoot(root, filePath) {
605
+ const relative$1 = path.relative(root, filePath);
606
+ return relative$1 === "" || !!relative$1 && !relative$1.startsWith("..") && !path.isAbsolute(relative$1);
607
+ }
608
+ function isDependencyFile(filePath) {
609
+ return filePath.split(/[\\/]/).includes("node_modules");
610
+ }
611
+ function isBareImport(source) {
612
+ return /^(?![a-z]:)[\w@](?!.*:\/\/)/i.test(source);
613
+ }
614
+ function parseStringLiteral(raw) {
615
+ const trimmed = raw.trim();
616
+ const quote = trimmed[0];
617
+ if (quote !== "\"" && quote !== "'" && quote !== "`") return null;
618
+ if (trimmed.at(-1) !== quote) return null;
619
+ if (quote === "`" && trimmed.includes("${")) return null;
620
+ try {
621
+ if (quote === "\"") return JSON.parse(trimmed);
622
+ return JSON.parse(`"${trimmed.slice(1, -1).replace(/"/g, "\\\"")}"`);
623
+ } catch {
624
+ return trimmed.slice(1, -1);
625
+ }
626
+ }
627
+
476
628
  //#endregion
477
629
  //#region node/vite/inspect.ts
478
630
  async function createInspectPlugin(options, pluginOptions) {
@@ -533,7 +685,7 @@ function createLayoutWrapperPlugin({ data, utils }) {
533
685
 
534
686
  //#endregion
535
687
  //#region package.json
536
- var version = "52.15.1";
688
+ var version = "52.15.2";
537
689
 
538
690
  //#endregion
539
691
  //#region node/integrations/addons.ts
@@ -1123,39 +1275,6 @@ const templateConfigs = {
1123
1275
  }
1124
1276
  };
1125
1277
 
1126
- //#endregion
1127
- //#region node/virtual/deprecated.ts
1128
- /**
1129
- * Kept for backward compatibility, use #slidev/slides instead
1130
- *
1131
- * @deprecated
1132
- */
1133
- const templateLegacyRoutes = {
1134
- id: "/@slidev/routes",
1135
- getContent() {
1136
- return [`export { slides } from '#slidev/slides'`, `console.warn('[slidev] #slidev/routes is deprecated, use #slidev/slides instead')`].join("\n");
1137
- }
1138
- };
1139
- /**
1140
- * Kept for backward compatibility, use #slidev/title-renderer instead
1141
- *
1142
- * @deprecated
1143
- */
1144
- const templateLegacyTitles = {
1145
- id: "/@slidev/titles.md",
1146
- getContent() {
1147
- return `
1148
- <script setup lang="ts">
1149
- import TitleRenderer from '#slidev/title-renderer'
1150
- defineProps<{ no: number | string }>()
1151
- console.warn('/@slidev/titles.md is deprecated, import from #slidev/title-renderer instead')
1152
- <\/script>
1153
-
1154
- <TitleRenderer :no="no" />
1155
- `;
1156
- }
1157
- };
1158
-
1159
1278
  //#endregion
1160
1279
  //#region node/virtual/global-layers.ts
1161
1280
  const id = `/@slidev/global-layers`;
@@ -1345,23 +1464,6 @@ const templateSlides = {
1345
1464
  }
1346
1465
  };
1347
1466
 
1348
- //#endregion
1349
- //#region node/virtual/titles.ts
1350
- const templateTitleRendererMd = {
1351
- id: "/@slidev/title-renderer.md",
1352
- getContent({ data }) {
1353
- const lines = data.slides.map(({ title }, i) => `<template ${i === 0 ? "v-if" : "v-else-if"}="no === ${i + 1}">\n\n${title}\n\n</template>`);
1354
- lines.push(`<script setup lang="ts">`, `import { useSlideContext } from '@slidev/client/context.ts'`, `import { computed } from 'vue'`, `const props = defineProps<{ no?: number | string }>()`, `const { $page } = useSlideContext()`, `const no = computed(() => +(props.no ?? $page.value))`, `<\/script>`);
1355
- return lines.join("\n");
1356
- }
1357
- };
1358
- const templateTitleRenderer = {
1359
- id: "/@slidev/title-renderer",
1360
- async getContent() {
1361
- return "export { default } from \"/@slidev/title-renderer.md\"";
1362
- }
1363
- };
1364
-
1365
1467
  //#endregion
1366
1468
  //#region node/virtual/index.ts
1367
1469
  const templates = [
@@ -2768,6 +2870,7 @@ function ViteSlidevPlugin(options, pluginOptions = {}, serverOptions = {}) {
2768
2870
  createLayoutWrapperPlugin(options),
2769
2871
  createContextInjectionPlugin(),
2770
2872
  createVuePlugin(options, pluginOptions),
2873
+ createSlideImportGuardPlugin(),
2771
2874
  createHmrPatchPlugin(),
2772
2875
  createComponentsPlugin(options, pluginOptions),
2773
2876
  createIconsPlugin(options, pluginOptions),
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@slidev/cli",
3
3
  "type": "module",
4
- "version": "52.15.1",
4
+ "version": "52.15.2",
5
5
  "description": "Presentation slides for developers",
6
6
  "author": "Anthony Fu <anthonyfu117@hotmail.com>",
7
7
  "license": "MIT",
@@ -111,9 +111,9 @@
111
111
  "vue": "^3.5.33",
112
112
  "yaml": "^2.8.3",
113
113
  "yargs": "^18.0.0",
114
- "@slidev/types": "52.15.1",
115
- "@slidev/parser": "52.15.1",
116
- "@slidev/client": "52.15.1"
114
+ "@slidev/parser": "52.15.2",
115
+ "@slidev/types": "52.15.2",
116
+ "@slidev/client": "52.15.2"
117
117
  },
118
118
  "devDependencies": {
119
119
  "@hedgedoc/markdown-it-plugins": "^2.1.4",