lumpiajs 1.0.6 → 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.
package/README.md CHANGED
@@ -1,195 +1,72 @@
1
1
  # 🥟 LumpiaJS
2
2
 
3
- **Bahasa Pemrograman Web dengan Kearifan Lokal Semarangan.**
4
- _Framework ini dibuat untuk seru-seruan (have fun) dan biar bikin web jadi lebih cepat dan menyenangkan!_ (Rencananya sih gitu... wkwkwk)
5
-
6
- ## 🚀 Cara Pakai (Quick Start)
7
-
8
- Kamu bisa pilih cara yang paling enak buat mulai bikin (masak) web:
9
-
10
- ### 1. Langsung Gas (Tanpa Install)
11
-
12
- Kalau malas install-install, pastikan komputer kamu sudah ada Node.js, lalu langsung aja pakai `npx`:
13
-
14
- **Langkah 1: Buat Project**
15
-
16
- ```bash
17
- npx lumpiajs create-project warung-ku
18
- ```
19
-
20
- _(Atau pakai istilah lokal: `npx lumpiajs buka-cabang warung-ku`)_
21
-
22
- **Langkah 2: Masuk & Install Bumbu (Dependencies)**
23
- Penting! Kamu harus install dependencies biar `import` framework-nya jalan.
24
-
25
- ```bash
26
- cd warung-ku
27
- npm install
28
- ```
29
-
30
- **Langkah 3: Nyalakan Kompor (Server)**
31
-
32
- ```bash
33
- npm start
34
- ```
35
-
36
- _(Atau manual: `npx lumpia dodolan`)_
37
- Websitemu bakal jalan di `http://localhost:3000`.
3
+ **Bahasa Pemrograman Web dengan Kearifan Lokal Semarangan.**
38
4
 
39
5
  ---
40
6
 
41
- ### 2. Install Global (Biar Bisa Dipakai Terus)
42
-
43
- Kalau kamu pengen perintah `lumpia` bisa dipanggil dari mana saja di terminal:
44
-
45
- ```bash
46
- # 1. Install dulu secara global
47
- npm install -g lumpiajs
48
-
49
- # 2. Bikin project baru
50
- lumpia create-project toko-lumpia
7
+ ## 🦄 Fitur Unik: Laravel Syntax di JavaScript! (`->`)
51
8
 
52
- # 3. Masuk folder & install npm
53
- cd toko-lumpia
54
- npm install
55
-
56
- # 4. Jalanin server
57
- lumpia dodolan
58
- ```
59
-
60
- **Cara Update ke Versi Terbaru:**
61
-
62
- ```bash
63
- npm install -g lumpiajs@latest
9
+ ```javascript
10
+ // Valid di LumpiaJS (.lmp)
11
+ const users = await DB.table('users')->where('active', 1)->get();
12
+ Jalan->get('/', 'HomeController@index');
64
13
  ```
65
14
 
66
15
  ---
67
16
 
68
- ## 🏗️ Struktur Project (Standar MVC)
17
+ ## 🏗️ Cara Deploy ke Production (Server Asli)
69
18
 
70
- LumpiaJS sekarang menggunakan arsitektur **MVC (Model-View-Controller)** yang mengikuti standar internasional, jadi developer Laravel atau Express pasti langsung paham.
19
+ Ini yang sering ditanyain: **"Mas, file mana yang harus saya upload ke hosting?"**
71
20
 
72
- ```
73
- warung-ku/
74
- ├── app/
75
- │ ├── controllers/ # Otak Logika (Controller)
76
- │ └── models/ # Pengolah Data (Model)
77
- ├── routes/
78
- │ └── web.js # Rute URL
79
- ├── views/ # Tampilan (.lmp)
80
- ├── package.json
81
- └── ...
82
- ```
21
+ Tenang, LumpiaJS punya fitur **Goreng** (Build) biar kamu nggak bingung.
83
22
 
84
- ### 1. Routes (`routes/web.js`)
23
+ ### 1. Goreng Project (Build)
85
24
 
86
- Tempat mengatur alamat URL web kamu.
25
+ Jalankan perintah ini di komputermu:
87
26
 
88
- ```javascript
89
- import { Jalan } from "lumpiajs";
90
-
91
- // Jalan.gawe(url, 'NamaController@method')
92
- Jalan.gawe("/", "HomeController@index");
93
- Jalan.gawe("/api/products", "ProductController@index");
27
+ ```bash
28
+ lumpia goreng
94
29
  ```
