mwalajs 1.1.14 → 1.1.16
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/createProject copy.mjs +140 -0
- package/createProject.mjs +205 -79
- package/package.json +1 -1
- package/test/README.md +591 -0
- package/test/app.mjs +28 -0
- package/test/controllers/fileController.mjs +15 -0
- package/test/controllers/homeController.mjs +28 -0
- package/test/migrations/20250308115724_create_users.mjs +45 -0
- package/test/migrations/20250724111240_create_transactions.mjs +19 -0
- package/test/migrations/20260321052103_create_users.mjs +19 -0
- package/test/migrations/20260321052120_create_logs.mjs +19 -0
- package/test/migrations/20260321073512_create_user12.mjs +20 -0
- package/test/migrations/migration_log.json +1 -0
- package/test/models/exampleModel.mjs +5 -0
- package/test/models/h.mjs +1 -0
- package/test/public/styles.css +115 -0
- package/test/routes/homeRoutes.mjs +12 -0
- package/test/views/about.ejs +159 -0
- package/test/views/h.ejs +10 -0
- package/test/views/h.ejs.mjs +10 -0
- package/test/views/h.mjs +10 -0
- package/test/views/index.ejs +227 -0
- package/test/views/sitemap.xml +1 -0
- package/test/views/steps.ejs +514 -0
- package/test/views/welcome.ejs +257 -0
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import readline from 'readline';
|
|
4
|
+
import os from 'os';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Get global template path (FIXED)
|
|
9
|
+
*/
|
|
10
|
+
function getMwalajsPath() {
|
|
11
|
+
const envPath = process.env.MWALAJSPATH;
|
|
12
|
+
|
|
13
|
+
if (envPath && fs.existsSync(envPath)) {
|
|
14
|
+
return envPath;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* IMPORTANT FIX:
|
|
19
|
+
* Get path of installed npm package, NOT cwd
|
|
20
|
+
*/
|
|
21
|
+
try {
|
|
22
|
+
const modulePath = path.dirname(fileURLToPath(import.meta.url));
|
|
23
|
+
|
|
24
|
+
// go up to package root
|
|
25
|
+
const rootPath = path.resolve(modulePath, '..');
|
|
26
|
+
|
|
27
|
+
if (fs.existsSync(path.join(rootPath, 'app.mjs'))) {
|
|
28
|
+
return rootPath;
|
|
29
|
+
}
|
|
30
|
+
} catch (err) {}
|
|
31
|
+
|
|
32
|
+
const fallbackPaths = {
|
|
33
|
+
win32: 'C:\\Program Files\\mwalajs',
|
|
34
|
+
linux: '/usr/local/lib/mwalajs',
|
|
35
|
+
darwin: '/usr/local/lib/mwalajs'
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const fallback = fallbackPaths[os.platform()];
|
|
39
|
+
|
|
40
|
+
if (fallback && fs.existsSync(fallback)) {
|
|
41
|
+
return fallback;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
throw new Error("❌ MwalaJS template source not found. Set MWALAJSPATH.");
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Ask helper
|
|
49
|
+
*/
|
|
50
|
+
function askQuestion(rl, question) {
|
|
51
|
+
return new Promise(resolve => {
|
|
52
|
+
rl.question(question, ans => resolve(ans.trim()));
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Create project
|
|
58
|
+
*/
|
|
59
|
+
export async function createProject(projectArg) {
|
|
60
|
+
const rl = readline.createInterface({
|
|
61
|
+
input: process.stdin,
|
|
62
|
+
output: process.stdout
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
try {
|
|
66
|
+
let projectName = projectArg?.trim();
|
|
67
|
+
|
|
68
|
+
if (!projectName) {
|
|
69
|
+
projectName = await askQuestion(rl, "Enter project name: ");
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (!projectName) {
|
|
73
|
+
console.error("❌ Project name required");
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const newProjectPath = path.join(process.cwd(), projectName);
|
|
78
|
+
|
|
79
|
+
const templatePath = getMwalajsPath();
|
|
80
|
+
|
|
81
|
+
if (!fs.existsSync(templatePath)) {
|
|
82
|
+
throw new Error("Template path not found: " + templatePath);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (fs.existsSync(newProjectPath)) {
|
|
86
|
+
console.error(`❌ Folder already exists: ${projectName}`);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
console.log(`📦 Creating project: ${projectName}`);
|
|
91
|
+
console.log(`📁 From template: ${templatePath}`);
|
|
92
|
+
|
|
93
|
+
fs.mkdirSync(newProjectPath, { recursive: true });
|
|
94
|
+
|
|
95
|
+
const itemsToCopy = [
|
|
96
|
+
"app.mjs",
|
|
97
|
+
"controllers",
|
|
98
|
+
"migrations",
|
|
99
|
+
"routes",
|
|
100
|
+
"views",
|
|
101
|
+
"middlewares",
|
|
102
|
+
"models",
|
|
103
|
+
"public",
|
|
104
|
+
"README.md"
|
|
105
|
+
];
|
|
106
|
+
|
|
107
|
+
let copied = 0;
|
|
108
|
+
|
|
109
|
+
for (const item of itemsToCopy) {
|
|
110
|
+
const src = path.join(templatePath, item);
|
|
111
|
+
const dest = path.join(newProjectPath, item);
|
|
112
|
+
|
|
113
|
+
if (fs.existsSync(src)) {
|
|
114
|
+
console.log(`✔ Copying ${item}`);
|
|
115
|
+
fs.copySync(src, dest);
|
|
116
|
+
copied++;
|
|
117
|
+
} else {
|
|
118
|
+
console.warn(`⚠ Missing template item: ${item}`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
console.log("\n━━━━━━━━━━━━━━━━━━━━━━━━━━");
|
|
123
|
+
console.log(`✅ Project created: ${projectName}`);
|
|
124
|
+
console.log(`📁 Location: ${newProjectPath}`);
|
|
125
|
+
console.log(`📦 Files copied: ${copied}/${itemsToCopy.length}`);
|
|
126
|
+
console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━");
|
|
127
|
+
|
|
128
|
+
} catch (err) {
|
|
129
|
+
console.error("❌ Create project failed:", err.message);
|
|
130
|
+
} finally {
|
|
131
|
+
rl.close();
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* CLI support
|
|
137
|
+
*/
|
|
138
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
139
|
+
createProject(process.argv[2]);
|
|
140
|
+
}
|
package/createProject.mjs
CHANGED
|
@@ -1,111 +1,237 @@
|
|
|
1
1
|
// createProject.mjs
|
|
2
|
-
import fs from
|
|
3
|
-
import path from
|
|
4
|
-
import readline from
|
|
5
|
-
import os from
|
|
2
|
+
import fs from "fs-extra";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import readline from "readline";
|
|
5
|
+
import os from "os";
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
8
|
+
* Get template source safely
|
|
9
9
|
*/
|
|
10
10
|
function getMwalajsPath() {
|
|
11
|
-
|
|
11
|
+
const envPath = process.env.MWALAJSPATH;
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
const defaultPaths = [
|
|
14
|
+
envPath,
|
|
15
|
+
"C:\\Program Files\\mwalajs",
|
|
16
|
+
"/usr/local/lib/mwalajs",
|
|
17
|
+
"/var/www/mwalajs",
|
|
18
|
+
path.join(process.cwd(), "template") // fallback local dev template
|
|
19
|
+
];
|
|
14
20
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
darwin: '/usr/local/lib/mwalajs'
|
|
19
|
-
};
|
|
21
|
+
for (const p of defaultPaths) {
|
|
22
|
+
if (p && fs.existsSync(p)) return p;
|
|
23
|
+
}
|
|
20
24
|
|
|
21
|
-
|
|
22
|
-
|
|
25
|
+
return null; // IMPORTANT: we will generate manual scaffold
|
|
26
|
+
}
|
|
23
27
|
|
|
24
|
-
|
|
25
|
-
|
|
28
|
+
/**
|
|
29
|
+
* Ask CLI input
|
|
30
|
+
*/
|
|
31
|
+
function ask(rl, q) {
|
|
32
|
+
return new Promise((resolve) => rl.question(q, (a) => resolve(a.trim())));
|
|
26
33
|
}
|
|
27
34
|
|
|
28
35
|
/**
|
|
29
|
-
*
|
|
36
|
+
* Manual fallback template generator (VERY IMPORTANT FIX)
|
|
30
37
|
*/
|
|
31
|
-
function
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
38
|
+
function createManualTemplate(target) {
|
|
39
|
+
console.log("⚠ No template found. Creating manual MwalaJS scaffold...");
|
|
40
|
+
|
|
41
|
+
const structure = [
|
|
42
|
+
"controllers",
|
|
43
|
+
"routes",
|
|
44
|
+
"models",
|
|
45
|
+
"views",
|
|
46
|
+
"views/layouts",
|
|
47
|
+
"views/pages",
|
|
48
|
+
"middlewares",
|
|
49
|
+
"migrations",
|
|
50
|
+
"public/css",
|
|
51
|
+
"public/js",
|
|
52
|
+
"public/images"
|
|
53
|
+
];
|
|
54
|
+
|
|
55
|
+
structure.forEach((dir) => {
|
|
56
|
+
fs.mkdirSync(path.join(target, dir), { recursive: true });
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// app.mjs
|
|
60
|
+
fs.writeFileSync(
|
|
61
|
+
path.join(target, "app.mjs"),
|
|
62
|
+
`import mwalajs from 'mwalajs';
|
|
63
|
+
import path from 'path';
|
|
64
|
+
import { fileURLToPath } from 'url';
|
|
65
|
+
|
|
66
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
67
|
+
const __dirname = path.dirname(__filename);
|
|
68
|
+
|
|
69
|
+
mwalajs.set('view engine', 'ejs');
|
|
70
|
+
mwalajs.set('views', path.join(__dirname, 'views'));
|
|
71
|
+
mwalajs.useStatic(path.join(__dirname, 'public'));
|
|
72
|
+
|
|
73
|
+
mwalajs.get('/', (req, res) => {
|
|
74
|
+
res.render('pages/index', { title: 'MwalaJS App' });
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
const port = process.env.PORT || 3000;
|
|
78
|
+
mwalajs.listen(port, () => {
|
|
79
|
+
console.log('🚀 Server running on http://localhost:' + port);
|
|
80
|
+
});
|
|
81
|
+
`
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
// sample controller
|
|
85
|
+
fs.writeFileSync(
|
|
86
|
+
path.join(target, "controllers/homeController.mjs"),
|
|
87
|
+
`export const homeController = {
|
|
88
|
+
getHome: (req, res) => {
|
|
89
|
+
res.render('pages/index', { title: 'Home Page' });
|
|
90
|
+
}
|
|
91
|
+
};`
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
// sample route
|
|
95
|
+
fs.writeFileSync(
|
|
96
|
+
path.join(target, "routes/homeRoutes.mjs"),
|
|
97
|
+
`import mwalajs from 'mwalajs';
|
|
98
|
+
import { homeController } from '../controllers/homeController.mjs';
|
|
99
|
+
|
|
100
|
+
const router = mwalajs.Router();
|
|
101
|
+
|
|
102
|
+
router.get('/', homeController.getHome);
|
|
103
|
+
|
|
104
|
+
export { router as homeRoutes };
|
|
105
|
+
`
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
// sample view
|
|
109
|
+
fs.writeFileSync(
|
|
110
|
+
path.join(target, "views/pages/index.ejs"),
|
|
111
|
+
`<!DOCTYPE html>
|
|
112
|
+
<html>
|
|
113
|
+
<head>
|
|
114
|
+
<title><%= title %></title>
|
|
115
|
+
<style>
|
|
116
|
+
body { font-family: Arial; background:#0f172a; color:white; text-align:center; padding:50px; }
|
|
117
|
+
.card { background:#1e293b; padding:20px; border-radius:12px; display:inline-block; }
|
|
118
|
+
</style>
|
|
119
|
+
</head>
|
|
120
|
+
<body>
|
|
121
|
+
<div class="card">
|
|
122
|
+
<h1>🚀 Welcome to MwalaJS</h1>
|
|
123
|
+
<p><%= title %></p>
|
|
124
|
+
</div>
|
|
125
|
+
</body>
|
|
126
|
+
</html>`
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
// package.json
|
|
130
|
+
fs.writeFileSync(
|
|
131
|
+
path.join(target, "package.json"),
|
|
132
|
+
`{
|
|
133
|
+
"name": "mwalajs-app",
|
|
134
|
+
"type": "module",
|
|
135
|
+
"scripts": {
|
|
136
|
+
"start": "node app.mjs"
|
|
137
|
+
},
|
|
138
|
+
"dependencies": {
|
|
139
|
+
"mwalajs": "*"
|
|
140
|
+
}
|
|
141
|
+
}`
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
fs.writeFileSync(
|
|
145
|
+
path.join(target, "README.md"),
|
|
146
|
+
`# MwalaJS App
|
|
147
|
+
|
|
148
|
+
Run:
|
|
149
|
+
npm install
|
|
150
|
+
npm start
|
|
151
|
+
`
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
console.log("✅ Manual template created successfully!");
|
|
35
155
|
}
|
|
36
156
|
|
|
37
157
|
/**
|
|
38
|
-
*
|
|
158
|
+
* Main project creator
|
|
39
159
|
*/
|
|
40
160
|
export async function createProject(projectArg) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
161
|
+
const rl = readline.createInterface({
|
|
162
|
+
input: process.stdin,
|
|
163
|
+
output: process.stdout
|
|
164
|
+
});
|
|
45
165
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
let projectName = projectArg?.trim();
|
|
166
|
+
try {
|
|
167
|
+
let projectName = projectArg?.trim();
|
|
49
168
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
169
|
+
if (!projectName) {
|
|
170
|
+
projectName = await ask(rl, "Enter project name: ");
|
|
171
|
+
}
|
|
53
172
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
173
|
+
if (!projectName) {
|
|
174
|
+
console.log("❌ Project name required");
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
58
177
|
|
|
59
|
-
|
|
60
|
-
const newProjectPath = path.join(currentDir, projectName);
|
|
178
|
+
const target = path.join(process.cwd(), projectName);
|
|
61
179
|
|
|
62
|
-
|
|
180
|
+
if (fs.existsSync(target)) {
|
|
181
|
+
console.log("❌ Folder already exists");
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
63
184
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
185
|
+
fs.mkdirSync(target, { recursive: true });
|
|
186
|
+
|
|
187
|
+
const templatePath = getMwalajsPath();
|
|
188
|
+
|
|
189
|
+
if (!templatePath) {
|
|
190
|
+
createManualTemplate(target);
|
|
191
|
+
} else {
|
|
192
|
+
console.log("📦 Using template from:", templatePath);
|
|
193
|
+
|
|
194
|
+
const items = [
|
|
195
|
+
"controllers",
|
|
196
|
+
"routes",
|
|
197
|
+
"models",
|
|
198
|
+
"views",
|
|
199
|
+
"middlewares",
|
|
200
|
+
"migrations",
|
|
201
|
+
"public",
|
|
202
|
+
"app.mjs",
|
|
203
|
+
"README.md"
|
|
204
|
+
];
|
|
205
|
+
|
|
206
|
+
for (const item of items) {
|
|
207
|
+
const src = path.join(templatePath, item);
|
|
208
|
+
const dest = path.join(target, item);
|
|
209
|
+
|
|
210
|
+
if (fs.existsSync(src)) {
|
|
211
|
+
fs.copySync(src, dest);
|
|
212
|
+
console.log("✔ copied:", item);
|
|
213
|
+
} else {
|
|
214
|
+
console.log("⚠ missing:", item);
|
|
67
215
|
}
|
|
216
|
+
}
|
|
68
217
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
"controllers",
|
|
75
|
-
"migrations",
|
|
76
|
-
"routes",
|
|
77
|
-
"views",
|
|
78
|
-
"middlewares",
|
|
79
|
-
"models",
|
|
80
|
-
"README.md",
|
|
81
|
-
"public"
|
|
82
|
-
];
|
|
83
|
-
|
|
84
|
-
for (const item of itemsToCopy) {
|
|
85
|
-
const src = path.join(mwalajsSourcePath, item);
|
|
86
|
-
const dest = path.join(newProjectPath, item);
|
|
87
|
-
|
|
88
|
-
if (fs.existsSync(src)) {
|
|
89
|
-
console.log(`Copying '${item}'...`);
|
|
90
|
-
fs.copySync(src, dest);
|
|
91
|
-
} else {
|
|
92
|
-
console.warn(`⚠ '${item}' not found. Skipping...`);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
218
|
+
// fallback if empty project
|
|
219
|
+
if (!fs.existsSync(path.join(target, "app.mjs"))) {
|
|
220
|
+
createManualTemplate(target);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
95
223
|
|
|
96
|
-
|
|
97
|
-
|
|
224
|
+
console.log("\n🎉 Project created successfully!");
|
|
225
|
+
console.log("📁 Path:", target);
|
|
98
226
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
227
|
+
} catch (err) {
|
|
228
|
+
console.error("❌ Create project failed:", err.message);
|
|
229
|
+
} finally {
|
|
230
|
+
rl.close();
|
|
231
|
+
}
|
|
104
232
|
}
|
|
105
233
|
|
|
106
|
-
|
|
107
|
-
* CLI run support
|
|
108
|
-
*/
|
|
234
|
+
// CLI support
|
|
109
235
|
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
110
|
-
|
|
236
|
+
createProject(process.argv[2]);
|
|
111
237
|
}
|