mwalajs 1.0.1

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.
Files changed (57) hide show
  1. package/.env +5 -0
  2. package/LICENSE +21 -0
  3. package/README.md +542 -0
  4. package/app.mjs +23 -0
  5. package/bin/backupnewclean.js +162 -0
  6. package/bin/mwala.mjs +176 -0
  7. package/config/createTablesetdb.mjs +38 -0
  8. package/config/createdatabase.mjs +157 -0
  9. package/config/serverConfig.mjs +1 -0
  10. package/controllers/fileController.mjs +15 -0
  11. package/controllers/homeController.mjs +28 -0
  12. package/createProject.mjs +120 -0
  13. package/migrations/20250308115724_create_users.mjs +45 -0
  14. package/migrations/20250724111240_create_transactions.mjs +19 -0
  15. package/migrations/migration_log.json +1 -0
  16. package/models/exampleModel.mjs +5 -0
  17. package/mwala +5 -0
  18. package/mwala.cmd +2 -0
  19. package/mwalajs/index.js +109 -0
  20. package/mwalajs/index.mjs +121 -0
  21. package/mwalajs/package-lock.json +836 -0
  22. package/mwalajs/package.json +16 -0
  23. package/package.json +58 -0
  24. package/public/styles.css +115 -0
  25. package/routes/homeRoutes.mjs +12 -0
  26. package/runMigrations.mjs +137 -0
  27. package/setupMwalajs.mjs +58 -0
  28. package/ujasi/README.md +542 -0
  29. package/ujasi/app.mjs +33 -0
  30. package/ujasi/bin/backupnewclean.js +162 -0
  31. package/ujasi/bin/mwala.mjs +176 -0
  32. package/ujasi/config/createTablesetdb.mjs +38 -0
  33. package/ujasi/config/createdatabase.mjs +156 -0
  34. package/ujasi/config/serverConfig.mjs +1 -0
  35. package/ujasi/controllers/fileController.mjs +15 -0
  36. package/ujasi/controllers/homeController.mjs +28 -0
  37. package/ujasi/models/exampleModel.mjs +5 -0
  38. package/ujasi/mwalajs/index.js +109 -0
  39. package/ujasi/mwalajs/index.mjs +121 -0
  40. package/ujasi/mwalajs/package-lock.json +836 -0
  41. package/ujasi/mwalajs/package.json +16 -0
  42. package/ujasi/package-lock.json +8546 -0
  43. package/ujasi/package.json +58 -0
  44. package/ujasi/public/styles.css +115 -0
  45. package/ujasi/routes/homeRoutes.mjs +12 -0
  46. package/ujasi/runMigrations.mjs +137 -0
  47. package/ujasi/setupMwalajs.mjs +58 -0
  48. package/ujasi/views/about.ejs +159 -0
  49. package/ujasi/views/index.ejs +227 -0
  50. package/ujasi/views/sitemap.xml +1 -0
  51. package/ujasi/views/steps.ejs +514 -0
  52. package/ujasi/views/welcome.ejs +257 -0
  53. package/views/about.ejs +159 -0
  54. package/views/index.ejs +227 -0
  55. package/views/sitemap.xml +1 -0
  56. package/views/steps.ejs +514 -0
  57. package/views/welcome.ejs +257 -0
