@slidev/cli 51.6.0 → 51.7.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.
@@ -0,0 +1,433 @@
1
+ import { getRoots } from "./resolver-BShaA6qw.js";
2
+ import fs from "node:fs/promises";
3
+ import path, { dirname, relative } from "node:path";
4
+ import process from "node:process";
5
+ import { blue, cyan, dim, green, yellow } from "ansis";
6
+ import { clearUndefined, ensureSuffix, slash } from "@antfu/utils";
7
+ import { resolve as resolve$1 } from "mlly";
8
+ import { Buffer } from "node:buffer";
9
+ import { outlinePdfFactory } from "@lillallol/outline-pdf";
10
+ import { parseRangeString } from "@slidev/parser/core";
11
+ import { Presets, SingleBar } from "cli-progress";
12
+ import * as pdfLib from "pdf-lib";
13
+ import { PDFDocument } from "pdf-lib";
14
+
15
+ //#region node/commands/export.ts
16
+ function addToTree(tree, info, slideIndexes, level = 1) {
17
+ const titleLevel = info.level;
18
+ if (titleLevel && titleLevel > level && tree.length > 0 && tree[tree.length - 1].titleLevel < titleLevel) addToTree(tree[tree.length - 1].children, info, slideIndexes, level + 1);
19
+ else tree.push({
20
+ no: info.index,
21
+ children: [],
22
+ level,
23
+ titleLevel: titleLevel ?? level,
24
+ path: String(slideIndexes[info.index + 1]),
25
+ hideInToc: Boolean(info.frontmatter?.hideInToc),
26
+ title: info.title
27
+ });
28
+ }
29
+ function makeOutline(tree) {
30
+ return tree.map(({ title, path: path$1, level, children }) => {
31
+ const rootOutline = title ? `${path$1}|${"-".repeat(level - 1)}|${title}` : null;
32
+ const childrenOutline = makeOutline(children);
33
+ return childrenOutline.length > 0 ? `${rootOutline}\n${childrenOutline}` : rootOutline;
34
+ }).filter((outline) => !!outline).join("\n");
35
+ }
36
+ function createSlidevProgress(indeterminate = false) {
37
+ function getSpinner(n = 0) {
38
+ return [
39
+ cyan("●"),
40
+ green("◆"),
41
+ blue("■"),
42
+ yellow("▲")
43
+ ][n % 4];
44
+ }
45
+ let current = 0;
46
+ let spinner = 0;
47
+ let timer;
48
+ const progress = new SingleBar({
49
+ clearOnComplete: true,
50
+ hideCursor: true,
51
+ format: ` {spin} ${yellow("rendering")}${indeterminate ? dim(yellow("...")) : " {bar} {value}/{total}"}`,
52
+ linewrap: false,
53
+ barsize: 30
54
+ }, Presets.shades_grey);
55
+ return {
56
+ bar: progress,
57
+ start(total) {
58
+ progress.start(total, 0, { spin: getSpinner(spinner) });
59
+ timer = setInterval(() => {
60
+ spinner += 1;
61
+ progress.update(current, { spin: getSpinner(spinner) });
62
+ }, 200);
63
+ },
64
+ update(v) {
65
+ current = v;
66
+ progress.update(v, { spin: getSpinner(spinner) });
67
+ },
68
+ stop() {
69
+ clearInterval(timer);
70
+ progress.stop();
71
+ }
72
+ };
73
+ }
74
+ async function exportNotes({ port = 18724, base = "/", output = "notes", timeout = 3e4, wait = 0 }) {
75
+ const { chromium } = await importPlaywright();
76
+ const browser = await chromium.launch();
77
+ const context = await browser.newContext();
78
+ const page = await context.newPage();
79
+ const progress = createSlidevProgress(true);
80
+ progress.start(1);
81
+ if (!output.endsWith(".pdf")) output = `${output}.pdf`;
82
+ await page.goto(`http://localhost:${port}${base}presenter/print`, {
83
+ waitUntil: "networkidle",
84
+ timeout
85
+ });
86
+ await page.waitForLoadState("networkidle");
87
+ await page.emulateMedia({ media: "screen" });
88
+ if (wait) await page.waitForTimeout(wait);
89
+ await page.pdf({
90
+ path: output,
91
+ margin: {
92
+ left: 0,
93
+ top: 0,
94
+ right: 0,
95
+ bottom: 0
96
+ },
97
+ printBackground: true,
98
+ preferCSSPageSize: true
99
+ });
100
+ progress.stop();
101
+ browser.close();
102
+ return output;
103
+ }
104
+ async function exportSlides({ port = 18724, total = 0, range: range$1, format = "pdf", output = "slides", slides, base = "/", timeout = 3e4, wait = 0, dark = false, routerMode = "history", width = 1920, height = 1080, withClicks = false, executablePath = void 0, withToc = false, perSlide = false, scale = 1, waitUntil, omitBackground = false }) {
105
+ const pages = parseRangeString(total, range$1);
106
+ const { chromium } = await importPlaywright();
107
+ const browser = await chromium.launch({ executablePath });
108
+ const context = await browser.newContext({
109
+ viewport: {
110
+ width,
111
+ height: perSlide ? height : height * pages.length
112
+ },
113
+ deviceScaleFactor: scale
114
+ });
115
+ const page = await context.newPage();
116
+ const progress = createSlidevProgress(!perSlide);
117
+ progress.start(pages.length);
118
+ if (format === "pdf") await genPagePdf();
119
+ else if (format === "png") await genPagePng(output);
120
+ else if (format === "md") await genPageMd();
121
+ else if (format === "pptx") {
122
+ const buffers = await genPagePng(false);
123
+ await genPagePptx(buffers);
124
+ } else throw new Error(`[slidev] Unsupported exporting format "${format}"`);
125
+ progress.stop();
126
+ browser.close();
127
+ const relativeOutput = slash(relative(".", output));
128
+ return relativeOutput.startsWith(".") ? relativeOutput : `./${relativeOutput}`;
129
+ async function go(no, clicks) {
130
+ const query = new URLSearchParams();
131
+ if (withClicks) query.set("print", "clicks");
132
+ else query.set("print", "true");
133
+ if (range$1) query.set("range", range$1);
134
+ if (clicks) query.set("clicks", clicks);
135
+ const url = routerMode === "hash" ? `http://localhost:${port}${base}?${query}#${no}` : `http://localhost:${port}${base}${no}?${query}`;
136
+ await page.goto(url, {
137
+ waitUntil,
138
+ timeout
139
+ });
140
+ if (waitUntil) await page.waitForLoadState(waitUntil);
141
+ await page.emulateMedia({
142
+ colorScheme: dark ? "dark" : "light",
143
+ media: "screen"
144
+ });
145
+ const slide = no === "print" ? page.locator("body") : page.locator(`[data-slidev-no="${no}"]`);
146
+ await slide.waitFor();
147
+ {
148
+ const elements = slide.locator(".slidev-slide-loading");
149
+ const count = await elements.count();
150
+ for (let index = 0; index < count; index++) await elements.nth(index).waitFor({ state: "detached" });
151
+ }
152
+ {
153
+ const elements = slide.locator("[data-waitfor]");
154
+ const count = await elements.count();
155
+ for (let index = 0; index < count; index++) {
156
+ const element = elements.nth(index);
157
+ const attribute = await element.getAttribute("data-waitfor");
158
+ if (attribute) await element.locator(attribute).waitFor({ state: "visible" }).catch((e) => {
159
+ console.error(e);
160
+ process.exitCode = 1;
161
+ });
162
+ }
163
+ }
164
+ {
165
+ const frames = page.frames();
166
+ await Promise.all(frames.map((frame) => frame.waitForLoadState()));
167
+ }
168
+ {
169
+ const container = slide.locator("#mermaid-rendering-container");
170
+ const count = await container.count();
171
+ if (count > 0) {
172
+ while (true) {
173
+ const element = container.locator("div").first();
174
+ if (await element.count() === 0) break;
175
+ await element.waitFor({ state: "detached" });
176
+ }
177
+ await container.evaluate((node) => node.style.display = "none");
178
+ }
179
+ }
180
+ {
181
+ const elements = slide.locator(".monaco-aria-container");
182
+ const count = await elements.count();
183
+ for (let index = 0; index < count; index++) {
184
+ const element = elements.nth(index);
185
+ await element.evaluate((node) => node.style.display = "none");
186
+ }
187
+ }
188
+ if (wait) await page.waitForTimeout(wait);
189
+ }
190
+ async function getSlidesIndex() {
191
+ const clicksBySlide = {};
192
+ const slides$1 = page.locator(".print-slide-container");
193
+ const count = await slides$1.count();
194
+ for (let i = 0; i < count; i++) {
195
+ const id = await slides$1.nth(i).getAttribute("id") || "";
196
+ const path$1 = Number(id.split("-")[0]);
197
+ clicksBySlide[path$1] = (clicksBySlide[path$1] || 0) + 1;
198
+ }
199
+ const slideIndexes = Object.fromEntries(Object.entries(clicksBySlide).reduce((acc, [path$1, clicks], i) => {
200
+ acc.push([path$1, clicks + (acc[i - 1]?.[1] ?? 0)]);
201
+ return acc;
202
+ }, []));
203
+ return slideIndexes;
204
+ }
205
+ function getClicksFromUrl(url) {
206
+ return url.match(/clicks=([1-9]\d*)/)?.[1];
207
+ }
208
+ async function genPageWithClicks(fn, no, clicks) {
209
+ await fn(no, clicks);
210
+ if (withClicks) {
211
+ await page.keyboard.press("ArrowRight", { delay: 100 });
212
+ const _clicks = getClicksFromUrl(page.url());
213
+ if (_clicks && clicks !== _clicks) await genPageWithClicks(fn, no, _clicks);
214
+ }
215
+ }
216
+ async function genPagePdfPerSlide() {
217
+ const buffers = [];
218
+ const genPdfBuffer = async (i, clicks) => {
219
+ await go(i, clicks);
220
+ const pdf = await page.pdf({
221
+ width,
222
+ height,
223
+ margin: {
224
+ left: 0,
225
+ top: 0,
226
+ right: 0,
227
+ bottom: 0
228
+ },
229
+ pageRanges: "1",
230
+ printBackground: true,
231
+ preferCSSPageSize: true
232
+ });
233
+ buffers.push(pdf);
234
+ };
235
+ let idx = 0;
236
+ for (const i of pages) {
237
+ await genPageWithClicks(genPdfBuffer, i);
238
+ progress.update(++idx);
239
+ }
240
+ let mergedPdf = await PDFDocument.create({});
241
+ for (const pdfBytes of buffers) {
242
+ const pdf = await PDFDocument.load(pdfBytes);
243
+ const copiedPages = await mergedPdf.copyPages(pdf, pdf.getPageIndices());
244
+ copiedPages.forEach((page$1) => {
245
+ mergedPdf.addPage(page$1);
246
+ });
247
+ }
248
+ addPdfMetadata(mergedPdf);
249
+ if (withToc) mergedPdf = await addTocToPdf(mergedPdf);
250
+ const buffer = await mergedPdf.save();
251
+ await fs.writeFile(output, buffer);
252
+ }
253
+ async function genPagePdfOnePiece() {
254
+ await go("print");
255
+ await page.pdf({
256
+ path: output,
257
+ width,
258
+ height,
259
+ margin: {
260
+ left: 0,
261
+ top: 0,
262
+ right: 0,
263
+ bottom: 0
264
+ },
265
+ printBackground: true,
266
+ preferCSSPageSize: true
267
+ });
268
+ let pdfData = await fs.readFile(output);
269
+ let pdf = await PDFDocument.load(pdfData);
270
+ addPdfMetadata(pdf);
271
+ if (withToc) pdf = await addTocToPdf(pdf);
272
+ pdfData = Buffer.from(await pdf.save());
273
+ await fs.writeFile(output, pdfData);
274
+ }
275
+ async function genPagePngOnePiece(writeToDisk) {
276
+ const result = [];
277
+ await go("print");
278
+ const slideContainers = page.locator(".print-slide-container");
279
+ const count = await slideContainers.count();
280
+ for (let i = 0; i < count; i++) {
281
+ progress.update(i + 1);
282
+ const id = await slideContainers.nth(i).getAttribute("id") || "";
283
+ const slideNo = +id.split("-")[0];
284
+ const buffer = await slideContainers.nth(i).screenshot({ omitBackground });
285
+ const filename = `${withClicks ? id : slideNo}.png`;
286
+ result.push({
287
+ slideIndex: slideNo - 1,
288
+ buffer,
289
+ filename
290
+ });
291
+ if (writeToDisk) await fs.writeFile(path.join(writeToDisk, filename), buffer);
292
+ }
293
+ return result;
294
+ }
295
+ async function genPagePngPerSlide(writeToDisk) {
296
+ const result = [];
297
+ const genScreenshot = async (no, clicks) => {
298
+ await go(no, clicks);
299
+ const buffer = await page.screenshot({ omitBackground });
300
+ const filename = `${no.toString().padStart(2, "0")}${clicks ? `-${clicks}` : ""}.png`;
301
+ result.push({
302
+ slideIndex: no - 1,
303
+ buffer,
304
+ filename
305
+ });
306
+ if (writeToDisk) await fs.writeFile(path.join(writeToDisk, filename), buffer);
307
+ };
308
+ for (const no of pages) await genPageWithClicks(genScreenshot, no);
309
+ return result;
310
+ }
311
+ function genPagePdf() {
312
+ if (!output.endsWith(".pdf")) output = `${output}.pdf`;
313
+ return perSlide ? genPagePdfPerSlide() : genPagePdfOnePiece();
314
+ }
315
+ async function genPagePng(writeToDisk) {
316
+ if (writeToDisk) {
317
+ await fs.rm(writeToDisk, {
318
+ force: true,
319
+ recursive: true
320
+ });
321
+ await fs.mkdir(writeToDisk, { recursive: true });
322
+ }
323
+ return perSlide ? genPagePngPerSlide(writeToDisk) : genPagePngOnePiece(writeToDisk);
324
+ }
325
+ async function genPageMd() {
326
+ const pngs = await genPagePng(dirname(output));
327
+ const content = slides.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");
328
+ await fs.writeFile(ensureSuffix(".md", output), content);
329
+ }
330
+ async function genPagePptx(pngs) {
331
+ const { default: PptxGenJS } = await import("pptxgenjs");
332
+ const pptx = new PptxGenJS();
333
+ const layoutName = `${width}x${height}`;
334
+ pptx.defineLayout({
335
+ name: layoutName,
336
+ width: width / 96,
337
+ height: height / 96
338
+ });
339
+ pptx.layout = layoutName;
340
+ const titleSlide = slides[0];
341
+ pptx.author = titleSlide?.frontmatter?.author;
342
+ pptx.company = "Created using Slidev";
343
+ if (titleSlide?.title) pptx.title = titleSlide?.title;
344
+ if (titleSlide?.frontmatter?.info) pptx.subject = titleSlide?.frontmatter?.info;
345
+ pngs.forEach(({ slideIndex, buffer: buffer$1 }) => {
346
+ const slide = pptx.addSlide();
347
+ slide.background = { data: `data:image/png;base64,${buffer$1.toString("base64")}` };
348
+ const note = slides[slideIndex].note;
349
+ if (note) slide.addNotes(note);
350
+ });
351
+ const buffer = await pptx.write({ outputType: "nodebuffer" });
352
+ if (!output.endsWith(".pptx")) output = `${output}.pptx`;
353
+ await fs.writeFile(output, buffer);
354
+ }
355
+ function addPdfMetadata(pdf) {
356
+ const titleSlide = slides[0];
357
+ if (titleSlide?.title) pdf.setTitle(titleSlide.title);
358
+ if (titleSlide?.frontmatter?.info) pdf.setSubject(titleSlide.frontmatter.info);
359
+ if (titleSlide?.frontmatter?.author) pdf.setAuthor(titleSlide.frontmatter.author);
360
+ if (titleSlide?.frontmatter?.keywords) if (Array.isArray(titleSlide?.frontmatter?.keywords)) pdf.setKeywords(titleSlide?.frontmatter?.keywords);
361
+ else pdf.setKeywords(titleSlide?.frontmatter?.keywords.split(","));
362
+ }
363
+ async function addTocToPdf(pdf) {
364
+ const outlinePdf = outlinePdfFactory(pdfLib);
365
+ const slideIndexes = await getSlidesIndex();
366
+ const tocTree = slides.filter((slide) => slide.title).reduce((acc, slide) => {
367
+ addToTree(acc, slide, slideIndexes);
368
+ return acc;
369
+ }, []);
370
+ const outline = makeOutline(tocTree);
371
+ return await outlinePdf({
372
+ outline,
373
+ pdf
374
+ });
375
+ }
376
+ }
377
+ function getExportOptions(args, options, outFilename) {
378
+ const config = {
379
+ ...options.data.config.export,
380
+ ...args,
381
+ ...clearUndefined({
382
+ waitUntil: args["wait-until"],
383
+ withClicks: args["with-clicks"],
384
+ executablePath: args["executable-path"],
385
+ withToc: args["with-toc"],
386
+ perSlide: args["per-slide"],
387
+ omitBackground: args["omit-background"]
388
+ })
389
+ };
390
+ const { entry, output, format, timeout, wait, waitUntil, range: range$1, dark, withClicks, executablePath, withToc, perSlide, scale, omitBackground } = config;
391
+ outFilename = output || options.data.config.exportFilename || outFilename || `${path.basename(entry, ".md")}-export`;
392
+ return {
393
+ output: outFilename,
394
+ slides: options.data.slides,
395
+ total: options.data.slides.length,
396
+ range: range$1,
397
+ format: format || "pdf",
398
+ timeout: timeout ?? 3e4,
399
+ wait: wait ?? 0,
400
+ waitUntil: waitUntil === "none" ? void 0 : waitUntil ?? "networkidle",
401
+ dark: dark || options.data.config.colorSchema === "dark",
402
+ routerMode: options.data.config.routerMode,
403
+ width: options.data.config.canvasWidth,
404
+ height: Math.round(options.data.config.canvasWidth / options.data.config.aspectRatio),
405
+ withClicks: withClicks ?? format === "pptx",
406
+ executablePath,
407
+ withToc: withToc || false,
408
+ perSlide: perSlide || false,
409
+ scale: scale || 2,
410
+ omitBackground: omitBackground ?? false
411
+ };
412
+ }
413
+ async function importPlaywright() {
414
+ const { userRoot, userWorkspaceRoot } = await getRoots();
415
+ try {
416
+ return await import(await resolve$1("playwright-chromium", { url: userRoot }));
417
+ } catch {}
418
+ if (userWorkspaceRoot !== userRoot) try {
419
+ return await import(await resolve$1("playwright-chromium", { url: userWorkspaceRoot }));
420
+ } catch {}
421
+ const { resolveGlobal } = await import("resolve-global");
422
+ try {
423
+ const imported = await import(resolveGlobal("playwright-chromium"));
424
+ return imported.default ?? imported;
425
+ } catch {}
426
+ try {
427
+ return await import("playwright-chromium");
428
+ } catch {}
429
+ throw new Error("The exporting for Slidev is powered by Playwright, please install it via `npm i -D playwright-chromium`");
430
+ }
431
+
432
+ //#endregion
433
+ export { exportNotes, exportSlides, getExportOptions };
package/dist/index.d.ts CHANGED
@@ -1,14 +1,19 @@
1
- import * as vite from 'vite';
2
- import { InlineConfig, PluginOption } from 'vite';
3
- import { ResolvedSlidevOptions, SlidevServerOptions, SlidevEntryOptions, ResolvedSlidevUtils, SlidevPluginOptions } from '@slidev/types';
4
- import * as fs from '@slidev/parser/fs';
5
- export { fs as parser };
1
+ import * as vite0 from "vite";
2
+ import { InlineConfig, PluginOption } from "vite";
3
+ import * as parser from "@slidev/parser/fs";
4
+ import { ResolvedSlidevOptions, ResolvedSlidevUtils, SlidevEntryOptions, SlidevPluginOptions, SlidevServerOptions } from "@slidev/types";
6
5
 
