UNPKG

@practica/create-node-app

Version:

Create Node.js app that is packed with best practices AND strive for simplicity

230 lines (229 loc) 13.4 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.renderWizard = void 0; const react_1 = __importDefault(require("react")); const ink_1 = require("ink"); const ink_multi_select_1 = __importDefault(require("ink-multi-select")); const ink_select_input_1 = __importDefault(require("ink-select-input")); const ink_text_input_1 = require("ink-text-input"); const figlet_1 = __importDefault(require("figlet")); const generateService = __importStar(require("../generation-logic/generate-service")); const generation_options_1 = require("../generation-logic/generation-options"); const QuestionsWizard = () => { const initialQuestionsWizard = { isOver: false, chosenName: "", finalMessage: "", chosenFramework: "", chosenDB: "", showWarningMessage: true, showNameQuestion: false, showFrameworkQuestion: false, showDBTypeQuestion: false, showFeatures: false, advice: "", title: figlet_1.default.textSync("Practica", { font: "Big", horizontalLayout: "full", verticalLayout: "default", width: 60, whitespaceBreak: true, }), generationStatusMessage: "", }; const [questionsWizard, setQuestionsWizard] = react_1.default.useState(initialQuestionsWizard); const features = [ { label: "Logger", value: "logger" }, { label: "Request-ID - Correlation-ID", value: "request-id" }, { label: "Error-Handler", value: "error-handling" }, ]; const flavours = [ { label: "Minimal", value: "minimal", advice: "Configuration only things such as linters. When you want to code everything yourself", }, { label: "Full-flow", value: "full-flow", advice: "Demonstrates full request flow. Packs common best practices. \n \n ✅ 82/120 Best Practices ", }, { label: "Fully featured", value: "fully-featured", advice: "All our best practices are packed inside. Might be an overkill for some apps", }, { label: "Cherry pick", value: "cherry-pick", advice: "Specifically choose the features that you need", }, ]; const databases = [ { label: "Postgres", value: "pg", advice: "Strikes great balance between popularity and flexibility. Can handle both relational workload and light noSQL/JSON workload", }, { label: "mySQL", value: "my-sql", advice: "Classic DB that mostly leans toward relational and structured data", }, { label: "Mongo", value: "mongo", advice: "Great DB for scenarios when a flexible schema is needed", }, ]; const frameworks = [ { label: "Express", value: "express", advice: "A minimalist web library that is easy to learn. A great choice when in a need to have full-control. \n \n ⭐️ 91,000 stars \n \n ⬇️ 1,200,000 downloads/week", }, { label: "Fastify", value: "my-fastify", advice: "A minimalist web library that is easy to learn. A great choice when in a need to have full-control. \n \n ⭐️ 91,000 stars \n \n ⬇️ 1,200,000 downloads/week", }, { label: "Nest.JS", value: "nestjs", advice: "A minimalist web library that is easy to learn. A great choice when in a need to have full-control. \n \n ⭐️ 91,000 stars \n \n ⬇️ 1,200,000 downloads/week", }, ]; const handleNameChoose = (name) => { setQuestionsWizard({ ...questionsWizard, chosenName: name, showDBTypeQuestion: false, showNameQuestion: false, showFrameworkQuestion: true, }); }; const warningWasConfirmed = () => { setQuestionsWizard({ ...questionsWizard, showWarningMessage: false, advice: "Determines the root folder and the libraries scope name. For example, @your-org/logger", showNameQuestion: true, }); }; const handleFrameworkChoose = (chosenOption) => { setQuestionsWizard({ ...questionsWizard, chosenFramework: chosenOption.value, showFrameworkQuestion: false, showDBTypeQuestion: true, }); }; const handleFeaturesChoose = (selected) => { }; const handleFlavourChoose = async (selected) => { setQuestionsWizard({ ...questionsWizard, finalMessage: "🔁 Creating your app now. This might take a few seconds...", isOver: true, }); const generationOptions = (0, generation_options_1.factorDefaultOptions)({ installDependencies: true, targetDirectory: process.cwd(), webFramework: questionsWizard.chosenFramework, }); await generateService.generateApp(generationOptions); setQuestionsWizard({ ...questionsWizard, isOver: true, finalMessage: "✅ Your app is ready and packed with great practices inside", }); }; const handleDBChoose = async (chosenOption) => { setQuestionsWizard({ ...questionsWizard, chosenDB: chosenOption.value, showDBTypeQuestion: false, showFlavourQuestion: true, }); }; const onSelectItemChange = (selectedItem) => { const allOptions = [...databases, ...frameworks, ...flavours]; const chosenItem = allOptions.find((option) => option.value === selectedItem.value)?.advice; const activeAdvice = chosenItem ? chosenItem : ""; setQuestionsWizard({ ...questionsWizard, advice: activeAdvice }); }; react_1.default.useEffect(() => { }, []); return (react_1.default.createElement(ink_1.Box, { width: "100%", alignSelf: "center", flexDirection: "column" }, react_1.default.createElement(ink_1.Box, { flexDirection: "row", width: "100%", flexBasis: "100%" }, react_1.default.createElement(ink_1.Text, { wrap: "wrap" }, questionsWizard.title)), !questionsWizard.isOver ? (react_1.default.createElement(ink_1.Box, { flexDirection: "row" }, react_1.default.createElement(ink_1.Box, { width: "50%", alignSelf: "flex-start", borderStyle: "classic", borderColor: "grey", height: 15, paddingX: 3, marginX: 3, alignItems: "flex-start" }, react_1.default.createElement(ink_1.Box, { flexDirection: "column" }, react_1.default.createElement(ink_1.Box, { paddingY: 1, alignSelf: "flex-start" }, react_1.default.createElement(ink_1.Text, { color: "white", bold: true }, "\u29BE Just a few questions first"), react_1.default.createElement(ink_1.Newline, null), react_1.default.createElement(ink_1.Spacer, null)), react_1.default.createElement(ink_1.Box, null, react_1.default.createElement(ink_1.Box, { display: questionsWizard.showFeaturesQuestion ? "flex" : "none" }, react_1.default.createElement(ink_1.Text, { color: "green" }, "Cherry-pick features:"), react_1.default.createElement(ink_1.Spacer, null), react_1.default.createElement(ink_multi_select_1.default, { items: features, onSelect: handleFeaturesChoose })), questionsWizard.showWarningMessage ? (react_1.default.createElement(ink_1.Box, { display: questionsWizard.showWarningMessage ? "flex" : "none" }, react_1.default.createElement(ink_1.Text, { color: "grey" }, "\uD83D\uDD16 This is an alpha version of this wizard which is meant for demo purposes. Whatever technologies you'll choose, for now the generated app will be based on Express + Postgres. Enter to continue or CTRL + C to exit"), react_1.default.createElement(ink_1.Spacer, null), react_1.default.createElement(ink_text_input_1.UncontrolledTextInput, { initialValue: "", onSubmit: warningWasConfirmed }))) : (react_1.default.createElement(react_1.default.Fragment, null)), questionsWizard.showFlavourQuestion ? (react_1.default.createElement(ink_1.Box, { display: questionsWizard.showFlavourQuestion ? "flex" : "none" }, react_1.default.createElement(ink_1.Text, { color: "green" }, "Which level of starter:"), react_1.default.createElement(ink_1.Spacer, null), react_1.default.createElement(ink_select_input_1.default, { items: flavours, onHighlight: onSelectItemChange, onSelect: handleFlavourChoose }))) : (react_1.default.createElement(react_1.default.Fragment, null)), questionsWizard.showNameQuestion ? (react_1.default.createElement(ink_1.Box, { display: questionsWizard.showNameQuestion ? "flex" : "none" }, react_1.default.createElement(ink_1.Text, { color: "green" }, "Name of your app or organization:"), react_1.default.createElement(ink_1.Spacer, null), react_1.default.createElement(ink_text_input_1.UncontrolledTextInput, { initialValue: "", onSubmit: handleNameChoose }))) : (react_1.default.createElement(react_1.default.Fragment, null)), questionsWizard.showDBTypeQuestion ? (react_1.default.createElement(ink_1.Box, { display: questionsWizard.showDBTypeQuestion ? "flex" : "none" }, react_1.default.createElement(ink_1.Text, { color: "green" }, "Which is your preferred DB:"), react_1.default.createElement(ink_1.Spacer, null), react_1.default.createElement(ink_select_input_1.default, { items: databases, onSelect: handleDBChoose, onHighlight: onSelectItemChange }))) : (react_1.default.createElement(react_1.default.Fragment, null)), questionsWizard.showFrameworkQuestion ? (react_1.default.createElement(ink_1.Box, { display: questionsWizard.showFrameworkQuestion ? "flex" : "none" }, react_1.default.createElement(ink_1.Text, { color: "green" }, "Your preferred framework:"), react_1.default.createElement(ink_1.Spacer, null), react_1.default.createElement(ink_select_input_1.default, { items: frameworks, onSelect: handleFrameworkChoose, onHighlight: onSelectItemChange }))) : (react_1.default.createElement(react_1.default.Fragment, null))))), react_1.default.createElement(ink_1.Box, { width: "30%", borderStyle: "classic", borderColor: "grey", height: 15, paddingX: 5, marginX: 3, alignItems: "flex-start", alignSelf: "flex-end" }, react_1.default.createElement(ink_1.Box, { flexDirection: "column" }, react_1.default.createElement(ink_1.Box, { paddingY: 1, alignSelf: "flex-start" }, react_1.default.createElement(ink_1.Text, { color: "white", bold: true }, "\u29BE More Info")), react_1.default.createElement(ink_1.Box, null, react_1.default.createElement(ink_1.Text, null, questionsWizard.advice)))))) : (react_1.default.createElement(react_1.default.Fragment, null)), questionsWizard.isOver ? (react_1.default.createElement(ink_1.Box, { flexDirection: "row", width: "100%", flexBasis: "100%" }, react_1.default.createElement(ink_1.Text, { wrap: "wrap", color: "white", bold: true }, questionsWizard.finalMessage))) : (react_1.default.createElement(react_1.default.Fragment, null)))); }; //<SelectInput items={items} onSelect={handleSubmit} /> const renderWizard = () => { (0, ink_1.render)(react_1.default.createElement(QuestionsWizard, null)); }; exports.renderWizard = renderWizard;