95
30
 
96
- ### 2. Controllers (`app/controllers`)
97
-
98
- Otak dari aplikasimu. Class harus meng-extend `Controller`.
31
+ _(Atau: `lumpia build`)_
99
32
 
100
- ```javascript
101
- import { Controller } from "lumpiajs";
102
-
103
- export default class HomeController extends Controller {
104
- index() {
105
- // Tampilkan file di folder views/home.lmp
106
- // Kirim data 'pesan' ke view
107
- return this.tampil("home", {
108
- pesan: "Halo Dunia!",
109
- tanggal: new Date().toLocaleDateString(),
110
- });
111
- }
112
- }
113
- ```
33
+ Sistem akan memasak projectmu:
114
34
 
115
- ### 3. Views (`views`)
35
+ - Mentranspile sintaks `->` menjadi JS standard.
36
+ - Mengkompilasi CSS (minify Tailwind/Bootstrap).
37
+ - Menyiapkan folder `dist` yang siap saji.
116
38
 
117
- File `.lmp` adalah tempat kamu menulis HTML, CSS, dan JS Semarangan dalam satu file.
118
- Gunakan `{{ nama_variabel }}` untuk menampilkan data dari Controller.
39
+ ### 2. Upload ke Server
119
40
 
120
- ```html
121
- <lump>
122
- <klambi> /* CSS di sini */ h1 { color: #d35400; } </klambi>
41
+ Setelah digoreng, akan muncul folder **`dist`**.
123
42
 
124
- <kulit>
125
- <!-- HTML di sini -->
126
- <h1>{{ pesan }}</h1>
127
- <p>Tanggal server: {{ tanggal }}</p>
128
- </kulit>
43
+ 👉 **HANYA ISI FOLDER `dist`** inilah yang perlu kamu upload ke server.
44
+ (Isinya: `server.js`, `package.json`, `.env`, folder `app`, `routes`, `views`, `public`)
129
45
 
130
- <isi>
131
- // JavaScript Client-side (Bahasa Semarangan) gawe sapa() { alert("Halo,
132
- Lur!"); }
133
- </isi>
134
- </lump>
135
- ```
46
+ ### 3. Install & Start di Server
136
47
 
137
- ### 4. Models (`app/models`)
48
+ Di panel hosting (Terminal/SSH) atau VPS:
138
49
 
139
- Tempat mengolah data (Database/API). Mendukung gaya penulisan ala Eloquent.
50
+ ```bash
51
+ # Masuk ke folder yang barusan diupload
52
+ cd /path/to/your/app
140
53
 
141
- ```javascript
142
- import { Model } from "lumpiajs";
54
+ # Install dependencies (LumpiaJS core, mysql driver, dll)
55
+ npm install --production
143
56
 
