From 126641591958f2851861a3cc4d17b715b28a69d6 Mon Sep 17 00:00:00 2001 From: Krishna Acondy Date: Mon, 3 Aug 2020 08:19:37 +0100 Subject: [PATCH 1/5] feat(create-react-app): create react seed app when sasjs create is called with the --react flag --- src/cli.js | 26 ++++++++++++++------------ src/main.js | 4 ++-- src/sasjs-create/index.js | 16 ++++++++++++---- src/utils/utils.js | 18 ++++++++++++++++++ 4 files changed, 46 insertions(+), 18 deletions(-) diff --git a/src/cli.js b/src/cli.js index 84a1395ca..484762cd3 100644 --- a/src/cli.js +++ b/src/cli.js @@ -26,7 +26,7 @@ function parseCommand(rawArgs) { const parameters = processRunParameters(args.slice(1)); return { name, parameters }; } - return { name, parameters: args[1] }; + return { name, parameters: args }; } return null; } @@ -139,25 +139,27 @@ export async function cli(args) { } switch (command.name) { case "create": - await createFileStructure(command.parameters); + const projectName = command.parameters[1]; + const appType = (command.parameters[2] || "").replace("--", ""); + await createFileStructure(projectName, appType); break; case "compile": - await compileServices(command.parameters); + await compileServices(command.parameters[1]); break; case "build": - await buildServices(command.parameters); + await buildServices(command.parameters[1]); break; case "deploy": - await deployServices(command.parameters); + await deployServices(command.parameters[1]); break; case "db": - await buildDBs(command.parameters); + await buildDBs(command.parameters[1]); break; case "compilebuild": - await compileBuildServices(command.parameters); + await compileBuildServices(command.parameters[1]); break; case "compilebuilddeploy": - await compileBuildDeployServices(command.parameters); + await compileBuildDeployServices(command.parameters[1]); break; case "help": await showHelp(); @@ -166,16 +168,16 @@ export async function cli(args) { await showVersion(); break; case "web": - await buildWebApp(command.parameters); + await buildWebApp(command.parameters[1]); break; case "listcontexts": - await listContexts(command.parameters); + await listContexts(command.parameters[1]); break; case "add": - await add(command.parameters); + await add(command.parameters[1]); break; case "run": - const { filePath, targetName } = command.parameters; + const { filePath, targetName } = command.parameters[1]; await run(filePath, targetName); break; default: diff --git a/src/main.js b/src/main.js index df695a0e7..d30a43aa0 100644 --- a/src/main.js +++ b/src/main.js @@ -10,8 +10,8 @@ import { getContexts } from "./sasjs-listcontexts"; import { runSasCode } from "./sasjs-run"; import chalk from "chalk"; -export async function createFileStructure(parentFolderName) { - await create(parentFolderName) +export async function createFileStructure(parentFolderName, appType) { + await create(parentFolderName, appType) .then(() => console.log( chalk.greenBright.bold.italic( diff --git a/src/sasjs-create/index.js b/src/sasjs-create/index.js index 3fa9a8630..88a525c05 100644 --- a/src/sasjs-create/index.js +++ b/src/sasjs-create/index.js @@ -3,24 +3,30 @@ import path from "path"; import { setupNpmProject, setupGitIgnore, - asyncForEach + asyncForEach, + createReactApp, } from "../utils/utils"; import { getFolders, getConfiguration } from "../utils/config-utils"; import { createFolderStructure, createFolder, createFile, - fileExists + fileExists, } from "../utils/file-utils"; import chalk from "chalk"; -export async function create(parentFolderName = ".") { +export async function create(parentFolderName = ".", appType = "") { const config = await getConfiguration(path.join(__dirname, "../config.json")); const fileStructure = await getFileStructure(); console.log(chalk.greenBright("Creating folders and files...")); if (parentFolderName !== ".") { await createFolder(path.join(process.projectDir, parentFolderName)); } + + if (appType === "react") { + await createReactApp(path.join(process.projectDir, parentFolderName)); + } + await asyncForEach(fileStructure, async (folder, index) => { const pathExists = await fileExists( path.join(process.projectDir, parentFolderName, folder.folderName) @@ -45,7 +51,9 @@ export async function create(parentFolderName = ".") { await createFile(configDestinationPath, JSON.stringify(config, null, 1)); } }); - await setupNpmProject(parentFolderName); + if (!appType) { + await setupNpmProject(parentFolderName); + } await setupGitIgnore(parentFolderName); } diff --git a/src/utils/utils.js b/src/utils/utils.js index 567742cab..aa3523f4a 100644 --- a/src/utils/utils.js +++ b/src/utils/utils.js @@ -15,6 +15,21 @@ export function diff(x, y) { return x.filter((a) => !y.includes(a)); } +export async function createReactApp(folderPath) { + return new Promise(async (resolve, _) => { + console.log( + chalk.greenBright("Creating react app in", chalk.cyanBright(folderPath)) + ); + shelljs.exec( + `cd ${folderPath} && git clone https://github.com/sasjs/react-seed-app.git && mv react-seed-app/{.,}* . && rm -rf .git && rm -rf react-seed-app`, + { + silent: true, + } + ); + return resolve(); + }); +} + export async function setupNpmProject(folderPath) { return new Promise(async (resolve, _) => { const isExistingProject = await inExistingProject(folderPath); @@ -51,6 +66,9 @@ export async function setupGitIgnore(folderPath) { await createFile(gitIgnoreFilePath, `${gitIgnoreContent}\nsasjsbuild/\n`); console.log(chalk.greenBright("Existing .gitignore is updated.")); } else { + shelljs.exec(`cd ${folderPath} && git init`, { + silent: true, + }); await createFile(gitIgnoreFilePath, "node_modules/\nsasjsbuild/\n.env\n"); console.log(chalk.greenBright("Created .gitignore file.")); } From 5e1550a6f3abee09608f6c49cb6753ac86b6f0d4 Mon Sep 17 00:00:00 2001 From: Krishna Acondy Date: Mon, 3 Aug 2020 08:43:43 +0100 Subject: [PATCH 2/5] feat(create-angular-app): create an angular app when sasjs create is called with the --angular flag --- src/sasjs-create/index.js | 3 +++ src/utils/utils.js | 17 ++++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/sasjs-create/index.js b/src/sasjs-create/index.js index 88a525c05..931f569a4 100644 --- a/src/sasjs-create/index.js +++ b/src/sasjs-create/index.js @@ -5,6 +5,7 @@ import { setupGitIgnore, asyncForEach, createReactApp, + createAngularApp, } from "../utils/utils"; import { getFolders, getConfiguration } from "../utils/config-utils"; import { @@ -25,6 +26,8 @@ export async function create(parentFolderName = ".", appType = "") { if (appType === "react") { await createReactApp(path.join(process.projectDir, parentFolderName)); + } else if (appType === "angular") { + await createAngularApp(path.join(process.projectDir, parentFolderName)); } await asyncForEach(fileStructure, async (folder, index) => { diff --git a/src/utils/utils.js b/src/utils/utils.js index aa3523f4a..f95be55e6 100644 --- a/src/utils/utils.js +++ b/src/utils/utils.js @@ -18,7 +18,7 @@ export function diff(x, y) { export async function createReactApp(folderPath) { return new Promise(async (resolve, _) => { console.log( - chalk.greenBright("Creating react app in", chalk.cyanBright(folderPath)) + chalk.greenBright("Creating React app in", chalk.cyanBright(folderPath)) ); shelljs.exec( `cd ${folderPath} && git clone https://github.com/sasjs/react-seed-app.git && mv react-seed-app/{.,}* . && rm -rf .git && rm -rf react-seed-app`, @@ -30,6 +30,21 @@ export async function createReactApp(folderPath) { }); } +export async function createAngularApp(folderPath) { + return new Promise(async (resolve, _) => { + console.log( + chalk.greenBright("Creating Angular app in", chalk.cyanBright(folderPath)) + ); + shelljs.exec( + `cd ${folderPath} && git clone https://github.com/sasjs/angular-seed-app.git && mv angular-seed-app/{.,}* . && rm -rf .git && rm -r angular-seed-app && pwd`, + { + silent: true, + } + ); + return resolve(); + }); +} + export async function setupNpmProject(folderPath) { return new Promise(async (resolve, _) => { const isExistingProject = await inExistingProject(folderPath); From df715c3bdcd2680dbcad9c35c684e9b63121e900 Mon Sep 17 00:00:00 2001 From: Krishna Acondy Date: Tue, 11 Aug 2020 20:45:04 +0100 Subject: [PATCH 3/5] feat(create-web-app): implement creation of React, Angular and minimal web apps with the -t option --- src/cli.js | 35 ++++++++++++++++++++++++- src/sasjs-create/index.js | 55 ++++++++++++++++++++++----------------- src/utils/utils.js | 53 +++++++++++++++++++++++-------------- 3 files changed, 99 insertions(+), 44 deletions(-) diff --git a/src/cli.js b/src/cli.js index 484762cd3..fed79509b 100644 --- a/src/cli.js +++ b/src/cli.js @@ -16,6 +16,7 @@ import { import { fileExists } from "./utils/file-utils"; import path from "path"; import chalk from "chalk"; +import { exit } from "process"; function parseCommand(rawArgs) { checkNodeVersion(); @@ -140,7 +141,7 @@ export async function cli(args) { switch (command.name) { case "create": const projectName = command.parameters[1]; - const appType = (command.parameters[2] || "").replace("--", ""); + const appType = processCreateParameters(command.parameters); await createFileStructure(projectName, appType); break; case "compile": @@ -260,3 +261,35 @@ function processRunParameters(parameters) { targetName: parameters.length === 3 ? parameters[2] : "default", }; } + +function processCreateParameters(parameters) { + const supportedTypes = ["react", "angular", "minimal"]; + let type = ""; + if (parameters.length > 2 && parameters[2] !== "-t") { + console.error( + chalk.redBright( + `Invalid usage.\nCorrect syntax is ${chalk.cyanBright( + "sasjs create -t " + )}.` + ) + ); + exit(1); + } + + if (parameters.length !== 4) { + return type; + } + type = parameters[3].trim(); + if (!supportedTypes.includes(type)) { + console.error( + chalk.redBright( + `Invalid web app type.\nSupported types are ${chalk.cyanBright( + "angular" + )}, ${chalk.cyanBright("react")} and ${chalk.cyanBright("minimal")}.` + ) + ); + exit(1); + } + + return type; +} diff --git a/src/sasjs-create/index.js b/src/sasjs-create/index.js index 931f569a4..15932f1ee 100644 --- a/src/sasjs-create/index.js +++ b/src/sasjs-create/index.js @@ -6,6 +6,7 @@ import { asyncForEach, createReactApp, createAngularApp, + createMinimalApp, } from "../utils/utils"; import { getFolders, getConfiguration } from "../utils/config-utils"; import { @@ -28,32 +29,38 @@ export async function create(parentFolderName = ".", appType = "") { await createReactApp(path.join(process.projectDir, parentFolderName)); } else if (appType === "angular") { await createAngularApp(path.join(process.projectDir, parentFolderName)); + } else if (appType === "minimal") { + await createMinimalApp(path.join(process.projectDir, parentFolderName)); + } else { + await asyncForEach(fileStructure, async (folder, index) => { + const pathExists = await fileExists( + path.join(process.projectDir, parentFolderName, folder.folderName) + ); + if (pathExists) { + throw new Error( + `${chalk.redBright( + `The folder ${chalk.cyanBright( + folder.folderName + )} already exists! Please remove any unnecessary files and try again.` + )}` + ); + } + await createFolderStructure(folder, parentFolderName); + if (index === 0) { + const configDestinationPath = path.join( + process.projectDir, + parentFolderName, + folder.folderName, + "sasjsconfig.json" + ); + await createFile( + configDestinationPath, + JSON.stringify(config, null, 1) + ); + } + }); } - await asyncForEach(fileStructure, async (folder, index) => { - const pathExists = await fileExists( - path.join(process.projectDir, parentFolderName, folder.folderName) - ); - if (pathExists) { - throw new Error( - `${chalk.redBright( - `The folder ${chalk.cyanBright( - folder.folderName - )} already exists! Please remove any unnecessary files and try again.` - )}` - ); - } - await createFolderStructure(folder, parentFolderName); - if (index === 0) { - const configDestinationPath = path.join( - process.projectDir, - parentFolderName, - folder.folderName, - "sasjsconfig.json" - ); - await createFile(configDestinationPath, JSON.stringify(config, null, 1)); - } - }); if (!appType) { await setupNpmProject(parentFolderName); } diff --git a/src/utils/utils.js b/src/utils/utils.js index f95be55e6..bc375529b 100644 --- a/src/utils/utils.js +++ b/src/utils/utils.js @@ -1,6 +1,7 @@ import shelljs from "shelljs"; import chalk from "chalk"; import path from "path"; +import ora from "ora"; import { fileExists, createFile, readFile } from "./file-utils"; import { getLocalRcFile } from "./config-utils"; @@ -17,34 +18,48 @@ export function diff(x, y) { export async function createReactApp(folderPath) { return new Promise(async (resolve, _) => { - console.log( - chalk.greenBright("Creating React app in", chalk.cyanBright(folderPath)) - ); - shelljs.exec( - `cd ${folderPath} && git clone https://github.com/sasjs/react-seed-app.git && mv react-seed-app/{.,}* . && rm -rf .git && rm -rf react-seed-app`, - { - silent: true, - } - ); + createApp(folderPath, "https://github.com/sasjs/react-seed-app.git"); return resolve(); }); } export async function createAngularApp(folderPath) { return new Promise(async (resolve, _) => { - console.log( - chalk.greenBright("Creating Angular app in", chalk.cyanBright(folderPath)) - ); - shelljs.exec( - `cd ${folderPath} && git clone https://github.com/sasjs/angular-seed-app.git && mv angular-seed-app/{.,}* . && rm -rf .git && rm -r angular-seed-app && pwd`, - { - silent: true, - } + createApp(folderPath, "https://github.com/sasjs/angular-seed-app.git"); + return resolve(); + }); +} + +export async function createMinimalApp(folderPath) { + return new Promise(async (resolve, _) => { + createApp( + folderPath, + "https://github.com/sasjs/minimal-seed-app.git", + false ); return resolve(); }); } +function createApp(folderPath, repoUrl, installDependencies = true) { + const spinner = ora( + chalk.greenBright("Creating web app in", chalk.cyanBright(folderPath)) + ); + spinner.start(); + shelljs.exec(`cd ${folderPath} && git clone ${repoUrl} . && rm -rf .git`, { + silent: true, + }); + spinner.stop(); + if (installDependencies) { + spinner.text = chalk.greenBright("Installing dependencies..."); + spinner.start(); + shelljs.exec(`cd ${folderPath} && npm install`, { + silent: true, + }); + spinner.stop(); + } +} + export async function setupNpmProject(folderPath) { return new Promise(async (resolve, _) => { const isExistingProject = await inExistingProject(folderPath); @@ -79,13 +94,13 @@ export async function setupGitIgnore(folderPath) { if (gitIgnoreExists) { const gitIgnoreContent = await readFile(gitIgnoreFilePath); await createFile(gitIgnoreFilePath, `${gitIgnoreContent}\nsasjsbuild/\n`); - console.log(chalk.greenBright("Existing .gitignore is updated.")); + console.log(chalk.greenBright("Existing .gitignore has been updated.")); } else { shelljs.exec(`cd ${folderPath} && git init`, { silent: true, }); await createFile(gitIgnoreFilePath, "node_modules/\nsasjsbuild/\n.env\n"); - console.log(chalk.greenBright("Created .gitignore file.")); + console.log(chalk.greenBright(".gitignore file has been created.")); } } From d6ecae7a2d26db5cf43a43fbfd6d7dae0f5f80f1 Mon Sep 17 00:00:00 2001 From: Krishna Acondy Date: Tue, 11 Aug 2020 20:52:56 +0100 Subject: [PATCH 4/5] chore(create-web-app): update help text --- src/sasjs-help/index.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/sasjs-help/index.js b/src/sasjs-help/index.js index 8b8dbeb92..df1599a63 100644 --- a/src/sasjs-help/index.js +++ b/src/sasjs-help/index.js @@ -11,6 +11,12 @@ export async function printHelpText() { e.g. sasjs create my-sas-project - if no foldername is specified, it creates the folder structure in the current working directory. - If this is an existing NPM project, it will update package.json with the @sasjs/core dependency. + - An additional option can be specified to create a web app from a template. + This supports creation of Angular, React and minimal web apps. + e.g. ${chalk.cyanBright( + "sasjs create my-sas-project --template react" + )} + ${chalk.cyanBright("sasjs create my-sas-project -t angular")} * ${chalk.greenBright("help")} - displays this help text * ${chalk.greenBright("version")} - displays currenlty installed version * ${chalk.greenBright( From a4efadb4a1f2af9132e4159f80a72862b5bdf9f8 Mon Sep 17 00:00:00 2001 From: Krishna Acondy Date: Tue, 11 Aug 2020 20:53:26 +0100 Subject: [PATCH 5/5] feat(create-web-app): add --template alias for templated web app creation --- src/cli.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/cli.js b/src/cli.js index fed79509b..40b8e40c4 100644 --- a/src/cli.js +++ b/src/cli.js @@ -265,11 +265,16 @@ function processRunParameters(parameters) { function processCreateParameters(parameters) { const supportedTypes = ["react", "angular", "minimal"]; let type = ""; - if (parameters.length > 2 && parameters[2] !== "-t") { + if ( + parameters.length > 2 && + !(parameters[2] === "-t" || parameters[2] === "--template") + ) { console.error( chalk.redBright( `Invalid usage.\nCorrect syntax is ${chalk.cyanBright( "sasjs create -t " + )} or ${chalk.cyanBright( + "sasjs create --template " )}.` ) );