thoth-markup-lang 10.5.0 → 12.0.0
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 +223 -23
- package/engine.php +287 -31
- package/package.json +20 -4
- package/thoth.js +367 -115
package/engine.php
CHANGED
|
@@ -1,18 +1,35 @@
|
|
|
1
1
|
<?php
|
|
2
2
|
/**
|
|
3
|
-
* THOTH Sovereign Runtime Engine
|
|
3
|
+
* THOTH Sovereign Runtime Engine v12.0.0 - The Sovereign Cloud
|
|
4
4
|
* Architect: Engineer Abdelfatah Abdelhamed 🇪🇬
|
|
5
5
|
* --------------------------------------------------
|
|
6
|
-
* الميزات
|
|
6
|
+
* الميزات المدمجة (النسخة النهائية):
|
|
7
7
|
* 1. التوثيق المعماري: إلزامية وجود TYPE THOTH في السطر الأول.
|
|
8
8
|
* 2. نظام Middleware (Auth Guard): التحكم الكامل في صلاحيات الوصول.
|
|
9
9
|
* 3. نظام البيانات الديناميكي: JSON Binding & Recursive Loops.
|
|
10
10
|
* 4. نظام Meta SEO الذكي: توليد عناصر Meta بناءً على البيانات.
|
|
11
|
-
* 5.
|
|
11
|
+
* 5. Python-Style Traceback: متتبع أخطاء ذكي يحدد السطر ونوع الخطأ بدقة.
|
|
12
|
+
* 6. High-Performance Core: تسريع التحليل باستخدام دوال PHP الحديثة.
|
|
13
|
+
* 7. Sovereign Components: القدرة على تعريف وإعادة استخدام المكونات.
|
|
14
|
+
* 8. State Management: حقن متغيرات الحالة لإنشاء واجهات تفاعلية.
|
|
15
|
+
* 9. Layout Engine: نظام شبكات مدمج (Row / Column) بخواص Flexbox.
|
|
16
|
+
* 10. Smart Routing: نظام تنقل داخلي مدمج لبناء تطبيقات SPA.
|
|
17
|
+
* 11. API Fetch Engine [NEW]: جلب البيانات الخارجية برمجياً بدون كتابة JS.
|
|
12
18
|
*/
|
|
13
19
|
|
|
14
20
|
session_start();
|
|
15
21
|
|
|
22
|
+
/**
|
|
23
|
+
* كلاس استثناءات مخصص للغة تحوت لتتبع الأخطاء بذكاء
|
|
24
|
+
*/
|
|
25
|
+
class ThothSyntaxError extends Exception {
|
|
26
|
+
public $lineContent;
|
|
27
|
+
public function __construct($message, $code = 0, $lineContent = "", Throwable $previous = null) {
|
|
28
|
+
$this->lineContent = $lineContent;
|
|
29
|
+
parent::__construct($message, $code, $previous);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
16
33
|
class ThothEngine {
|
|
17
34
|
private $tagMap = [
|
|
18
35
|
'Title' => 'h1', 'Sub' => 'h2', 'Heading' => 'h3', 'Text' => 'p',
|
|
@@ -20,7 +37,8 @@ class ThothEngine {
|
|
|
20
37
|
'Header' => 'header', 'Footer' => 'footer', 'Bold' => 'strong',
|
|
21
38
|
'Link' => 'a', 'Image' => 'img', 'List' => 'ul', 'Item' => 'li',
|
|
22
39
|
'Button' => 'button', 'Input' => 'input', 'Break' => 'br',
|
|
23
|
-
'Line' => 'hr', 'Layout' => 'main'
|
|
40
|
+
'Line' => 'hr', 'Layout' => 'main',
|
|
41
|
+
'Row' => 'div', 'Column' => 'div'
|
|
24
42
|
];
|
|
25
43
|
|
|
26
44
|
private $voidTags = ['img', 'br', 'hr', 'input', 'meta', 'link'];
|
|
@@ -28,12 +46,18 @@ class ThothEngine {
|
|
|
28
46
|
private $dataContext = [];
|
|
29
47
|
private $devMode = true;
|
|
30
48
|
private $currentLine = 0;
|
|
49
|
+
private $currentFile = "";
|
|
50
|
+
|
|
51
|
+
private $components = [];
|
|
52
|
+
private $stateVars = [];
|
|
31
53
|
|
|
32
54
|
/**
|
|
33
55
|
* المدخل الرئيسي للمحرك
|
|
34
56
|
*/
|
|
35
57
|
public function render($filePath, $isSubCall = false) {
|
|
36
58
|
$safePath = basename($filePath);
|
|
59
|
+
$this->currentFile = $safePath;
|
|
60
|
+
|
|
37
61
|
if (!file_exists($safePath)) {
|
|
38
62
|
return $this->errorPage("404 | THOTH Missing", "الملف غير موجود في النطاق السيادي.");
|
|
39
63
|
}
|
|
@@ -43,9 +67,12 @@ class ThothEngine {
|
|
|
43
67
|
// --- شرط السيادة: التحقق من نوع الملف ---
|
|
44
68
|
$firstLine = trim($lines[0]);
|
|
45
69
|
if ($firstLine !== "TYPE THOTH") {
|
|
46
|
-
return $this->devErrorOverlay("
|
|
70
|
+
return $this->devErrorOverlay("SyntaxError: Missing Identity Protocol. File must begin with TYPE THOTH.", 1, $lines[0]);
|
|
47
71
|
}
|
|
48
|
-
unset($lines[0]);
|
|
72
|
+
unset($lines[0]);
|
|
73
|
+
|
|
74
|
+
// استخراج المسار الحالي لنظام الـ Routing
|
|
75
|
+
$requestedRoute = isset($_GET['route']) ? '/' . ltrim($_GET['route'], '/') : '/';
|
|
49
76
|
|
|
50
77
|
try {
|
|
51
78
|
$htmlBody = "";
|
|
@@ -58,59 +85,138 @@ class ThothEngine {
|
|
|
58
85
|
$repeatBuffer = [];
|
|
59
86
|
$repeatKey = "";
|
|
60
87
|
$repeatIndent = 0;
|
|
88
|
+
|
|
89
|
+
$isDefiningComponent = false;
|
|
90
|
+
$currentComponentName = "";
|
|
91
|
+
$componentIndent = 0;
|
|
61
92
|
|
|
62
93
|
foreach ($lines as $index => $line) {
|
|
63
94
|
$this->currentLine = $index + 1;
|
|
64
95
|
$trimmed = trim($line);
|
|
65
|
-
|
|
96
|
+
|
|
97
|
+
if ($trimmed === "" || str_starts_with($trimmed, '#')) continue;
|
|
98
|
+
|
|
66
99
|
$indent = strlen($line) - strlen(ltrim($line));
|
|
67
100
|
|
|
68
|
-
//
|
|
101
|
+
// Guard System
|
|
69
102
|
if ($skipUntilIndent !== -1) {
|
|
70
103
|
if ($indent > $skipUntilIndent) continue;
|
|
71
104
|
else $skipUntilIndent = -1;
|
|
72
105
|
}
|
|
73
106
|
|
|
107
|
+
// --- 1. التنقل الذكي (Smart Routing) ---
|
|
108
|
+
if (str_starts_with($trimmed, 'Route "')) {
|
|
109
|
+
preg_match('/Route "([^"]+)"/', $trimmed, $matches);
|
|
110
|
+
$routePath = $matches[1] ?? '';
|
|
111
|
+
if ($routePath !== $requestedRoute) {
|
|
112
|
+
$skipUntilIndent = $indent;
|
|
113
|
+
}
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// --- 2. Middleware ---
|
|
74
118
|
if (preg_match('/Auth="([^"]+)"/', $trimmed, $matches)) {
|
|
75
119
|
if (!$this->checkAuth($matches[1])) {
|
|
76
120
|
$skipUntilIndent = $indent;
|
|
77
121
|
continue;
|
|
78
122
|
}
|
|
79
123
|
}
|
|
124
|
+
|
|
125
|
+
// --- 3. Sovereign Components ---
|
|
126
|
+
if ($isDefiningComponent) {
|
|
127
|
+
if ($indent > $componentIndent) {
|
|
128
|
+
$this->components[$currentComponentName][] = $line;
|
|
129
|
+
continue;
|
|
130
|
+
} else {
|
|
131
|
+
$isDefiningComponent = false;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (str_starts_with($trimmed, 'Define ')) {
|
|
136
|
+
$sep = $this->findSeparator($trimmed);
|
|
137
|
+
if($sep === -1) throw new ThothSyntaxError("ComponentError: Missing ':' in Define statement.", $this->currentLine, $line);
|
|
138
|
+
$currentComponentName = trim(substr($trimmed, 7, $sep - 7));
|
|
139
|
+
$this->components[$currentComponentName] = [];
|
|
140
|
+
$componentIndent = $indent;
|
|
141
|
+
$isDefiningComponent = true;
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// --- 4. State Management ---
|
|
146
|
+
if (str_starts_with($trimmed, 'State ')) {
|
|
147
|
+
$parts = explode(':', substr($trimmed, 6), 2);
|
|
148
|
+
if (count($parts) === 2) {
|
|
149
|
+
$stateKey = trim($parts[0]);
|
|
150
|
+
$stateVal = trim($parts[1]);
|
|
151
|
+
$this->stateVars[$stateKey] = $stateVal;
|
|
152
|
+
} else {
|
|
153
|
+
throw new ThothSyntaxError("StateError: Invalid State syntax. Expected 'State name: value'.", $this->currentLine, $line);
|
|
154
|
+
}
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// --- 5. API Fetch Engine (الربط الخارجي السيادي) ---
|
|
159
|
+
if (str_starts_with($trimmed, 'API ')) {
|
|
160
|
+
if (preg_match('/API\s+([a-zA-Z0-9_]+)="([^"]+)"/', $trimmed, $matches)) {
|
|
161
|
+
$apiKey = $matches[1];
|
|
162
|
+
$apiUrl = $matches[2];
|
|
163
|
+
$this->fetchExternalApi($apiKey, $apiUrl, $this->currentLine, $line);
|
|
164
|
+
} else {
|
|
165
|
+
throw new ThothSyntaxError("APIError: Invalid API syntax. Expected 'API name=\"URL\"'.", $this->currentLine, $line);
|
|
166
|
+
}
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
80
169
|
|
|
81
|
-
// Repeat System
|
|
170
|
+
// --- 6. Repeat System ---
|
|
82
171
|
if ($isRepeatMode) {
|
|
83
172
|
if ($indent > $repeatIndent) { $repeatBuffer[] = $line; continue; }
|
|
84
173
|
else { $htmlBody .= $this->processRepeat($repeatKey, $repeatBuffer); $isRepeatMode = false; $repeatBuffer = []; }
|
|
85
174
|
}
|
|
86
175
|
|
|
87
|
-
if (
|
|
176
|
+
if (str_starts_with($trimmed, 'Repeat Over="')) {
|
|
88
177
|
preg_match('/Over="([^"]+)"/', $trimmed, $matches);
|
|
178
|
+
if(empty($matches[1])) throw new ThothSyntaxError("LoopError: Missing valid array key in Over statement.", $this->currentLine, $line);
|
|
89
179
|
$repeatKey = $matches[1] ?? '';
|
|
90
180
|
$repeatIndent = $indent; $isRepeatMode = true; continue;
|
|
91
181
|
}
|
|
92
182
|
|
|
93
|
-
//
|
|
94
|
-
if (
|
|
95
|
-
if (
|
|
96
|
-
if (
|
|
183
|
+
// --- 7. DataSource & Imports ---
|
|
184
|
+
if (str_starts_with($trimmed, 'DataSource:')) { $this->loadData(trim(substr($trimmed, 11))); continue; }
|
|
185
|
+
if (str_starts_with($trimmed, 'Var ')) { $this->parseVariable($trimmed); continue; }
|
|
186
|
+
if (str_starts_with($trimmed, 'Import:')) {
|
|
187
|
+
$importFile = trim(substr($trimmed, 7));
|
|
188
|
+
if(!file_exists($importFile)) throw new ThothSyntaxError("ImportError: Module '$importFile' not found.", $this->currentLine, $line);
|
|
189
|
+
$htmlBody .= $this->render($importFile, true); continue;
|
|
190
|
+
}
|
|
97
191
|
|
|
98
192
|
$line = $this->resolveDynamicData($line);
|
|
99
193
|
$trimmed = trim($line);
|
|
100
194
|
|
|
101
|
-
// Raw Injection (CSS/JS)
|
|
195
|
+
// --- 8. Raw Injection (CSS/JS) ---
|
|
102
196
|
if ($inRawMode) {
|
|
103
197
|
if ($indent <= $rawIndent && !empty($trimmed)) { $inRawMode = false; $htmlBody .= "</$rawType>\n"; }
|
|
104
198
|
else { $htmlBody .= $line . "\n"; continue; }
|
|
105
199
|
}
|
|
106
200
|
|
|
107
201
|
$sep = $this->findSeparator($trimmed);
|
|
202
|
+
|
|
108
203
|
$cmdPart = ($sep !== -1) ? trim(substr($trimmed, 0, $sep)) : $trimmed;
|
|
109
204
|
$val = ($sep !== -1) ? trim(substr($trimmed, $sep + 1)) : "";
|
|
110
205
|
|
|
111
206
|
$spacePos = strpos($cmdPart, ' ');
|
|
112
207
|
$cmd = ($spacePos !== false) ? substr($cmdPart, 0, $spacePos) : $cmdPart;
|
|
113
208
|
$attrs = ($spacePos !== false) ? trim(substr($cmdPart, $spacePos)) : "";
|
|
209
|
+
|
|
210
|
+
// Component Instantiation
|
|
211
|
+
if (isset($this->components[$cmd])) {
|
|
212
|
+
$componentHtml = $this->processComponent($cmd, $attrs, $indent);
|
|
213
|
+
$htmlBody .= $componentHtml;
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if($sep === -1 && !empty($trimmed) && !isset($this->tagMap[explode(' ', $trimmed)[0]]) && !in_array(strtolower(explode(' ', $trimmed)[0]), $this->voidTags) && $cmd !== "StyleSheet" && $cmd !== "Scripting"){
|
|
218
|
+
throw new ThothSyntaxError("ParseError: Invalid syntax or missing separator ':'. Unrecognized command or component '$cmd'.", $this->currentLine, $line);
|
|
219
|
+
}
|
|
114
220
|
|
|
115
221
|
if ($cmd === "StyleSheet" || $cmd === "Scripting") {
|
|
116
222
|
$inRawMode = true; $rawType = ($cmd === "StyleSheet") ? "style" : "script";
|
|
@@ -124,12 +230,38 @@ class ThothEngine {
|
|
|
124
230
|
}
|
|
125
231
|
|
|
126
232
|
$tag = isset($this->tagMap[$cmd]) ? $this->tagMap[$cmd] : strtolower($cmd);
|
|
233
|
+
|
|
234
|
+
// --- 9. Layout Engine ---
|
|
235
|
+
$injectedStyle = "";
|
|
236
|
+
if ($cmd === 'Row') {
|
|
237
|
+
$injectedStyle = "display:flex; flex-wrap:wrap;";
|
|
238
|
+
if (preg_match('/gap="([^"]+)"/', $attrs, $m)) $injectedStyle .= " gap:{$m[1]};";
|
|
239
|
+
if (preg_match('/align="([^"]+)"/', $attrs, $m)) $injectedStyle .= " align-items:{$m[1]};";
|
|
240
|
+
$attrs = preg_replace('/(gap|align)="[^"]+"/', '', $attrs);
|
|
241
|
+
} elseif ($cmd === 'Column') {
|
|
242
|
+
$injectedStyle = "display:flex; flex-direction:column;";
|
|
243
|
+
if (preg_match('/width="([^"]+)"/', $attrs, $m)) $injectedStyle .= " flex:0 0 {$m[1]}; max-width:{$m[1]};";
|
|
244
|
+
else $injectedStyle .= " flex:1;";
|
|
245
|
+
$attrs = preg_replace('/width="[^"]+"/', '', $attrs);
|
|
246
|
+
}
|
|
247
|
+
|
|
127
248
|
$cleanAttrs = preg_replace('/Auth="[^"]+"/', '', $attrs);
|
|
128
|
-
$
|
|
249
|
+
$cleanAttrs = $this->injectStateBindings($tag, $cleanAttrs);
|
|
250
|
+
|
|
251
|
+
if (!empty($injectedStyle)) {
|
|
252
|
+
if (strpos($cleanAttrs, 'style="') !== false) {
|
|
253
|
+
$cleanAttrs = preg_replace('/style="([^"]*)"/', 'style="$1 ' . $injectedStyle . '"', $cleanAttrs);
|
|
254
|
+
} else {
|
|
255
|
+
$cleanAttrs .= ' style="' . trim($injectedStyle) . '"';
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
$openingTag = "<$tag" . ($cleanAttrs ? " " . trim($cleanAttrs) : "") . ">";
|
|
129
260
|
|
|
130
261
|
if (in_array($tag, $this->voidTags)) {
|
|
131
262
|
$htmlBody .= str_repeat(" ", $indent) . $openingTag . "\n";
|
|
132
263
|
} elseif ($val !== "") {
|
|
264
|
+
$val = $this->injectStateText($val);
|
|
133
265
|
$htmlBody .= str_repeat(" ", $indent) . $openingTag . $val . "</$tag>\n";
|
|
134
266
|
} else {
|
|
135
267
|
$htmlBody .= str_repeat(" ", $indent) . $openingTag . "\n";
|
|
@@ -142,8 +274,10 @@ class ThothEngine {
|
|
|
142
274
|
|
|
143
275
|
return ($isSubCall) ? $htmlBody : $this->generateFullHTML($htmlBody);
|
|
144
276
|
|
|
277
|
+
} catch (ThothSyntaxError $e) {
|
|
278
|
+
return $this->devErrorOverlay($e->getMessage(), $this->currentLine, $e->lineContent);
|
|
145
279
|
} catch (Exception $e) {
|
|
146
|
-
return $this->devErrorOverlay($e->getMessage(), $this->currentLine);
|
|
280
|
+
return $this->devErrorOverlay("RuntimeError: " . $e->getMessage(), $this->currentLine, "System Execution Error");
|
|
147
281
|
}
|
|
148
282
|
}
|
|
149
283
|
|
|
@@ -152,6 +286,31 @@ class ThothEngine {
|
|
|
152
286
|
return (isset($_SESSION['user_role']) && $_SESSION['user_role'] === $role);
|
|
153
287
|
}
|
|
154
288
|
|
|
289
|
+
/**
|
|
290
|
+
* دالة جلب البيانات من الـ APIs الخارجية
|
|
291
|
+
*/
|
|
292
|
+
private function fetchExternalApi($key, $url, $lineNum, $lineContent) {
|
|
293
|
+
$options = [
|
|
294
|
+
'http' => [
|
|
295
|
+
'method' => 'GET',
|
|
296
|
+
'header' => "User-Agent: THOTH-Sovereign-Engine/12.0\r\n"
|
|
297
|
+
]
|
|
298
|
+
];
|
|
299
|
+
$context = stream_context_create($options);
|
|
300
|
+
$response = @file_get_contents($url, false, $context);
|
|
301
|
+
|
|
302
|
+
if ($response === false) {
|
|
303
|
+
throw new ThothSyntaxError("APIError: Failed to fetch external data from '$url'.", $lineNum, $lineContent);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
$data = json_decode($response, true);
|
|
307
|
+
if ($data === null) {
|
|
308
|
+
throw new ThothSyntaxError("APIParseError: Received invalid JSON response from '$url'.", $lineNum, $lineContent);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
$this->dataContext[$key] = $data;
|
|
312
|
+
}
|
|
313
|
+
|
|
155
314
|
private function processRepeat($key, $linesBuffer) {
|
|
156
315
|
$dataArray = $this->dataContext[$key] ?? [];
|
|
157
316
|
$output = "";
|
|
@@ -163,6 +322,54 @@ class ThothEngine {
|
|
|
163
322
|
}
|
|
164
323
|
return $output;
|
|
165
324
|
}
|
|
325
|
+
|
|
326
|
+
private function processComponent($componentName, $attrsStr, $baseIndent) {
|
|
327
|
+
$buffer = $this->components[$componentName];
|
|
328
|
+
$output = "";
|
|
329
|
+
preg_match_all('/([a-zA-Z0-9_]+)="([^"]+)"/', $attrsStr, $matches);
|
|
330
|
+
$props = [];
|
|
331
|
+
if(!empty($matches[1])) {
|
|
332
|
+
foreach($matches[1] as $idx => $propName) {
|
|
333
|
+
$props['@'.$propName] = $matches[2][$idx];
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
$subEngine = new ThothEngine();
|
|
338
|
+
$subEngine->dataContext = $this->dataContext;
|
|
339
|
+
$subEngine->variables = array_merge($this->variables, $props);
|
|
340
|
+
$subEngine->tagMap = $this->tagMap;
|
|
341
|
+
$subEngine->voidTags = $this->voidTags;
|
|
342
|
+
|
|
343
|
+
$tempCode = "TYPE THOTH\n";
|
|
344
|
+
foreach($buffer as $l) {
|
|
345
|
+
$tempCode .= str_repeat(" ", $baseIndent) . $l . "\n";
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
$tempFile = tempnam(sys_get_temp_dir(), 'thoth_comp_');
|
|
349
|
+
file_put_contents($tempFile, $tempCode);
|
|
350
|
+
$output = $subEngine->render($tempFile, true);
|
|
351
|
+
unlink($tempFile);
|
|
352
|
+
|
|
353
|
+
return $output;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
private function injectStateBindings($tag, $attrs) {
|
|
357
|
+
if (preg_match('/action="([^"]+)"/', $attrs, $match)) {
|
|
358
|
+
$action = $match[1];
|
|
359
|
+
$jsAction = "thothState.dispatch('{$action}')";
|
|
360
|
+
$attrs = preg_replace('/action="[^"]+"/', "onclick=\"{$jsAction}\"", $attrs);
|
|
361
|
+
}
|
|
362
|
+
return $attrs;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
private function injectStateText($text) {
|
|
366
|
+
foreach ($this->stateVars as $key => $val) {
|
|
367
|
+
if (strpos($text, "@{{$key}}") !== false) {
|
|
368
|
+
$text = str_replace("@{{$key}}", "<span data-thoth-state='{$key}'>{$val}</span>", $text);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
return $text;
|
|
372
|
+
}
|
|
166
373
|
|
|
167
374
|
private function resolveDynamicData($text) {
|
|
168
375
|
$text = str_replace(array_keys($this->variables), array_values($this->variables), $text);
|
|
@@ -173,7 +380,8 @@ class ThothEngine {
|
|
|
173
380
|
|
|
174
381
|
private function findSeparator($text) {
|
|
175
382
|
$inQuotes = false;
|
|
176
|
-
|
|
383
|
+
$len = strlen($text);
|
|
384
|
+
for ($i = 0; $i < $len; $i++) {
|
|
177
385
|
if ($text[$i] === '"') $inQuotes = !$inQuotes;
|
|
178
386
|
if ($text[$i] === ':' && !$inQuotes) return $i;
|
|
179
387
|
}
|
|
@@ -193,28 +401,76 @@ class ThothEngine {
|
|
|
193
401
|
}
|
|
194
402
|
|
|
195
403
|
private function errorPage($title, $msg) {
|
|
196
|
-
return "<div style='font-family:sans-serif; background:#
|
|
404
|
+
return "<div style='font-family:sans-serif; background:#020617; color:#fff; height:100vh; display:flex; flex-direction:column; align-items:center; justify-content:center;'><h1>$title</h1><p style='color:#06b6d4'>$msg</p></div>";
|
|
197
405
|
}
|
|
198
406
|
|
|
199
|
-
private function devErrorOverlay($msg, $line) {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
407
|
+
private function devErrorOverlay($msg, $line, $lineContent = "") {
|
|
408
|
+
$escapedContent = htmlspecialchars($lineContent);
|
|
409
|
+
return "
|
|
410
|
+
<div style='position:fixed; top:0; left:0; width:100%; height:100%; background:rgba(2,6,23,0.95); z-index:99999; display:flex; align-items:center; justify-content:center; font-family:\"Fira Code\", monospace;'>
|
|
411
|
+
<div style='background:#0f172a; border:1px solid #ef4444; width:80%; max-width:800px; padding:30px; border-radius:12px; box-shadow:0 0 30px rgba(239, 68, 68, 0.2); color:#e2e8f0;'>
|
|
412
|
+
|
|
413
|
+
<div style='border-bottom: 1px solid #334155; padding-bottom:15px; mb-4;'>
|
|
414
|
+
<h2 style='color:#ef4444; margin:0; font-size:1.5rem;'>⚠️ THOTH Traceback (most recent call last):</h2>
|
|
415
|
+
</div>
|
|
416
|
+
|
|
417
|
+
<div style='padding: 20px 0;'>
|
|
418
|
+
<p style='margin:0 0 10px 0; color:#94a3b8;'>File <span style='color:#06b6d4;'>\"{$this->currentFile}\"</span>, line <span style='color:#f59e0b; font-weight:bold;'>$line</span>, in <module></p>
|
|
419
|
+
|
|
420
|
+
<div style='background:#000; padding:15px; border-radius:8px; border-left:4px solid #ef4444; overflow-x:auto;'>
|
|
421
|
+
<div style='color:#f87171;'>$line | <span style='color:#e2e8f0;'>$escapedContent</span></div>
|
|
422
|
+
<div style='color:#ef4444; margin-top:5px;'> ^</div>
|
|
423
|
+
</div>
|
|
424
|
+
|
|
425
|
+
<p style='margin:20px 0 0 0; color:#ef4444; font-weight:bold; font-size:1.1rem;'>$msg</p>
|
|
426
|
+
</div>
|
|
427
|
+
|
|
428
|
+
<div style='border-top: 1px solid #334155; padding-top:15px; text-align:right;'>
|
|
429
|
+
<button onclick='location.reload()' style='background:#ef4444; color:#fff; padding:8px 24px; border:none; border-radius:6px; cursor:pointer; font-weight:bold; font-family:inherit;'>RESTART ENGINE</button>
|
|
430
|
+
</div>
|
|
431
|
+
</div>
|
|
432
|
+
</div>";
|
|
205
433
|
}
|
|
206
434
|
|
|
207
435
|
private function generateFullHTML($body) {
|
|
208
436
|
$title = $this->dataContext['site_title'] ?? "THOTH Compiled System";
|
|
209
437
|
$desc = $this->dataContext['site_desc'] ?? "Architected by Abdelfatah Abdelhamed";
|
|
210
438
|
|
|
439
|
+
$stateJson = json_encode($this->stateVars);
|
|
440
|
+
$stateScript = "
|
|
441
|
+
<script>
|
|
442
|
+
// THOTH Frontend State Engine v12.0
|
|
443
|
+
const thothState = {
|
|
444
|
+
data: $stateJson,
|
|
445
|
+
dispatch: function(actionStr) {
|
|
446
|
+
if(actionStr.startsWith('set:')) {
|
|
447
|
+
let logic = actionStr.replace('set:', '').split('=');
|
|
448
|
+
let key = logic[0];
|
|
449
|
+
let expr = logic[1];
|
|
450
|
+
if(expr.includes('+1')) this.data[key] = parseInt(this.data[key]) + 1;
|
|
451
|
+
else if(expr.includes('-1')) this.data[key] = parseInt(this.data[key]) - 1;
|
|
452
|
+
else this.data[key] = expr;
|
|
453
|
+
this.render();
|
|
454
|
+
}
|
|
455
|
+
},
|
|
456
|
+
render: function() {
|
|
457
|
+
document.querySelectorAll('[data-thoth-state]').forEach(el => {
|
|
458
|
+
let key = el.getAttribute('data-thoth-state');
|
|
459
|
+
if(this.data[key] !== undefined) el.innerText = this.data[key];
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
};
|
|
463
|
+
</script>";
|
|
464
|
+
|
|
211
465
|
$liveReload = $this->devMode ? "<script>
|
|
212
466
|
let lastMod = null;
|
|
213
467
|
setInterval(async () => {
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
468
|
+
try {
|
|
469
|
+
const res = await fetch(window.location.href, { method: 'HEAD' });
|
|
470
|
+
const etag = res.headers.get('etag');
|
|
471
|
+
if (lastMod && etag !== lastMod) location.reload();
|
|
472
|
+
lastMod = etag;
|
|
473
|
+
} catch(e) {}
|
|
218
474
|
}, 2000);
|
|
219
475
|
</script>" : "";
|
|
220
476
|
|
|
@@ -222,9 +478,9 @@ class ThothEngine {
|
|
|
222
478
|
" <meta charset='UTF-8'>\n" .
|
|
223
479
|
" <meta name='viewport' content='width=device-width, initial-scale=1.0'>\n" .
|
|
224
480
|
" <meta name='description' content='$desc'>\n" .
|
|
225
|
-
" <meta name='generator' content='THOTH Sovereign Engine
|
|
481
|
+
" <meta name='generator' content='THOTH Sovereign Engine 12.0.0'>\n" .
|
|
226
482
|
" <title>$title</title>\n" .
|
|
227
|
-
"</head>\n<body>\n$body\n$liveReload</body>\n</html>";
|
|
483
|
+
"</head>\n<body style=\"margin:0; font-family:sans-serif;\">\n$body\n$stateScript\n$liveReload</body>\n</html>";
|
|
228
484
|
}
|
|
229
485
|
}
|
|
230
486
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "thoth-markup-lang",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "THOTH Sovereign Suite:
|
|
3
|
+
"version": "12.0.0",
|
|
4
|
+
"description": "THOTH Sovereign Suite v12.0.0 (The Sovereign Cloud): The ultimate indentation-based reactive web engine. Features native API Fetch Engine, Smart Routing (SPA builder), Native Layouts (Flexbox), Sovereign Components, State Management, Python-style tracebacks, and an ultra-high-performance runtime. Engineered by Engineer Abdelfatah Abdelhamed.",
|
|
5
5
|
"main": "thoth.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"thoth": "./thoth.js"
|
|
@@ -14,13 +14,29 @@
|
|
|
14
14
|
"serve": "node thoth.js serve --port 3000 --strict",
|
|
15
15
|
"validate": "node thoth.js validate --all",
|
|
16
16
|
"auth-setup": "node thoth.js auth --init",
|
|
17
|
-
"version": "echo THOTH
|
|
17
|
+
"version": "echo THOTH v12.0.0 The Sovereign Cloud Intelligence Suite"
|
|
18
18
|
},
|
|
19
19
|
"keywords": [
|
|
20
20
|
"thoth",
|
|
21
21
|
"thoth-lang",
|
|
22
22
|
"markup-language",
|
|
23
23
|
"sovereign-engine",
|
|
24
|
+
"sovereign-cloud",
|
|
25
|
+
"api-fetch",
|
|
26
|
+
"data-fetching",
|
|
27
|
+
"rest-api",
|
|
28
|
+
"web-engine",
|
|
29
|
+
"smart-routing",
|
|
30
|
+
"spa-builder",
|
|
31
|
+
"layout-engine",
|
|
32
|
+
"flexbox-grid",
|
|
33
|
+
"core-framework",
|
|
34
|
+
"sovereign-components",
|
|
35
|
+
"state-management",
|
|
36
|
+
"reactive-ui",
|
|
37
|
+
"pulse-edition",
|
|
38
|
+
"python-style-traceback",
|
|
39
|
+
"smart-error-handling",
|
|
24
40
|
"type-thoth-identification",
|
|
25
41
|
"strict-markup",
|
|
26
42
|
"indentation-logic",
|
|
@@ -36,7 +52,7 @@
|
|
|
36
52
|
"performance-runtime",
|
|
37
53
|
"high-speed-compiler"
|
|
38
54
|
],
|
|
39
|
-
"author": "Abdelfatah Abdelhamed <abdelfatahabdelhamed.kfs@gmail.com>",
|
|
55
|
+
"author": "Engineer Abdelfatah Abdelhamed <abdelfatahabdelhamed.kfs@gmail.com>",
|
|
40
56
|
"license": "MIT",
|
|
41
57
|
"engines": {
|
|
42
58
|
"node": ">=14.0.0"
|