import * as figlet from "figlet" ; import * as inquirer from "inquirer" ; import * as fs from "fs" ; import * as path from "path" ; import * as shell from "shelljs" ; import * as template from "./utils/template" ; import chalk from "chalk" ; import * as yargs from "yargs" ; const PROGRAMMING_LANGUAGE = fs . readdirSync ( path . join ( __dirname , "templates" ) ) ; const JAVASCRIPTFRAMEWORK = fs . readdirSync ( path . join ( __dirname , "templates/javascript" ) ) ; const TYPESCRIPTFRAMEWORK = fs . readdirSync ( path . join ( __dirname , "templates/typescript" ) ) ; const TUTORIALSTARTER = fs . readdirSync ( path . join ( __dirname , "templates/tutorials" ) ) ; const VUEJS = fs . readdirSync ( path . join ( __dirname , "templates/javascript/vue-js" ) ) ; const REACTTS = fs . readdirSync ( path . join ( __dirname , "templates/typescript/react-ts" ) ) ; const REACTJS = fs . readdirSync ( path . join ( __dirname , "templates/javascript/react-js" ) ) ; const NODETS = fs . readdirSync ( path . join ( __dirname , "templates/typescript/node-ts" ) ) ; const NODEJS = fs . readdirSync ( path . join ( __dirname , "templates/javascript/node-js" ) ) ; const FULLSTACKTS = fs . readdirSync ( path . join ( __dirname , "templates/typescript/fullstack-starters" ) ) ; const FULLSTACKJS = fs . readdirSync ( path . join ( __dirname , "templates/javascript/fullstack-starters" ) ) ; const REACT_NATIVE_EXPO_TS = fs . readdirSync ( path . join ( __dirname , "templates/typescript/react-native-expo-ts" ) ) ; const REACT_NATIVE_EXPO_JS = fs . readdirSync ( path . join ( __dirname , "templates/javascript/react-native-expo-js" ) ) ; const REACT_NATIVE_CLI_TS = fs . readdirSync ( path . join ( __dirname , "templates/typescript/react-native-ts" ) ) ; const REACT_NATIVE_CLI_JS = fs . readdirSync ( path . join ( __dirname , "templates/javascript/react-native-js" ) ) ; const ANGULARJS = fs . readdirSync ( path . join ( __dirname , "templates/javascript/angular-js" ) ) ; const QUESTIONS = [ { name : "programmingLanguage" , type : "list" , message : "Hello, I am Quicksi your personal assistant, what starter would you like to choose" , choices : PROGRAMMING_LANGUAGE , when : ( ) => ! yargs . argv [ "programmingLanguage" ] , } , { name : "javaScriptFrameworkLibrary" , type : "list" , message : "Here are the javascript project framework or libraries you can pick from" , choices : JAVASCRIPTFRAMEWORK , when : ( answer1 ) => { return answer1 . programmingLanguage === "javascript" ; } , } , { name : "typescriptFrameworkLibrary" , type : "list" , message : "Here are the typescript project framework or libraries you can pick from" , choices : TYPESCRIPTFRAMEWORK , when : ( answer2 ) => { return answer2 . programmingLanguage === "typescript" ; } , } , { name : "tutorialStarters" , type : "list" , message : "Scrolling through might be bothering, but you can easily get the starter with the input field" , choices : [ "Input field" , "Scroll select" ] , when : ( answer2 ) => { return answer2 . programmingLanguage === "tutorials" ; } , } , { name : "tutorialInput" , type : "input" , message : "I'm so glad you listened to me. Now input the tutorial starter code" , validate : ( value ) => { const array = TUTORIALSTARTER ; const doubled = array . map ( ( n ) => n === value ) ; for ( let i in doubled ) { if ( doubled [ i ] === true ) { return true ; } return "Sorry code doesn't exist. Please try a valid code" ; } return "next" ; } , when : ( answer2 ) => { return answer2 . tutorialStarters === "Input field" ; } , } , { name : "tutorialScroll" , type : "list" , message : "Scroll and select the tutorial starter you want to generate" , choices : TUTORIALSTARTER , when : ( answer2 ) => { return answer2 . tutorialStarters === "Scroll select" ; } , } , { name : "tsStarters" , type : "list" , message : "Almost there! Choose the starter you want quicksi to generate for you?" , choices : REACTTS , when : ( answer6 ) => { return answer6 . typescriptFrameworkLibrary === "react-ts" ; } , } , { name : "tsStarters" , type : "list" , message : "Almost ready! Choose the starter you want quicksi to generate for you" , choices : NODETS , when : ( answer6 ) => { return answer6 . typescriptFrameworkLibrary === "node-ts" ; } , } , { name : "tsStarters" , type : "list" , message : "Pretty much done! Choose the starter you want quicksi to generate for you" , choices : FULLSTACKTS , when : ( answer6 ) => { return answer6 . typescriptFrameworkLibrary === "fullstack-starters" ; } , } , { name : "tsStarters" , type : "list" , message : "So close! Choose the starter you want quicksi to generate for you" , choices : REACT_NATIVE_EXPO_TS , when : ( answer6 ) => { return answer6 . typescriptFrameworkLibrary === "react-native-expo-ts" ; } , } , { name : "tsStarters" , type : "list" , message : "Be ready soon! Choose the starter you want quicksi to generate for you" , choices : REACT_NATIVE_CLI_TS , when : ( answer6 ) => { return answer6 . typescriptFrameworkLibrary === "react-native-ts" ; } , } , { name : "jsStarters" , type : "list" , message : "Nearly finished! Choose the starter you want quicksi to generate for you" , choices : ANGULARJS , when : ( answer4 ) => { return answer4 . javaScriptFrameworkLibrary === "angular-js" ; } , } , { name : "jsStarters" , type : "list" , message : "Nearly finished! Choose the starter you want quicksi to generate for you" , choices : REACTJS , when : ( answer4 ) => { return answer4 . javaScriptFrameworkLibrary === "react-js" ; } , } , { name : "jsStarters" , type : "list" , message : "Almost made it! Choose the starter you want to generate for you" , choices : NODEJS , when : ( answer4 ) => { return answer4 . javaScriptFrameworkLibrary === "node-js" ; } , } , { name : "jsStarters" , type : "list" , message : "Nearly finished! Choose the starter you want quicksi to generate for you" , choices : VUEJS , when : ( answer4 ) => { return answer4 . javaScriptFrameworkLibrary === "vue-js" ; } , } , { name : "jsStarters" , type : "list" , message : "So close! Choose the starter you want quicksi to generate for you" , choices : FULLSTACKJS , when : ( answer6 ) => { return answer6 . javaScriptFrameworkLibrary === "fullstack-starters" ; } , } , { name : "jsStarters" , type : "list" , message : "Pretty much done! Choose the starter you want quicksi to generate for you" , choices : REACT_NATIVE_EXPO_JS , when : ( answer6 ) => { return answer6 . javaScriptFrameworkLibrary === "react-native-expo-js" ; } , } , { name : "jsStarters" , type : "list" , message : "Almost made it! Choose the starter you want to generate for you" , choices : REACT_NATIVE_CLI_JS , when : ( answer6 ) => { return answer6 . javaScriptFrameworkLibrary === "react-native-js" ; } , } , { name : "name" , type : "input" , message : "Last but not the least, tell me you project name:" , when : ( ) => ! yargs . argv [ "name" ] , validate : ( input ) => { if ( /^([A-Za-z\-\_\d])+$/ . test ( input ) ) return true ; else return "Project name may only include letters, numbers, underscores and hashes." ; } , } , ] ; const CURR_DIR = process . cwd ( ) ; export interface TemplateConfig { files ? : string [ ] ; postMessage ? : string ; } export interface CliOptions { projectName : string ; templateName : string ; templatePath : string ; tartgetPath : string ; config : TemplateConfig ; } inquirer . prompt ( QUESTIONS ) . then ( ( answers ) => { let projectStarter ; let projectChoice ; let templatePath ; let projectFramework ; answers = Object . assign ( { } , answers , yargs . argv ) ; const projectLang = answers [ "programmingLanguage" ] ; if ( projectLang === "tutorials" ) { projectStarter = answers [ "tutorialInput" ] || answers [ "tutorialScroll" ] ; projectChoice = projectLang + "/" + projectStarter ; templatePath = path . join ( __dirname , "templates" , projectLang , projectStarter ) ; } if ( projectLang === "javascript" || projectLang === "typescript" ) { projectFramework = answers [ "javaScriptFrameworkLibrary" ] || answers [ "typescriptFrameworkLibrary" ] ; projectStarter = answers [ "jsStarters" ] || answers [ "tsStarters" ] ; projectChoice = projectLang + "/" + projectFramework + "/" + projectStarter ; templatePath = path . join ( __dirname , "templates" , projectLang , projectFramework , projectStarter ) ; } /**
     * If you created a new Framework or library, pass it here,
     * as another condition
     */ console . log ( projectChoice , "projectChoice" ) ; const projectName = answers [ "name" ] ; const tartgetPath = path . join ( CURR_DIR , projectName ) ; const templateConfig = getTemplateConfig ( templatePath ) ; const options = { projectName , templateName : projectChoice , templatePath , tartgetPath , config : templateConfig , } ; if ( ! createProject ( tartgetPath ) ) { return ; } createDirectoryContents ( templatePath , projectName , templateConfig ) ; if ( ! postProcess ( options ) ) { return ; } showMessage ( options ) ; } ) ; function showMessage ( options ) { console . log ( "" ) ; figlet ( "QUICKSI" , ( err , data ) => { if ( err ) { console . log ( chalk . red ( "Something went wrong..." ) ) ; console . dir ( err ) ; return ; } console . log ( chalk . yellow ( data ) ) ; } ) ; const output2 = "💡💡 Quicksi has successfully generated a project starter for you" ; console . log ( "" ) ; console . log ( chalk . green ( output2 ) ) ; console . log ( chalk . green ( `cd ${ options . projectName }` ) ) ; console . log ( chalk . yellow ( `if there are two lock files, kindly delete one` ) ) ; console . log ( chalk . green ( `Checkout the README file of the project, for further details on starting the app.` ) ) ; console . log ( "" ) ; console . log ( chalk . yellow ( `💡 Quicksi is a bot who love developers, show some love, give it a star 🌟 <https://bit.ly/2KhW4s5>` ) ) ; console . log ( chalk . yellow ( `You can contribute too 🦸‍♂️, see how <https://bit.ly/3cligNY>` ) ) ; const message = options . config . postMessage ; if ( message ) { console . log ( "" ) ; console . log ( chalk . yellow ( message ) ) ; console . log ( "" ) ; } } function getTemplateConfig ( templatePath ) { const configPath = path . join ( templatePath , ".template.json" ) ; if ( ! fs . existsSync ( configPath ) ) return { } ; const templateConfigContent = fs . readFileSync ( configPath ) ; if ( templateConfigContent ) { return JSON . parse ( templateConfigContent . toString ( ) ) ; } return { } ; } function createProject ( projectPath ) { if ( fs . existsSync ( projectPath ) ) { console . log ( chalk . red ( `Folder ${ projectPath } exists. Delete or use another name.` ) ) ; return false ; } fs . mkdirSync ( projectPath ) ; return true ; } function postProcess ( options ) { if ( isNode ( options ) ) { return postProcessNode ( options ) ; } return true ; } function isNode ( options ) { return fs . existsSync ( path . join ( options . templatePath , "package.json" ) ) ; } function postProcessNode ( options ) { shell . cd ( options . tartgetPath ) ; let cmd = "" ; if ( shell . which ( "yarn" ) ) { cmd = "yarn" ; } else if ( shell . which ( "npm" ) ) { cmd = "npm install && npm update" ; } if ( cmd ) { const result = shell . exec ( cmd ) ; if ( result . code !== 0 ) { return false ; } } else { console . log ( chalk . red ( "No yarn or npm found. Cannot run installation." ) ) ; } return true ; } const SKIP_FILES = [ "node_modules" , ".template.json" ] ; function createDirectoryContents ( templatePath , projectName , config ) { const filesToCreate = fs . readdirSync ( templatePath ) ; filesToCreate . forEach ( ( file ) => { const origFilePath = path . join ( templatePath , file ) ; const stats = fs . statSync ( origFilePath ) ; if ( SKIP_FILES . indexOf ( file ) > - 1 ) return ; if ( stats . isFile ( ) ) { let contents = fs . readFileSync ( origFilePath , "utf8" ) ; contents = template . render ( contents , { projectName } ) ; const writePath = path . join ( CURR_DIR , projectName , file ) ; fs . writeFileSync ( writePath , contents , "utf8" ) ; } else if ( stats . isDirectory ( ) ) { fs . mkdirSync ( path . join ( CURR_DIR , projectName , file ) ) ; createDirectoryContents ( path . join ( templatePath , file ) , path . join ( projectName , file ) , config ) ; } } ) ; }