Skip to content

Commit

Permalink
Merge pull request #26 from amoskyalo/amos/projectInit
Browse files Browse the repository at this point in the history
Feat: Added ability to choose preferred architecture.
  • Loading branch information
amoskyalo authored Mar 5, 2024
2 parents c02da8a + 1558a12 commit a5358df
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 18 deletions.
54 changes: 54 additions & 0 deletions commands/monorepoInit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
const { spawn } = require('child_process');
const { join } = require('path');
const { logger } = require('../utils/logger');
const { mkdir, writeFile } = require('fs').promises;

const lernaJsonContent = `{
"$schema": "node_modules/lerna/schemas/lerna-schema.json",
"version": "0.1.0",
"npmClient": "yarn"
}`

function monorepoInit(monorepoName, next) {
logger.info("Setting your project with lerna init...");

async function createMonorepoApp() {
try {
await mkdir(monorepoName);
} catch (error) {
throw new Error(error);
}
}

Promise.all([createMonorepoApp()]).then(() => {
process.chdir(monorepoName);

const lerna_child_process = spawn('lerna', ['init'], { shell: true, stdio: 'inherit' });

lerna_child_process.on('close', async () => {
async function createPackagesFolder() {
try {
await mkdir(join(process.cwd(), "packages"));
} catch (error) {
throw error;
}
}

async function updateLernaJson() {
try {
await writeFile(join(process.cwd(), "lerna.json"), lernaJsonContent);
} catch (error) {
throw error;
}
}

Promise.all([createPackagesFolder(), updateLernaJson()]).then(() => {
process.chdir('packages');

next();
}).catch((error) => { throw error });
})
}).catch((error) => { throw error });
};

module.exports = monorepoInit;
15 changes: 12 additions & 3 deletions commands/projectInit.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const ComponentGenerator = require('../utils/getComponentTemplate');
// 4. Install material UI, and material UI icons;
// 5. Create components folder and install all components;

