@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
JavaScript
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
});
}
}