UNPKG

@reliverse/rse

Version:

@reliverse/rse is your all-in-one companion for bootstrapping and improving any kind of projects (especially web apps built with frameworks like Next.js) — whether you're kicking off something new or upgrading an existing app. It is also a little AI-power

376 lines (375 loc) 11.4 kB
import { re } from "@reliverse/relico"; import { relinka } from "@reliverse/relinka"; import { selectPrompt, inputPrompt, multiselectPrompt } from "@reliverse/rempts"; import { endTitle, UNKNOWN_VALUE } from "../../constants.js"; import { randomProjectFrameworkTitle, getRandomMessage } from "../../db/messages.js"; import { createWebProject } from "../../init/use-template/cp-mod.js"; import { experimental } from "../../utils/badgeNotifiers.js"; import { recommended } from "../../utils/badgeNotifiers.js"; import { TEMP_BROWSER_TEMPLATE_OPTIONS, TEMP_VSCODE_TEMPLATE_OPTIONS, TEMP_FULLSTACK_WEBSITE_TEMPLATE_OPTIONS, TEMP_SEPARATED_WEBSITE_TEMPLATE_OPTIONS } from "../../utils/projectRepository.js"; export async function configureBrowserExtension() { const browserExtensionConfig = { displayName: await inputPrompt({ title: "What's the display name of your extension?", defaultValue: "My Extension", validate: (value) => { if (!value?.trim()) { return "Display name is required"; } return true; } }), description: await inputPrompt({ title: "Provide a short description of your extension", defaultValue: "A VS Code extension", validate: (value) => { if (!value?.trim()) { return "Description is required"; } return true; } }), features: await multiselectPrompt({ title: "What kind of features will your extension include?", options: [ { label: "Commands", value: "commands", hint: re.dim("Add custom commands to VS Code") }, { label: "WebView", value: "webview", hint: re.dim("Create custom UI panels") }, { label: "Language Support", value: "language", hint: re.dim("Add support for a programming language") }, { label: "Themes", value: "themes", hint: re.dim("Create custom color themes") } ] }), activation: await selectPrompt({ title: "When should your extension activate?", options: [ { label: "On Command", value: "onCommand", hint: re.dim("Activate when a specific command is run") }, { label: "On Language", value: "onLanguage", hint: re.dim("Activate for specific file types") }, { label: "On Startup", value: "startup", hint: re.dim("Activate when VS Code starts") } ] }), publisher: await inputPrompt({ title: "What's your VS Code marketplace publisher ID?", content: "Create one at https://marketplace.visualstudio.com/manage", validate: (value) => { if (!value?.trim()) { return "Publisher ID is required"; } if (!/^[a-z0-9][a-z0-9-]*[a-z0-9]$/i.test(value)) { return "Invalid publisher ID format"; } return true; } }) }; return browserExtensionConfig; } export async function configureVSCodeExtension() { const vscodeExtensionConfig = { displayName: await inputPrompt({ title: "What's the display name of your extension?", defaultValue: "My Extension", validate: (value) => { if (!value?.trim()) { return "Display name is required"; } return true; } }), description: await inputPrompt({ title: "Provide a short description of your extension", defaultValue: "A VS Code extension", validate: (value) => { if (!value?.trim()) { return "Description is required"; } return true; } }), features: await multiselectPrompt({ title: "What kind of features will your extension include?", options: [ { label: "Commands", value: "commands", hint: re.dim("Add custom commands to VS Code") }, { label: "WebView", value: "webview", hint: re.dim("Create custom UI panels") }, { label: "Language Support", value: "language", hint: re.dim("Add support for a programming language") }, { label: "Themes", value: "themes", hint: re.dim("Create custom color themes") } ] }), activation: await selectPrompt({ title: "When should your extension activate?", options: [ { label: "On Command", value: "onCommand", hint: re.dim("Activate when a specific command is run") }, { label: "On Language", value: "onLanguage", hint: re.dim("Activate for specific file types") }, { label: "On Startup", value: "startup", hint: re.dim("Activate when VS Code starts") } ] }), publisher: await inputPrompt({ title: "What's your VS Code marketplace publisher ID?", content: "Create one at https://marketplace.visualstudio.com/manage", validate: (value) => { if (!value?.trim()) { return "Publisher ID is required"; } if (!/^[a-z0-9][a-z0-9-]*[a-z0-9]$/i.test(value)) { return "Invalid publisher ID format"; } return true; } }) }; return vscodeExtensionConfig; } export async function optionCreateVSCodeExtension(projectName, cwd, isDev, memory, config, skipPrompts) { const template = await selectPrompt({ endTitle, title: "Which VS Code extension template would you like to use?", options: [ ...Object.values(TEMP_VSCODE_TEMPLATE_OPTIONS), { separator: true }, { label: re.italic(re.dim("More templates coming soon")), value: UNKNOWN_VALUE, disabled: true } ] }); const vscodeExtensionConfig = await configureVSCodeExtension(); if (vscodeExtensionConfig) { await createWebProject({ projectName, initialProjectName: projectName, selectedRepo: template, message: getRandomMessage("category"), isDev, config, memory, cwd, skipPrompts }); } else { relinka("error", "No VS Code extension config provided"); } } export async function optionCreateBrowserExtension(projectName, cwd, isDev, memory, config, skipPrompts) { const template = await selectPrompt({ endTitle, title: "Which browser extension template would you like to use?", options: [ ...Object.values(TEMP_BROWSER_TEMPLATE_OPTIONS), { separator: true }, { label: re.italic(re.dim("More templates coming soon")), value: UNKNOWN_VALUE, disabled: true } ] }); const browserExtensionConfig = await configureBrowserExtension(); if (browserExtensionConfig) { await createWebProject({ projectName, initialProjectName: projectName, selectedRepo: template, message: getRandomMessage("category"), isDev, config, memory, cwd, skipPrompts }); } else { relinka("error", "No browser extension config provided"); } } export async function optionCreateWebProject(projectName, cwd, isDev, memory, config, isMultiConfig, mrse, skipPrompts) { if (isMultiConfig) { for (const multiConfig of mrse) { let template = multiConfig.projectTemplate; if (template === UNKNOWN_VALUE) { let architecture = multiConfig.projectArchitecture; if (architecture === UNKNOWN_VALUE) { architecture = await selectPrompt({ endTitle, title: "Which architecture would you prefer?", options: [ { label: `${re.bold("Fullstack")} ${recommended}`, value: "fullstack" }, { label: `${re.dim("Separated frontend and backend")} ${experimental}`, value: "separated" } ] }); } template = await selectPrompt({ endTitle, title: "Which template would you like to use?", options: architecture === "fullstack" ? Object.values(TEMP_FULLSTACK_WEBSITE_TEMPLATE_OPTIONS) : Object.values(TEMP_SEPARATED_WEBSITE_TEMPLATE_OPTIONS) }); } const settingUpMsg = `Setting up project #${mrse.indexOf(multiConfig) + 1}...`; await createWebProject({ projectName, initialProjectName: projectName, selectedRepo: template, message: settingUpMsg, isDev, config: multiConfig, memory, cwd, skipPrompts }); } } else { let projectFramework = config.projectFramework; if (projectFramework === UNKNOWN_VALUE) { const result = await selectPrompt({ endTitle, title: randomProjectFrameworkTitle[Math.floor(Math.random() * randomProjectFrameworkTitle.length)] ?? "What project framework best fits your project?", options: [ { label: "Next.js", value: "nextjs", hint: re.dim("recommended for most projects") }, { label: "...", hint: re.dim("coming soon"), value: UNKNOWN_VALUE, disabled: true } ] }); if (result !== "nextjs") { relinka("error", "Invalid projectFramework selected"); return; } projectFramework = result; } let websiteSubcategory = config.projectSubcategory; if (websiteSubcategory === UNKNOWN_VALUE) { const selectedSubcategory = await selectPrompt({ endTitle, title: getRandomMessage("subcategory"), options: [ { label: "E-commerce", value: "e-commerce" }, { label: "...", hint: re.dim("coming soon"), value: UNKNOWN_VALUE, disabled: true } ] }); websiteSubcategory = selectedSubcategory; } let template; if (config.projectTemplate !== UNKNOWN_VALUE) { template = config.projectTemplate; } else { let architecture = config.projectArchitecture; if (architecture === UNKNOWN_VALUE) { architecture = await selectPrompt({ endTitle, title: "Which architecture would you prefer?", options: [ { label: `${re.bold("Fullstack")} ${recommended}`, value: "fullstack" }, { label: `${re.dim("Separated frontend and backend")} ${experimental}`, value: "separated" } ] }); } const result = await selectPrompt({ endTitle, title: "Which template would you like to use?", options: architecture === "fullstack" ? Object.values(TEMP_FULLSTACK_WEBSITE_TEMPLATE_OPTIONS) : Object.values(TEMP_SEPARATED_WEBSITE_TEMPLATE_OPTIONS) }); template = result; } const settingUpMsg = isMultiConfig ? `Setting up project #${mrse.indexOf(config) + 1}...` : getRandomMessage("details"); await createWebProject({ projectName, initialProjectName: projectName, selectedRepo: template, message: settingUpMsg, isDev, config, memory, cwd, skipPrompts }); } }