Skip to content

Commit

Permalink
feat: improve glee command (#890)
Browse files Browse the repository at this point in the history
Co-authored-by: AyushNautiyalDeveloper <[email protected]>%0ACo-authored-by: ayush-coder-hai <[email protected]>%0ACo-authored-by: souvik <[email protected]>
  • Loading branch information
ayushnau and Souvikns authored Feb 1, 2024
1 parent 5b6d532 commit 6cfd356
Showing 1 changed file with 218 additions and 26 deletions.
244 changes: 218 additions & 26 deletions src/commands/new/glee.ts
Original file line number Diff line number Diff line change
@@ -1,55 +1,247 @@
import {Flags} from '@oclif/core';
import { Flags } from '@oclif/core';
import { promises as fPromises } from 'fs';
import Command from '../../base';
import { resolve, join } from 'path';
import path, { resolve, join } from 'path';
import fs from 'fs-extra';
import { Specification, load } from '../../models/SpecificationFile';
import yaml from 'js-yaml';
import { prompt } from 'inquirer';
// eslint-disable-next-line
// @ts-ignore
import Generator from '@asyncapi/generator';

export default class NewGlee extends Command {
static description = 'Creates a new Glee project';

protected commandName = 'glee';

static flags = {
help: Flags.help({ char: 'h' }),
name: Flags.string({ char: 'n', description: 'name of the project', default: 'project' }),
template: Flags.string({ char: 't', description: 'name of the template', default: 'default' }),
name: Flags.string({
char: 'n',
description: 'Name of the Project',
default: 'project',
}),
template: Flags.string({
char: 't',
description: 'Name of the Template',
default: 'default',
}),
file: Flags.string({
char: 'f',
description:
'The path to the AsyncAPI file for generating a Glee project.',
}),
'force-write': Flags.boolean({
default: false,
description:
'Force writing of the generated files to given directory even if it is a git repo with unstaged files or not empty dir (defaults to false)',
}),
};

async run() {
const { flags } = await this.parse(NewGlee); // NOSONAR
async getFilteredServers(serversObject: any) {
console.log({ serversObject });
const servers = Object.keys(serversObject);

const projectName = flags.name;
const templateName = flags.template;
const localServers = await prompt([
{
name: 'LOCAL_SERVERS',
message:
'Select all of the servers that you want glee to set up and run a server for (local servers):',
type: 'checkbox',
choices() {
return servers;
},
},
]);

const PROJECT_DIRECTORY = join(process.cwd(), projectName);
const GLEE_TEMPLATES_DIRECTORY = resolve(__dirname, '../../../assets/create-glee-app/templates/', templateName);
return servers.filter(
(server) => !localServers.LOCAL_SERVERS.includes(server)
);
}
async createTemporaryFile(
asyncapiInput: Specification,
filteredRemoteServers: string[],
file: any
) {
const asyncapiObject = asyncapiInput.toJson();
asyncapiObject['x-remoteServers'] = filteredRemoteServers;

delete asyncapiObject.filePath;
delete asyncapiObject.kind;

const updatedAsyncApiContent = yaml.dump(asyncapiObject, {
lineWidth: -1,
});

const currentFileDirectory = path.join(__dirname, file);

fs.writeFileSync(currentFileDirectory, updatedAsyncApiContent);
return { currentFileDirectory, updatedAsyncApiContent };
}
async validateFile(file: any, projectName: any, PROJECT_DIRECTORY: any) {
try {
await fPromises.mkdir(PROJECT_DIRECTORY);
const validExtensions = ['.yaml', '.yml', '.json'];
const fileExtension = path.extname(file);

if (!validExtensions.includes(fileExtension)) {
throw new Error(
'CLI Support only yml, yaml, and json extension for file'
);
}

if (
fs.existsSync(PROJECT_DIRECTORY) &&
fs.readdirSync(PROJECT_DIRECTORY).length > 0
) {
throw new Error(
`Unable to create the project. We tried to use "${projectName}" as the directory of your new project but it already exists (${PROJECT_DIRECTORY}). Please specify a different name for the new project. For example, run the following command instead:\n\n asyncapi new ${this.commandName} -f ${file} --name ${projectName}-1\n`
);
}
} catch (error: any) {
this.error(error.message);
}
}

async handleGenerateProjectWithFile(
file: any,
CURRENT_GLEE_TEMPLATE: any,
projectName: string,
forceWrite: boolean
) {
const PROJECT_DIRECTORY = path.join(process.cwd(), projectName);
await this.validateFile(file, projectName, PROJECT_DIRECTORY);

try {
console.log(file);
const asyncapiInput = (await load(file)) || (await load());
console.log(asyncapiInput);

const serversObject = asyncapiInput.toJson()?.servers;
let filteredRemoteServers: any[] = [];
if (serversObject) {
filteredRemoteServers = await this.getFilteredServers(serversObject);
}

const temporaryFileDirectory = 'asyncapi.yaml';
const { currentFileDirectory, updatedAsyncApiContent } =
await this.createTemporaryFile(
asyncapiInput,
filteredRemoteServers,
temporaryFileDirectory
);

const generator = new Generator(
CURRENT_GLEE_TEMPLATE,
PROJECT_DIRECTORY,
{ forceWrite }
);
await generator.generateFromString(updatedAsyncApiContent);
fs.unlinkSync(currentFileDirectory);

this.log(
`Success! Created ${projectName} at ${PROJECT_DIRECTORY}\n\nNext steps:\n\n cd ${projectName}\n npm install --ignore-scripts\n\nImplement the function in functions and auth folder and run the project with:\n npm run dev`
);
} catch (err: any) {
switch (err.code) {
case 'EEXIST':
this.error(`Unable to create the project. We tried to use "${projectName}" as the directory of your new project but it already exists (${PROJECT_DIRECTORY}). Please specify a different name for the new project. For example, run the following command instead:\n\n asyncapi new ${this.commandName} --name ${projectName}-1\n`);
break;
case 'EACCES':
this.error(`Unable to create the project. We tried to access the "${PROJECT_DIRECTORY}" directory but it was not possible due to file access permissions. Please check the write permissions of your current working directory ("${process.cwd()}").`);
this.error(
`Unable to create the project. We tried to access the "${PROJECT_DIRECTORY}" directory but it was not possible due to file access permissions. Please check the write permissions of your current working directory ("${process.cwd()}").`
);
break;
case 'EPERM':
this.error(`Unable to create the project. We tried to create the "${PROJECT_DIRECTORY}" directory but the operation requires elevated privileges. Please check the privileges for your current user.`);
this.error(
`Unable to create the project. We tried to create the "${PROJECT_DIRECTORY}" directory but the operation requires elevated privileges. Please check the privileges for your current user.`
);
break;
default:
this.error(`Unable to create the project. Please check the following message for further info about the error:\n\n${err}`);
this.error(
`Unable to create the project. Please check the following message for further info about the error:\n\n${err}`
);
}
}
}
async run() {
const { flags } = await this.parse(NewGlee); // NOSONAR

try {
await fs.copy(GLEE_TEMPLATES_DIRECTORY, PROJECT_DIRECTORY);
await fPromises.rename(`${PROJECT_DIRECTORY}/env`, `${PROJECT_DIRECTORY}/.env`);
await fPromises.rename(`${PROJECT_DIRECTORY}/gitignore`, `${PROJECT_DIRECTORY}/.gitignore`);
await fPromises.rename(`${PROJECT_DIRECTORY}/README-template.md`, `${PROJECT_DIRECTORY}/README.md`);
this.log(`Your project "${projectName}" has been created successfully!\n\nNext steps:\n\n cd ${projectName}\n npm install\n npm run dev\n\nAlso, you can already open the project in your favorite editor and start tweaking it.`);
} catch (err) {
this.error(`Unable to create the project. Please check the following message for further info about the error:\n\n${err}`);
const {
name: projectName,
template: templateName,
file,
'force-write': forceWrite,
} = flags;

const PROJECT_DIRECTORY = join(process.cwd(), projectName);

const GLEE_TEMPLATES_DIRECTORY = resolve(
__dirname,
'../../../assets/create-glee-app/templates/',
templateName
);

const CURRENT_GLEE_TEMPLATE =
'https://github.com/KhudaDad414/glee-generator-template';

if (file && templateName && templateName !== 'default') {
this.error('You cannot use both --t and --f in the same command.');
}

if (file) {
console.log('file running');
await this.handleGenerateProjectWithFile(
file,
CURRENT_GLEE_TEMPLATE,
projectName,
forceWrite
);
} else {
try {
await fPromises.mkdir(PROJECT_DIRECTORY);
} catch (err: any) {
switch (err.code) {
case 'EEXIST':
this.error(
`Unable to create the project. We tried to use "${projectName}" as the directory of your new project but it already exists (${PROJECT_DIRECTORY}). Please specify a different name for the new project. For example, run the following command instead:\n\n asyncapi new ${this.commandName} --name ${projectName}-1\n`
);
break;
case 'EACCES':
this.error(
`Unable to create the project. We tried to access the "${PROJECT_DIRECTORY}" directory but it was not possible due to file access permissions. Please check the write permissions of your current working directory ("${process.cwd()}").`
);
break;
case 'EPERM':
this.error(
`Unable to create the project. We tried to create the "${PROJECT_DIRECTORY}" directory but the operation requires elevated privileges. Please check the privileges for your current user.`
);
break;
default:
this.error(
`Unable to create the project. Please check the following message for further info about the error:\n\n${err}`
);
}
}

try {
await fs.copy(GLEE_TEMPLATES_DIRECTORY, PROJECT_DIRECTORY);
await fPromises.rename(
`${PROJECT_DIRECTORY}/env`,
`${PROJECT_DIRECTORY}/.env`
);
await fPromises.rename(
`${PROJECT_DIRECTORY}/gitignore`,
`${PROJECT_DIRECTORY}/.gitignore`
);
await fPromises.rename(
`${PROJECT_DIRECTORY}/README-template.md`,
`${PROJECT_DIRECTORY}/README.md`
);
this.log(
`Your project "${projectName}" has been created successfully!\n\nNext steps:\n\n cd ${projectName}\n npm install\n npm run dev\n\nAlso, you can already open the project in your favorite editor and start tweaking it.`
);
} catch (err) {
this.error(
`Unable to create the project. Please check the following message for further info about the error:\n\n${err}`
);
}
}
}
}

0 comments on commit 6cfd356

Please sign in to comment.