crud-generator-ts
Version:
CRUD generator for TypeScript Express applications
217 lines (192 loc) • 8.21 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.run = void 0;
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const generateFiles = (resourceName) => {
var _a, _b;
const className = resourceName.charAt(0).toUpperCase() + resourceName.slice(1);
const fileName = resourceName
.replace(/([A-Z])/g, '-$1')
.toLowerCase()
.replace(/^-/, '');
const entityTemplate = `import { Entity, Column, PrimaryColumn, BeforeInsert, BeforeUpdate, DeleteDateColumn, PrimaryGeneratedColumn } from 'typeorm';
export class ${className} {
id: number;
// add your columns here
created_at: Date;
updated_at?: Date;
deleted_at?: Date;
}`;
const controllerTemplate = `
import { Body, Controller, Delete, Get, Path, Post, Put, Route, Tags } from 'tsoa';
import { AppDataSource } from '../infra/database/main';
import { ${className}Repository } from '../repositories/${fileName}-repository';
export class ${className}Controller extends Controller {
private repository = new ${className}Repository(AppDataSource);
public async getAll(): Promise<any> {
return await this.repository.findAll();
}
public async getById( id: number): Promise<any> {
return await this.repository.findById(id);
}
public async create( body: any): Promise<any> {
return await this.repository.create(body);
}
public async update( id: number, body: any): Promise<any> {
return await this.repository.update(id, body);
}
public async delete( id: number): Promise<any> {
await this.repository.deleteById(id);
return { message: 'Deletado com sucesso' };
}
}
`;
const repositoryTemplate = `
import { DataSource, Repository } from 'typeorm';
import { ${className} } from '../infra/entity/${fileName}';
export class ${className}Repository {
private repository: Repository<${className}>;
constructor(dataSource: DataSource) {
this.repository = dataSource.getRepository(${className});
}
async findAll(): Promise<${className}[]> {
return await this.repository.find();
}
async findById(id: number): Promise<${className} | null> {
return await this.repository.findOne({ where: { id } });
}
async create(entity: Partial<${className}>): Promise<${className}> {
const newEntity = this.repository.create(entity);
return await this.repository.save(newEntity);
}
async update(id: number, updatedData: Partial<${className}>): Promise<${className} | null> {
const entity = await this.findById(id);
if (!entity) {
return null;
}
Object.assign(entity, updatedData);
return await this.repository.save(entity);
}
async deleteById(id: number): Promise<void> {
await this.repository.delete(id);
}
}
`;
const routeTemplate = `import { Router } from 'express';
import { ${className}Controller } from '../controllers/${fileName}-controller';
export const ${fileName.replace(/-/g, '')}Routes = Router();
const ${resourceName}Controller = new ${className}Controller();
${fileName.replace(/-/g, '')}Routes.get('/', async (_req, res) => {
const response = await ${resourceName}Controller.getAll();
res.status(200).json(response);
});
${fileName.replace(/-/g, '')}Routes.get('/:id', async (req, res) => {
const response = await ${resourceName}Controller.getById(parseInt(req.params.id));
res.status(200).json(response);
});
${fileName.replace(/-/g, '')}Routes.post('/', async (req, res) => {
const response = await ${resourceName}Controller.create(req.body);
res.status(201).json(response);
});
${fileName.replace(/-/g, '')}Routes.put('/:id', async (req, res) => {
const response = await ${resourceName}Controller.update(parseInt(req.params.id), req.body);
res.status(200).json(response);
});
${fileName.replace(/-/g, '')}Routes.delete('/:id', async (req, res) => {
await ${resourceName}Controller.delete(parseInt(req.params.id));
res.status(200).json({ message: 'Registro deletado com sucesso' });
});`;
const dirs = [
'src/infra/entity',
'src/controllers',
'src/repositories',
'src/routes'
].map(dir => dir.split('/').join(path_1.default.sep));
dirs.forEach(dir => {
if (!fs_1.default.existsSync(dir)) {
fs_1.default.mkdirSync(dir, { recursive: true });
}
});
fs_1.default.writeFileSync(`src/infra/entity/${fileName}.ts`, entityTemplate.trim());
fs_1.default.writeFileSync(`src/controllers/${fileName}-controller.ts`, controllerTemplate.trim());
fs_1.default.writeFileSync(`src/repositories/${fileName}-repository.ts`, repositoryTemplate.trim());
fs_1.default.writeFileSync(`src/routes/${fileName}.routes.ts`, routeTemplate.trim());
const entityIndexPath = 'src/infra/entity/index.ts';
let entityIndexContent = fs_1.default.existsSync(entityIndexPath)
? fs_1.default.readFileSync(entityIndexPath, 'utf8')
: '';
const importLine = `import { ${className} } from './${fileName}';`;
const exportLine = ` ${className}`;
if (!entityIndexContent.includes(importLine)) {
if (!entityIndexContent) {
entityIndexContent = `${importLine}\n\nexport {\n${exportLine}\n};`;
}
else {
let imports = ((_a = entityIndexContent.match(/(import.*;\n)*/g)) === null || _a === void 0 ? void 0 : _a[0]) || '';
let exports = ((_b = entityIndexContent.match(/export {([\s\S]*?)};/)) === null || _b === void 0 ? void 0 : _b[1]) || '';
imports = `${importLine}\n${imports}`.trim();
exports = exports
.split(',')
.filter(Boolean)
.map(e => e.trim())
.concat([exportLine])
.join(',\n ');
entityIndexContent = `${imports}\n\nexport {\n ${exports}\n};`;
}
fs_1.default.writeFileSync(entityIndexPath, entityIndexContent);
}
const routesIndexPath = 'src/routes/index.ts';
let routesIndexContent = fs_1.default.existsSync(routesIndexPath)
? fs_1.default.readFileSync(routesIndexPath, 'utf8')
: `import { isAuthenticated } from '../middlewares/auth';\nimport { Router } from 'express';\n\nconst routes = Router();\n\nexport default routes;`;
const routeImportLine = `import { ${fileName.replace(/-/g, '')}Routes } from './${fileName}.routes';`;
const routeUseLine = `routes.use('/${fileName}', isAuthenticated, ${fileName.replace(/-/g, '')}Routes);`;
if (!routesIndexContent.includes(routeImportLine)) {
let [imports, rest] = routesIndexContent.split('\nconst routes');
imports = `${routeImportLine}\n${imports}`.trim();
let [declaration, uses, export_] = rest.split('\nexport');
uses = uses.split('\n')
.filter(line => line.trim())
.concat([routeUseLine])
.join('\n');
routesIndexContent = `${imports}\n\nconst routes${declaration}\n${uses}\n\nexport${export_}`;
fs_1.default.writeFileSync(routesIndexPath, routesIndexContent);
}
console.log(`Resource ${className} created successfully!`);
};
const run = () => {
const resourceName = process.argv[2];
if (!resourceName) {
console.error('Please provide a resource name!');
process.exit(1);
}
generateFiles(resourceName);
};
exports.run = run;