144
- // Contoh penggunaan di Controller:
145
- // Model.use(dataProduk).dimana('harga', '<', 5000).kabeh();
57
+ # Jalankan Aplikasi
58
+ npm start
146
59
  ```
147
60
 
148
61
  ---
149
62
 
150
- ## 🧐 Kamus Bahasa (Transpiler)
151
-
152
- Khusus di dalam tag **`<isi>`** (pada file `.lmp`), kamu bisa menggunakan sintaks unik ini:
153
-
154
- - `ono` ➔ `let`
155
- - `paten` ➔ `const`
156
- - `gawe` ➔ `function`
157
- - `yen` ➔ `if`
158
- - `liyane` ➔ `else`
159
- - `mandek` ➔ `return`
160
- - `ora` ➔ `!`
161
- - `panjang()` ➔ `.length`
162
-
163
- ---
164
-
165
- ## 🤝 Cara Lapor Masalah atau Kasih Saran
166
-
167
- Baru nemu bug? Atau punya ide jenius biar LumpiaJS makin jos? Sampaikan saja!
168
-
169
- Caranya gampang:
170
-
171
- 1. Buka link ini: [https://github.com/fastroware/lumpiajs/issues](https://github.com/fastroware/lumpiajs/issues)
172
- 2. Klik tombol warna hijau bertuliskan **"New Issue"**.
173
- 3. Isi Judul dengan jelas.
174
- 4. Jelaskan masalah atau saranmu di kolom deskripsi.
175
- 5. Klik **"Submit new issue"**.
176
-
177
- Selesai! Masukanmu akan saya baca pas lagi senggang.
178
-
179
- ---
180
-
181
- ## ⚠️ DISCLAIMER (PENTING BANGET, WAJIB DIBACA!) ⚠️
182
-
183
- **LumpiaJS ini 100% project _Have Fun_ & Eksperimen.**
184
-
185
- Kami **TIDAK BERTANGGUNG JAWAB** atas segala bentuk kerugian yang mungkin terjadi akibat penggunaan software ini, termasuk tapi tidak terbatas pada:
63
+ ## 🗄️ Database
186
64
 
187
- - Kebocoran data.
188
- - Hilangnya file penting.
189
- - Komputer meledak (lebay, tapi tetap saja hati-hati).
190
- - Kerugian materiil maupun immateriil lainnya.
65
+ Database (MySQL) itu **SERVICE**, bukan file. Jadi:
191
66
 
192
- Gunakan framework ini dengan resiko ditanggung sendiri (_Use at your own risk_). Kalau ada error di production karena nekat pakai ini, jangan nyalahin kami ya! 🙏
67
+ 1. Export database dari localhost (phpMyAdmin -> Export .sql).
68
+ 2. Import file .sql itu ke database di server production kamu.
69
+ 3. Edit file `.env` yang sudah diupload, sesuaikan `DB_HOST`, `DB_USER`, `DB_PASSWORD` dengan credential server.
193
70
 
194
71
  ---
195
72
 
package/bin/lumpia.js CHANGED
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { createProject } from '../lib/commands/create.js';
3
3
  import { serveProject } from '../lib/commands/serve.js';
4
+ import { buildProject } from '../lib/commands/build.js'; // Import build
4
5
 
5
6
  async function main() {
6
7
  const args = process.argv.slice(2);
@@ -10,18 +11,18 @@ async function main() {
10
11
  if (perintah === 'create-project' || perintah === 'buka-cabang') {
11
12
  createProject(parameter);
12
13
  }
13
- else if (perintah === 'dodolan' || perintah === 'serve') {
14
+ else if (perintah === 'dodolan' || perintah === 'serve' || perintah === 'kukus') {
14
15
  serveProject();
15
16
  }
16
- else if (perintah === 'goreng') {
17
- console.log("🚧 Fitur 'goreng' saiki wis otomatis digabung karo 'dodolan' via JIT Compiler MVC.");
18
- console.log(" Silakan gunake: lumpia dodolan");
17
+ else if (perintah === 'goreng' || perintah === 'build') {
18
+ buildProject(); // Activate functionality
19
19
  }
20
20
  else {
21
- console.log('Perintah ora dikenal.');
21
+ console.log('Perintah ora dikenal / Command not recognized.');
22
22
  console.log('------------------------------------------------');
23
- console.log('1. lumpia create-project <nama> (Bikin project)');
24
- console.log('2. lumpia dodolan (Jalanin server)');
23
+ console.log('1. lumpia create-project <nama> (Alias: buka-cabang)');
24
+ console.log('2. lumpia serve (Alias: kukus, dodolan)');
25
+ console.log('3. lumpia build (Alias: goreng)');
25
26
  console.log('------------------------------------------------');
26
27
  }
27
28
  }
package/index.js CHANGED
@@ -1,4 +1,7 @@
1
1
 
2
2
  export { Jalan, routes } from './lib/core/Router.js';
3
- export { LumpiaModel as Model } from './lib/core/Model.js';
3
+ export { LumpiaModel as Model } from './lib/core/Model.js'; // Model (Array / Static)
4
+ export { DB } from './lib/core/DB.js'; // DB (MySQL)
4
5
  export { Controller } from './lib/core/Controller.js';
6
+ export { loadEnv } from './lib/core/Env.js';
7
+ export { loadConfig } from './lib/core/Config.js';
@@ -0,0 +1,246 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { spawnSync } from 'child_process';
4
+ import { loadConfig } from '../core/Config.js';
5
+
6
+ // Transpiler Logic (Sama kayak serve.js tapi ini permanen ke disk)
7
+ function transpileContent(content) {
8
+ let code = content;
9
+ // 1. Import: .lmp -> .js
10
+ code = code.replace(/from\s+['"](.+?)\.lmp['"]/g, "from '$1.js'");
11
+ // 2. Syntax: "->" -> "."
12
+ code = code.split('\n').map(line => {
13
+ if (line.trim().startsWith('//')) return line;
14
+ return line.replace(/->/g, '.');
15
+ }).join('\n');
16
+ return code;
17
+ }
18
+
19
+ function processDirectory(source, dest) {
20
+ if (!fs.existsSync(dest)) fs.mkdirSync(dest, { recursive: true });
21
+
22
+ const items = fs.readdirSync(source);
23
+ items.forEach(item => {
24
+ const srcPath = path.join(source, item);
25
+ const destPath = path.join(dest, item);
26
+ const stat = fs.statSync(srcPath);
27
+
28
+ if (stat.isDirectory()) {
29
+ processDirectory(srcPath, destPath);
30
+ } else {
31
+ if (item.endsWith('.lmp')) {
32
+ // Transpile .lmp to .js
33
+ const content = fs.readFileSync(srcPath, 'utf8');
34
+ const jsContent = transpileContent(content);
35
+ const jsDest = destPath.replace('.lmp', '.js');
36
+ fs.writeFileSync(jsDest, jsContent);
37
+ } else if (item.endsWith('.js') || item.endsWith('.json') || item.endsWith('.css') || item.endsWith('.html')) {
38
+ // Copy as is (but maybe transpile .js too for "->" support if mixed?)
39
+ // For safety, let's also transpile .js files just in case user used "->" there
40
+ if (item.endsWith('.js')) {
41
+ const content = fs.readFileSync(srcPath, 'utf8');
42
+ const jsContent = transpileContent(content);
43
+ fs.writeFileSync(destPath, jsContent);
44
+ } else {
45
+ fs.copyFileSync(srcPath, destPath);
46
+ }
47
+ } else {
48
+ fs.copyFileSync(srcPath, destPath);
49
+ }
50
+ }
51
+ });
52
+ }
53
+
54
+ const serverScript = `
55
+ import http from 'http';
56
+ import fs from 'fs';
57
+ import path from 'path';
58
+ import { routes, Jalan } from 'lumpiajs/lib/core/Router.js';
59
+ import { loadEnv } from 'lumpiajs/lib/core/Env.js';
60
+ import { loadConfig } from 'lumpiajs/lib/core/Config.js';
61
+
62
+ const root = process.cwd();
63
+ const env = loadEnv(root);
64
+ const config = loadConfig(root);
65
+
66
+ // ROUTE MATCHER (Copied from Core)
67
+ function matchRoute(definedRoute, method, pathname) {
68
+ if (definedRoute.method !== method) return null;
69
+ if (definedRoute.path === pathname) return { params: {} };
70
+ const paramNames = [];
71
+ const regexPath = definedRoute.path.replace(/\\{([a-zA-Z0-9_]+)\\}/g, (match, name) => {
72
+ paramNames.push(name);
73
+ return '([^/]+)';
74
+ });
75
+ if (regexPath === definedRoute.path) return null;
76
+ const regex = new RegExp('^' + regexPath + '$');
77
+ const match = pathname.match(regex);
78
+ if (match) {
79
+ const params = {};
80
+ paramNames.forEach((name, index) => params[name] = match[index + 1]);
81
+ return { params };
82
+ }
83
+ return null;
84
+ }
85
+
86
+ async function start() {
87
+ // 1. Load Routes (Compiled JS)
88
+ const routesUrl = path.join(root, 'routes', 'web.js');
89
+ if (fs.existsSync(routesUrl)) {
90
+ await import('file://' + routesUrl);
91
+ } else {
92
+ console.error("❌ Error: routes/web.js not found in build!");
93
+ }
94
+
95
+ // 2. Start Server
96
+ const server = http.createServer(async (req, res) => {
97
+ const method = req.method;
98
+ const url = new URL(req.url, 'http://' + req.headers.host);
99
+ const pathname = url.pathname;
100
+
101
+ // Static Files
102
+ const publicMap = {
103
+ '/css/': path.join(root, 'public', 'css'),
104
+ '/vendor/': path.join(root, 'public', 'vendor')
105
+ };
106
+ for (const [prefix, localPath] of Object.entries(publicMap)) {
107
+ if (pathname.startsWith(prefix)) {
108
+ const relativePath = pathname.slice(prefix.length);
109
+ const filePath = path.join(localPath, relativePath);
110
+ if (fs.existsSync(filePath) && fs.lstatSync(filePath).isFile()) {
111
+ const ext = path.extname(filePath);
112
+ const mime = ext === '.css' ? 'text/css' : (ext === '.js' ? 'text/javascript' : 'application/octet-stream');
113
+ res.writeHead(200, {'Content-Type': mime});
114
+ res.end(fs.readFileSync(filePath));
115
+ return;
116
+ }
117
+ }
118
+ }
119
+
120
+ // Routing
121
+ let match = null;
122
+ let params = {};
123
+ for (const route of routes) {
124
+ const result = matchRoute(route, method, pathname);
125
+ if (result) {
126
+ match = route;
127
+ params = result.params;
128
+ break;
129
+ }
130
+ }
131
+
132
+ if (match) {
133
+ try {
134
+ const [controllerName, methodName] = match.action.split('@');
135
+ const controllerPath = path.join(root, 'app', 'controllers', controllerName + '.js');
136
+ if (!fs.existsSync(controllerPath)) throw new Error('Controller ' + controllerName + ' not found');
137
+
138
+ const module = await import('file://' + controllerPath);
139
+ const ControllerClass = module.default;
140
+ const instance = new ControllerClass();
141
+ instance.env = env;
142
+ instance.params = params;
143
+ instance.config = config;
144
+
145
+ const result = await instance[methodName](...Object.values(params));
146
+ if (result.type === 'html') {
147
+ res.writeHead(200, {'Content-Type': 'text/html'});
148
+ res.end(result.content);
149
+ } else if (result.type === 'json') {
150
+ res.writeHead(200, {'Content-Type': 'application/json'});
151
+ res.end(result.content);
152
+ } else {
153
+ res.writeHead(200, {'Content-Type': 'text/plain'});
154
+ res.end(String(result));
155
+ }
156
+ } catch (e) {
157
+ console.error(e);
158
+ res.writeHead(500, {'Content-Type': 'text/html'});
159
+ res.end('<h1>500 Server Error</h1>');
160
+ }
161
+ } else {
162
+ res.writeHead(404);
163
+ res.end('404 Not Found');
164
+ }
165
+ });
166
+
167
+ const port = env.PORT || 3000;
168
+ server.listen(port, () => {
169
+ console.log('🚀 Production Server running on port ' + port);
170
+ });
171
+ }
172
+
173
+ start();
174
+ `;
175
+
176
+ export function buildProject() {
177
+ const root = process.cwd();
178
+ const dist = path.join(root, 'dist');
179
+ const config = loadConfig(root);
180
+
181
+ console.log('🍳 Mulai Menggoreng (Building Project)...');
182
+
183
+ // 1. Cleanup Old Dist
184
+ if (fs.existsSync(dist)) {
185
+ fs.rmSync(dist, { recursive: true, force: true });
186
+ }
187
+ fs.mkdirSync(dist);
188
+
189
+ // 2. Build Assets (Tailwind)
190
+ if (config.klambi === 'tailwindcss') {
191
+ console.log('🎨 Compiling Tailwind CSS (Minified)...');
192
+ const cmd = process.platform === 'win32' ? 'npx.cmd' : 'npx';
193
+ spawnSync(cmd, ['tailwindcss', '-i', './aset/css/style.css', '-o', './public/css/style.css', '--minify'], {
194
+ cwd: root, stdio: 'inherit', shell: true
195
+ });
196
+ }
197
+
198
+ // 3. Copy & Transpile Code
199
+ console.log('📂 Copying & Transpiling (.lmp -> .js)...');
200
+ processDirectory(path.join(root, 'app'), path.join(dist, 'app'));
201
+ processDirectory(path.join(root, 'routes'), path.join(dist, 'routes'));
202
+ processDirectory(path.join(root, 'views'), path.join(dist, 'views')); // Views .lmp usually not imported, but kept as is? OR Transpiled?
203
+ // Wait, View.js reads raw .lmp file content. So views should strictly be copied AS IS, or renamed to .lmp but content untouched generally?
204
+ // Actually View.js `renderLumpia` expects file path.
205
+ // Let's COPY views folder AS IS (recursive copy), no renaming extensions usually needed for View Engine unless we change View.js to look for .html?
206
+ // Lumpia View Engine expects `<lump>` tags.
207
+ // Let's just copy views folder using simple copy to ensure .lmp extension stays for view engine to find it.
208
+
209
+ // RE-DO views copy: FORCE copy only
210
+ // Overwrite the 'processDirectory' for views to be simple copy
211
+ fs.cpSync(path.join(root, 'views'), path.join(dist, 'views'), { recursive: true });
212
+
213
+ // 4. Copy Static Assets
214
+ if (fs.existsSync(path.join(root, 'public'))) {
215
+ fs.cpSync(path.join(root, 'public'), path.join(dist, 'public'), { recursive: true });
216
+ }
217
+
218
+ // 5. Configs & Env
219
+ fs.copyFileSync(path.join(root, 'package.json'), path.join(dist, 'package.json'));
220
+ fs.copyFileSync(path.join(root, 'config.lmp'), path.join(dist, 'config.lmp'));
221
+ if (fs.existsSync(path.join(root, '.env'))) {
222
+ fs.copyFileSync(path.join(root, '.env'), path.join(dist, '.env'));
223
+ }
224
+
225
+ // 6. Generate Standalone Server Entry
226
+ fs.writeFileSync(path.join(dist, 'server.js'), serverScript);
227
+
228
+ // 7. Update package.json in dist
229
+ const pkg = JSON.parse(fs.readFileSync(path.join(dist, 'package.json'), 'utf8'));
230
+ pkg.scripts = {
231
+ "start": "node server.js"
232
+ };
233
+ // Ensure lumpiajs dependency is preserved
234
+ fs.writeFileSync(path.join(dist, 'package.json'), JSON.stringify(pkg, null, 2));
235
+
236
+ console.log('✅ Mateng! (Build Finished)');
237
+ console.log('----------------------------------------------------');
238
+ console.log('🎁 Yang harus dikirim ke Server (Production):');
239
+ console.log(' 📂 Folder: dist/');
240
+ console.log('');
241
+ console.log('👉 Cara Deploy:');
242
+ console.log(' 1. Upload isi folder "dist" ke server.');
243
+ console.log(' 2. Jalankan "npm install --production" di server.');
244
+ console.log(' 3. Jalankan "npm start".');
245
+ console.log('----------------------------------------------------');
246
+ }