UNPKG

@astro-paper/cli

Version:

A comprehensive CLI tool for AstroPaper blog theme management

135 lines (134 loc) 4.42 kB
import dayjs from 'dayjs'; import { z } from 'zod/v4'; import { Command } from 'commander'; import kebabCase from 'lodash.kebabcase'; import { confirm, isCancel, log, text } from '@clack/prompts'; import { handleError } from '../utils/handle-error.js'; import { getSiteConfig } from '../utils/get-site-config.js'; import { getProjectRoot } from '../utils/get-project-root.js'; const optionsSchema = z.object({ title: z.string().optional(), path: z.string().optional(), yes: z.boolean().optional(), draft: z.boolean().optional(), featured: z.boolean().optional(), }); export const addNewPost = new Command() .name('new') .argument('[title]', 'The title of the post') .description('Add a new post to the blog') .option('-p, --path <path>', 'The path to the post (e.g. "./examples/posts/")') .option('-y, --yes', 'Create post with default values') .option('-d,--draft', 'Create as draft') .option('-f, --featured', 'Mark as featured') .action(async (title, opts) => { try { log.info('Adding new post'); const projectRoot = await getProjectRoot(); if (!projectRoot) { log.error('Not in an AstroPaper project. \nPlease run this command inside your AstroPaper project.'); process.exit(1); } const options = optionsSchema.parse({ title, ...opts, }); const postInfo = await askPostInfo(projectRoot, options); console.log(postInfo); } catch (error) { console.log(''); handleError(error); } }); const DEFAULT_TITLE = 'New Post'; const DEFAULT_DESCRIPTION = 'A brief description of this blog post.'; const DEFAULT_PATH = './'; async function askPostInfo(projectRoot, options) { const { yes, draft, featured } = options; const siteConfig = await getSiteConfig(projectRoot); if (!siteConfig) { log.error('Could not find SITE config in config.ts'); process.exit(1); } if (yes) { const { author } = siteConfig; const title = options.title || DEFAULT_TITLE; return { title, author, description: DEFAULT_DESCRIPTION, pubDatetime: dayjs().toISOString(), fileName: kebabCase(title), tags: ['others'], draft: draft ?? true, featured: featured ?? false, }; } let title = options.title; let path = options.path; if (!title) { title = await text({ message: 'What is the title of the post?', placeholder: DEFAULT_TITLE, }); } if (isCancel(title)) { process.exit(0); } const description = await text({ message: 'What is the description of the post?', placeholder: DEFAULT_DESCRIPTION, }); if (isCancel(description)) { process.exit(0); } if (!path) { path = await text({ message: 'Where should the post be created? (e.g. "./examples/posts")', placeholder: DEFAULT_PATH, }); if (isCancel(path)) { process.exit(0); } } const defaultSlug = kebabCase(title ?? DEFAULT_TITLE); const slug = await text({ message: 'What is the slug of the post? (e.g. "my-first-post")', placeholder: defaultSlug, }); if (isCancel(slug)) { process.exit(0); } const author = await text({ message: 'What is the author of the post?', placeholder: siteConfig.author, }); const isDraft = await confirm({ message: 'Create as draft?', initialValue: draft ?? true, }); const isFeatured = await confirm({ message: 'Mark as featured?', initialValue: featured ?? false, }); const tags = await text({ message: 'Tags (eg: others, astro, React Query):', placeholder: 'others', }); if (isCancel(tags)) { process.exit(0); } return { title: title ?? DEFAULT_TITLE, description: description ?? DEFAULT_DESCRIPTION, path: path ?? DEFAULT_PATH, slug: slug ?? defaultSlug, author: author ?? siteConfig.author, pubDatetime: dayjs().toISOString(), fileName: kebabCase(title ?? DEFAULT_TITLE), tags: tags ? tags.split(',').map(tag => tag.trim()) : ['others'], draft: isDraft, featured: isFeatured, }; }