free-framework 4.6.4 → 4.6.6
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/compiler/lexer.js +2 -1
- package/compiler/parser.js +7 -0
- package/package.json +1 -1
- package/runtime/server.js +28 -12
package/compiler/lexer.js
CHANGED
|
@@ -23,7 +23,8 @@ const KEYWORDS = new Set([
|
|
|
23
23
|
'route', 'model', 'component', 'page', 'view', 'link', 'state', 'on', 'style',
|
|
24
24
|
'middleware', 'auth', 'login', 'register', 'upload', 'path', 'maxSize', 'error',
|
|
25
25
|
'text', 'action', 'validate', 'store', 'onMount', 'onDestroy', 'queue', 'mail',
|
|
26
|
-
'loop', 'condition', 'script', 'if', 'for'
|
|
26
|
+
'loop', 'condition', 'script', 'if', 'for',
|
|
27
|
+
'get', 'post', 'put', 'delete', 'patch', 'head', 'options'
|
|
27
28
|
]);
|
|
28
29
|
|
|
29
30
|
function tokenize(code, filename = 'unknown.free') {
|
package/compiler/parser.js
CHANGED
|
@@ -21,6 +21,9 @@ function parse(tokens, filename = 'unknown.free', source = '') {
|
|
|
21
21
|
if (token.type === 'KEYWORD') {
|
|
22
22
|
if (token.value === 'route') {
|
|
23
23
|
ast.push(parseRoute(tokens, filename, source));
|
|
24
|
+
} else if (['get', 'post', 'put', 'delete', 'patch', 'head', 'options'].includes(token.value)) {
|
|
25
|
+
tokens.unshift(token); // put back the method
|
|
26
|
+
ast.push(parseRoute(tokens, filename, source));
|
|
24
27
|
} else if (token.value === 'model') {
|
|
25
28
|
ast.push(parseModel(tokens));
|
|
26
29
|
} else if (token.value === 'component') {
|
|
@@ -66,6 +69,10 @@ function parseRoute(tokens, filename, source) {
|
|
|
66
69
|
}
|
|
67
70
|
}
|
|
68
71
|
if (tokens[0] && tokens[0].value === '}') tokens.shift();
|
|
72
|
+
} else if (tokens[0] && tokens[0].value === '-' && tokens[1] && tokens[1].value === '>') {
|
|
73
|
+
tokens.shift(); // consume -
|
|
74
|
+
tokens.shift(); // consume >
|
|
75
|
+
view = tokens.shift().value;
|
|
69
76
|
}
|
|
70
77
|
return { type: 'route', method, path, view, middleware, handler, line: methodToken.line };
|
|
71
78
|
}
|
package/package.json
CHANGED
package/runtime/server.js
CHANGED
|
@@ -15,38 +15,53 @@ const { LRUCache } = require('lru-cache');
|
|
|
15
15
|
|
|
16
16
|
class FreeServer {
|
|
17
17
|
constructor() {
|
|
18
|
-
console.log(`[Free Engine] ⚙️ Runtime Core v4.6.
|
|
18
|
+
console.log(`[Free Engine] ⚙️ Runtime Core v4.6.5 initializing...`);
|
|
19
19
|
this.app = new HyperExpress.Server();
|
|
20
20
|
this.viewsPath = process.env.VIEWS_PATH || nodePath.join(process.cwd(), 'views');
|
|
21
21
|
this.namedMiddlewares = {};
|
|
22
22
|
this.errorViews = {};
|
|
23
23
|
this.plugins = [];
|
|
24
24
|
|
|
25
|
-
//
|
|
25
|
+
// 1. Absolute Top Logger
|
|
26
|
+
this.app.use((req, res, next) => {
|
|
27
|
+
console.log(`[Free Engine] 📥 [${new Date().toLocaleTimeString()}] Incoming: ${req.method} ${req.url}`);
|
|
28
|
+
|
|
29
|
+
// Track response
|
|
30
|
+
const start = Date.now();
|
|
31
|
+
res.on('finish', () => {
|
|
32
|
+
console.log(`[Free Engine] 📤 [${new Date().toLocaleTimeString()}] Sent: ${req.method} ${req.url} (${res.statusCode}) - ${Date.now() - start}ms`);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
if (typeof next === 'function') {
|
|
36
|
+
return next();
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// 2. Global Error Handler
|
|
26
41
|
this.app.set_error_handler((req, res, error) => {
|
|
27
42
|
console.error(`[Free Engine] 🔥 Global Uncaught Error:`, error);
|
|
28
43
|
this.handleError(req, res, error);
|
|
29
44
|
});
|
|
30
45
|
|
|
31
|
-
|
|
32
|
-
console.log(`[Free Engine] 📥 Request: ${req.method} ${req.url}`);
|
|
33
|
-
if (next) next();
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
// Static Asset Serving Middleware
|
|
46
|
+
// 3. Static Asset Serving (Simplified & Safe)
|
|
37
47
|
const publicPath = nodePath.join(process.cwd(), 'public');
|
|
38
48
|
this.app.use((req, res, next) => {
|
|
39
|
-
|
|
40
|
-
|
|
49
|
+
if (req.path === '/' || !req.path.includes('.')) {
|
|
50
|
+
return typeof next === 'function' ? next() : null;
|
|
51
|
+
}
|
|
41
52
|
|
|
53
|
+
const lookupPath = req.path.startsWith('/') ? req.path.substring(1) : req.path;
|
|
42
54
|
const fullPath = nodePath.join(publicPath, lookupPath);
|
|
55
|
+
|
|
43
56
|
if (fs.existsSync(fullPath) && fs.statSync(fullPath).isFile()) {
|
|
57
|
+
console.log(`[Free Engine] 📄 Serving static: ${lookupPath}`);
|
|
44
58
|
const ext = nodePath.extname(fullPath);
|
|
45
59
|
const mimes = { '.js': 'application/javascript', '.css': 'text/css', '.png': 'image/png', '.jpg': 'image/jpeg', '.svg': 'image/svg+xml' };
|
|
46
60
|
res.type(mimes[ext] || 'text/plain');
|
|
47
61
|
return res.send(fs.readFileSync(fullPath));
|
|
48
62
|
}
|
|
49
|
-
|
|
63
|
+
|
|
64
|
+
if (typeof next === 'function') next();
|
|
50
65
|
});
|
|
51
66
|
|
|
52
67
|
this.app.get('/test-static', (req, res) => res.send('Static serving test'));
|
|
@@ -180,7 +195,8 @@ class FreeServer {
|
|
|
180
195
|
|
|
181
196
|
start(port = 3000) {
|
|
182
197
|
this.app.get('/health', (req, res) => res.send('OK'));
|
|
183
|
-
|
|
198
|
+
console.log(`[Free Engine] 📡 Binding to 127.0.0.1:${port}...`);
|
|
199
|
+
this.app.listen(port, '127.0.0.1').then(() => {
|
|
184
200
|
const blueUnderline = "\x1b[34m\x1b[4m";
|
|
185
201
|
const reset = "\x1b[0m";
|
|
186
202
|
console.log(`⚡ Free Engine Ignite: ${blueUnderline}http://localhost:${port}${reset}`);
|