@@ -0,0 +1,162 @@
1
+
2
+ import { execSync } from 'child_process';
3
+ import fs from 'fs';
4
+ import path from 'path';
5
+ import { fileURLToPath, pathToFileURL } from 'url';
6
+
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = path.dirname(__filename);
9
+
10
+ // Dynamically import modules using relative paths
11
+ const { getDbConnection } = await import(pathToFileURL(path.join(__dirname, '../config/createdatabase.mjs')).href);
12
+ const { createTable, dropTable, migrateAll, rollbackLastMigration } = await import(pathToFileURL(path.join(__dirname, '../runMigrations.mjs')).href);
13
+ const { setupMwalajs } = await import(pathToFileURL(path.join(__dirname, '../setupMwalajs.mjs')).href);
14
+
15
+ const args = process.argv.slice(2);
16
+ const command = args[0];
17
+
18
+ if (!command || command === 'help' || command === 'h') {
19
+ console.log(`
20
+ MwalaJS CLI - List of Commands:
21
+
22
+ General:
23
+ - mwala -v | --version → Show the version.
24
+ - mwala help | h → Show this help.
25
+
26
+ Project Management:
27
+ - mwala create-project → Create a new MwalaJS project.
28
+ - mwala init → Initialize MwalaJS.
29
+
30
+ Running App:
31
+ - mwala serve | app.mjs → Start the MwalaJS application.
32
+
33
+ Database:
34
+ - mwala create-db → Create the database.
35
+ - mwala create-table <name> → Create a table.
36
+ - mwala drop-table <name> → Drop a table.
37
+ - mwala migrate all → Run all migrations.
38
+ - mwala rollback all → Roll back last migration.
39
+
40
+ Code Generation:
41
+ - mwala generate model <name>
42
+ - mwala generate controller <name>
43
+ - mwala generate route <name>
44
+ - mwala generate view <name>
45
+ - mwala generate midware <name>
46
+ `);
47
+ process.exit(0);
48
+ }
49
+
50
+ switch (command) {
51
+ case 'version':
52
+ case '-v':
53
+ case '--version':
54
+ console.log('MwalaJS Version: 1.0.0');
55
+ process.exit(0);
56
+
57
+ case 'create-project':
58
+ console.log('Project creation logic goes here.');
59
+ // await createProject(); // Uncomment when implemented
60
+ break;
61
+
62
+ case 'serve':
63
+ case 'app.mjs':
64
+ try {
65
+ execSync('node app.mjs', { stdio: 'inherit' });
66
+ } catch (err) {
67
+ console.error(`Failed to start app: ${err.message}`);
68
+ process.exit(1);
69
+ }
70
+ break;
71
+
72
+ case 'init':
73
+ setupMwalajs();
74
+ break;
75
+
76
+ case 'generate': {
77
+ const subCommand = args[1]?.toLowerCase();
78
+ const name = args[2];
79
+
80
+ if (!subCommand || !name) {
81
+ console.error('Specify both type and name: mwala generate <type> <name>');
82
+ process.exit(1);
83
+ }
84
+
85
+ const map = {
86
+ model: 'models',
87
+ controller: 'controllers',
88
+ route: 'routes',
89
+ view: 'views',
90
+ midware: 'middlewares'
91
+ };
92
+
93
+ if (!map[subCommand]) {
94
+ console.error(`Unknown type '${subCommand}'. Use: ${Object.keys(map).join(', ')}`);
95
+ process.exit(1);
96
+ }
97
+
98
+ const filePath = path.join(process.cwd(), map[subCommand], `${name}.mjs`);
99
+ if (fs.existsSync(filePath)) {
100
+ console.log(`${subCommand} "${name}" already exists.`);
101
+ process.exit(1);
102
+ }
103
+
104
+ const templates = {
105
+ model: `export const ${name}Model = {};`,
106
+ controller: `export const ${name}Controller = { get${name}Page: (req, res) => res.render('${name}', { title: '${name} Page' }) };`,
107
+ route: `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 };`,
108
+ view: `<!DOCTYPE html>\n<html lang="en">\n<head><meta charset="UTF-8"><title>${name} Page</title></head>\n<body>\n<h1>${name} View Page</h1>\n</body>\n</html>`,
109
+ midware: `export const ${name} = (req, res, next) => { next(); };`
110
+ };
111
+
112
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
113
+ fs.writeFileSync(filePath, templates[subCommand]);
114
+ console.log(`${subCommand} "${name}" created at ${filePath}`);
115
+ break;
116
+ }
117
+
118
+ case 'create-db':
119
+ getDbConnection().then(() => console.log('Database created.')).catch(err => {
120
+ console.error(`Database error: ${err.message}`);
121
+ process.exit(1);
122
+ });
123
+ break;
124
+
125
+ case 'create-table':
126
+ if (!args[1]) {
127
+ console.error('Specify table name.');
128
+ process.exit(1);
129
+ }
130
+ createTable(args[1]);
131
+ break;
132
+
133
+ case 'drop-table':
134
+ if (!args[1]) {
135
+ console.error('Specify table name.');
136
+ process.exit(1);
137
+ }
138
+ dropTable(args[1]);
139
+ break;
140
+
141
+ case 'migrate':
142
+ if (args[1] === 'all') {
143
+ migrateAll();
144
+ } else {
145
+ console.error('Use: mwala migrate all');
146
+ process.exit(1);
147
+ }
148
+ break;
149
+
150
+ case 'rollback':
151
+ if (args[1] === 'all') {
152
+ rollbackLastMigration();
153
+ } else {
154
+ console.error('Use: mwala rollback all');
155
+ process.exit(1);
156
+ }
157
+ break;
158
+
159
+ default:
160
+ console.error(`Unknown command: "${command}". Run "mwala help" for options.`);
161
+ process.exit(1);
162
+ }
package/bin/mwala.mjs ADDED
@@ -0,0 +1,176 @@
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 '--version':
57
+ console.log('MwalaJS Version: 1.0.1');
58
+ process.exit(0);
59
+
60
+ case 'create-project':
61
+ createProject();
62
+ break;
63
+
64
+ case 'serve':
65
+ case 'app.mjs':
66
+ try {
67
+ execSync('node app.mjs', { stdio: 'inherit' });
68
+ } catch (error) {
69
+ console.error(` Failed to run the app: ${error.message}`);
70
+ process.exit(1);
71
+ }
72
+ break;
73
+
74
+ case 'init':
75
+ setupMwalajs();
76
+ break;
77
+
78
+ case 'generate': {
79
+ const subCommand = args[1]?.toLowerCase();
80
+ const name = args[2];
81
+
82
+ if (!subCommand || !name) {
83
+ console.log(' Please specify both subCommand and name.');
84
+ process.exit(1);
85
+ }
86
+
87
+ const paths = {
88
+ model: 'models',
89
+ controller: 'controllers',
90
+ route: 'routes',
91
+ view: 'views',
92
+ midware: 'middlewares'
93
+ };
94
+
95
+ if (!paths[subCommand]) {
96
+ console.log(` Invalid subCommand: ${subCommand}. Valid options are: ${Object.keys(paths).join(', ')}`);
97
+ process.exit(1);
98
+ }
99
+
100
+ const filePath = path.join(process.cwd(), paths[subCommand], `${name}.mjs`);
101
+
102
+ if (fs.existsSync(filePath)) {
103
+ console.log(` ${name} ${subCommand} already exists.`);
104
+ process.exit(1);
105
+ }
106
+
107
+ let content = '';
108
+ switch (subCommand) {
109
+ case 'model':
110
+ content = `export const ${name}Model = {};`;
111
+ break;
112
+ case 'controller':
113
+ content = `export const ${name}Controller = { get${name}Page: (req, res) => { res.render('${name}', { title: '${name} Page' }); } };`;
114
+ break;
115
+ case 'route':
116
+ 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 };`;
117
+ break;
118
+ case 'view':
119
+ 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>`;
120
+ break;
121
+ case 'midware':
122
+ content = `export const ${name} = (req, res, next) => { next(); };`;
123
+ break;
124
+ }
125
+
126
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
127
+ fs.writeFileSync(filePath, content);
128
+ console.log(` ${name} ${subCommand} created successfully in ${paths[subCommand]}/.`);
129
+ break;
130
+ }
131
+
132
+ case 'create-db':
133
+ getDbConnection().then(() => console.log('Database created.')).catch(err => {
134
+ console.error(` Failed to create database: ${err.message}`);
135
+ process.exit(1);
136
+ });
137
+ break;
138
+
139
+ case 'create-table':
140
+ if (!args[1]) {
141
+ console.error(' Please specify a table name.');
142
+ process.exit(1);
143
+ }
144
+ createTable(args[1]);
145
+ break;
146
+
147
+ case 'drop-table':
148
+ if (!args[1]) {
149
+ console.error(' Please specify a table name.');
150
+ process.exit(1);
151
+ }
152
+ dropTable(args[1]);
153
+ break;
154
+
155
+ case 'migrate':
156
+ if (args[1] === 'all') {
157
+ migrateAll();
158
+ } else {
159
+ console.error(' Invalid migration command. Use: mwala migrate all');
160
+ process.exit(1);
161
+ }
162
+ break;
163
+ case 'rollback':
164
+ if (args[1] === 'all') {
165
+
166
+ rollbackLastMigration();
167
+ } else {
168
+ console.error(' Invalid migration command. Use: mwala roll-back all');
169
+ process.exit(1);
170
+ }
171
+ break;
172
+
173
+ default:
174
+ console.error(` Unknown command: ${command}. Run "mwala help" to see available commands.`);
175
+ process.exit(1);
176
+ }
@@ -0,0 +1,38 @@
1
+ import Sequelize from 'sequelize';
2
+ import mongoose from 'mongoose';
3
+ import dotenv from 'dotenv';
4
+
5
+ dotenv.config();
6
+
7
+ const dbType = process.env.DB_TYPE || 'mysql';
8
+
9
+ let sequelize;
10
+ let mongooseConnection;
11
+
12
+ /**
13
+ * ✅ Fungua connection kulingana na aina ya database
14
+ */
15
+ if (['mysql', 'postgres', 'sqlite'].includes(dbType)) {
16
+ sequelize = new Sequelize({
17
+ dialect: dbType,
18
+ host: process.env.DB_HOST || 'localhost',
19
+ database: process.env.DB_NAME,
20
+ username: process.env.DB_USER,
21
+ password: process.env.DB_PASSWORD,
22
+ port: process.env.DB_PORT || (dbType === 'mysql' ? 3306 : 5432),
23
+ storage: dbType === 'sqlite' ? process.env.DB_STORAGE || 'database.sqlite' : undefined,
24
+ logging: false
25
+ });
26
+
27
+ } else if (dbType === 'mongodb') {
28
+ const mongoUri = `mongodb://${process.env.DB_HOST || 'localhost'}:${process.env.DB_PORT || 27017}/${process.env.DB_NAME}`;
29
+ mongooseConnection = mongoose.connect(mongoUri, {
30
+ useNewUrlParser: true,
31
+ useUnifiedTopology: true
32
+ });
33
+
34
+ } else {
35
+ throw new Error('Unsupported database type. Check your .env configuration.');
36
+ }
37
+
38
+ export { sequelize, mongooseConnection };
@@ -0,0 +1,157 @@
1
+ import fs from 'fs';
2
+ import readlineSync from 'readline-sync';
3
+ import mysql from 'mysql2/promise';
4
+ import { MongoClient } from 'mongodb';
5
+ import sqlite3 from 'sqlite3';
6
+ import pkg from 'pg';
7
+ import dotenv from 'dotenv';
8
+
9
+ const { Client } = pkg;
10
+
11
+ // Function to reset the .env file before processing
12
+ const resetEnvFile = () => {
13
+ try {
14
+ fs.writeFileSync('.env', '', 'utf8'); // Empty the .env file
15
+ console.log(' Cleared .env file.');
16
+ } catch (error) {
17
+ console.error(' Failed to clear .env file:', error.message);
18
+ }
19
+ };
20
+
21
+ // Function to write data to the .env file
22
+ const writeToEnv = (data) => {
23
+ const envContent = Object.keys(data)
24
+ .map(key => `${key}=${data[key]}`)
25
+ .join('\n');
26
+
27
+ fs.writeFileSync('.env', envContent, 'utf8');
28
+ };
29
+
30
+
31
+ // Function to create the database connection
32
+ export const getDbConnection = async () => {
33
+ resetEnvFile(); // Clear .env file before proceeding
34
+
35
+ dotenv.config(); // Reload the (now empty) .env file
36
+
37
+ // Supported database types
38
+ const supportedDbTypes = {
39
+ mysql: 'mysql',
40
+ my: 'mysql',
41
+ postgresql: 'postgresql',
42
+ pg: 'postgresql',
43
+ mongodb: 'mongodb',
44
+ mn: 'mongodb',
45
+ sqlite: 'sqlite',
46
+ sq: 'sqlite'
47
+ };
48
+
49
+ let dbType;
50
+ while (true) {
51
+ dbType = readlineSync.question('Enter the database type (mysql/my, postgresql/pg, mongodb/mn, sqlite/sq): ').toLowerCase();
52
+ if (supportedDbTypes[dbType]) {
53
+ dbType = supportedDbTypes[dbType]; // Normalize input
54
+ break;
55
+ } else {
56
+ console.log('❌ Invalid database type. Please enter a valid option.');
57
+ }
58
+ }
59
+
60
+ // Prompt for database details
61
+ const dbName = readlineSync.question('Enter the database name: ').trim();
62
+ if (!dbName) {
63
+ console.log(' Database name cannot be empty.');
64
+ return;
65
+ }
66
+
67
+ let dbHost = 'localhost';
68
+ let dbUser = '';
69
+ let dbPassword = '';
70
+
71
+ if (dbType !== 'sqlite') {
72
+ dbHost = readlineSync.question('Enter the database host (default: localhost): ') || 'localhost';
73
+ dbUser = readlineSync.question('Enter the database user: ').trim();
74
+ dbPassword = readlineSync.question('Enter the database password: ', { hideEchoBack: true }).trim();
75
+ }
76
+
77
+ // Save valid details to .env
78
+ const envData = {
79
+ DB_TYPE: dbType,
80
+ DB_NAME: dbName,
81
+ DB_HOST: dbHost,
82
+ DB_USER: dbUser,
83
+ DB_PASSWORD: dbPassword,
84
+ };
85
+
86
+ writeToEnv(envData);
87
+ console.log(' Database credentials saved to .env file.');
88
+
89
+ let connection;
90
+
91
+ try {
92
+ if (dbType === 'mysql') {
93
+ const tempConnection = await mysql.createConnection({
94
+ host: dbHost,
95
+ user: dbUser,
96
+ password: dbPassword,
97
+ });
98
+
99
+ const [rows] = await tempConnection.query(`SHOW DATABASES LIKE '${dbName}'`);
100
+ if (rows.length === 0) {
101
+ await tempConnection.query(`CREATE DATABASE \`${dbName}\``);
102
+ console.log(` MySQL Database "${dbName}" created successfully.`);
103
+ } else {
104
+ console.log(` MySQL Database "${dbName}" already exists.`);
105
+ }
106
+
107
+ connection = await mysql.createConnection({
108
+ host: dbHost,
109
+ user: dbUser,
110
+ password: dbPassword,
111
+ database: dbName,
112
+ });
113
+
114
+ await tempConnection.end();
115
+ } else if (dbType === 'postgresql') {
116
+ const tempClient = new Client({
117
+ host: dbHost,
118
+ user: dbUser,
119
+ password: dbPassword,
120
+ });
121
+
122
+ await tempClient.connect();
123
+
124
+ const checkDb = await tempClient.query(`SELECT datname FROM pg_database WHERE datname = '${dbName}'`);
125
+ if (checkDb.rows.length === 0) {
126
+ await tempClient.query(`CREATE DATABASE ${dbName}`);
127
+ console.log(` PostgreSQL Database "${dbName}" created successfully.`);
128
+ } else {
129
+ console.log(` PostgreSQL Database "${dbName}" already exists.`);
130
+ }
131
+
132
+ await tempClient.end();
133
+
134
+ connection = new Client({
135
+ host: dbHost,
136
+ user: dbUser,
137
+ password: dbPassword,
138
+ database: dbName,
139
+ });
140
+
141
+ await connection.connect();
142
+ } else if (dbType === 'mongodb') {
143
+ connection = await MongoClient.connect(`mongodb://${dbHost}:27017`);
144
+ console.log(` MongoDB connection to "${dbName}" established.`);
145
+ } else if (dbType === 'sqlite') {
146
+ connection = new sqlite3.Database(`./${dbName}.sqlite`);
147
+ console.log(` SQLite Database "${dbName}.sqlite" is ready.`);
148
+ } else {
149
+ throw new Error(` Unsupported DB type: ${dbType}`);
150
+ }
151
+ } catch (error) {
152
+ console.error(` Failed to create database: ${error.message}`);
153
+ return;
154
+ }
155
+
156
+ return connection;
157
+ };
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,15 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+
4
+ export const fileController = {
5
+ uploadFile: (req, res) => {
6
+ const file = req.file;
7
+ if (file) {
8
+ const uploadPath = path.join(__dirname, '../public/uploads/', file.originalname);
9
+ fs.writeFileSync(uploadPath, file.buffer);
10
+ res.send('File uploaded successfully');
11
+ } else {
12
+ res.status(400).send('No file uploaded');
13
+ }
14
+ },
15
+ };
@@ -0,0 +1,28 @@
1
+ //homeController.mjs
2
+ export const homeController = {
3
+ getHomePage: (req, res) => {
4
+ res.render('index', { title: 'Welcome to MwalaJS MVC' });
5
+ }
6
+
7
+ };
8
+
9
+
10
+ export const Steps = {
11
+ getSteps: (req, res) => {
12
+ res.render('steps', { title: 'Welcome to MwalaJS MVC' });
13
+ }
14
+ };
15
+
16
+ export const welcome = {
17
+ getwelcome: (req, res) => {
18
+ res.render('welcome', { title: 'Welcome to MwalaJS MVC' });
19
+ }
20
+ };
21
+
22
+
23
+ export const about = {
24
+ getabout: (req, res) => {
25
+ res.render('about', { title: 'Welcome to MwalaJS MVC' });
26
+ }
27
+ };
28
+
@@ -0,0 +1,120 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+ import readline from 'readline';
4
+ import { exec } from 'child_process';
5
+ import os from 'os';
6
+
7
+ /**
8
+ * Detect base source path from environment or defaults
9
+ */
10
+ function getMwalajsPath() {
11
+ const envPath = process.env.MWALAJSPATH;
12
+
13
+ if (envPath && fs.existsSync(envPath)) return envPath;
14
+
15
+ const defaultPaths = {
16
+ win32: 'C:\\Program Files\\mwalajs',
17
+ linux: '/usr/local/lib/mwalajs',
18
+ darwin: '/usr/local/lib/mwalajs'
19
+ };
20
+
21
+ const fallback = defaultPaths[os.platform()];
22
+ if (fs.existsSync(fallback)) return fallback;
23
+
24
+ console.warn(" mwalajs source path not found. Using current directory.");
25
+ return process.cwd(); // fallback
26
+ }
27
+
28
+ /**
29
+ * Function to create a new project folder, copy required files, and auto-enter the directory.
30
+ */
31
+ async function createProject() {
32
+ const rl = readline.createInterface({
33
+ input: process.stdin,
34
+ output: process.stdout
35
+ });
36
+
37
+ rl.question(" Enter the name of the new project: ", async (projectName) => {
38
+ const currentDir = process.cwd();
39
+ const newProjectPath = path.join(currentDir, projectName);
40
+
41
+ const mwalajsSourcePath = getMwalajsPath();
42
+
43
+ try {
44
+ if (fs.existsSync(newProjectPath)) {
45
+ console.error(` Error: Folder '${projectName}' already exists.`);
46
+ rl.close();
47
+ return;
48
+ }
49
+
50
+ console.log(` Creating folder: ${newProjectPath}...`);
51
+ fs.mkdirSync(newProjectPath);
52
+
53
+ const itemsToCopy = [
54
+ "app.mjs", "controllers", "mwalajs", "routes",
55
+ "views", "middlewares", "models", "package.json",
56
+ "README.md", "public"
57
+ ];
58
+
59
+ for (const item of itemsToCopy) {
60
+ const src = path.join(mwalajsSourcePath, item);
61
+ const dest = path.join(newProjectPath, item);
62
+
63
+ if (fs.existsSync(src)) {
64
+ console.log(` Copying '${item}'...`);
65
+ fs.copySync(src, dest);
66
+ } else {
67
+ console.warn(` '${item}' not found in source. Skipping...`);
68
+ }
69
+ }
70
+
71
+ console.log(` Project '${projectName}' created successfully!`);
72
+ console.log(` Location: ${newProjectPath}`);
73
+
74
+ // Open terminal automatically
75
+ const platform = os.platform();
76
+
77
+ if (platform === 'win32') {
78
+ exec(`start cmd.exe /K "cd /d ${newProjectPath}"`);
79
+ } else if (platform === 'darwin') {
80
+ exec(`open -a Terminal "${newProjectPath}"`);
81
+ } else if (platform === 'linux') {
82
+ // Try gnome-terminal, x-terminal-emulator, or konsole
83
+ const termCmds = [
84
+ `gnome-terminal -- bash -c 'cd "${newProjectPath}" && bash'`,
85
+ `x-terminal-emulator -e 'bash -c "cd \\"${newProjectPath}\\"; exec bash"'`,
86
+ `konsole --workdir "${newProjectPath}"`
87
+ ];
88
+ let opened = false;
89
+
90
+ for (const cmd of termCmds) {
91
+ try {
92
+ exec(cmd, (error) => {
93
+ if (!error && !opened) opened = true;
94
+ });
95
+ break;
96
+ } catch {}
97
+ }
98
+
99
+ if (!opened) {
100
+ console.log(" Please manually open the folder:", newProjectPath);
101
+ }
102
+ } else {
103
+ console.log(" Unknown OS. Please open manually:", newProjectPath);
104
+ }
105
+
106
+ } catch (err) {
107
+ console.error(" Project creation failed:", err.message);
108
+ } finally {
109
+ rl.close();
110
+ }
111
+ });
112
+ }
113
+
114
+ // Export if used as a module
115
+ export { createProject };
116
+
117
+ // Run directly
118
+ if (import.meta.url === `file://${process.argv[1]}`) {
119
+ createProject();
120
+ }