diff --git a/src/commands/plugin/index.ts b/src/commands/plugin/index.ts index f7fec39..b157174 100644 --- a/src/commands/plugin/index.ts +++ b/src/commands/plugin/index.ts @@ -14,34 +14,36 @@ import * as yaml from "js-yaml"; import { cwd } from "process"; import chalk from "chalk"; import ora from "ora"; +import { spawn } from "child_process"; // Load the plugins list from JSON file - const pluginsFilePath = path.resolve(__dirname, '../../../pluginsList.json'); - if (!fs.existsSync(pluginsFilePath)) { - console.error("Error: pluginsList.json file not found!"); - process.exit(1); - } - const pluginsData = fs.readFileSync(pluginsFilePath, { encoding: "utf-8" }); - const availablePlugins = JSON.parse(pluginsData); - - // or Search the plugins list from npm - // const command = "npm search @godspeedsystems/plugins --json"; - // const stdout = execSync(command, { encoding: "utf-8" }); - // const availablePlugins = JSON.parse(stdout.trim()); - - // Map to the format expected by the UI - const pluginNames = availablePlugins.map((plugin: { value: string; name: string; description: string }) => ({ - value: plugin.value, - Name: plugin.name.split("plugins-")[1], - Description: plugin.description, - })); +const pluginsFilePath = path.resolve(__dirname, "../../../pluginsList.json"); +if (!fs.existsSync(pluginsFilePath)) { + console.error("Error: pluginsList.json file not found!"); + process.exit(1); +} +const pluginsData = fs.readFileSync(pluginsFilePath, { encoding: "utf-8" }); +const availablePlugins = JSON.parse(pluginsData); + +// or Search the plugins list from npm +// const command = "npm search @godspeedsystems/plugins --json"; +// const stdout = execSync(command, { encoding: "utf-8" }); +// const availablePlugins = JSON.parse(stdout.trim()); + +// Map to the format expected by the UI +const pluginNames = availablePlugins.map( + (plugin: { value: string; name: string; description: string }) => ({ + value: plugin.value, + Name: plugin.name.split("plugins-")[1], + Description: plugin.description, + }) +); const program = new Command(); type ModuleType = "DS" | "ES" | "BOTH"; const addAction = async (pluginsList: string[]) => { - // install that package const spinner = ora({ text: "Installing plugins... ", spinner: { @@ -54,177 +56,120 @@ const addAction = async (pluginsList: string[]) => { try { spinner.start(); - // Use spawnCommand instead of spawnSync - const child = spawnSync( - "npm", - [ - "install", - ...pluginsList, - "--quiet", - "--no-warnings", - "--silent", - "--progress=false", - ], - { - stdio: "inherit", // Redirect output - } - ); + const child = spawn("pnpm", ["add", ...pluginsList, "--silent"], { + stdio: "inherit", + }); - await new Promise((resolve) => { - child.on("close", () => { - resolve(); + await new Promise((resolve, reject) => { + child.on("close", (code) => { + if (code === 0) resolve(); + else reject(new Error(`pnpm install failed with code ${code}`)); }); }); - spinner.stop(); // Stop the spinner when the installation is complete - console.log("\nPlugins installed successfully!"); + spinner.succeed("Plugins installed successfully!"); console.log(chalk.cyan.bold("Happy coding with Godspeed! šŸš€šŸŽ‰\n")); } catch (error: any) { - spinner.stop(); // Stop the spinner in case of an error + spinner.fail("Failed to install plugins."); console.error("Error during installation:", error.message); } } - // Call the installPlugin function + // Install plugins before proceeding await installPlugin(pluginsList); - pluginsList.map(async (pluginName: string) => { - try { - const Module = await import( - path.join(process.cwd(), "node_modules", pluginName) - ); + await Promise.all( + pluginsList.map(async (pluginName) => { + try { + const Module = await import( + path.join(process.cwd(), "node_modules", pluginName) + ); - let moduleType = Module.SourceType as ModuleType; - let loaderFileName = Module.Type as string; - let yamlFileName = Module.CONFIG_FILE_NAME as string; - let defaultConfig = Module.DEFAULT_CONFIG || ({} as PlainObject); + let moduleType = Module.SourceType; + let loaderFileName = Module.Type as string; + let yamlFileName = Module.CONFIG_FILE_NAME as string; + let defaultConfig = Module.DEFAULT_CONFIG || {}; - switch (moduleType) { - case "BOTH": - { - mkdirSync( - path.join(process.cwd(), "src", "eventsources", "types"), - { - recursive: true, - } + switch (moduleType) { + case "BOTH": { + const eventSourcePath = path.join( + process.cwd(), + "src", + "eventsources" + ); + const dataSourcePath = path.join( + process.cwd(), + "src", + "datasources" ); - mkdirSync(path.join(process.cwd(), "src", "datasources", "types"), { - recursive: true, - }); + + mkdirSync(path.join(eventSourcePath, "types"), { recursive: true }); + mkdirSync(path.join(dataSourcePath, "types"), { recursive: true }); writeFileSync( - path.join( - process.cwd(), - "src", - "eventsources", - "types", - `${loaderFileName}.ts` - ), - ` - import { EventSource } from '${pluginName}'; - export default EventSource; - ` + path.join(eventSourcePath, "types", `${loaderFileName}.ts`), + `import { EventSource } from '${pluginName}';\nexport default EventSource;` ); writeFileSync( - path.join( - process.cwd(), - "src", - "eventsources", - `${yamlFileName}.yaml` - ), + path.join(eventSourcePath, `${yamlFileName}.yaml`), yaml.dump({ type: loaderFileName, ...defaultConfig }) ); writeFileSync( - path.join( - process.cwd(), - "src", - "datasources", - "types", - `${loaderFileName}.ts` - ), - ` - import { DataSource } from '${pluginName}'; - export default DataSource; - ` + path.join(dataSourcePath, "types", `${loaderFileName}.ts`), + `import { DataSource } from '${pluginName}';\nexport default DataSource;` ); writeFileSync( - path.join( - process.cwd(), - "src", - "datasources", - `${yamlFileName}.yaml` - ), + path.join(dataSourcePath, `${yamlFileName}.yaml`), yaml.dump({ type: loaderFileName, ...defaultConfig }) ); + break; } - break; - case "DS": - { - mkdirSync(path.join(process.cwd(), "src", "datasources", "types"), { - recursive: true, - }); + case "DS": { + const dataSourcePath = path.join( + process.cwd(), + "src", + "datasources" + ); + mkdirSync(path.join(dataSourcePath, "types"), { recursive: true }); + writeFileSync( - path.join( - process.cwd(), - "src", - "datasources", - "types", - `${loaderFileName}.ts` - ), - ` - import { DataSource } from '${pluginName}'; - export default DataSource; - ` + path.join(dataSourcePath, "types", `${loaderFileName}.ts`), + `import { DataSource } from '${pluginName}';\nexport default DataSource;` ); - // special case for prisma for now - // @ts-ignore + if (Module.Type !== "prisma") { writeFileSync( - path.join( - process.cwd(), - "src", - "datasources", - `${yamlFileName}.yaml` - ), + path.join(dataSourcePath, `${yamlFileName}.yaml`), yaml.dump({ type: loaderFileName, ...defaultConfig }) ); } + break; } - break; - case "ES": { - mkdirSync(path.join(process.cwd(), "src", "eventsources", "types"), { - recursive: true, - }); - writeFileSync( - path.join( - process.cwd(), - "src", - "eventsources", - "types", - `${loaderFileName}.ts` - ), - ` - import { EventSource } from '${pluginName}'; - export default EventSource; - ` - ); - writeFileSync( - path.join( + case "ES": { + const eventSourcePath = path.join( process.cwd(), "src", - "eventsources", - `${yamlFileName}.yaml` - ), - yaml.dump({ type: loaderFileName, ...defaultConfig }) - ); + "eventsources" + ); + mkdirSync(path.join(eventSourcePath, "types"), { recursive: true }); + + writeFileSync( + path.join(eventSourcePath, "types", `${loaderFileName}.ts`), + `import { EventSource } from '${pluginName}';\nexport default EventSource;` + ); + writeFileSync( + path.join(eventSourcePath, `${yamlFileName}.yaml`), + yaml.dump({ type: loaderFileName, ...defaultConfig }) + ); + break; + } } + } catch (error) { + console.error(`Unable to import module '${pluginName}':`, error); } - } catch (error) { - console.error("unable to import the module.", error); - } - }); - // create folder for eventsource or datasource respective file + }) + ); }; const add = program @@ -245,7 +190,7 @@ const add = program const missingPlugins = pluginNames.filter( (plugin: { value: string | number }) => !localpluginsList[plugin.value] ); - + if (!givenPluginName) { if (pluginNames.length === 0) { console.error("No plugins found."); @@ -330,34 +275,26 @@ const removeAction = async (pluginsList: string[]) => { try { spinner.start(); - // Use spawnCommand instead of spawnSync - const child = spawnSync( - "npm", - [ - "uninstall", - ...pluginsList, - "--quiet", - "--no-warnings", - "--silent", - "--progress=false", - ], - { - stdio: "inherit", // Redirect output - } - ); + const child = spawn("pnpm", ["remove", ...pluginsList, "--silent"], { + stdio: "inherit", // Ensure proper output handling + }); - await new Promise((resolve) => { - child.on("close", () => { - resolve(); + await new Promise((resolve, reject) => { + child.on("close", (code) => { + if (code === 0) { + resolve(); + } else { + reject(new Error(`pnpm remove failed with code ${code}`)); + } }); }); - spinner.stop(); // Stop the spinner when the installation is complete + spinner.stop(); // Stop the spinner when uninstallation is complete console.log("\nPlugins uninstalled successfully!"); console.log(chalk.cyan.bold("Happy coding with Godspeed! šŸš€šŸŽ‰\n")); } catch (error: any) { spinner.stop(); // Stop the spinner in case of an error - console.error("Error during installation:", error.message); + console.error("Error during uninstallation:", error.message); } } @@ -480,7 +417,7 @@ const remove = program console.error("There are no eventsource/datasource plugins installed."); return; } - + let pkgPath = path.join(cwd(), "package.json"); pluginsList = existsSync(pkgPath) ? JSON.parse(readFileSync(pkgPath, { encoding: "utf-8" })).dependencies @@ -594,7 +531,6 @@ const update = program } } - let pkgPath = path.join(cwd(), "package.json"); pluginsList = existsSync(pkgPath) ? JSON.parse(readFileSync(pkgPath, { encoding: "utf-8" })).dependencies diff --git a/src/index.ts b/src/index.ts index 03407e2..1c5fbff 100755 --- a/src/index.ts +++ b/src/index.ts @@ -12,12 +12,12 @@ import devOpsPluginCommands from "./commands/devops-plugin"; import pluginCommands from "./commands/plugin"; import prismaCommands from "./commands/prisma"; import otelCommands from "./commands/otel"; -import {genGraphqlSchema} from "./utils/index"; +import { genGraphqlSchema } from "./utils/index"; const fsExtras = require("fs-extra"); import { cwd } from "process"; import fs, { readFileSync } from "fs"; import { homedir } from "node:os"; -import { readdir } from 'fs/promises'; +import { readdir } from "fs/promises"; import { globSync } from "glob"; import inquirer from "inquirer"; @@ -96,19 +96,31 @@ const updateServicesJson = async (add = true) => { }; if (add) { - const exists = servicesData.services.some((service: any) => service.path === process.cwd()); + const exists = servicesData.services.some( + (service: any) => service.path === process.cwd() + ); if (!exists) servicesData.services.push(currentProject); } else { - servicesData.services = servicesData.services.filter((service: any) => service.path !== process.cwd()); + servicesData.services = servicesData.services.filter( + (service: any) => service.path !== process.cwd() + ); } - await fs.promises.writeFile(servicesFile, JSON.stringify(servicesData, null, 2), "utf-8"); + await fs.promises.writeFile( + servicesFile, + JSON.stringify(servicesData, null, 2), + "utf-8" + ); console.log(chalk.green("Project data updated successfully.")); } catch (error: any) { if (error.code === "EACCES") { const action = add ? "link" : "unlink"; - console.error("\x1b[31mPermission denied: Cannot write to services.json\x1b[0m"); - console.error(`\x1b[33mTry running: \x1b[1msudo godspeed ${action}\x1b[0m`); + console.error( + "\x1b[31mPermission denied: Cannot write to services.json\x1b[0m" + ); + console.error( + `\x1b[33mTry running: \x1b[1msudo godspeed ${action}\x1b[0m` + ); } else { console.error("\x1b[31mAn error occurred:\x1b[0m", error); } @@ -205,44 +217,41 @@ const updateServicesJson = async (add = true) => { // } // }); - program .command("dev") .description("run godspeed development server.") .action(async () => { if (await isAGodspeedProject()) { - spawnSync("npm", ["run", "dev"], { - stdio: "inherit", - }); + spawnSync("pnpm", ["run", "dev"], { stdio: "inherit" }); } }); program .command("clean") - .description(`clean the previous build.`) - .action(async (options) => { - if (isAGodspeedProject()) { - spawnSync("npm", ["run", "clean"], { - stdio: "inherit", - }); + .description("clean the previous build.") + .action(async () => { + if (await isAGodspeedProject()) { + spawnSync("pnpm", ["run", "clean"], { stdio: "inherit" }); } }); - program + program .command("link") - .description("Link a local Godspeed project to the global environment for development in godspeed-daemon.") + .description( + "Link a local Godspeed project to the global environment for development in godspeed-daemon." + ) .action(async () => { if (await isAGodspeedProject()) { - updateServicesJson(true); + await updateServicesJson(true); } }); - + program .command("unlink") .description("Unlink a local Godspeed project from the global environment.") - .action(async() => { + .action(async () => { if (await isAGodspeedProject()) { - updateServicesJson(false); + await updateServicesJson(false); } }); @@ -252,43 +261,42 @@ const updateServicesJson = async (add = true) => { "scans your prisma datasources and generate CRUD APIs events and workflows" ) .action(async () => { - if (isAGodspeedProject()) { - spawnSync("npm", ["run", "gen-crud-api"], { stdio: "inherit" }); + if (await isAGodspeedProject()) { + spawnSync("pnpm", ["run", "gen-crud-api"], { stdio: "inherit" }); } }); - program + + program .command("gen-graphql-schema") - .description( - "scans your graphql events and generate graphql schema" - ) + .description("scans your graphql events and generate graphql schema") .action(async () => { - if (isAGodspeedProject()) { - await genGraphqlSchema() + if (await isAGodspeedProject()) { + await genGraphqlSchema(); } }); + program .command("build") .description("build the godspeed project. create a production build.") - .action(async (options) => { + .action(async () => { if (await isAGodspeedProject()) { - spawnSync("npm", ["run", "build"], { + spawnSync("pnpm", ["run", "build"], { stdio: "inherit", env: { - // NODE_ENV: "production", ...process.env, }, }); } }); + program .command("preview") .description("preview the production build.") - .action(async (options) => { + .action(async () => { if (await isAGodspeedProject()) { - spawnSync("npm", ["run", "preview"], { + spawnSync("pnpm", ["run", "preview"], { stdio: "inherit", env: { - // NODE_ENV: "production", ...process.env, }, }); @@ -296,28 +304,28 @@ const updateServicesJson = async (add = true) => { }); // fetch the list of installed devops-plugins - const pluginPath = path.resolve(homedir(), `.godspeed/devops-plugins/node_modules/@godspeedsystems/`); + const pluginPath = path.resolve( + homedir(), + `.godspeed/devops-plugins/node_modules/@godspeedsystems/` + ); + + const devopsPluginSubCommand = program + .command("devops-plugin") + .description(`manages godspeed devops-plugins.`); + + devopsPluginSubCommand.addCommand(devOpsPluginCommands.install); - const devopsPluginSubCommand = program.command('devops-plugin') - .description(`manages godspeed devops-plugins.`) + devopsPluginSubCommand.addCommand(devOpsPluginCommands.list); - devopsPluginSubCommand - .addCommand(devOpsPluginCommands.install); + devopsPluginSubCommand.addCommand(devOpsPluginCommands.remove); - devopsPluginSubCommand - .addCommand(devOpsPluginCommands.list); - - devopsPluginSubCommand - .addCommand(devOpsPluginCommands.remove); - - devopsPluginSubCommand - .addCommand(devOpsPluginCommands.update); + devopsPluginSubCommand.addCommand(devOpsPluginCommands.update); const devopsPluginHelp = ` To see help for any installed devops plugin, you can run: help `; - devopsPluginSubCommand.on('--help', () => { + devopsPluginSubCommand.on("--help", () => { console.log(devopsPluginHelp); }); @@ -330,19 +338,25 @@ const updateServicesJson = async (add = true) => { .description("installed godspeed devops plugin") .allowUnknownOption(true) .action(async () => { - const installedPluginPath = path.resolve(pluginPath, installedPluginName, "dist/index.js"); + const installedPluginPath = path.resolve( + pluginPath, + installedPluginName, + "dist/index.js" + ); // check if installedPluginPath exists. if (!fs.existsSync(installedPluginPath)) { - console.error(`${installedPluginName} is not installed properly. Please make sure ${installedPluginPath} exists.`); + console.error( + `${installedPluginName} is not installed properly. Please make sure ${installedPluginPath} exists.` + ); return; } const args = process.argv.slice(4); // Spawn the plugin with all arguments and options - spawnSync('node', [installedPluginPath, ...args], { - stdio: 'inherit', + spawnSync("node", [installedPluginPath, ...args], { + stdio: "inherit", }); }); } diff --git a/src/utils/index.ts b/src/utils/index.ts index 6278f8c..f4da3de 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -11,8 +11,15 @@ import chalk from "chalk"; import { spawnSync } from "child_process"; import spawnCommand from "cross-spawn"; import ora from "ora"; -import { yamlLoader as loadYaml, generateSwaggerJSON, logger , PlainObject, yamlLoader} from '@godspeedsystems/core'; -const { exec } = require('child_process'); +import { + yamlLoader as loadYaml, + generateSwaggerJSON, + logger, + PlainObject, + yamlLoader, +} from "@godspeedsystems/core"; +const { exec } = require("child_process"); +import { spawn, execSync } from "child_process"; const userID = (): string => { if (process.platform == "linux") { @@ -163,7 +170,7 @@ export const compileAndCopyOrJustCopy = async ( isUpdateCall = fsExtras .lstatSync(path.resolve(process.cwd(), ".godspeed")) .isFile(); - } catch (error) { } + } catch (error) {} fileList.map(async (sourceFilePath: string) => { if (fsExtras.lstatSync(sourceFilePath).isFile()) { @@ -173,17 +180,17 @@ export const compileAndCopyOrJustCopy = async ( relativeDestinationPath = !isUpdateCall ? path.relative( - path.resolve(projectDirPath, sourceFolder), - sourceFilePath - ) - : path.resolve( - projectDirPath, - destinationFolder, - path.relative( path.resolve(projectDirPath, sourceFolder), sourceFilePath ) - ); + : path.resolve( + projectDirPath, + destinationFolder, + path.relative( + path.resolve(projectDirPath, sourceFolder), + sourceFilePath + ) + ); let finalDestinationWithFileName = path.resolve( projectDirPath, @@ -242,66 +249,87 @@ export const compileAndCopyOrJustCopy = async ( } }; - - export const installDependencies = async ( projectDirPath: string, projectName: string ) => { + async function ensurePnpmInstalled() { + try { + execSync("pnpm -v", { stdio: "ignore" }); // Check if pnpm exists + return true; + } catch { + console.log( + chalk.yellow("\nāš ļø pnpm is not installed. Installing pnpm...") + ); + try { + execSync("npm install -g pnpm", { stdio: "inherit" }); // Install pnpm globally + console.log(chalk.green("\nāœ… pnpm installed successfully!\n")); + return true; + } catch (err) { + console.error( + chalk.red( + "\nāŒ Failed to install pnpm. Please install it manually: `npm install -g pnpm`\n" + ) + ); + return false; + } + } + } + async function installPlugin() { + if (!(await ensurePnpmInstalled())) return; // Stop if pnpm installation fails const spinner = ora({ spinner: { frames: ["šŸŒ ", "šŸŒŽ ", "šŸŒ ", "🌐 ", "šŸŒ‘ ", "šŸŒ’ ", "šŸŒ“ ", "šŸŒ” "], interval: 180, }, - }).start("installing dependencies..."); + }).start("Installing dependencies..."); + try { - // Use spawnCommand instead of spawnSync - const child = spawnCommand( - "npm", - [ - "install", - "--quiet", - "--no-warnings", - "--silent", - "--progress=false" - ], - { - cwd: projectDirPath, - stdio: "inherit", // Redirect output - } - ); - child.on("close", () => { - spinner.stop(); // Stop the spinner when the installation is complete - console.log("\ndependencies installed successfully!"); + const child = spawn("pnpm", ["install", "--ignore-scripts", "--silent"], { + cwd: projectDirPath, + stdio: "inherit", + shell: true, + }); - console.log( - `${chalk.green("\nSuccessfully created the project")} ${chalk.yellow( - projectName - )}.` - ); + child.on("close", (code) => { + spinner.stop(); + if (code === 0) { + console.log("\nāœ… Dependencies installed successfully!"); + console.log( + `${chalk.green( + "\nSuccessfully created the project" + )} ${chalk.yellow(projectName)}.` + ); + console.log( + `${chalk.green( + "Use `godspeed help` command for available commands." + )} ${chalk.green.bold( + "\n\nHappy building microservices with Godspeed! šŸš€šŸŽ‰\n" + )}` + ); + } else { + spinner.fail("āŒ Dependency installation failed."); + } + }); - console.log( - `${chalk.green( - "Use `godspeed help` command for available commands." - )} ${chalk.green.bold( - "\n\nHappy building microservices with Godspeed! šŸš€šŸŽ‰\n" - )}` - ); + child.on("error", (err) => { + spinner.fail("āŒ Error starting the installation process."); + console.error(err); }); } catch (error: any) { - spinner.stop(); // Stop the spinner in case of an error - console.error("Error during installation:", error.message); + spinner.stop(); + console.error("āŒ Error during installation:", error.message); } } - - // Call the installPlugin function await installPlugin(); - }; -export const installPackage = async (projectDirPath: string, package_name: string) => { +export const installPackage = async ( + projectDirPath: string, + package_name: string +) => { async function installprisma(): Promise { const command = `npm install ${package_name}`; @@ -311,22 +339,23 @@ export const installPackage = async (projectDirPath: string, package_name: strin stdio: "inherit", // Redirect output }); - child.on('exit', (code: any) => { + child.on("exit", (code: any) => { if (code === 0) { resolve(); } else { - reject(new Error(`Command exited with non-zero status code: ${code}`)); + reject( + new Error(`Command exited with non-zero status code: ${code}`) + ); } }); - child.on('error', (error: any) => { + child.on("error", (error: any) => { reject(error); }); }); } - await installprisma() -} - + await installprisma(); +}; export const generateProjectFromDotGodspeed = async ( projectName: string, @@ -366,7 +395,7 @@ export const generateProjectFromDotGodspeed = async ( ); // generate package.json, tsConfig.json - for (let file of ['package.json', 'tsconfig.json']) { + for (let file of ["package.json", "tsconfig.json"]) { const packageJson = await fsExtras.readJson( path.resolve(projectDirPath, `.template/${file}`) ); @@ -383,7 +412,6 @@ export const generateProjectFromDotGodspeed = async ( ); } - // generate .swcrc file const swcrc = await fsExtras.readJson( path.resolve(projectDirPath, ".template/dot-configs/.swcrc") @@ -483,23 +511,24 @@ export const generateProjectFromDotGodspeed = async ( } catch (error) { log.fatal("Error while generating files.", error); } -} +}; export const genGraphqlSchema = async () => { try { - const availableApoloeventsources = globSync( - path.join(process.cwd(), 'src/eventsources/*.yaml').replace(/\\/g, '/') + path.join(process.cwd(), "src/eventsources/*.yaml").replace(/\\/g, "/") ); // Filter files that contain 'Apollo' in their name - const apolloEventsources = availableApoloeventsources - .map((file) => path.parse(file).name); + const apolloEventsources = availableApoloeventsources.map( + (file) => path.parse(file).name + ); const questions = [ { - type: 'checkbox', - name: 'selectedOptions', - message: 'Please select the Graphql Event Sources for which you wish to generate the Graphql schema from Godspeed event defs:', + type: "checkbox", + name: "selectedOptions", + message: + "Please select the Graphql Event Sources for which you wish to generate the Graphql schema from Godspeed event defs:", choices: apolloEventsources, }, ]; @@ -508,9 +537,11 @@ export const genGraphqlSchema = async () => { try { const answers = await inquirer.prompt(questions); if (answers.selectedOptions.length == 0) { - console.log(chalk.red("Please select atleast one GraphQL eventsource")) + console.log( + chalk.red("Please select atleast one GraphQL eventsource") + ); } else { - await createSwaggerFile(answers.selectedOptions) + await createSwaggerFile(answers.selectedOptions); } } catch (error) { console.error(error); @@ -518,8 +549,8 @@ export const genGraphqlSchema = async () => { } runPrompt(); } catch (error) { - console.log(error) - }; + console.log(error); + } const createSwaggerFile = async (eventSources: string[]) => { const eventPath = path.join(process.cwd(), "/src/events"); @@ -527,57 +558,83 @@ export const genGraphqlSchema = async () => { const allEventsSchema: PlainObject = await loadYaml(eventPath, true); //all events of the project const definitions: PlainObject = await loadYaml(definitionsPath, false); eventSources.map(async (eventSourceName: string) => { - logger.info('Generating graphql schema for %s. First we will create swagger schema in %s', eventSourceName, os.tmpdir()); + logger.info( + "Generating graphql schema for %s. First we will create swagger schema in %s", + eventSourceName, + os.tmpdir() + ); // Find out the events for this eventSourceName key const eventSchemas = Object.fromEntries( Object.entries(allEventsSchema).filter(([key]) => { const eventSourceKey = key.split(".")[0]; - // eventSourceKey is the name of eventsources in this event definition. + // eventSourceKey is the name of eventsources in this event definition. // It could be one like 'http' or more like 'http & graphql' if (eventSourceKey == eventSourceName) { return true; } - const eventSources = eventSourceKey.split('&').map((s) => s.trim()); + const eventSources = eventSourceKey.split("&").map((s) => s.trim()); return eventSources.includes(eventSourceName); }) ); if (Object.keys(eventSchemas).length === 0) { - logger.fatal(chalk.red(`Did not find any events for the ${eventSourceName} eventsource. Why don't you define the first one in the events folder?`)) + logger.fatal( + chalk.red( + `Did not find any events for the ${eventSourceName} eventsource. Why don't you define the first one in the events folder?` + ) + ); process.exit(1); } // let swaggerSchema = await generateSwaggerui(eventSchemas,definitions); - let eventSourceConfig = yaml.parse(fsExtras.readFileSync(process.cwd() + `/src/eventsources/${eventSourceName}.yaml`, { encoding: 'utf-8' }) ); + let eventSourceConfig = yaml.parse( + fsExtras.readFileSync( + process.cwd() + `/src/eventsources/${eventSourceName}.yaml`, + { encoding: "utf-8" } + ) + ); //The yaml file of the eventsource - let swaggerSchema = generateSwaggerJSON(eventSchemas, definitions, eventSourceConfig); + let swaggerSchema = generateSwaggerJSON( + eventSchemas, + definitions, + eventSourceConfig + ); // For swagger-to-graphql plugin we need to save this file somewhere - const swaggerFilePath = path.join( os.tmpdir(), eventSourceName + '-swagger.json'); - + const swaggerFilePath = path.join( + os.tmpdir(), + eventSourceName + "-swagger.json" + ); + // Write the swagger.json file in the temp folder - await fsExtras.writeFileSync(swaggerFilePath, JSON.stringify(swaggerSchema, null, 2)); - - logger.info('Generated and saved swagger schema at temporary location %s. Now generating graphql schema from the same.', swaggerFilePath); - + await fsExtras.writeFileSync( + swaggerFilePath, + JSON.stringify(swaggerSchema, null, 2) + ); + + logger.info( + "Generated and saved swagger schema at temporary location %s. Now generating graphql schema from the same.", + swaggerFilePath + ); + // genereate graphql schema await generateGraphqlSchema(eventSourceName, swaggerFilePath); - }); + }; +}; - - } -} - -async function generateGraphqlSchema(eventSourceName: string, swaggerFilePath: string) { +async function generateGraphqlSchema( + eventSourceName: string, + swaggerFilePath: string +) { const command = `npx swagger-to-graphql --swagger-schema=${swaggerFilePath} > ./src/eventsources/${eventSourceName}.graphql`; exec(command, (error: any, stdout: any, stderr: any) => { if (error) { console.log( - chalk.red.bold(`Failed to generate Graphql schema for eventsource ${eventSourceName}`) - ); - console.log( - chalk.red(error.message) + chalk.red.bold( + `Failed to generate Graphql schema for eventsource ${eventSourceName}` + ) ); + console.log(chalk.red(error.message)); return; } if (stderr) { @@ -585,40 +642,45 @@ async function generateGraphqlSchema(eventSourceName: string, swaggerFilePath: s return; } console.log( - chalk.green(`Graphql schema generated successfuly for eventsource ${eventSourceName} at ./src/eventsources/${eventSourceName}.graphql`) - + chalk.green( + `Graphql schema generated successfuly for eventsource ${eventSourceName} at ./src/eventsources/${eventSourceName}.graphql` + ) ); }); } -const generateSwaggerui = async (eventsSchema: PlainObject, definitions: PlainObject) => { +const generateSwaggerui = async ( + eventsSchema: PlainObject, + definitions: PlainObject +) => { let finalSpec: PlainObject = {}; const swaggerCommonPart = { - "openapi": "3.0.0", - "info": { - "version": "0.0.1", - "title": "Godspeed: Sample Microservice", - "description": "Sample API calls demonstrating the functionality of Godspeed framework", - "termsOfService": "http://swagger.io/terms/", - "contact": { - "name": "Mindgrep Technologies Pvt Ltd", - "email": "talktous@mindgrep.com", - "url": "https://docs.mindgrep.com/docs/microservices/intro" + openapi: "3.0.0", + info: { + version: "0.0.1", + title: "Godspeed: Sample Microservice", + description: + "Sample API calls demonstrating the functionality of Godspeed framework", + termsOfService: "http://swagger.io/terms/", + contact: { + name: "Mindgrep Technologies Pvt Ltd", + email: "talktous@mindgrep.com", + url: "https://docs.mindgrep.com/docs/microservices/intro", + }, + license: { + name: "Apache 2.0", + url: "https://www.apache.org/licenses/LICENSE-2.0.html", }, - "license": { - "name": "Apache 2.0", - "url": "https://www.apache.org/licenses/LICENSE-2.0.html" - } }, - "paths": {} + paths: {}, }; let swaggerSpecBase = JSON.parse(JSON.stringify(swaggerCommonPart)); finalSpec = swaggerSpecBase; Object.keys(eventsSchema).forEach((event: any) => { - let apiEndPoint = event.split('.')[2]; - apiEndPoint = apiEndPoint.replace(/:([^\/]+)/g, '{$1}'); //We take :path_param. OAS3 takes {path_param} - const method = event.split('.')[1]; + let apiEndPoint = event.split(".")[2]; + apiEndPoint = apiEndPoint.replace(/:([^\/]+)/g, "{$1}"); //We take :path_param. OAS3 takes {path_param} + const method = event.split(".")[1]; const eventSchema = eventsSchema[event]; //Initialize the schema for this method, for given event @@ -644,4 +706,3 @@ const generateSwaggerui = async (eventsSchema: PlainObject, definitions: PlainOb return finalSpec; }; -