|
1 | | -/* eslint-disable @typescript-eslint/no-var-requires */ |
2 | | -import chalk from 'chalk' |
3 | | -import minimist from 'minimist' |
| 1 | +import path from 'path' |
| 2 | +import fs from 'fs-extra' |
| 3 | +import yargs, { Argv } from 'yargs' |
| 4 | +import { prompt } from 'enquirer' |
| 5 | +import { blue } from 'kolorist' |
| 6 | +import { version } from '../package.json' |
| 7 | +import { build } from './build' |
| 8 | +import { createServer } from './server' |
| 9 | +import * as parser from './parser' |
4 | 10 |
|
5 | | -const argv: any = minimist(process.argv.slice(2)) |
6 | | - |
7 | | -console.log(chalk.cyan`Slidev ` + chalk.yellow`v${require('../package.json').version}`) |
8 | | - |
9 | | -const command = argv._[0] |
10 | | -const entry = argv._[command ? 1 : 0] || 'slides.md' |
11 | | - |
12 | | -if (!command || command === 'dev') { |
13 | | - import('./server') |
14 | | - .then(i => i.createServer(entry, argv)) |
15 | | - .then(server => server.listen()) |
16 | | - .catch((err) => { |
17 | | - console.error(chalk.red('failed to start server. error:\n'), err) |
18 | | - process.exit(1) |
| 11 | +function commonOptions(args: Argv<{}>) { |
| 12 | + return args |
| 13 | + .positional('entry', { |
| 14 | + default: 'slides.md', |
| 15 | + type: 'string', |
| 16 | + describe: 'path to the slides markdown entry', |
19 | 17 | }) |
20 | | -} |
21 | | -else if (command === 'build') { |
22 | | - import('./build') |
23 | | - .then(i => i.build(entry, argv)) |
24 | | - .catch((err) => { |
25 | | - console.error(chalk.red('build error:\n'), err) |
26 | | - process.exit(1) |
| 18 | + .option('template', { |
| 19 | + alias: 't', |
| 20 | + type: 'string', |
| 21 | + describe: 'overide theme', |
27 | 22 | }) |
28 | 23 | } |
29 | | -else if (command === 'export') { |
30 | | - import('./export') |
31 | | - .then(i => i.genratePDF(entry, argv)) |
32 | | - .catch((err) => { |
33 | | - console.error(chalk.red('export error:\n'), err) |
34 | | - process.exit(1) |
| 24 | + |
| 25 | +const cli = yargs |
| 26 | + .scriptName('slidev') |
| 27 | + .usage('$0 [args]') |
| 28 | + .version(version) |
| 29 | + .showHelpOnFail(false) |
| 30 | + .alias('h', 'help') |
| 31 | + .alias('v', 'version') |
| 32 | + |
| 33 | +cli.command( |
| 34 | + '* [entry]', |
| 35 | + 'Start a local server for Slidev', |
| 36 | + args => commonOptions(args) |
| 37 | + .option('port', { |
| 38 | + alias: 'p', |
| 39 | + default: 3030, |
| 40 | + type: 'number', |
| 41 | + describe: 'port', |
35 | 42 | }) |
36 | | -} |
37 | | -else if (command === 'format') { |
38 | | - import('./parser') |
39 | | - .then(async({ load, prettify, save }) => { |
40 | | - const data = await load(entry) |
41 | | - prettify(data) |
42 | | - await save(data) |
| 43 | + .option('open', { |
| 44 | + alias: 'o', |
| 45 | + default: true, |
| 46 | + type: 'boolean', |
| 47 | + describe: 'open in browser', |
43 | 48 | }) |
44 | | - .catch((err) => { |
45 | | - console.error(chalk.red('export error:\n'), err) |
46 | | - process.exit(1) |
| 49 | + .help(), |
| 50 | + async({ entry, port, open }) => { |
| 51 | + if (!fs.existsSync(entry)) { |
| 52 | + const { create } = await prompt<{create: boolean}>({ |
| 53 | + name: 'create', |
| 54 | + type: 'confirm', |
| 55 | + message: `Entry file ${entry} does not exist, do you want to create it?`, |
| 56 | + }) |
| 57 | + if (create) |
| 58 | + await fs.copyFile(path.resolve(__dirname, '../template.md'), entry) |
| 59 | + else |
| 60 | + process.exit(0) |
| 61 | + } |
| 62 | + |
| 63 | + const server = await createServer(entry, { |
| 64 | + server: { |
| 65 | + port, |
| 66 | + open, |
| 67 | + }, |
47 | 68 | }) |
48 | | -} |
49 | | -else { |
50 | | - console.log(chalk.red(`unknown command "${command}".`)) |
51 | | - process.exit(1) |
52 | | -} |
| 69 | + server.listen() |
| 70 | + server.watcher.add(entry) |
| 71 | + }, |
| 72 | +) |
| 73 | + |
| 74 | +cli.command( |
| 75 | + 'build [entry]', |
| 76 | + 'Build hostable SPA', |
| 77 | + args => commonOptions(args) |
| 78 | + .help(), |
| 79 | + async({ entry }) => { |
| 80 | + await build(entry) |
| 81 | + }, |
| 82 | +) |
| 83 | + |
| 84 | +cli.command( |
| 85 | + 'format [entry]', |
| 86 | + 'Format the markdown file', |
| 87 | + args => commonOptions(args) |
| 88 | + .help(), |
| 89 | + async({ entry }) => { |
| 90 | + const data = await parser.load(entry) |
| 91 | + parser.prettify(data) |
| 92 | + await parser.save(data) |
| 93 | + }, |
| 94 | +) |
| 95 | + |
| 96 | +cli.command( |
| 97 | + 'export [entry]', |
| 98 | + 'Export slides to PDF', |
| 99 | + args => commonOptions(args) |
| 100 | + .option('output', { |
| 101 | + type: 'string', |
| 102 | + describe: 'path to the the port output', |
| 103 | + }) |
| 104 | + .help(), |
| 105 | + async({ entry, output }) => { |
| 106 | + output = output || `${path.basename(entry, '.md')}.pdf` |
| 107 | + process.env.NODE_ENV = 'production' |
| 108 | + const { genratePDF } = await import('./export') |
| 109 | + await genratePDF(entry, output, { logLevel: 'error' }) |
| 110 | + console.log(blue(`PDF Exported: ./${output}`)) |
| 111 | + process.exit(0) |
| 112 | + }, |
| 113 | +) |
| 114 | + |
| 115 | +cli.help().parse() |
0 commit comments