7
- declare function createServer(options: ResolvedSlidevOptions, viteConfig?: InlineConfig, serverOptions?: SlidevServerOptions): Promise<vite.ViteDevServer>;
6
+ //#region node/commands/serve.d.ts
7
+ declare function createServer(options: ResolvedSlidevOptions, viteConfig?: InlineConfig, serverOptions?: SlidevServerOptions): Promise<vite0.ViteDevServer>;
8
8
 
9
+ //#endregion
10
+ //#region node/options.d.ts
9
11
  declare function resolveOptions(entryOptions: SlidevEntryOptions, mode: ResolvedSlidevOptions['mode']): Promise<ResolvedSlidevOptions>;
10
12
  declare function createDataUtils(resolved: Omit<ResolvedSlidevOptions, 'utils'>): Promise<ResolvedSlidevUtils>;
11
13
 
14
+ //#endregion
15
+ //#region node/vite/index.d.ts
12
16
  declare function ViteSlidevPlugin(options: ResolvedSlidevOptions, pluginOptions?: SlidevPluginOptions, serverOptions?: SlidevServerOptions): Promise<PluginOption[]>;
13
17
 
14
- export { ViteSlidevPlugin, createDataUtils, createServer, resolveOptions };
18
+ //#endregion
19
+ export { ViteSlidevPlugin, createDataUtils, createServer, parser, resolveOptions };
package/dist/index.js CHANGED
@@ -1,17 +1,5 @@
1
- import {
2
- createServer
3
- } from "./chunk-BCA62OS7.js";
4
- import {
5
- ViteSlidevPlugin,
6
- createDataUtils,
7
- parser,
8
- resolveOptions
9
- } from "./chunk-Y2DHOFI5.js";
10
- import "./chunk-TJFRPB4N.js";
11
- export {
12
- ViteSlidevPlugin,
13
- createDataUtils,
14
- createServer,
15
- parser,
16
- resolveOptions
17
- };
1
+ import { ViteSlidevPlugin, createDataUtils, parser, resolveOptions } from "./shared-bpaLqEdy.js";
2
+ import "./resolver-BShaA6qw.js";
3
+ import { createServer } from "./serve-Cg-fgcfD.js";
4
+
5
+ export { ViteSlidevPlugin, createDataUtils, createServer, parser, resolveOptions };
@@ -0,0 +1,155 @@
1
+ import { dirname, join, relative, resolve } from "node:path";
2
+ import process from "node:process";
3
+ import { underline, yellow } from "ansis";
4
+ import * as fs$1 from "node:fs";
5
+ import { fileURLToPath } from "node:url";
6
+ import { ensurePrefix, slash } from "@antfu/utils";
7
+ import { resolvePath } from "mlly";
8
+ import { parseNi, run } from "@antfu/ni";
9
+ import globalDirs from "global-directory";
10
+ import prompts from "prompts";
11
+ import { resolveGlobal } from "resolve-global";
12
+ import { findClosestPkgJsonPath, findDepPkgJsonPath } from "vitefu";
13
+
14
+ //#region node/resolver.ts
15
+ const cliRoot = fileURLToPath(new URL("..", import.meta.url));
16
+ const isInstalledGlobally = {};
17
+ /**
18
+ * Resolve path for import url on Vite client side
19
+ */
20
+ async function resolveImportUrl(id) {
21
+ return toAtFS(await resolveImportPath(id, true));
22
+ }
23
+ function toAtFS(path$1) {
24
+ return `/@fs${ensurePrefix("/", slash(path$1))}`;
25
+ }
26
+ async function resolveImportPath(importName, ensure = false) {
27
+ try {
28
+ return await resolvePath(importName, { url: import.meta.url });
29
+ } catch {}
30
+ if (isInstalledGlobally.value) try {
31
+ return resolveGlobal(importName);
32
+ } catch {}
33
+ if (ensure) throw new Error(`Failed to resolve package "${importName}"`);
34
+ }
35
+ async function findPkgRoot(dep, parent, ensure = false) {
36
+ const pkgJsonPath = await findDepPkgJsonPath(dep, parent);
37
+ const path$1 = pkgJsonPath ? dirname(pkgJsonPath) : isInstalledGlobally.value ? await findGlobalPkgRoot(dep, false) : void 0;
38
+ if (ensure && !path$1) throw new Error(`Failed to resolve package "${dep}"`);
39
+ return path$1;
40
+ }
41
+ async function findGlobalPkgRoot(name, ensure = false) {
42
+ const yarnPath = join(globalDirs.yarn.packages, name);
43
+ if (fs$1.existsSync(`${yarnPath}/package.json`)) return yarnPath;
44
+ const npmPath = join(globalDirs.npm.packages, name);
45
+ if (fs$1.existsSync(`${npmPath}/package.json`)) return npmPath;
46
+ if (ensure) throw new Error(`Failed to resolve global package "${name}"`);
47
+ }
48
+ async function resolveEntry(entryRaw) {
49
+ if (!fs$1.existsSync(entryRaw) && !entryRaw.endsWith(".md") && !/[/\\]/.test(entryRaw)) entryRaw += ".md";
50
+ const entry = resolve(entryRaw);
51
+ if (!fs$1.existsSync(entry)) {
52
+ const { create } = await prompts({
53
+ name: "create",
54
+ type: "confirm",
55
+ initial: "Y",
56
+ message: `Entry file ${yellow(`"${entry}"`)} does not exist, do you want to create it?`
57
+ });
58
+ if (create) fs$1.copyFileSync(resolve(cliRoot, "template.md"), entry);
59
+ else process.exit(0);
60
+ }
61
+ return slash(entry);
62
+ }
63
+ /**
64
+ * Create a resolver for theme or addon
65
+ */
66
+ function createResolver(type, officials) {
67
+ async function promptForInstallation(pkgName) {
68
+ const { confirm } = await prompts({
69
+ name: "confirm",
70
+ initial: "Y",
71
+ type: "confirm",
72
+ message: `The ${type} "${pkgName}" was not found ${underline(isInstalledGlobally.value ? "globally" : "in your project")}, do you want to install it now?`
73
+ });
74
+ if (!confirm) process.exit(1);
75
+ if (isInstalledGlobally.value) await run(parseNi, ["-g", pkgName]);
76
+ else await run(parseNi, [pkgName]);
77
+ }
78
+ return async function(name, importer) {
79
+ const { userRoot } = await getRoots();
80
+ if (name === "none") return ["", null];
81
+ if (name[0] === "/") return [name, name];
82
+ if (name.startsWith("@/")) return [name, resolve(userRoot, name.slice(2))];
83
+ if (name[0] === "." || name[0] !== "@" && name.includes("/")) return [name, resolve(dirname(importer), name)];
84
+ if (name.startsWith(`@slidev/${type}-`) || name.startsWith(`slidev-${type}-`)) {
85
+ const pkgRoot = await findPkgRoot(name, importer);
86
+ if (!pkgRoot) await promptForInstallation(name);
87
+ return [name, await findPkgRoot(name, importer, true)];
88
+ }
89
+ {
90
+ const possiblePkgNames = [
91
+ `@slidev/${type}-${name}`,
92
+ `slidev-${type}-${name}`,
93
+ name
94
+ ];
95
+ for (const pkgName$1 of possiblePkgNames) {
96
+ const pkgRoot = await findPkgRoot(pkgName$1, importer);
97
+ if (pkgRoot) return [pkgName$1, pkgRoot];
98
+ }
99
+ }
100
+ const pkgName = officials[name] ?? (name[0] === "@" ? name : `slidev-${type}-${name}`);
101
+ await promptForInstallation(pkgName);
102
+ return [pkgName, await findPkgRoot(pkgName, importer, true)];
103
+ };
104
+ }
105
+ function getUserPkgJson(userRoot) {
106
+ const path$1 = resolve(userRoot, "package.json");
107
+ if (fs$1.existsSync(path$1)) return JSON.parse(fs$1.readFileSync(path$1, "utf-8"));
108
+ return {};
109
+ }
110
+ function hasWorkspacePackageJSON(root) {
111
+ const path$1 = join(root, "package.json");
112
+ try {
113
+ fs$1.accessSync(path$1, fs$1.constants.R_OK);
114
+ } catch {
115
+ return false;
116
+ }
117
+ const content = JSON.parse(fs$1.readFileSync(path$1, "utf-8")) || {};
118
+ return !!content.workspaces;
119
+ }
120
+ function hasRootFile(root) {
121
+ const ROOT_FILES = ["pnpm-workspace.yaml"];
122
+ return ROOT_FILES.some((file) => fs$1.existsSync(join(root, file)));
123
+ }
124
+ /**
125
+ * Search up for the nearest workspace root
126
+ */
127
+ function searchForWorkspaceRoot(current, root = current) {
128
+ if (hasRootFile(current)) return current;
129
+ if (hasWorkspacePackageJSON(current)) return current;
130
+ const dir = dirname(current);
131
+ if (!dir || dir === current) return root;
132
+ return searchForWorkspaceRoot(dir, root);
133
+ }
134
+ let rootsInfo = null;
135
+ async function getRoots(entry) {
136
+ if (rootsInfo) return rootsInfo;
137
+ if (!entry) throw new Error("[slidev] Cannot find roots without entry");
138
+ const userRoot = dirname(entry);
139
+ isInstalledGlobally.value = slash(relative(userRoot, process.argv[1])).includes("/.pnpm/") || (await import("is-installed-globally")).default;
140
+ const clientRoot = await findPkgRoot("@slidev/client", cliRoot, true);
141
+ const closestPkgRoot = dirname(await findClosestPkgJsonPath(userRoot) || userRoot);
142
+ const userPkgJson = getUserPkgJson(closestPkgRoot);
143
+ const userWorkspaceRoot = searchForWorkspaceRoot(closestPkgRoot);
144
+ rootsInfo = {
145
+ cliRoot,
146
+ clientRoot,
147
+ userRoot,
148
+ userPkgJson,
149
+ userWorkspaceRoot
150
+ };
151
+ return rootsInfo;
152
+ }
153
+
154
+ //#endregion
155
+ export { createResolver, getRoots, isInstalledGlobally, resolveEntry, resolveImportPath, resolveImportUrl, toAtFS };
@@ -0,0 +1,14 @@
1
+ import { resolveViteConfigs } from "./shared-bpaLqEdy.js";
2
+ import { join } from "node:path";
3
+ import process from "node:process";
4
+ import { createServer } from "vite";
5
+
6
+ //#region node/commands/serve.ts
7
+ async function createServer$1(options, viteConfig = {}, serverOptions) {
8
+ process.env.EDITOR = process.env.EDITOR || "code";
9
+ const inlineConfig = await resolveViteConfigs(options, { optimizeDeps: { entries: [join(options.clientRoot, "main.ts")] } }, viteConfig, "serve", serverOptions);
10
+ return await createServer(inlineConfig);
11
+ }
12
+
13
+ //#endregion
14
+ export { createServer$1 as createServer };