UNPKG

grapi-cli

Version:

a cli tool to generate loopback 4 applications with extra features like caching & fuzzy search

78 lines (77 loc) 4.29 kB
import { Args, Command, Flags } from '@oclif/core'; import chalk from 'chalk'; import { processOptions, execute, standardFlags, prompt } from '../utils/index.js'; import { Project, SyntaxKind } from 'ts-morph'; export default class App extends Command { static description = 'generate application.'; static args = { name: Args.string({ description: 'name of the application.' }), //the argument shouldn't be required here!!!! }; static flags = { ...standardFlags, name: Flags.string({ description: 'Application class name.' }), description: Flags.string({ description: 'Description of the application.' }), outdir: Flags.string({ description: 'Project root directory for the application.' }), eslint: Flags.boolean({ description: 'Add ESLint to LoopBack4 application project.' }), prettier: Flags.boolean({ description: 'Add Prettier to LoopBack4 application project.' }), mocha: Flags.boolean({ description: 'Add Mocha to LoopBack4 application project.' }), loopbackBuild: Flags.boolean({ description: 'Add @loopback/build module’s script set to LoopBack4 application project.' }), vscode: Flags.boolean({ description: 'Add VSCode config files to LoopBack4 application project' }), docker: Flags.boolean({ description: 'Generate Dockerfile and add npm scripts to build/run the project in a docker container.' }), repositories: Flags.boolean({ description: 'include repository imports and RepositoryMixin.' }), services: Flags.boolean({ description: 'include service-proxy imports and ServiceMixin.' }), controllerDirs: Flags.boolean({ description: 'a comma seperated list of directory names to use as controller directories.' }), apiconnect: Flags.boolean({ description: 'Include ApiConnectComponent.' }), }; async run() { const parsed = await this.parse(App); if (!parsed.flags.config) return prompt('app', parsed.flags, parsed.args); let options = processOptions(parsed.flags); if (!options.name && parsed.args.name) { options.name = parsed.args.name; } let configs = ''; if (Object.keys(options).length) { configs = ` --config='${JSON.stringify(options)}' `; } let argument = ''; if (parsed.args.name) { argument = ` ${parsed.args.name}`; } const command = `lb4${argument}${configs}--yes`; const executed = await execute(command, 'generating application.'); if (executed.stderr) console.log(chalk.bold(chalk.green(executed.stderr))); if (executed.stdout) console.log(chalk.bold(chalk.green(executed.stdout))); if (!options.controllerDirs) return; const controllerDirs = options.controllerDirs.split(','); const project = new Project({}); const invokedFrom = process.cwd(); project.addSourceFilesAtPaths(`${invokedFrom}/${options.name}/src/**/*.ts`); const applicationPath = `${invokedFrom}/${options.name}/src/application.ts`; const applicationFile = project.getSourceFileOrThrow(applicationPath); const applicationClass = applicationFile.getClasses()[0]; const constructor = applicationClass.getConstructors()[0]; const staticCall = constructor.getStatements().find(statement => statement.getText().includes(`this.bootOptions`)); const sourceFile = project.createSourceFile('temp.ts', staticCall?.getText()); const objectLiteral = sourceFile.getFirstDescendant(node => node.getKind() === SyntaxKind.ObjectLiteralExpression); const dirsProperty = objectLiteral .getDescendantsOfKind(SyntaxKind.PropertyAssignment) .find(prop => prop.getName() === 'dirs'); if (dirsProperty) { const arrayLiteral = dirsProperty.getInitializerIfKind(SyntaxKind.ArrayLiteralExpression); if (arrayLiteral) { controllerDirs.forEach(dir => { arrayLiteral.addElement(`'${dir}'`); }); } } if (staticCall) { staticCall.replaceWithText(sourceFile.getText()); } applicationFile.saveSync(); } }