async function projectInit(appName, installAll) {
async function projectInit(appName, installAll, architecture) {
// exec('node -v', (error, stdout, stderr) => {
// if (error) {
// console.log(error);
Expand Down Expand Up @@ -43,9 +43,18 @@ async function projectInit(appName, installAll) {
// })
// });

function getCommand() {
switch (architecture) {
case 'mono-repo': return { command: "yarn", args: ["create", "react-app", appName] };
default: return { command: "npx", args: ["create-react-app", appName] }
}
}

const { command, args } = getCommand();

logger.success("\nSetting up react project...")

const child = spawn('npx', ['create-react-app', appName], { shell: true, stdio: 'inherit' });
const child = spawn(command, args, { shell: true, stdio: 'inherit' });

child.on("error", error => {
throw new Error(error);
Expand All @@ -57,7 +66,7 @@ async function projectInit(appName, installAll) {
try {
process.chdir(appName);

runInstall(getPackageManager(), async () => {
runInstall(architecture === "mono-repo" ? "yarn" : getPackageManager(), async () => {
const answers = installAll ?
componentChoices.map(c => c.value) :
await checkbox({
Expand Down
71 changes: 62 additions & 9 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
#!/usr/bin/env node

const { exec } = require('child_process')
const { program } = require('commander');
const { getPackageManager } = require('./utils/getPackageManager');
const { logger } = require('./utils/logger');
const { select, confirm, input } = require('@inquirer/prompts');
const CLI = require('clui');
const boxen = require('boxen');
const themeInit = require('./commands/themeInit');
const validateMUI = require('./utils/validateMaterial');
const validateTheme = require('./commands/validateTheme');
const projectInit = require('./commands/projectInit');
const monorepoInit = require('./commands/monorepoInit');
const installComponent = require('./commands/installComponent');

Spinner = CLI.Spinner;

const lerna_spinner = new Spinner('Installing lerna... ', ['⣾', '⣽', '⣻', '⢿', '⡿', '⣟', '⣯', '⣷']);

program.version("0.0.1").description("Material UI CLI");

// generate theme template
Expand Down Expand Up @@ -36,11 +45,16 @@ program
.option('--ignore-warn [string], ignore warning in theme')
.action(options => validateMUI(() => validateTheme(options)));

// install single component to existing project.
program.command('install component')
.description('Install a Material-UI component')
.action(() => validateMUI(() => installComponent()));

// initialize new project.
program.command('project-init')
.option('-a, --all, Install all components')
.description("Create a new react project")
.action((options) => {
.action(async (options) => {
const appName = process.argv[3];

if (!appName) {
Expand All @@ -49,16 +63,55 @@ program.command('project-init')
process.exit(1);
}

projectInit(appName, options.all || false);
});
const tool = await select({
message: "Choose your preferred tool for your project:",
choices: [
{ name: "CRA", value: "cra" },
{ name: "Vite", value: "vite" },
{ name: "Next.js", value: "next.js" }
]
});

program.command('install component')
.description('Install a Material-UI component')
.action(() => {
validateMUI(() => installComponent());
});
const architecture = await select({
message: "Choose your preferred project architecture:",
choices: [
{ name: "Monorepo", value: "mono-repo" },
{ name: "Polyrepo", value: "poly-repo" }
]
});

if (architecture === "mono-repo") {
logger.info(boxen(`Since you've chosen a monorepo setup, we'll use Lerna to manage our packages. Lerna is ideal for monorepo management, simplifying tasks like versioning and publishing. Check out the docs: https://lerna.js.org/docs/getting-started`, { padding: 1 }))

const monorepoName = await input({ message: "Enter your monorepo app name" });

program.command("package").action(() => console.log(getPackageManager()));
const useWorkspaces = await confirm({ message: "Would you like to integrate Yarn Workspaces with Lerna for better dependency management?" });

if (useWorkspaces) {
exec("lerna --version", async (error, stdout, stderr) => {
if (error && error.message.includes("'lerna' is not recognized")) {
const installLerna = await confirm({ message: "Lerna could not be found in your machine. Would you like to install it?" });
if (installLerna) {
lerna_spinner.start();
exec('npm install -g lerna', (error, stdout, stderr) => {
if (error) {
throw new Error(error);
}

logger.info(stdout);
lerna_spinner.stop();

monorepoInit(monorepoName, () => projectInit(appName, options.all || false, architecture));
})
}
}

monorepoInit(monorepoName, () => projectInit(appName, options.all || false, architecture));
})
}
} else {
projectInit(appName, options.all || false, architecture);
}
});

program.parse(process.argv);
2 changes: 1 addition & 1 deletion utils/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const componentsCategories = ["Inputs", "DataDisplay", "Feedback", "Surfaces", "
const installMUICommand = "@mui/icons-material @mui/material @emotion/styled @emotion/react";

const componentChoices = [
{ name: "App Bar", value: { name: "AppBar", category: "Surfaces" } },
{ name: "App Bar", value: { name: "AppBar", category: "Inputs" } },
{ name: "AutoComplete", value: { name: "AutoComplete", category: "Inputs" } },
{ name: "Data Grid", value: { name: "DataGrid", category: "DataDisplay" } },
{ name: "Dates", value: { name: "Dates", category: "Inputs" } },
Expand Down
10 changes: 5 additions & 5 deletions utils/getComponentTemplate.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class ComponentGenerator {
const appCSSPath = path.join(process.cwd(), "src", "App.css");

const createComponentsDir = async () => {
async function createCategory(category){
async function createCategory(category) {
const categoryPath = path.join(componentsPath, category);
try {
await mkdir(categoryPath, { recursive: true });
Expand All @@ -33,7 +33,7 @@ class ComponentGenerator {
}
}

const createComponentTemplate = async (name, category) =>{
const createComponentTemplate = async (name, category) => {
const categoryPath = path.join(componentsPath, category);
const templatePath = this.getComponentTemplate(name, category);
const filesPath = path.join(categoryPath, `${name}.jsx`);
Expand Down Expand Up @@ -63,7 +63,7 @@ class ComponentGenerator {
await mkdir(themePath);
themeInit({}, false);
} catch (error) {
throw new Error(error);
throw error
}
}

Expand All @@ -72,7 +72,7 @@ class ComponentGenerator {
try {
await writeFile(appJsEntryPath, getEntryPointContents())
} catch (error) {
throw new Error(error);
throw error
}
}

Expand All @@ -81,7 +81,7 @@ class ComponentGenerator {
try {
await writeFile(appCSSPath, getAppCssContents());
} catch (error) {
throw new Error(error);
throw error
}
}

Expand Down

0 comments on commit a5358df

Please sign in to comment.