rad-api 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,156 @@
1
+ # KAPI - Rapid API Development Tool
2
+
3
+ Un outil puissant pour générer rapidement des fichiers de routes, contrôleurs et modèles pour votre API.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install -g rad-api
9
+ ```
10
+
11
+ Ou pour le développement local :
12
+
13
+ ```bash
14
+ npm link
15
+ ```
16
+
17
+ ## Utilisation
18
+
19
+ ### Générer une route
20
+
21
+ Générez un fichier de route complet pour une table spécifique :
22
+
23
+ ```bash
24
+ kapi generate route <tableName>
25
+ ```
26
+
27
+ #### Exemple :
28
+
29
+ ```bash
30
+ kapi generate route citations
31
+ ```
32
+
33
+ Cela créera un fichier `citations.routes.js` avec :
34
+ - Configuration Prisma MariaDB
35
+ - Fonction `all()` pour récupérer tous les enregistrements
36
+ - Gestion des erreurs complète
37
+ - Logs de requête
38
+
39
+ #### Fichier généré (`citations.routes.js`) :
40
+
41
+ ```javascript
42
+ import { PrismaMariaDb } from '@prisma/adapter-mariadb';
43
+ import { PrismaClient } from '../../../generated/prisma/client.js';
44
+
45
+ const maria = new PrismaMariaDb({
46
+ host: process.env.DATABASE_HOST,
47
+ port: process.env.DATABASE_PORT,
48
+ user: process.env.DATABASE_USER,
49
+ password: process.env.DATABASE_PASSWORD,
50
+ database: process.env.DATABASE_NAME
51
+ });
52
+
53
+ const prisma = new PrismaClient({ adapter: maria });
54
+
55
+ export const all = async (req, res) => {
56
+ req.log?.info('all Citations endpoint');
57
+ try {
58
+ const allCitation = await main();
59
+ res.status(200);
60
+ res.json(allCitation);
61
+ } catch (error) {
62
+ req.log?.error('Error fetching Citations:', error);
63
+ return res.status(500).json({ msg: 'Internal Server Error' });
64
+ }
65
+ };
66
+
67
+ async function main() {
68
+ const allCitation = await prisma.Citations.findMany()
69
+ console.log('All Citations:', JSON.stringify(allCitation, null, 2))
70
+ return allCitation;
71
+ }
72
+ ```
73
+
74
+ ## Fonctionnalités
75
+
76
+ - ✅ Génération automatique de fichiers de routes
77
+ - ✅ Conversion intelligente des noms (singulier/pluriel, PascalCase)
78
+ - ✅ Intégration Prisma MariaDB préinstallée
79
+ - ✅ Gestion des erreurs et logs
80
+ - ✅ Protection contre les fichiers dupliqués
81
+ - ✅ Messages de sortie détaillés et utiles
82
+
83
+ ## Structure du projet
84
+
85
+ ```
86
+ RAD-api/
87
+ ├── index.js # Point d'entrée CLI
88
+ ├── package.json
89
+ ├── README.md
90
+ └── src/
91
+ ├── commands/
92
+ │ └── generate.js # Logique de génération
93
+ ├── templates/
94
+ │ └── route.template.js # Template de route
95
+ └── utils/
96
+ ├── parser.js # Parser d'arguments
97
+ ├── fileHelper.js # Utilitaires de fichier
98
+ └── stringHelper.js # Utilitaires de chaîne
99
+ ```
100
+
101
+ ## Options d'environnement
102
+
103
+ Le fichier généré utilise les variables d'environnement suivantes :
104
+
105
+ ```
106
+ DATABASE_HOST = Adresse du serveur MariaDB
107
+ DATABASE_PORT = Port MariaDB (par défaut: 3306)
108
+ DATABASE_USER = Utilisateur MariaDB
109
+ DATABASE_PASSWORD = Mot de passe MariaDB
110
+ DATABASE_NAME = Nom de la base de données
111
+ ```
112
+
113
+ ## Exemples d'utilisation
114
+
115
+ ### Tables simples
116
+ ```bash
117
+ kapi generate route products
118
+ kapi generate route categories
119
+ kapi generate route customers
120
+ ```
121
+
122
+ ### Tables plurielles
123
+ ```bash
124
+ kapi generate route citations # Génère handlers pour la table "Citations"
125
+ kapi generate route users # Génère handlers pour la table "Users"
126
+ ```
127
+
128
+ ## Gestion des erreurs
129
+
130
+ L'outil gère automatiquement :
131
+ - Les fichiers déjà existants ✓
132
+ - Les noms de table vides ✓
133
+ - Les répertoires manquants (création automatique) ✓
134
+
135
+ ## Développement
136
+
137
+ Pour ajouter de nouvelles commandes :
138
+
139
+ 1. Créez un template dans `src/templates/`
140
+ 2. Créez un fichier de commande dans `src/commands/`
141
+ 3. Ajoutez la logique de parsing dans `index.js`
142
+
143
+ ## Améliorations futures
144
+
145
+ - [ ] `kapi generate controller <tableName>` - Générer les contrôleurs
146
+ - [ ] `kapi generate model <tableName>` - Générer les modèles Prisma
147
+ - [ ] `kapi generate crud <tableName>` - Générer CRUD complet
148
+ - [ ] `kapi config` - Configuration interactive
149
+
150
+ ## Licence
151
+
152
+ ISC
153
+
154
+ ## Auteur
155
+
156
+ kferrandon
package/index.js ADDED
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { parseArgs } from './src/utils/parser.js';
4
+ import { generate } from './src/commands/generate.js';
5
+
6
+ async function main() {
7
+ const args = parseArgs(process.argv.slice(2));
8
+ console.log(args);
9
+ try {
10
+ if (args.command === 'generate') {
11
+ if (!args.table) {
12
+ console.error('❌ Error: Table name is required');
13
+ console.log('Usage: kapi generate route <tableName>');
14
+ process.exit(1);
15
+ }
16
+ if (args.type) {
17
+ await generate(args.type, args.table, args.path);
18
+ }
19
+
20
+ }
21
+ else {
22
+ console.log('🔧 KAPI - Rapid API Development');
23
+ console.log('\nUsage:');
24
+ console.log(' kapi generate route <tableName> - Generate a route file for a table');
25
+ console.log(' kapi generate controller <tableName> - Generate a controller file for a table');
26
+ console.log('\nExamples:');
27
+ console.log(' kapi generate route citations');
28
+ console.log(' kapi generate route users');
29
+ }
30
+ } catch (error) {
31
+ console.error('❌ Error:', error.message);
32
+ process.exit(1);
33
+ }
34
+ }
35
+
36
+ main();
package/package.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "rad-api",
3
+ "version": "1.0.0",
4
+ "description": "RAD pour créer des routes, controller, model ... etc",
5
+ "main": "index.js",
6
+ "type": "module",
7
+ "bin": {
8
+ "kapi": "index.js"
9
+ },
10
+ "scripts": {
11
+ "test": "echo \"Error: no test specified\" && exit 1"
12
+ },
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "git+https://github.com/kferrandonFulbert/rad-api.git"
16
+ },
17
+ "keywords": [
18
+ "RAD",
19
+ "API",
20
+ "automation"
21
+ ],
22
+ "author": "kferrandon",
23
+ "license": "ISC",
24
+ "bugs": {
25
+ "url": "https://github.com/kferrandonFulbert/rad-api/issues"
26
+ },
27
+ "homepage": "https://github.com/kferrandonFulbert/rad-api#readme"
28
+ }
@@ -0,0 +1,44 @@
1
+ import { readTemplate, writeFile, getOutputPath, fileExists } from '../utils/fileHelper.js';
2
+ import { formatTableName } from '../utils/stringHelper.js';
3
+
4
+ export async function generate(type, tableName, pathOverride='output') {
5
+ try {
6
+ // Valider le nom de la table
7
+ if (!tableName || tableName.trim() === '') {
8
+ throw new Error('Table name cannot be empty');
9
+ }
10
+
11
+ // Formater les noms
12
+ const { tableSingular, tablePlural } = formatTableName(tableName);
13
+
14
+ // Récupérer le template
15
+ let content = readTemplate('route');
16
+
17
+ // Remplacer les placeholders
18
+ content = content.replace(/{{TABLE_SINGULAR}}/g, tableSingular);
19
+ content = content.replace(/{{TABLE_PLURAL}}/g, tablePlural);
20
+
21
+ // Déterminer le chemin de sortie
22
+ const outputPath = getOutputPath(tableName, type, pathOverride);
23
+
24
+ // Vérifier si le fichier existe déjà
25
+ if (fileExists(outputPath)) {
26
+ throw new Error(`File ${tableName}.${type}s.js already exists. Please choose a different name or remove the existing file.`);
27
+ }
28
+
29
+ // Écrire le fichier
30
+ writeFile(outputPath, content);
31
+
32
+ console.log(`✅ ${type} file created successfully!`);
33
+ console.log(`📁 Location: ${outputPath}`);
34
+ console.log(`\n📝 File content generated for table: ${tablePlural}`);
35
+ console.log(` - Handler: all() - Get all ${tablePlural}`);
36
+ console.log(`\n🚀 Next steps:`);
37
+ console.log(` 1. Import this route in your main ${type}`);
38
+ console.log(` 2. Ensure your Prisma client is properly configured`);
39
+ console.log(` 3. Update the adapter path if needed: ../../../generated/prisma/client.js`);
40
+
41
+ } catch (error) {
42
+ throw error;
43
+ }
44
+ }
@@ -0,0 +1,31 @@
1
+ import { PrismaMariaDb } from '@prisma/adapter-mariadb';
2
+ import { PrismaClient } from '../../../generated/prisma/client.js';
3
+
4
+ const maria = new PrismaMariaDb({
5
+ host: process.env.DATABASE_HOST,
6
+ port: process.env.DATABASE_PORT,
7
+ user: process.env.DATABASE_USER,
8
+ password: process.env.DATABASE_PASSWORD,
9
+ database: process.env.DATABASE_NAME
10
+ });
11
+
12
+ const prisma = new PrismaClient({ adapter: maria });
13
+
14
+ export const all = async (req, res) => {
15
+ req.log?.info('all {{TABLE_PLURAL}} endpoint');
16
+ try {
17
+ const all{{TABLE_SINGULAR}} = await main();
18
+
19
+ res.status(200);
20
+ res.json(all{{TABLE_SINGULAR}});
21
+ } catch (error) {
22
+ req.log?.error('Error fetching {{TABLE_PLURAL}}:', error);
23
+ return res.status(500).json({ msg: 'Internal Server Error' });
24
+ }
25
+ };
26
+
27
+ async function main() {
28
+ const all{{TABLE_SINGULAR}} = await prisma.{{TABLE_PLURAL}}.findMany()
29
+ console.log('All {{TABLE_PLURAL}}:', JSON.stringify(all{{TABLE_SINGULAR}}, null, 2))
30
+ return all{{TABLE_SINGULAR}};
31
+ }
@@ -0,0 +1,23 @@
1
+ import { Router } from 'express';
2
+ import { all } from '../controllers/citations.controller.js';
3
+ import { authMiddleware } from '../middlewares/auth.middleware.js';
4
+
5
+ const router = Router();
6
+
7
+ /**
8
+ * @openapi
9
+ * /{TABLE_SINGULAR}/:
10
+ * get:
11
+ * summary: get all {TABLE_PLURAL}
12
+ * responses:
13
+ * 200:
14
+ * description: OK
15
+ * content:
16
+ * application/json:
17
+ * schema:
18
+ * type: object
19
+ *
20
+ */
21
+ router.get('/', all);
22
+
23
+ export default router;
@@ -0,0 +1,42 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { fileURLToPath } from 'url';
4
+
5
+ const __filename = fileURLToPath(import.meta.url);
6
+ const __dirname = path.dirname(__filename);
7
+
8
+ export function getOutputPath(tableName, type = 'route', pathOverride = 'output') {
9
+ // Le fichier sera créé dans le répertoire output
10
+ let cwd =null;
11
+ if (pathOverride === 'output') {
12
+ cwd = process.cwd() + "/" + pathOverride;
13
+ } else {
14
+ cwd = pathOverride;
15
+ }
16
+
17
+ return path.join(cwd, `${tableName}.${type}.js`);
18
+ }
19
+
20
+ export function fileExists(filePath) {
21
+ return fs.existsSync(filePath);
22
+ }
23
+
24
+ export function writeFile(filePath, content) {
25
+ const dir = path.dirname(filePath);
26
+
27
+ // Créer le répertoire s'il n'existe pas
28
+ if (!fs.existsSync(dir)) {
29
+ fs.mkdirSync(dir, { recursive: true });
30
+ }
31
+
32
+ fs.writeFileSync(filePath, content, 'utf-8');
33
+ }
34
+
35
+ export function getTemplatePath(templateName) {
36
+ return path.join(__dirname, '..', 'templates', `${templateName}.template.js`);
37
+ }
38
+
39
+ export function readTemplate(templateName) {
40
+ const templatePath = getTemplatePath(templateName);
41
+ return fs.readFileSync(templatePath, 'utf-8');
42
+ }
@@ -0,0 +1,24 @@
1
+ export function parseArgs(args) {
2
+ const result = {
3
+ command: null,
4
+ type: null,
5
+ table: null,
6
+ path: 'output'
7
+ };
8
+
9
+ if (args.length === 0) return result;
10
+
11
+ result.command = args[0]; // 'generate'
12
+
13
+ if (args.length > 1) {
14
+ result.type = args[1]; // 'route'
15
+ }
16
+
17
+ if (args.length > 2) {
18
+ result.table = args[2]; // 'citations'
19
+ }
20
+ if (args.length > 3) {
21
+ result.path = args[3]; // 'path'
22
+ }
23
+ return result;
24
+ }
@@ -0,0 +1,36 @@
1
+ export function capitalize(str) {
2
+ return str.charAt(0).toUpperCase() + str.slice(1);
3
+ }
4
+
5
+ export function singularize(word) {
6
+ // Règles simples de singularisation pour le français/anglais
7
+ if (word.endsWith('ies')) {
8
+ return word.slice(0, -3) + 'y';
9
+ }
10
+ if (word.endsWith('es')) {
11
+ return word.slice(0, -2);
12
+ }
13
+ if (word.endsWith('s')) {
14
+ return word.slice(0, -1);
15
+ }
16
+ return word;
17
+ }
18
+
19
+ export function toPascalCase(str) {
20
+ return str
21
+ .split(/[-_]/)
22
+ .map(word => capitalize(word))
23
+ .join('');
24
+ }
25
+
26
+ export function formatTableName(tableName) {
27
+ const plural = tableName.toLowerCase();
28
+ const singular = toPascalCase(singularize(tableName));
29
+ const pluralPascal = toPascalCase(tableName);
30
+
31
+ return {
32
+ tableName: plural,
33
+ tableSingular: singular,
34
+ tablePlural: pluralPascal
35
+ };
36
+ }