Skip to content

Commit

Permalink
Merge pull request #11 from sasjs/create-web-app
Browse files Browse the repository at this point in the history
feat(create-web-apps): Add the ability to create web apps via the CLI
  • Loading branch information
krishna-acondy authored Aug 18, 2020
2 parents 325eff3 + a164fa4 commit a4a5280
Show file tree
Hide file tree
Showing 5 changed files with 155 additions and 43 deletions.
64 changes: 52 additions & 12 deletions src/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -26,7 +27,7 @@ function parseCommand(rawArgs) {
const parameters = processRunParameters(args.slice(1));
return { name, parameters };
}
return { name, parameters: args[1] };
return { name, parameters: args };
}
return null;
}
Expand Down Expand Up @@ -139,25 +140,27 @@ export async function cli(args) {
}
switch (command.name) {
case "create":
await createFileStructure(command.parameters);
const projectName = command.parameters[1];
const appType = processCreateParameters(command.parameters);
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();
Expand All @@ -166,16 +169,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:
Expand Down Expand Up @@ -258,3 +261,40 @@ 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" || parameters[2] === "--template")
) {
console.error(
chalk.redBright(
`Invalid usage.\nCorrect syntax is ${chalk.cyanBright(
"sasjs create <app-name> -t <app-type>"
)} or ${chalk.cyanBright(
"sasjs create <app-name> --template <app-type>"
)}.`
)
);
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;
}
4 changes: 2 additions & 2 deletions src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
72 changes: 45 additions & 27 deletions src/sasjs-create/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,49 +3,67 @@ import path from "path";
import {
setupNpmProject,
setupGitIgnore,
asyncForEach
asyncForEach,
createReactApp,
createAngularApp,
createMinimalApp,
} 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));
}
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"

if (appType === "react") {
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)
);
await createFile(configDestinationPath, JSON.stringify(config, null, 1));
}
});
await setupNpmProject(parentFolderName);
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);
}
await setupGitIgnore(parentFolderName);
}

Expand Down
6 changes: 6 additions & 0 deletions src/sasjs-help/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
52 changes: 50 additions & 2 deletions src/utils/utils.js
Original file line number Diff line number Diff line change
@@ -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";

Expand All @@ -15,6 +16,50 @@ export function diff(x, y) {
return x.filter((a) => !y.includes(a));
}

export async function createReactApp(folderPath) {
return new Promise(async (resolve, _) => {
createApp(folderPath, "https://github.com/sasjs/react-seed-app.git");
return resolve();
});
}

export async function createAngularApp(folderPath) {
return new Promise(async (resolve, _) => {
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);
Expand Down Expand Up @@ -49,10 +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."));
}
}

Expand Down

0 comments on commit a4a5280

Please sign in to comment.