diff --git a/src/utils/frameworks/angular/angular.mjs b/src/utils/frameworks/angular/angular.mjs index 583ae07..fc4f780 100644 --- a/src/utils/frameworks/angular/angular.mjs +++ b/src/utils/frameworks/angular/angular.mjs @@ -1,10 +1,10 @@ const framework = "angular"; -export default function (componentName, folder, anotherComponent) { - return { - componentName: componentName, - framework: framework.toLowerCase(), - template: "component.component.ts", - folder: folder, - anotherComponent: anotherComponent, - }; + +export default function (componentName, folder) { + return { + componentName, + framework: framework.toLowerCase(), + template: "component.component.ts", + folder: folder, + }; } diff --git a/src/utils/frameworks/angular/angular.mts b/src/utils/frameworks/angular/angular.mts index 677743f..0dc1de3 100644 --- a/src/utils/frameworks/angular/angular.mts +++ b/src/utils/frameworks/angular/angular.mts @@ -1,13 +1,10 @@ -import { Answers } from "../../wizard.mjs"; - const framework = "angular"; -export default function (componentName: string, folder: string, anotherComponent: boolean): Answers { +export default function (componentName: string, folder: string) { return { - componentName: componentName, + componentName, framework: framework.toLowerCase(), template: "component.component.ts", folder: folder, - anotherComponent: anotherComponent, }; } diff --git a/src/utils/frameworks/astro/astro.mjs b/src/utils/frameworks/astro/astro.mjs index 74688ea..62bfdcf 100644 --- a/src/utils/frameworks/astro/astro.mjs +++ b/src/utils/frameworks/astro/astro.mjs @@ -1,10 +1,9 @@ const framework = "astro"; -export default function (componentName, folder, anotherComponent) { - return { - componentName: componentName, - framework: framework.toLowerCase(), - template: "component.astro", - folder: folder, - anotherComponent: anotherComponent, - }; +export default function (componentName, folder) { + return { + componentName: componentName, + framework: framework.toLowerCase(), + template: "component.astro", + folder: folder, + }; } diff --git a/src/utils/frameworks/astro/astro.mts b/src/utils/frameworks/astro/astro.mts index 5312542..0afbb59 100644 --- a/src/utils/frameworks/astro/astro.mts +++ b/src/utils/frameworks/astro/astro.mts @@ -1,11 +1,10 @@ const framework = "astro"; -export default function (componentName: string, folder: string, anotherComponent: boolean) { +export default function (componentName: string, folder: string) { return { componentName: componentName, framework: framework.toLowerCase(), template: "component.astro", folder: folder, - anotherComponent: anotherComponent, }; } diff --git a/src/utils/frameworks/qwik/qwik.mjs b/src/utils/frameworks/qwik/qwik.mjs index 89c4920..ef49cfd 100644 --- a/src/utils/frameworks/qwik/qwik.mjs +++ b/src/utils/frameworks/qwik/qwik.mjs @@ -1,28 +1,28 @@ import inquirer from "inquirer"; const framework = "qwik"; -export default function (componentName, folder, anotherComponent) { - return inquirer - .prompt([ - { - type: "list", - name: "type", - message: "Choose wich type of component to create", - choices: ["Hello World", "useStore", "useStyles"], - }, +export default function (componentName, folder) { + return inquirer + .prompt([ + { + type: "list", + name: "type", + message: "Choose wich type of component to create", + choices: ["Hello World", "useStore", "useStyles"], + }, ]) - .then(answers => { - return { - componentName: componentName, - framework: framework.toLowerCase(), - template: answers.type === "Hello World" - ? "hello-world-component.tsx" - : answers.type === "useStore" - ? "usestore-component.tsx" - : answers.type === "useStyles" - ? "usestyles-component.tsx" - : "hello-world-component.tsx", - folder: folder, - anotherComponent: anotherComponent, - }; + .then((answers) => { + return { + componentName: componentName, + framework: framework.toLowerCase(), + template: + answers.type === "Hello World" + ? "hello-world-component.tsx" + : answers.type === "useStore" + ? "usestore-component.tsx" + : answers.type === "useStyles" + ? "usestyles-component.tsx" + : "hello-world-component.tsx", + folder: folder, + }; }); } diff --git a/src/utils/frameworks/qwik/qwik.mts b/src/utils/frameworks/qwik/qwik.mts index 6fbbab5..a026945 100644 --- a/src/utils/frameworks/qwik/qwik.mts +++ b/src/utils/frameworks/qwik/qwik.mts @@ -1,7 +1,7 @@ import inquirer from "inquirer"; const framework = "qwik"; -export default function (componentName: string, folder: string, anotherComponent: boolean) { +export default function (componentName: string, folder: string) { return inquirer .prompt([ { @@ -11,7 +11,7 @@ export default function (componentName: string, folder: string, anotherComponent choices: ["Hello World", "useStore", "useStyles"], }, ]) - .then(answers => { + .then((answers: { type: string }) => { return { componentName: componentName, framework: framework.toLowerCase(), @@ -24,7 +24,6 @@ export default function (componentName: string, folder: string, anotherComponent ? "usestyles-component.tsx" : "hello-world-component.tsx", folder: folder, - anotherComponent: anotherComponent, }; }); } diff --git a/src/utils/frameworks/react/react.mjs b/src/utils/frameworks/react/react.mjs index 06110be..7ab6fcc 100644 --- a/src/utils/frameworks/react/react.mjs +++ b/src/utils/frameworks/react/react.mjs @@ -1,52 +1,48 @@ import inquirer from "inquirer"; const framework = "react"; -export default function (componentName, folder, anotherComponent) { - return inquirer - .prompt([ - { - type: "confirm", - name: "typescript", - message: "Do you want to use Typescript?", - default: true, - }, +export default function (componentName, folder) { + return inquirer + .prompt([ + { + type: "confirm", + name: "typescript", + message: "Do you want to use Typescript?", + default: true, + }, + { + type: "list", + name: "css", + message: "Do you want to use any CSS framework?", + choices: ["Tailwind", "Styled Components", "CSS Module", "No"], + default: "No", + }, ]) - .then((answers) => { - const { typescript } = answers; - return inquirer - .prompt([ - { - type: "list", - name: "css", - message: "Do you want to use any CSS framework?", - choices: ["Tailwind", "Styled Components", "CSS Module", "No"], - default: "No", - }, - ]) - .then((answers) => { - const { css } = answers; - const extension = typescript ? "tsx" : "jsx"; - let templateBase = "function-component"; - switch (css) { - case "Tailwind": - templateBase += "-tailwind"; - break; - case "Styled Components": - templateBase += "-styled-components"; - break; - case "CSS Module": - templateBase += "-css-module"; - break; - default: - break; - } - const template = `${templateBase}.${extension}`; - return { - componentName: componentName, - framework: framework.toLowerCase(), - template: template, - folder: folder, - anotherComponent: anotherComponent, - }; - }); + .then((answers) => { + const { typescript } = answers; + const { css } = answers; + const extension = typescript ? "tsx" : "jsx"; + let templateBase = "function-component"; + + switch (css) { + case "Tailwind": + templateBase += "-tailwind"; + break; + case "Styled Components": + templateBase += "-styled-components"; + break; + case "CSS Module": + templateBase += "-css-module"; + break; + default: + break; + } + const template = `${templateBase}.${extension}`; + + return { + componentName: componentName, + framework: framework.toLowerCase(), + template: template, + folder: folder, + }; }); } diff --git a/src/utils/frameworks/react/react.mts b/src/utils/frameworks/react/react.mts index 049b262..fbdce9a 100644 --- a/src/utils/frameworks/react/react.mts +++ b/src/utils/frameworks/react/react.mts @@ -2,7 +2,7 @@ import inquirer from "inquirer"; const framework = "react"; -export default function (componentName: string, folder: string, anotherComponent: boolean) { +export default function (componentName: string, folder: string) { return inquirer .prompt([ { @@ -11,46 +11,40 @@ export default function (componentName: string, folder: string, anotherComponent message: "Do you want to use Typescript?", default: true, }, + { + type: "list", + name: "css", + message: "Do you want to use any CSS framework?", + choices: ["Tailwind", "Styled Components", "CSS Module", "No"], + default: "No", + }, ]) - .then((answers: { typescript: boolean }) => { + .then((answers: { typescript: boolean; css: string }) => { const { typescript } = answers; + const { css } = answers; + const extension = typescript ? "tsx" : "jsx"; + let templateBase = "function-component"; - return inquirer - .prompt([ - { - type: "list", - name: "css", - message: "Do you want to use any CSS framework?", - choices: ["Tailwind", "Styled Components", "CSS Module", "No"], - default: "No", - }, - ]) - .then((answers: { css: string }) => { - const { css } = answers; - const extension = typescript ? "tsx" : "jsx"; - let templateBase = "function-component"; - switch (css) { - case "Tailwind": - templateBase += "-tailwind"; - break; - case "Styled Components": - templateBase += "-styled-components"; - break; - case "CSS Module": - templateBase += "-css-module"; - break; - default: - break; - } - const template = `${templateBase}.${extension}`; + switch (css) { + case "Tailwind": + templateBase += "-tailwind"; + break; + case "Styled Components": + templateBase += "-styled-components"; + break; + case "CSS Module": + templateBase += "-css-module"; + break; + default: + break; + } + const template = `${templateBase}.${extension}`; - return { - componentName: componentName, - framework: framework.toLowerCase(), - template: template, - folder: folder, - anotherComponent: anotherComponent, - }; - }); + return { + componentName: componentName, + framework: framework.toLowerCase(), + template: template, + folder: folder, + }; }); } diff --git a/src/utils/frameworks/svelte/svelte.mjs b/src/utils/frameworks/svelte/svelte.mjs index 63e147c..846b895 100644 --- a/src/utils/frameworks/svelte/svelte.mjs +++ b/src/utils/frameworks/svelte/svelte.mjs @@ -1,22 +1,23 @@ import inquirer from "inquirer"; const framework = "svelte"; -export default function (componentName, folder, anotherComponent) { - return inquirer - .prompt([ - { - type: "confirm", - name: "typescript", - message: "Do you want to use Typescript?", - default: true, - }, +export default function (componentName, folder) { + return inquirer + .prompt([ + { + type: "confirm", + name: "typescript", + message: "Do you want to use Typescript?", + default: true, + }, ]) - .then((answers) => { - return { - componentName: componentName, - framework: framework.toLowerCase(), - template: answers.typescript ? "component-ts.svelte" : "component-js.svelte", - folder: folder, - anotherComponent: anotherComponent, - }; + .then((answers) => { + return { + componentName: componentName, + framework: framework.toLowerCase(), + template: answers.typescript + ? "component-ts.svelte" + : "component-js.svelte", + folder: folder, + }; }); } diff --git a/src/utils/frameworks/svelte/svelte.mts b/src/utils/frameworks/svelte/svelte.mts index 94ba8cb..506da04 100644 --- a/src/utils/frameworks/svelte/svelte.mts +++ b/src/utils/frameworks/svelte/svelte.mts @@ -1,7 +1,7 @@ import inquirer from "inquirer"; const framework = "svelte"; -export default function (componentName: string, folder: string, anotherComponent: boolean) { +export default function (componentName: string, folder: string) { return inquirer .prompt([ { @@ -17,7 +17,6 @@ export default function (componentName: string, folder: string, anotherComponent framework: framework.toLowerCase(), template: answers.typescript ? "component-ts.svelte" : "component-js.svelte", folder: folder, - anotherComponent: anotherComponent, }; }); } diff --git a/src/utils/frameworks/vue/vue.mjs b/src/utils/frameworks/vue/vue.mjs index c2c82a7..ec6c0eb 100644 --- a/src/utils/frameworks/vue/vue.mjs +++ b/src/utils/frameworks/vue/vue.mjs @@ -1,35 +1,50 @@ import inquirer from "inquirer"; import { prepareAdvanced } from "../../utils.mjs"; const framework = "vue"; -export default function (componentName, folder, anotherComponent) { - return inquirer - .prompt([ - { - type: "list", - name: "nuxt", - message: "Do you use Nuxt? The destination folder will be (./components)", - choices: ["yes", "No"], - default: "No", - }, - { - type: "list", - name: "api", - message: "Choose wich api to use", - choices: ["Composition", "Options"], - default: "Composition", - }, - ...prepareAdvanced(["props", "refs", "data", "mounted", "emits", "components"]), +export default function (componentName, folder) { + return inquirer + .prompt([ + { + type: "list", + name: "nuxt", + message: + "Do you use Nuxt? The destination folder will be (./components)", + choices: ["yes", "No"], + default: "No", + }, + { + type: "list", + name: "api", + message: "Choose wich api to use", + choices: ["Composition", "Options"], + default: "Composition", + }, + ...prepareAdvanced([ + "props", + "refs", + "data", + "mounted", + "emits", + "components", + ]), ]) - .then((answers) => { - return { - componentName: componentName, - framework: framework, - template: answers.api === "Composition" ? "component-composition.vue" : "component-options.vue", - folder: answers.nuxt === "yes" ? (folder === "" ? "../../components" : `../../components/${folder}`) : folder, - anotherComponent: anotherComponent, - advanced: answers.advanced, - api: answers.api.toLocaleLowerCase(), - advancedOpts: answers.advancedOpts || [], - }; + .then((answers) => { + return { + componentName: componentName, + framework: framework, + template: + answers.api === "Composition" + ? "component-composition.vue" + : "component-options.vue", + folder: + answers.nuxt === "yes" + ? folder === "" + ? "../../components" + : `../../components/${folder}` + : folder, + advanced: answers.advanced, + api: answers.api.toLocaleLowerCase(), + advancedOpts: answers.advancedOpts || [], + }; }); } diff --git a/src/utils/frameworks/vue/vue.mts b/src/utils/frameworks/vue/vue.mts index 58fd772..04980c0 100644 --- a/src/utils/frameworks/vue/vue.mts +++ b/src/utils/frameworks/vue/vue.mts @@ -2,7 +2,7 @@ import inquirer from "inquirer"; import { prepareAdvanced } from "../../utils.mjs"; const framework = "vue"; -export default function (componentName: string, folder: string, anotherComponent: boolean) { +export default function (componentName: string, folder: string) { return inquirer .prompt([ { @@ -33,7 +33,6 @@ export default function (componentName: string, folder: string, anotherComponent framework: framework, template: answers.api === "Composition" ? "component-composition.vue" : "component-options.vue", folder: answers.nuxt === "yes" ? (folder === "" ? "../../components" : `../../components/${folder}`) : folder, - anotherComponent: anotherComponent, advanced: answers.advanced, api: answers.api.toLocaleLowerCase(), advancedOpts: answers.advancedOpts || [], diff --git a/src/utils/utils.mjs b/src/utils/utils.mjs index 4abab05..c9a78aa 100644 --- a/src/utils/utils.mjs +++ b/src/utils/utils.mjs @@ -5,122 +5,166 @@ import { makeAngularComponent } from "./frameworks/angular/make-angular-componen import inquirer from "inquirer"; import advancedVueBuilder from "./frameworks/vue/helper.mjs"; import wizard from "./wizard.mjs"; -export default async function createComponent(componentName, framework, template, customFolder, api, advancedOpts) { - const destinationFolder = `${configs.BASE_DIR}${configs.COMPONENT_FOLDER}`; - if (!fs.existsSync(destinationFolder)) { - fs.mkdirSync(destinationFolder); +export default async function createComponent( + componentName, + framework, + template, + customFolder, + api, + advancedOpts +) { + const destinationFolder = `${configs.BASE_DIR}${configs.COMPONENT_FOLDER}`; + if (!fs.existsSync(destinationFolder)) { + fs.mkdirSync(destinationFolder); + } + const templateFilePath = path.join( + configs.INIT_PATH, + "src", + configs.STUBS_DIR, + framework, + template + ); + fs.readFile(templateFilePath, "utf8", async (err, data) => { + const customDestinationFolder = path.join( + configs.BASE_DIR, + configs.COMPONENT_FOLDER, + customFolder + ); + const extension = template.substring(template.indexOf(".")); + const compFileName = `${componentName}${extension}`; + if (!fs.existsSync(customDestinationFolder)) { + fs.mkdirSync(customDestinationFolder, { recursive: true }); } - const templateFilePath = path.join(configs.INIT_PATH, "src", configs.STUBS_DIR, framework, template); - fs.readFile(templateFilePath, "utf8", async (err, data) => { - const customDestinationFolder = path.join(configs.BASE_DIR, configs.COMPONENT_FOLDER, customFolder); - const extension = template.substring(template.indexOf(".")); - const compFileName = `${componentName}${extension}`; - if (!fs.existsSync(customDestinationFolder)) { - fs.mkdirSync(customDestinationFolder, { recursive: true }); + const filePathDestination = path.join( + configs.BASE_DIR, + configs.COMPONENT_FOLDER, + customFolder, + compFileName + ); + let output = data; + if (framework === "angular") { + makeAngularComponent(filePathDestination, output, componentName); + } else { + if (template.indexOf("advanced") !== -1) { + switch (framework) { + case "vue": + output = advancedVueBuilder(output, api, advancedOpts); + break; + default: + break; } - const filePathDestination = path.join(configs.BASE_DIR, configs.COMPONENT_FOLDER, customFolder, compFileName); - let output = data; - if (framework === "angular") { - makeAngularComponent(filePathDestination, output, componentName); - } - else { - if (template.indexOf("advanced") !== -1) { - switch (framework) { - case "vue": - output = advancedVueBuilder(output, api, advancedOpts); - break; - default: - break; - } - } - output = output.replaceAll("ComponentName", capitalizeFirstLetter(componentName)); - await checkFileExists(filePathDestination, output); - return filePathDestination; - } - if (path.parse(template).name === "function-component-css-module") { - const styleFileName = `${componentName}.module.css`; - const styleFilePathDestination = path.join(configs.BASE_DIR, configs.COMPONENT_FOLDER, customFolder, styleFileName); - await checkFileExists(styleFilePathDestination, `.${componentName} {\n\tfont-size: 1.125rem; /* 18px */\n\tline-height: 1.75rem; /* 28px */\n\tfont-weight: bold;\n}\n`); - return filePathDestination; - } - }); -} -export async function checkFileExists(filePathDestination, data) { - if (fs.existsSync(filePathDestination)) { - console.log(`⚠️ A component with this name and extension already exists in ${filePathDestination}`); - inquirer - .prompt([ - { - type: "confirm", - name: "duplicateFile", - message: "Do you want to continue with component creation? NOTE: this action will override the existing file", - default: false, - }, - ]) - .then((answer) => { - if (answer.duplicateFile) { - (async () => { - await writeFile(filePathDestination, data); - })(); - } - else { - return console.log("❌ File not created"); - } - }); + } + output = output.replaceAll( + "ComponentName", + capitalizeFirstLetter(componentName) + ); + await checkFileExists(filePathDestination, output); + return filePathDestination; } - else { - await writeFile(filePathDestination, data); + if (path.parse(template).name === "function-component-css-module") { + const styleFileName = `${componentName}.module.css`; + const styleFilePathDestination = path.join( + configs.BASE_DIR, + configs.COMPONENT_FOLDER, + customFolder, + styleFileName + ); + await checkFileExists( + styleFilePathDestination, + `.${componentName} {\n\tfont-size: 1.125rem; /* 18px */\n\tline-height: 1.75rem; /* 28px */\n\tfont-weight: bold;\n}\n` + ); + return filePathDestination; } + }); } -async function writeFile(filePathDestination, data) { - fs.writeFile(filePathDestination, data, (err) => { - if (err) { - console.error(err); +export async function checkFileExists(filePathDestination, data) { + if (fs.existsSync(filePathDestination)) { + console.log( + `⚠️ A component with this name and extension already exists in ${filePathDestination}` + ); + inquirer + .prompt([ + { + type: "confirm", + name: "duplicateFile", + message: + "Do you want to continue with component creation? NOTE: this action will override the existing file", + default: false, + }, + ]) + .then((answer) => { + if (answer.duplicateFile) { + (async () => { + await writeFile(filePathDestination, data); + })(); + } else { + return console.log("❌ File not created"); } - }); + }); + } else { + await writeFile(filePathDestination, data); + } +} +async function writeFile(filePathDestination, data) { + fs.writeFile(filePathDestination, data, (err) => { + if (err) { + console.error(err); + } + }); } export function createAnotherComponent() { - let vueApi; - (function (vueApi) { - vueApi["Composition"] = "composition"; - vueApi["Option"] = "option"; - })(vueApi || (vueApi = {})); - wizard() - .then((answers) => { - const { componentName, framework, template, folder, anotherComponent, advancedOpts, advanced } = answers; - const api = template.indexOf("composition") !== -1 ? vueApi.Composition : vueApi.Option; - const t = advanced ? "advanced-component.vue" : template; - createComponent(componentName, framework, t, folder, api, advancedOpts); - if (anotherComponent) { - createAnotherComponent(); - } + let vueApi; + (function (vueApi) { + vueApi["Composition"] = "composition"; + vueApi["Option"] = "option"; + })(vueApi || (vueApi = {})); + wizard() + .then((answers) => { + const { + componentName, + framework, + template, + folder, + anotherComponent, + advancedOpts, + advanced, + } = answers; + const api = + template.indexOf("composition") !== -1 + ? vueApi.Composition + : vueApi.Option; + const t = advanced ? "advanced-component.vue" : template; + createComponent(componentName, framework, t, folder, api, advancedOpts); + if (anotherComponent) { + createAnotherComponent(); + } }) - .catch((e) => { - console.error(e.message); + .catch((e) => { + console.error(e.message); }); - return; + return; } export function capitalizeFirstLetter(string) { - return string.charAt(0).toUpperCase() + string.slice(1); + return string.charAt(0).toUpperCase() + string.slice(1); } export function prepareAdvanced(options) { - const arr = [ - { - type: "confirm", - name: "advanced", - message: "Do you want to check for advanced options?", - default: false, - }, - { - type: "checkbox", - name: "advancedOpts", - message: "Pick the parts you want in your component?", - choices: options, - when: (answers) => { - return answers.advanced; - }, - default: false, - }, - ]; - return [...arr]; + const arr = [ + { + type: "confirm", + name: "advanced", + message: "Do you want to check for advanced options?", + default: false, + }, + { + type: "checkbox", + name: "advancedOpts", + message: "Pick the parts you want in your component?", + choices: options, + when: (answers) => { + return answers.advanced; + }, + default: false, + }, + ]; + return [...arr]; } diff --git a/src/utils/utils.mts b/src/utils/utils.mts index d2f357c..560d09b 100644 --- a/src/utils/utils.mts +++ b/src/utils/utils.mts @@ -3,7 +3,6 @@ import * as path from "node:path"; import { configs } from "./configs.cjs"; import { makeAngularComponent } from "./frameworks/angular/make-angular-component.mjs"; -import { resolve } from "path"; import inquirer from "inquirer"; import advancedVueBuilder, { vueApi } from "./frameworks/vue/helper.mjs"; import wizard, { Answers } from "./wizard.mjs"; diff --git a/src/utils/wizard.mjs b/src/utils/wizard.mjs index 5a3d053..4c6dbfe 100644 --- a/src/utils/wizard.mjs +++ b/src/utils/wizard.mjs @@ -9,111 +9,130 @@ import vueWizard from "./frameworks/vue/vue.mjs"; import { capitalizeFirstLetter } from "./utils.mjs"; const program = new Command(); const wizard = async () => { - // Parse command line arguments using commander - const frameworks = ["Vue", "Angular", "React", "Svelte", "Qwik", "Astro"]; - program - .option("--name ", "Specify a name") - .option("-f, --framework ", `Specify framework [${frameworks.join("|")}]`) - .option("--vue", "Create a Vue component") - .option("--angular", "Create an Angular component") - .option("--react", "Create a React component") - .option("--svelte", "Create a Svelte component") - .option("--qwik", "Create a Qwik component") - .option("--astro", "Create an Astro component") - .option("--folder ", "Specify the subfolder") - .option("--multiple", "Creating multiple components at once") - .parse(process.argv); - const options = program.opts(); - const componentNameFromFlag = options.name || ""; - const frameworkFromFlag = options.framework || options.vue - ? "vue" - : null || options.angular - ? "angular" - : null || options.react - ? "react" - : null || options.svelte - ? "svelte" - : null || options.qwik - ? "qwik" - : null || options.astro - ? "astro" - : null || ""; - const folderFromFlag = options.folder || ""; - const multipleFromFlag = options.multiple || false; - const prompts = []; - // Only ask for componentName if --name argument is not provided - if (!componentNameFromFlag) { - prompts.push({ - type: "input", - name: "componentName", - message: "Give a name to your component", - validate: (input) => { - const trimmedInput = input.trim(); - if (trimmedInput === "") { - return "Component name cannot be empty"; - } - if (multipleFromFlag && trimmedInput === "exit") { - process.exit(); - } - // Use a regular expression to check for only alphanumeric characters - const isValid = /^[A-Za-z0-9]+(-[A-Za-z0-9]+)*$/.test(trimmedInput); - return isValid || "Component name can only contain alphanumeric characters"; - }, - }); - } - if (!folderFromFlag) { - prompts.push({ - type: "input", - name: "folder", - message: "Custom path for the component (default: src/components)", - default: "", - }); - } - if (!frameworkFromFlag) { - prompts.push({ - type: "list", - name: "framework", - message: "Pick a framework to create the component for", - choices: frameworks, - }); - } - if (!multipleFromFlag) { - prompts.push({ - type: "confirm", - name: "anotherComponent", - message: "Do you want to create another component?", - default: false, - }); - } - return inquirer - .prompt(prompts) - .then((answers) => { - const folder = answers.folder || folderFromFlag; - const framework = answers.framework || capitalizeFirstLetter(frameworkFromFlag); - const componentName = answers.componentName || componentNameFromFlag; - const anotherComponent = answers.anotherComponent || multipleFromFlag; - switch (framework) { - case "Vue": - return vueWizard(componentName, folder, anotherComponent); - case "Angular": - return angularWizard(componentName, folder, anotherComponent); - case "React": - return reactWizard(componentName, folder, anotherComponent); - case "Svelte": - return svelteWizard(componentName, folder, anotherComponent); - case "Qwik": - return qwikWizard(componentName, folder, anotherComponent); - case "Astro": - return astroWizard(componentName, folder, anotherComponent); - default: - throw new Error("A valid framework must be selected"); + // Parse command line arguments using commander + const frameworks = ["Vue", "Angular", "React", "Svelte", "Qwik", "Astro"]; + program + .option("--name ", "Specify a name") + .option( + "-f, --framework ", + `Specify framework [${frameworks.join("|")}]` + ) + .option("--vue", "Create a Vue component") + .option("--angular", "Create an Angular component") + .option("--react", "Create a React component") + .option("--svelte", "Create a Svelte component") + .option("--qwik", "Create a Qwik component") + .option("--astro", "Create an Astro component") + .option("--folder ", "Specify the subfolder") + .option("--multiple", "Creating multiple components at once") + .parse(process.argv); + const options = program.opts(); + const componentNameFromFlag = options.name || ""; + const frameworkFromFlag = + options.framework || options.vue + ? "vue" + : null || options.angular + ? "angular" + : null || options.react + ? "react" + : null || options.svelte + ? "svelte" + : null || options.qwik + ? "qwik" + : null || options.astro + ? "astro" + : null || ""; + const folderFromFlag = options.folder || ""; + const multipleFromFlag = options.multiple || false; + + const prompts = []; + // Only ask for componentName if --name argument is not provided + if (!componentNameFromFlag) { + prompts.push({ + type: "input", + name: "componentName", + message: "Give a name to your component", + validate: (input) => { + const trimmedInput = input.trim(); + if (trimmedInput === "") { + return "Component name cannot be empty"; + } + if (multipleFromFlag && trimmedInput === "exit") { + process.exit(); } + // Use a regular expression to check for only alphanumeric characters + const isValid = /^[A-Za-z0-9]+(-[A-Za-z0-9]+)*$/.test(trimmedInput); + return ( + isValid || "Component name can only contain alphanumeric characters" + ); + }, + }); + } + if (!folderFromFlag) { + prompts.push({ + type: "input", + name: "folder", + message: "Custom path for the component (default: src/components)", + default: "", + }); + } + if (!frameworkFromFlag) { + prompts.push({ + type: "list", + name: "framework", + message: "Pick a framework to create the component for", + choices: frameworks, + }); + } + + return inquirer + .prompt(prompts) + .then((answers) => { + const folder = answers.folder || folderFromFlag; + const framework = + answers.framework || capitalizeFirstLetter(frameworkFromFlag); + const componentName = answers.componentName || componentNameFromFlag; + switch (framework) { + case "Vue": + return vueWizard(componentName, folder); + case "Angular": + return angularWizard(componentName, folder); + case "React": + return reactWizard(componentName, folder); + case "Svelte": + return svelteWizard(componentName, folder); + case "Qwik": + return qwikWizard(componentName, folder); + case "Astro": + return astroWizard(componentName, folder); + default: + throw new Error("A valid framework must be selected"); + } }) - .then((values) => { - return values; + .then((values) => { + if (!multipleFromFlag) { + return inquirer + .prompt([ + { + type: "confirm", + name: "anotherComponent", + message: "Do you want to create another component?", + default: false, + }, + ]) + .then((answers) => { + const { anotherComponent } = answers; + const completeValues = { + ...values, + anotherComponent: anotherComponent, + }; + return completeValues; + }); + } + return { ...values, anotherComponent: true }; }) - .catch((e) => { - throw new Error(e.message); + .catch((e) => { + throw new Error(e.message); }); }; export default wizard; diff --git a/src/utils/wizard.mts b/src/utils/wizard.mts index 95bc3bc..cc613fc 100644 --- a/src/utils/wizard.mts +++ b/src/utils/wizard.mts @@ -15,7 +15,7 @@ export type Answers = { framework: string; template: string; folder: string; - anotherComponent: boolean; + anotherComponent?: boolean; advanced?: boolean; advancedOpts?: string[]; api?: string; @@ -113,15 +113,6 @@ const wizard: () => Promise = async () => { }); } - if (!multipleFromFlag) { - prompts.push({ - type: "confirm", - name: "anotherComponent", - message: "Do you want to create another component?", - default: false, - }); - } - return inquirer .prompt(prompts) .then( @@ -129,33 +120,50 @@ const wizard: () => Promise = async () => { componentName: string; folder: string; framework: string; - anotherComponent: boolean; }) => { const folder: string = answers.folder || folderFromFlag; const framework: string = answers.framework || capitalizeFirstLetter(frameworkFromFlag); const componentName: string = answers.componentName || componentNameFromFlag; - const anotherComponent: boolean = answers.anotherComponent || multipleFromFlag; switch (framework) { case "Vue": - return vueWizard(componentName, folder, anotherComponent); + return vueWizard(componentName, folder); case "Angular": - return angularWizard(componentName, folder, anotherComponent); + return angularWizard(componentName, folder); case "React": - return reactWizard(componentName, folder, anotherComponent); + return reactWizard(componentName, folder); case "Svelte": - return svelteWizard(componentName, folder, anotherComponent); + return svelteWizard(componentName, folder); case "Qwik": - return qwikWizard(componentName, folder, anotherComponent); + return qwikWizard(componentName, folder); case "Astro": - return astroWizard(componentName, folder, anotherComponent); + return astroWizard(componentName, folder); default: throw new Error("A valid framework must be selected"); } } ) - .then((values: Answers | PromiseLike) => { - return values; + .then((values: Answers) => { + if (!multipleFromFlag) { + return inquirer + .prompt([ + { + type: "confirm", + name: "anotherComponent", + message: "Do you want to create another component?", + default: false, + }, + ]) + .then((answers: { values: Answers; anotherComponent: boolean }) => { + const { anotherComponent } = answers; + const completeValues = { + ...values, + anotherComponent: anotherComponent, + }; + return completeValues; + }); + } + return { ...values, anotherComponent: true }; }) .catch((e: Error) => { throw new Error(e.message);