lumpiajs 1.0.12 → 1.0.13

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.
@@ -1,5 +1,5 @@
1
1
 
2
- // ... (KAMUS & Imports same as before) ...
2
+ // ... (KAMUS same as before) ...
3
3
  const KAMUS = [
4
4
  { from: /paten\s/g, to: 'const ' },
5
5
  { from: /ono\s/g, to: 'let ' },
@@ -24,8 +24,12 @@ import { loadConfig } from '../core/Config.js';
24
24
 
25
25
  function transpileSemarangan(content) {
26
26
  let code = content;
27
+ // 1. Keep .lmp import relative for now, or assume .js
27
28
  code = code.replace(/from\s+['"](.+?)\.lmp['"]/g, "from '$1.js'");
28
- code = code.replace(/from\s+['"]lumpiajs['"]/g, "from './core/lumpia.js'");
29
+
30
+ // 2. DO NOT TOUCH 'lumpiajs' IMPORT.
31
+ // We will use Import Map in index.html to resolve 'lumpiajs' to './core/lumpia.js'
32
+ // This solves the relative path hell once and for all.
29
33
 
30
34
  code = code.split('\n').map(line => {
31
35
  let l = line;
@@ -46,18 +50,6 @@ function processDirectory(source, dest, rootDepth = 0) {
46
50
  } else {
47
51
  if (item.endsWith('.lmp') || item.endsWith('.js')) {
48
52
  let content = fs.readFileSync(srcPath, 'utf8');
49
- let backSteps = rootDepth > 0 ? '../'.repeat(rootDepth) : './';
50
- if(rootDepth === 0) backSteps = './'; // core is in dist/core/.
51
-
52
- // Fix path calculation to Core
53
- // dist/routes/web.js (depth 1) -> ../core/lumpia.js
54
- // dist/app/controllers/Home.js (depth 2) -> ../../core/lumpia.js
55
-
56
- // Let's rely on simple replace logic based on file type location usually known
57
- // But dynamic is better.
58
-
59
- content = content.replace(/from\s+['"]lumpiajs['"]/g, `from '${backSteps}../core/lumpia.js'`);
60
-
61
53
  content = transpileSemarangan(content);
62
54
  const finalDest = destPath.replace('.lmp', '.js');
63
55
  fs.writeFileSync(finalDest, content);
@@ -73,7 +65,21 @@ export class Controller {
73
65
  constructor() { this.params={}; }
74
66
  async tampil(viewName, data={}) {
75
67
  try {
76
- const res = await fetch('views/'+viewName+'.lmp');
68
+ // Fetch view must be relative to root of dist.
69
+ // Since we use Import Map, we are modernized.
70
+ // Better to assume deployment at known base or use explicit relative if possible.
71
+ // But fetch('views/...') is relative to current page URL.
72
+ // If current page is /2025/lumpiajs/produk, fetch('views/home.lmp') -> /2025/lumpiajs/views/home.lmp (Works!)
73
+ // Wait, if /produk is virtual path, browser thinks we are in folder /lumpiajs/.
74
+ // If /produk/detail/1 -> browser thinks folder is /lumpiajs/produk/detail/.
75
+ // Fetch 'views/...' will fail (404).
76
+
77
+ // SOLUSI: Selalu fetch dari ROOT relative (pakai Window Base yang kita set di index.html)
78
+ const basePath = window.LUMPIA_BASE || '';
79
+ // Ensure slash
80
+ const url = basePath + '/views/' + viewName + '.lmp';
81
+
82
+ const res = await fetch(url.replace('//', '/')); // simple cleanup
77
83
  if(!res.ok) throw new Error('View 404: ' + viewName);
78
84
  let html = await res.text();
79
85
 
@@ -116,42 +122,42 @@ const indexHtml = `<!DOCTYPE html>
116
122
  <meta charset="UTF-8">
117
123
  <meta name="viewport" content="width=device-width,initial-scale=1.0">
118
124
  <title>LumpiaJS</title>
125
+ <!-- IMPORT MAP: KUNCI SUKSES LOAD MODULE DI SUBFOLDER -->
126
+ <script type="importmap">
127
+ {
128
+ "imports": {
129
+ "lumpiajs": "./core/lumpia.js"
130
+ }
131
+ }
132
+ </script>
119
133
  <link rel="stylesheet" href="public/css/style.css">
134
+ <script>
135
+ // DETEKSI BASE PATH DENGAN LEBIH AMAN (Via current script location fallback)
136
+ // Kita ambil lokasi index.html ini sebagai 'Source of Truth' root aplikasi.
137
+ window.LUMPIA_BASE = window.location.pathname
138
+ .replace(new RegExp('/index\\\\.html$'), '')
139
+ .replace(new RegExp('/$'), '');
140
+ // console.log('Base:', window.LUMPIA_BASE);
141
+ </script>
120
142
  </head>
121
143
  <body>
122
144
  <div id="app">Loading...</div>
123
145
 
124
146
  <script type="module">
147
+ // Import Map makes this work:
125
148
  import { Jalan } from './routes/web.js';
126
149
 
127
150
  async function navigate() {
128
- // FIX: Gunakan new RegExp string biar aman dari escaping hell
129
- const cleanPath = (p) => p.replace(new RegExp('/index\\\\.html$'), '').replace(new RegExp('/$'), '');
130
-
131
- const basePath = cleanPath(window.location.pathname);
132
- // Tapi tunggu, basePath itu harusnya folder ROOT project.
133
- // Misal: /2025/lumpiajs/
134
- // URL saat ini: /2025/lumpiajs/index.html -> Base: /2025/lumpiajs
135
- // Kalau kita navigate ke sub-route (via history pushState): /2025/lumpiajs/produk
136
- // Maka window.location.pathname adalah /2025/lumpiajs/produk.
137
- // Kita HARUS tau base path awalnya apa. Kita bisa tebak dari script tag src location?
138
- // Atau kita asumsikan saat pertama load (yang biasanya index.html), itu lah base path.
139
-
140
- // Trik: Simpan base path di window variable saat pertama load (index.html)
141
- if (!window.LUMPIA_BASE) {
142
- window.LUMPIA_BASE = window.location.pathname.replace(new RegExp('/index\\\\.html$'), '').replace(new RegExp('/$'), '');
143
- }
144
-
145
151
  let currentPath = window.location.pathname;
146
- // Remove Base Path from Current Path to get "Route Path"
147
- if (currentPath.startsWith(window.LUMPIA_BASE)) {
152
+
153
+ // Normalize: Strip Base Path
154
+ if (window.LUMPIA_BASE && currentPath.startsWith(window.LUMPIA_BASE)) {
148
155
  currentPath = currentPath.substring(window.LUMPIA_BASE.length);
149
156
  }
150
157
  if (!currentPath || currentPath === '/index.html') currentPath = '/';
151
158
 
152
159
  let m = null, args = {};
153
160
  for(let r of Jalan.routes) {
154
- // Regex: Replace {slug} -> ([^/]+)
155
161
  let regexStr = '^' + r.p.replace(/{([a-zA-Z0-9_]+)}/g, '([^/]+)') + '$';
156
162
  let reg = new RegExp(regexStr);
157
163
  let res = currentPath.match(reg);
@@ -161,12 +167,13 @@ const indexHtml = `<!DOCTYPE html>
161
167
  if(m) {
162
168
  const [cName, fName] = m.a.split('@');
163
169
  try {
170
+ // Import Relative to index.html (selalu root dist)
164
171
  const mod = await import('./app/controllers/'+cName+'.js?'+Date.now());
165
172
  const C = mod.default; const i = new C(); i.params=args;
166
173
  await i[fName](...args);
167
174
  } catch(e) {
168
175
  console.error(e);
169
- document.getElementById('app').innerHTML='<h1>Error Loading Controller</h1><pre>'+e.message+'</pre>';
176
+ document.getElementById('app').innerHTML='<h1>Error</h1><pre>'+e.message+'</pre>';
170
177
  }
171
178
  } else {
172
179
  document.getElementById('app').innerHTML='<h1>404 Not Found</h1><p>Route: '+currentPath+'</p>';
@@ -174,16 +181,21 @@ const indexHtml = `<!DOCTYPE html>
174
181
  }
175
182
 
176
183
  window.addEventListener('popstate', navigate);
184
+
185
+ // SPA LINK INTERCEPTOR (SAT SET MODE)
177
186
  document.body.addEventListener('click', e => {
178
- if(e.target.tagName==='A' && e.target.href.startsWith(window.location.origin)) {
187
+ // Cari elemen <a> (bisa jadi klik di span dalam a)
188
+ const link = e.target.closest('a');
189
+ if (link && link.href.startsWith(window.location.origin)) {
190
+ // Ignore if target blank or control click
191
+ if (link.target === '_blank' || e.ctrlKey) return;
192
+
179
193
  e.preventDefault();
180
- history.pushState(null,'',e.target.href);
194
+ history.pushState(null, '', link.href);
181
195
  navigate();
182
196
  }
183
197
  });
184
198
 
185
- // Init Base Path immediately
186
- window.LUMPIA_BASE = window.location.pathname.replace(new RegExp('/index\\\\.html$'), '').replace(new RegExp('/$'), '');
187
199
  navigate();
188
200
  </script>
189
201
  </body>
@@ -194,7 +206,7 @@ export function buildProject() {
194
206
  const dist = path.join(root, 'dist');
195
207
  const config = loadConfig(root);
196
208
 
197
- console.log('🍳 Goreng Project (Mode Aman)...');
209
+ console.log('🍳 Goreng Project (Mode Import Map + Sat Set SPA)...');
198
210
  if (fs.existsSync(dist)) fs.rmSync(dist, { recursive: true, force: true });
199
211
  fs.mkdirSync(dist);
200
212
 
@@ -215,5 +227,5 @@ export function buildProject() {
215
227
 
216
228
  fs.writeFileSync(path.join(dist, '.htaccess'), `<IfModule mod_rewrite.c>\nRewriteEngine On\nRewriteRule ^index\\.html$ - [L]\nRewriteCond %{REQUEST_FILENAME} !-f\nRewriteCond %{REQUEST_FILENAME} !-d\nRewriteRule . index.html [L]\n</IfModule>`);
217
229
 
218
- console.log('✅ Mateng! Siap upload ke Laragon/Hosting.');
230
+ console.log('✅ Mateng! Siap dihidangkan di folder manapun.');
219
231
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lumpiajs",
3
- "version": "1.0.12",
3
+ "version": "1.0.13",
4
4
  "description": "Bahasa Pemrograman Semarangan",
5
5
  "type": "module",
6
6
  "main": "index.js",