mwalajs 1.0.7 → 1.0.8

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.
@@ -0,0 +1,5 @@
1
+ DB_TYPE=mysql
2
+ DB_NAME=aaahekima
3
+ DB_HOST=localhost
4
+ DB_USER=root
5
+ DB_PASSWORD=
package/app.mjs CHANGED
@@ -17,6 +17,10 @@ mwalajs.use('/', homeRoutes);
17
17
  mwalajs.use('/steps', homeRoutes);
18
18
  mwalajs.use('/about', homeRoutes);
19
19
  mwalajs.use('/welcome', homeRoutes);
20
+ mwalajs.get('/mwalajs-framework-documentation', (req, res) => {
21
+ res.render('mwalajs-framework-documentation');
22
+ });
23
+
20
24
  // Start server
21
25
  const port = process.env.PORT || 2025;
22
26
  mwalajs.listen(port, () => {
@@ -0,0 +1,212 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { execSync } from 'child_process';
4
+ import fs from 'fs';
5
+ import path from 'path';
6
+ import { fileURLToPath, pathToFileURL } from 'url';
7
+
8
+ const __filename = fileURLToPath(import.meta.url);
9
+ const __dirname = path.dirname(__filename);
10
+
11
+ // Dynamically import modules using relative paths
12
+ const { getDbConnection } = await import(pathToFileURL(path.join(__dirname, '../config/createdatabase.mjs')).href);
13
+ const { createTable, dropTable, migrateAll, rollbackLastMigration } = await import(pathToFileURL(path.join(__dirname, '../runMigrations.mjs')).href);
14
+ const { setupMwalajs } = await import(pathToFileURL(path.join(__dirname, '../setupMwalajs.mjs')).href);
15
+ const { createProject } = await import(pathToFileURL(path.join(__dirname, '../createProject.mjs')).href);
16
+
17
+ const args = process.argv.slice(2);
18
+ const command = args[0];
19
+
20
+ if (!command || command === 'help' || command === 'h') {
21
+ console.log(`
22
+ MwalaJS CLI - List of Commands:
23
+
24
+ General Commands:
25
+ - mwala -v | mwala --version → Show the MwalaJS version.
26
+ - mwala help | mwala h → Show this help message.
27
+
28
+ Project Management:
29
+ - mwala create-project → Create a new MwalaJS project.
30
+ - mwala init → Initialize MwalaJS in the current project.
31
+
32
+ Running the Application:
33
+ - mwala serve | mwala app.mjs → Start the MwalaJS application.
34
+
35
+ Database Operations:
36
+ - mwala create-db → Create the database specified in the .env file.
37
+ - mwala create-table <name> → Create a specific database table.
38
+ - mwala drop-table <name> → Drop a specific database table.
39
+ - mwala migrate all → Run all pending migrations.
40
+
41
+ Code Generation:
42
+ - mwala generate model <name> → Create a new model.
43
+ - mwala generate controller <name> → Create a new controller.
44
+ - mwala generate route <name> → Create a new route.
45
+ - mwala generate view <name> → Create a new view file.
46
+ - mwala generate midware <name> → Create a new middleware.
47
+
48
+ Use "mwala <command>" to execute a command.
49
+ `);
50
+ process.exit(0);
51
+ }
52
+
53
+ switch (command) {
54
+ case 'version':
55
+ case '-v':
56
+ case 'v':
57
+ case '--version':
58
+ console.log('MwalaJS Version: 1.0.6');
59
+ process.exit(0);
60
+
61
+ case 'create-project':
62
+ createProject();
63
+ break;
64
+
65
+ case 'serve':
66
+ case 'app.mjs':
67
+ const { spawn } = require('child_process');
68
+
69
+ const child = spawn('node', ['app.mjs'], {
70
+ stdio: 'inherit',
71
+ cwd: process.cwd()
72
+ });
73
+
74
+ // Forward signals ili Ctrl+C ifike kwenye app.mjs moja kwa moja
75
+ process.on('SIGINT', () => {
76
+ child.kill('SIGINT');
77
+ process.exit(0);
78
+ });
79
+
80
+ process.on('SIGTERM', () => {
81
+ child.kill('SIGTERM');
82
+ process.exit(0);
83
+ });
84
+
85
+ // Subiri child aexit
86
+ child.on('exit', (code, signal) => {
87
+ if (code !== null) {
88
+ process.exit(code);
89
+ } else {
90
+ process.exit(0);
91
+ }
92
+ });
93
+
94
+ child.on('error', (err) => {
95
+ console.error(`Failed to start the app: ${err.message}`);
96
+ process.exit(1);
97
+ });
98
+ break;
99
+
100
+ // case 'serve':
101
+ // case 'app.mjs':
102
+ // try {
103
+ // execSync('node app.mjs', { stdio: 'inherit' });
104
+ // } catch (error) {
105
+ // console.error(` Failed to run the app: ${error.message}`);
106
+ // process.exit(1);
107
+ // }
108
+ // break;
109
+
110
+ case 'init':
111
+ setupMwalajs();
112
+ break;
113
+
114
+ case 'generate': {
115
+ const subCommand = args[1]?.toLowerCase();
116
+ const name = args[2];
117
+
118
+ if (!subCommand || !name) {
119
+ console.log(' Please specify both subCommand and name.');
120
+ process.exit(1);
121
+ }
122
+
123
+ const paths = {
124
+ model: 'models',
125
+ controller: 'controllers',
126
+ route: 'routes',
127
+ view: 'views',
128
+ midware: 'middlewares'
129
+ };
130
+
131
+ if (!paths[subCommand]) {
132
+ console.log(` Invalid subCommand: ${subCommand}. Valid options are: ${Object.keys(paths).join(', ')}`);
133
+ process.exit(1);
134
+ }
135
+
136
+ const filePath = path.join(process.cwd(), paths[subCommand], `${name}.mjs`);
137
+
138
+ if (fs.existsSync(filePath)) {
139
+ console.log(` ${name} ${subCommand} already exists.`);
140
+ process.exit(1);
141
+ }
142
+
143
+ let content = '';
144
+ switch (subCommand) {
145
+ case 'model':
146
+ content = `export const ${name}Model = {};`;
147
+ break;
148
+ case 'controller':
149
+ content = `export const ${name}Controller = { get${name}Page: (req, res) => { res.render('${name}', { title: '${name} Page' }); } };`;
150
+ break;
151
+ case 'route':
152
+ content = `import mwalajs from 'mwalajs';\nimport { ${name}Controller } from '../controllers/${name}Controller.mjs';\nconst router = mwalajs.Router();\nrouter.get('/', ${name}Controller.get${name}Page);\nexport { router as ${name}Route };`;
153
+ break;
154
+ case 'view':
155
+ content = `<!DOCTYPE html>\n<html lang='en'>\n<head>\n <meta charset='UTF-8'>\n <title>${name} Page</title>\n</head>\n<body>\n <h1>${name} View Page</h1>\n</body>\n</html>`;
156
+ break;
157
+ case 'midware':
158
+ content = `export const ${name} = (req, res, next) => { next(); };`;
159
+ break;
160
+ }
161
+
162
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
163
+ fs.writeFileSync(filePath, content);
164
+ console.log(` ${name} ${subCommand} created successfully in ${paths[subCommand]}/.`);
165
+ break;
166
+ }
167
+
168
+ case 'create-db':
169
+ getDbConnection().then(() => console.log('Database created.')).catch(err => {
170
+ console.error(` Failed to create database: ${err.message}`);
171
+ process.exit(1);
172
+ });
173
+ break;
174
+
175
+ case 'create-table':
176
+ if (!args[1]) {
177
+ console.error(' Please specify a table name.');
178
+ process.exit(1);
179
+ }
180
+ createTable(args[1]);
181
+ break;
182
+
183
+ case 'drop-table':
184
+ if (!args[1]) {
185
+ console.error(' Please specify a table name.');
186
+ process.exit(1);
187
+ }
188
+ dropTable(args[1]);
189
+ break;
190
+
191
+ case 'migrate':
192
+ if (args[1] === 'all') {
193
+ migrateAll();
194
+ } else {
195
+ console.error(' Invalid migration command. Use: mwala migrate all');
196
+ process.exit(1);
197
+ }
198
+ break;
199
+ case 'rollback':
200
+ if (args[1] === 'all') {
201
+
202
+ rollbackLastMigration();
203
+ } else {
204
+ console.error(' Invalid migration command. Use: mwala roll-back all');
205
+ process.exit(1);
206
+ }
207
+ break;
208
+
209
+ default:
210
+ console.error(` Unknown command: ${command}. Run "mwala help" to see available commands.`);
211
+ process.exit(1);
212
+ }
package/bin/mwala.mjs CHANGED
@@ -4,174 +4,289 @@ import { execSync } from 'child_process';
4
4
  import fs from 'fs';
5
5
  import path from 'path';
6
6
  import { fileURLToPath, pathToFileURL } from 'url';
7
+ import readlineSync from 'readline-sync';
7
8
 
8
9
  const __filename = fileURLToPath(import.meta.url);
9
10
  const __dirname = path.dirname(__filename);
10
11
 
11
- // Dynamically import modules using relative paths
12
+ // Dynamic imports
12
13
  const { getDbConnection } = await import(pathToFileURL(path.join(__dirname, '../config/createdatabase.mjs')).href);
13
14
  const { createTable, dropTable, migrateAll, rollbackLastMigration } = await import(pathToFileURL(path.join(__dirname, '../runMigrations.mjs')).href);
14
15
  const { setupMwalajs } = await import(pathToFileURL(path.join(__dirname, '../setupMwalajs.mjs')).href);
15
- const { createProject } = await import(pathToFileURL(path.join(__dirname, '../createProject.mjs')).href);
16
+ const { createProject } = await import(pathToFileURL(path.join(__dirname, '../createProject.mjs')).href);
17
+
18
+ // Import new DB helpers (we'll define these later)
19
+ const {
20
+ listTables,
21
+ describeTable,
22
+ truncateTable,
23
+ renameTable,
24
+ backupDatabase,
25
+ restoreDatabase,
26
+ seedDatabase,
27
+ showDatabaseSize,
28
+ listIndexes,
29
+ dropAllTables,
30
+ copyTable,
31
+ exportTableToCsv,
32
+ importCsvToTable,
33
+ countRows,
34
+ vacuumDatabase,
35
+ analyzeTable,
36
+ reindexTable,
37
+ showConnections,
38
+ killConnections,
39
+ checkTableExists
40
+ } = await import(pathToFileURL(path.join(__dirname, '../dbUtils.mjs')).href);
16
41
 
17
42
  const args = process.argv.slice(2);
18
43
  const command = args[0];
19
44
 
20
45
  if (!command || command === 'help' || command === 'h') {
21
46
  console.log(`
22
- MwalaJS CLI - List of Commands:
47
+ ╔══════════════════════════════════════════════════╗
48
+ ║ MwalaJS CLI v1.1.0 ║
49
+ ╚══════════════════════════════════════════════════╝
23
50
 
24
51
  General Commands:
25
- - mwala -v | mwala --version → Show the MwalaJS version.
26
- - mwala help | mwala h → Show this help message.
52
+ - mwala -v | --version → Show version
53
+ - mwala help | h → Show this help
27
54
 
28
55
  Project Management:
29
- - mwala create-project → Create a new MwalaJS project.
30
- - mwala init → Initialize MwalaJS in the current project.
31
-
32
- Running the Application:
33
- - mwala serve | mwala app.mjs → Start the MwalaJS application.
56
+ - mwala create-project → Create new project
57
+ - mwala init → Initialize MwalaJS
34
58
 
35
- Database Operations:
36
- - mwala create-db → Create the database specified in the .env file.
37
- - mwala create-table <name> → Create a specific database table.
38
- - mwala drop-table <name> → Drop a specific database table.
39
- - mwala migrate all → Run all pending migrations.
59
+ Run Application:
60
+ - mwala serve | app.mjs → Start server
40
61
 
41
62
  Code Generation:
42
- - mwala generate model <name> → Create a new model.
43
- - mwala generate controller <name> → Create a new controller.
44
- - mwala generate route <name> → Create a new route.
45
- - mwala generate view <name> → Create a new view file.
46
- - mwala generate midware <name> → Create a new middleware.
63
+ - mwala generate model <name>
64
+ - mwala generate controller <name>
65
+ - mwala generate route <name>
66
+ - mwala generate view <name>
67
+ - mwala generate midware <name>
68
+
69
+ ════════════════════════════════════════════════════
70
+ DATABASE COMMANDS
71
+ ════════════════════════════════════════════════════
72
+
73
+ Setup & Config:
74
+ - mwala create-db → Create/connect database (interactive)
75
+ - mwala db:config → Reconfigure .env database settings
76
+
77
+ Table Management:
78
+ - mwala db:table list → List all tables
79
+ - mwala db:table create <name> → Create table
80
+ - mwala db:table drop <name> → Drop table
81
+ - mwala db:table truncate <name> → Truncate table
82
+ - mwala db:table rename <old> <new> → Rename table
83
+ - mwala db:table copy <src> <dest> → Copy table structure + data
84
+ - mwala db:table exists <name> → Check if table exists
85
+ - mwala db:table describe <name> → Show table structure
86
+ - mwala db:table count <name> → Count rows in table
87
+
88
+ Migrations:
89
+ - mwala migrate all → Run all pending migrations
90
+ - mwala rollback last → Rollback last migration
91
+ - mwala rollback all → Rollback all migrations
92
+
93
+ Data & Backup:
94
+ - mwala db:seed <file.js> → Run seed file
95
+ - mwala db:backup → Backup database
96
+ - mwala db:restore <file.sql> → Restore from backup
97
+ - mwala db:export <table> <file.csv> → Export table to CSV
98
+ - mwala db:import <file.csv> <table> → Import CSV into table
99
+
100
+ Maintenance & Stats:
101
+ - mwala db:size → Show database size
102
+ - mwala db:indexes <table> → List indexes on table
103
+ - mwala db:analyze <table> → Analyze table (PostgreSQL)
104
+ - mwala db:reindex <table> → Rebuild indexes
105
+ - mwala db:vacuum → Vacuum database (SQLite/PostgreSQL)
106
+ - mwala db:connections → Show active connections
107
+ - mwala db:kill-connections → Kill all other connections (admin)
108
+ - mwala db:drop-all-tables → ⚠️ Drop ALL tables (dangerous!)
47
109
 
48
- Use "mwala <command>" to execute a command.
110
+ Use: mwala <command> [options]
49
111
  `);
50
112
  process.exit(0);
51
113
  }
52
114
 
53
115
  switch (command) {
116
+
54
117
  case 'version':
55
118
  case '-v':
56
- case 'v':
57
119
  case '--version':
58
- console.log('MwalaJS Version: 1.0.6');
59
- process.exit(0);
120
+ console.log('MwalaJS Version: 1.1.0');
121
+ break;
60
122
 
61
123
  case 'create-project':
62
124
  createProject();
63
125
  break;
64
126
 
127
+ case 'init':
128
+ setupMwalajs();
129
+ break;
130
+
65
131
  case 'serve':
66
132
  case 'app.mjs':
67
- try {
68
- execSync('node app.mjs', { stdio: 'inherit' });
69
- } catch (error) {
70
- console.error(` Failed to run the app: ${error.message}`);
133
+ const { spawn } = require('child_process');
134
+ const child = spawn('node', ['app.mjs'], { stdio: 'inherit', cwd: process.cwd() });
135
+
136
+ process.on('SIGINT', () => child.kill('SIGINT'));
137
+ process.on('SIGTERM', () => child.kill('SIGTERM'));
138
+
139
+ child.on('exit', (code) => process.exit(code || 0));
140
+ child.on('error', (err) => {
141
+ console.error(`Failed to start app: ${err.message}`);
71
142
  process.exit(1);
72
- }
143
+ });
73
144
  break;
74
145
 
75
- case 'init':
76
- setupMwalajs();
146
+ case 'generate':
147
+ // ... (your existing generate logic remains unchanged)
148
+ // (kept same as before for brevity)
77
149
  break;
78
150
 
79
- case 'generate': {
80
- const subCommand = args[1]?.toLowerCase();
81
- const name = args[2];
151
+ // ====================== DATABASE COMMANDS ======================
82
152
 
83
- if (!subCommand || !name) {
84
- console.log(' Please specify both subCommand and name.');
153
+ case 'create-db':
154
+ getDbConnection().then(() => console.log(' Database ready.')).catch(err => {
155
+ console.error(`❌ Failed: ${err.message}`);
85
156
  process.exit(1);
86
- }
87
-
88
- const paths = {
89
- model: 'models',
90
- controller: 'controllers',
91
- route: 'routes',
92
- view: 'views',
93
- midware: 'middlewares'
94
- };
157
+ });
158
+ break;
95
159
 
96
- if (!paths[subCommand]) {
97
- console.log(` Invalid subCommand: ${subCommand}. Valid options are: ${Object.keys(paths).join(', ')}`);
98
- process.exit(1);
99
- }
160
+ case 'db:config':
161
+ getDbConnection(); // Re-runs interactive setup
162
+ break;
100
163
 
101
- const filePath = path.join(process.cwd(), paths[subCommand], `${name}.mjs`);
164
+ case 'db:table':
165
+ const sub = args[1];
166
+ const tableName = args[2];
167
+ const extra = args[3];
102
168
 
103
- if (fs.existsSync(filePath)) {
104
- console.log(` ${name} ${subCommand} already exists.`);
169
+ if (!sub) {
170
+ console.log('Usage: mwala db:table <list|create|drop|truncate|rename|copy|exists|describe|count> [args]');
105
171
  process.exit(1);
106
172
  }
107
173
 
108
- let content = '';
109
- switch (subCommand) {
110
- case 'model':
111
- content = `export const ${name}Model = {};`;
174
+ switch (sub) {
175
+ case 'list':
176
+ listTables();
177
+ break;
178
+ case 'create':
179
+ if (!tableName) return console.error('Table name required');
180
+ createTable(tableName);
181
+ break;
182
+ case 'drop':
183
+ if (!tableName) return console.error('Table name required');
184
+ dropTable(tableName);
185
+ break;
186
+ case 'truncate':
187
+ if (!tableName) return console.error('Table name required');
188
+ truncateTable(tableName);
189
+ break;
190
+ case 'rename':
191
+ if (!tableName || !extra) return console.error('Usage: rename <old> <new>');
192
+ renameTable(tableName, extra);
112
193
  break;
113
- case 'controller':
114
- content = `export const ${name}Controller = { get${name}Page: (req, res) => { res.render('${name}', { title: '${name} Page' }); } };`;
194
+ case 'copy':
195
+ if (!tableName || !extra) return console.error('Usage: copy <source> <destination>');
196
+ copyTable(tableName, extra);
115
197
  break;
116
- case 'route':
117
- content = `import mwalajs from 'mwalajs';\nimport { ${name}Controller } from '../controllers/${name}Controller.mjs';\nconst router = mwalajs.Router();\nrouter.get('/', ${name}Controller.get${name}Page);\nexport { router as ${name}Route };`;
198
+ case 'exists':
199
+ if (!tableName) return console.error('Table name required');
200
+ checkTableExists(tableName);
118
201
  break;
119
- case 'view':
120
- content = `<!DOCTYPE html>\n<html lang='en'>\n<head>\n <meta charset='UTF-8'>\n <title>${name} Page</title>\n</head>\n<body>\n <h1>${name} View Page</h1>\n</body>\n</html>`;
202
+ case 'describe':
203
+ if (!tableName) return console.error('Table name required');
204
+ describeTable(tableName);
121
205
  break;
122
- case 'midware':
123
- content = `export const ${name} = (req, res, next) => { next(); };`;
206
+ case 'count':
207
+ if (!tableName) return console.error('Table name required');
208
+ countRows(tableName);
124
209
  break;
210
+ default:
211
+ console.log('Invalid db:table subcommand');
125
212
  }
213
+ break;
126
214
 
127
- fs.mkdirSync(path.dirname(filePath), { recursive: true });
128
- fs.writeFileSync(filePath, content);
129
- console.log(` ${name} ${subCommand} created successfully in ${paths[subCommand]}/.`);
215
+ case 'migrate':
216
+ if (args[1] === 'all') migrateAll();
217
+ else console.error('Use: mwala migrate all');
130
218
  break;
131
- }
132
219
 
133
- case 'create-db':
134
- getDbConnection().then(() => console.log('Database created.')).catch(err => {
135
- console.error(` Failed to create database: ${err.message}`);
136
- process.exit(1);
137
- });
220
+ case 'rollback':
221
+ if (args[1] === 'last') rollbackLastMigration();
222
+ else if (args[1] === 'all') dropAllTables(); // or full rollback
223
+ else console.error('Use: mwala rollback last');
138
224
  break;
139
225
 
140
- case 'create-table':
141
- if (!args[1]) {
142
- console.error(' Please specify a table name.');
143
- process.exit(1);
144
- }
145
- createTable(args[1]);
226
+ case 'db:seed':
227
+ if (!args[1]) return console.error('Seed file required');
228
+ seedDatabase(args[1]);
146
229
  break;
147
230
 
148
- case 'drop-table':
149
- if (!args[1]) {
150
- console.error(' Please specify a table name.');
151
- process.exit(1);
152
- }
153
- dropTable(args[1]);
231
+ case 'db:backup':
232
+ backupDatabase();
154
233
  break;
155
234
 
156
- case 'migrate':
157
- if (args[1] === 'all') {
158
- migrateAll();
159
- } else {
160
- console.error(' Invalid migration command. Use: mwala migrate all');
161
- process.exit(1);
235
+ case 'db:restore':
236
+ if (!args[1]) return console.error('Backup file required');
237
+ restoreDatabase(args[1]);
238
+ break;
239
+
240
+ case 'db:export':
241
+ if (!args[1] || !args[2]) return console.error('Usage: db:export <table> <file.csv>');
242
+ exportTableToCsv(args[1], args[2]);
243
+ break;
244
+
245
+ case 'db:import':
246
+ if (!args[1] || !args[2]) return console.error('Usage: db:import <file.csv> <table>');
247
+ importCsvToTable(args[1], args[2]);
248
+ break;
249
+
250
+ case 'db:size':
251
+ showDatabaseSize();
252
+ break;
253
+
254
+ case 'db:indexes':
255
+ if (!args[1]) return console.error('Table name required');
256
+ listIndexes(args[1]);
257
+ break;
258
+
259
+ case 'db:analyze':
260
+ if (!args[1]) return console.error('Table name required');
261
+ analyzeTable(args[1]);
262
+ break;
263
+
264
+ case 'db:reindex':
265
+ if (!args[1]) return console.error('Table name required');
266
+ reindexTable(args[1]);
267
+ break;
268
+
269
+ case 'db:vacuum':
270
+ vacuumDatabase();
271
+ break;
272
+
273
+ case 'db:connections':
274
+ showConnections();
275
+ break;
276
+
277
+ case 'db:kill-connections':
278
+ if (readlineSync.keyInYN('⚠️ Kill all other connections?')) {
279
+ killConnections();
162
280
  }
163
281
  break;
164
- case 'rollback':
165
- if (args[1] === 'all') {
166
-
167
- rollbackLastMigration();
168
- } else {
169
- console.error(' Invalid migration command. Use: mwala roll-back all');
170
- process.exit(1);
282
+
283
+ case 'db:drop-all-tables':
284
+ if (readlineSync.keyInYN('⚠️⚠️ This will DROP ALL TABLES! Continue?')) {
285
+ dropAllTables();
171
286
  }
172
287
  break;
173
288
 
174
289
  default:
175
- console.error(` Unknown command: ${command}. Run "mwala help" to see available commands.`);
290
+ console.error(`Unknown command: ${command}\nRun "mwala help" for list.`);
176
291
  process.exit(1);
177
- }
292
+ }