thoth-markup-lang 11.0.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 -24
- package/engine.php +220 -21
- package/package.json +16 -3
- package/thoth.js +278 -104
package/README.md
CHANGED
|
@@ -1,43 +1,242 @@
|
|
|
1
|
-
# THOTH: The Sovereign Intelligence Suite
|
|
1
|
+
# ๐ง THOTH: The Sovereign Intelligence Suite
|
|
2
|
+
### v12.0.0 โ Sovereign Cloud Edition
|
|
2
3
|
|
|
3
4
|
<p align="center">
|
|
4
|
-
<img src="https://img.shields.io/npm/v/thoth-markup-lang?style=for-the-badge&color=06b6d4&logo=npm"
|
|
5
|
-
<img src="https://img.shields.io/badge/
|
|
6
|
-
<img src="https://img.shields.io/badge/
|
|
5
|
+
<img src="https://img.shields.io/npm/v/thoth-markup-lang?style=for-the-badge&color=06b6d4&logo=npm" />
|
|
6
|
+
<img src="https://img.shields.io/badge/Architecture-Sovereign-f59e0b?style=for-the-badge" />
|
|
7
|
+
<img src="https://img.shields.io/badge/Built%20In-Egypt%20๐ช๐ฌ-020617?style=for-the-badge" />
|
|
7
8
|
</p>
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
<p align="center">
|
|
11
|
+
<b>Not a framework. Not a library. This is a new way to think.</b>
|
|
12
|
+
</p>
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## โก What is THOTH?
|
|
17
|
+
|
|
18
|
+
THOTH is an **Asynchronous Reactive Web Engine** built to eliminate the chaos of traditional web development.
|
|
19
|
+
|
|
20
|
+
No closing tags.
|
|
21
|
+
No JS dependency for core logic.
|
|
22
|
+
No unnecessary complexity.
|
|
23
|
+
|
|
24
|
+
Just **pure architecture**.
|
|
25
|
+
|
|
26
|
+
> You donโt write code with THOTHโฆ you *define systems*.
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## ๐ง Why THOTH Exists
|
|
31
|
+
|
|
32
|
+
Modern web development is bloated:
|
|
33
|
+
- Too many frameworks
|
|
34
|
+
- Too much boilerplate
|
|
35
|
+
- Too much mental overhead
|
|
36
|
+
|
|
37
|
+
THOTH flips the table:
|
|
38
|
+
|
|
39
|
+
โ Indentation instead of tags
|
|
40
|
+
โ Native state instead of external stores
|
|
41
|
+
โ Built-in routing instead of config hell
|
|
42
|
+
โ Direct API binding without JavaScript
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## ๐ Core Features
|
|
47
|
+
|
|
48
|
+
### โ๏ธ Sovereign Cloud Engine
|
|
49
|
+
Fetch APIs natively:
|
|
50
|
+
```text
|
|
51
|
+
API users="https://jsonplaceholder.typicode.com/users"
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
### โก Native State System
|
|
57
|
+
```text
|
|
58
|
+
State counter: 0
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Reactive updates โ no re-render hacks.
|
|
10
62
|
|
|
11
63
|
---
|
|
12
64
|
|
|
13
|
-
|
|
65
|
+
### ๐ Smart SPA Routing
|
|
66
|
+
```text
|
|
67
|
+
Route "/":
|
|
68
|
+
Route "/dashboard":
|
|
69
|
+
```
|
|
14
70
|
|
|
15
|
-
|
|
71
|
+
Zero config. Zero libraries.
|
|
16
72
|
|
|
17
|
-
|
|
18
|
-
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
### ๐ Flex Layout Engine
|
|
76
|
+
```text
|
|
77
|
+
Row gap="20px" align="center":
|
|
78
|
+
Column width="300px":
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Responsive by design.
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
### ๐งฉ Component System
|
|
86
|
+
```text
|
|
87
|
+
Define Card:
|
|
88
|
+
Box:
|
|
89
|
+
Text: @{{title}}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Reusable. Clean. No duplication.
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
### ๐ Data Binding
|
|
97
|
+
```text
|
|
98
|
+
Text: @{{name}}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Direct binding. No middle layers.
|
|
19
102
|
|
|
20
103
|
---
|
|
21
104
|
|
|
22
|
-
|
|
105
|
+
### ๐ Auth Guards
|
|
106
|
+
```text
|
|
107
|
+
Header Auth="admin":
|
|
108
|
+
```
|
|
23
109
|
|
|
24
|
-
|
|
25
|
-
* **๐ Python-Style Tracebacks [NEW]:** Intelligent error handling that pinpoints exact file, line number, and syntax faults in both Terminal and a Browser Overlay.
|
|
26
|
-
* **๐ก๏ธ Strict Identification:** Mandatory `TYPE THOTH` protocol header to ensure uncompromised file sovereignty.
|
|
27
|
-
* **๐ Zero-Bracket Architecture:** Eliminates opening/closing DOM tags, reducing syntax noise by up to 70%.
|
|
28
|
-
* **๐ Recursive Data Binding:** Native integration with JSON flat-file databases using `@{{key}}` syntax.
|
|
29
|
-
* **๐ Procedural Middleware (Auth Guard):** Secure structural DOM nodes natively using `Auth="role"` attributes.
|
|
30
|
-
* **๐ Pulse Dev Server & Live Reload:** Integrated HTTP server with automated browser synchronization and state tracking.
|
|
31
|
-
* **๐ Advanced Meta SEO Engine:** Automated generation of HTML5 Meta Tags directly from your JSON data context.
|
|
32
|
-
* **๐ฆ Scoped Components:** Modular file architecture and management through the `Import:` directive.
|
|
33
|
-
* **๐ Hybrid Injection:** Native support for scoped `StyleSheet` (Raw CSS) and `Scripting` (Raw JS) inside the `.thoth` environment.
|
|
110
|
+
Security built into structure.
|
|
34
111
|
|
|
35
112
|
---
|
|
36
113
|
|
|
37
|
-
|
|
114
|
+
### ๐ Smart Tracebacks
|
|
115
|
+
Errors actually help you:
|
|
38
116
|
|
|
39
|
-
|
|
40
|
-
|
|
117
|
+
```text
|
|
118
|
+
File "app.thoth", line 12
|
|
119
|
+
APIError: Failed to fetch data
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## ๐ Quick Start
|
|
125
|
+
|
|
126
|
+
### 1. Install
|
|
41
127
|
|
|
42
128
|
```bash
|
|
43
|
-
npm install -g thoth-markup-lang
|
|
129
|
+
npm install -g thoth-markup-lang
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
### 2. Create App
|
|
135
|
+
|
|
136
|
+
**app.thoth**
|
|
137
|
+
```text
|
|
138
|
+
TYPE THOTH
|
|
139
|
+
|
|
140
|
+
Define UserCard:
|
|
141
|
+
Column width="300px":
|
|
142
|
+
Box class="card":
|
|
143
|
+
Sub: @{{name}}
|
|
144
|
+
Text: "Email: @{{email}}"
|
|
145
|
+
|
|
146
|
+
State active_users: 0
|
|
147
|
+
|
|
148
|
+
API users="https://jsonplaceholder.typicode.com/users"
|
|
149
|
+
|
|
150
|
+
Container:
|
|
151
|
+
Route "/":
|
|
152
|
+
Row gap="20px":
|
|
153
|
+
Repeat Over="users":
|
|
154
|
+
UserCard name="@{{name}}", email="@{{email}}"
|
|
155
|
+
|
|
156
|
+
Row:
|
|
157
|
+
Text: "Users: @{{active_users}}"
|
|
158
|
+
Button action="set:active_users=active_users+1": "Ping"
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
### 3. Run
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
thoth serve app.thoth
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
### 4. Build
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
thoth build app.thoth
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## ๐๏ธ Philosophy
|
|
180
|
+
|
|
181
|
+
THOTH is built on one idea:
|
|
182
|
+
|
|
183
|
+
> **Structure is more important than syntax.**
|
|
184
|
+
|
|
185
|
+
Everything else is noise.
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## ๐ฅ What Makes THOTH Different?
|
|
190
|
+
|
|
191
|
+
| Traditional Web | THOTH |
|
|
192
|
+
|------|--------|
|
|
193
|
+
| HTML + CSS + JS | One unified system |
|
|
194
|
+
| Manual state | Native state |
|
|
195
|
+
| React/Vue routing | Built-in routing |
|
|
196
|
+
| API via JS | Native API binding |
|
|
197
|
+
| JSX / Templates | Pure indentation |
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## ๐งช Example Output
|
|
202
|
+
|
|
203
|
+
From this:
|
|
204
|
+
```text
|
|
205
|
+
Text: "Hello World"
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
To clean HTML โ instantly.
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
## ๐ก๏ธ Sovereign Rules
|
|
213
|
+
|
|
214
|
+
Every file MUST start with:
|
|
215
|
+
|
|
216
|
+
```text
|
|
217
|
+
TYPE THOTH
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
No exceptions.
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
## ๐ Vision
|
|
225
|
+
|
|
226
|
+
THOTH is not trying to compete with frameworks.
|
|
227
|
+
|
|
228
|
+
Itโs trying to **replace the need for them**.
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
## ๐ Final Word
|
|
233
|
+
|
|
234
|
+
> โSovereignty is not writing codeโฆ
|
|
235
|
+
> it is controlling how code is written.โ
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
<p align="center">
|
|
240
|
+
<b>Engineered by Abdelfatah Abdelhamed</b><br>
|
|
241
|
+
<i>Cairo, Egypt ๐ช๐ฌ</i>
|
|
242
|
+
</p>
|
package/engine.php
CHANGED
|
@@ -1,15 +1,20 @@
|
|
|
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
11
|
* 5. Python-Style Traceback: ู
ุชุชุจุน ุฃุฎุทุงุก ุฐูู ูุญุฏุฏ ุงูุณุทุฑ ูููุน ุงูุฎุทุฃ ุจุฏูุฉ.
|
|
12
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.
|
|
13
18
|
*/
|
|
14
19
|
|
|
15
20
|
session_start();
|
|
@@ -32,7 +37,8 @@ class ThothEngine {
|
|
|
32
37
|
'Header' => 'header', 'Footer' => 'footer', 'Bold' => 'strong',
|
|
33
38
|
'Link' => 'a', 'Image' => 'img', 'List' => 'ul', 'Item' => 'li',
|
|
34
39
|
'Button' => 'button', 'Input' => 'input', 'Break' => 'br',
|
|
35
|
-
'Line' => 'hr', 'Layout' => 'main'
|
|
40
|
+
'Line' => 'hr', 'Layout' => 'main',
|
|
41
|
+
'Row' => 'div', 'Column' => 'div'
|
|
36
42
|
];
|
|
37
43
|
|
|
38
44
|
private $voidTags = ['img', 'br', 'hr', 'input', 'meta', 'link'];
|
|
@@ -41,6 +47,9 @@ class ThothEngine {
|
|
|
41
47
|
private $devMode = true;
|
|
42
48
|
private $currentLine = 0;
|
|
43
49
|
private $currentFile = "";
|
|
50
|
+
|
|
51
|
+
private $components = [];
|
|
52
|
+
private $stateVars = [];
|
|
44
53
|
|
|
45
54
|
/**
|
|
46
55
|
* ุงูู
ุฏุฎู ุงูุฑุฆูุณู ููู
ุญุฑู
|
|
@@ -60,7 +69,10 @@ class ThothEngine {
|
|
|
60
69
|
if ($firstLine !== "TYPE THOTH") {
|
|
61
70
|
return $this->devErrorOverlay("SyntaxError: Missing Identity Protocol. File must begin with TYPE THOTH.", 1, $lines[0]);
|
|
62
71
|
}
|
|
63
|
-
unset($lines[0]);
|
|
72
|
+
unset($lines[0]);
|
|
73
|
+
|
|
74
|
+
// ุงุณุชุฎุฑุงุฌ ุงูู
ุณุงุฑ ุงูุญุงูู ููุธุงู
ุงูู Routing
|
|
75
|
+
$requestedRoute = isset($_GET['route']) ? '/' . ltrim($_GET['route'], '/') : '/';
|
|
64
76
|
|
|
65
77
|
try {
|
|
66
78
|
$htmlBody = "";
|
|
@@ -73,30 +85,89 @@ class ThothEngine {
|
|
|
73
85
|
$repeatBuffer = [];
|
|
74
86
|
$repeatKey = "";
|
|
75
87
|
$repeatIndent = 0;
|
|
88
|
+
|
|
89
|
+
$isDefiningComponent = false;
|
|
90
|
+
$currentComponentName = "";
|
|
91
|
+
$componentIndent = 0;
|
|
76
92
|
|
|
77
93
|
foreach ($lines as $index => $line) {
|
|
78
94
|
$this->currentLine = $index + 1;
|
|
79
95
|
$trimmed = trim($line);
|
|
80
96
|
|
|
81
|
-
// ุชุณุฑูุน ู
ุนุงูุฌุฉ ุงูุฃุณุทุฑ ุงููุงุฑุบุฉ ูุงูุชุนูููุงุช ุจุงุณุชุฎุฏุงู
str_starts_with
|
|
82
97
|
if ($trimmed === "" || str_starts_with($trimmed, '#')) continue;
|
|
83
98
|
|
|
84
99
|
$indent = strlen($line) - strlen(ltrim($line));
|
|
85
100
|
|
|
86
|
-
//
|
|
101
|
+
// Guard System
|
|
87
102
|
if ($skipUntilIndent !== -1) {
|
|
88
103
|
if ($indent > $skipUntilIndent) continue;
|
|
89
104
|
else $skipUntilIndent = -1;
|
|
90
105
|
}
|
|
91
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 ---
|
|
92
118
|
if (preg_match('/Auth="([^"]+)"/', $trimmed, $matches)) {
|
|
93
119
|
if (!$this->checkAuth($matches[1])) {
|
|
94
120
|
$skipUntilIndent = $indent;
|
|
95
121
|
continue;
|
|
96
122
|
}
|
|
97
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
|
+
}
|
|
98
169
|
|
|
99
|
-
// Repeat System
|
|
170
|
+
// --- 6. Repeat System ---
|
|
100
171
|
if ($isRepeatMode) {
|
|
101
172
|
if ($indent > $repeatIndent) { $repeatBuffer[] = $line; continue; }
|
|
102
173
|
else { $htmlBody .= $this->processRepeat($repeatKey, $repeatBuffer); $isRepeatMode = false; $repeatBuffer = []; }
|
|
@@ -109,7 +180,7 @@ class ThothEngine {
|
|
|
109
180
|
$repeatIndent = $indent; $isRepeatMode = true; continue;
|
|
110
181
|
}
|
|
111
182
|
|
|
112
|
-
//
|
|
183
|
+
// --- 7. DataSource & Imports ---
|
|
113
184
|
if (str_starts_with($trimmed, 'DataSource:')) { $this->loadData(trim(substr($trimmed, 11))); continue; }
|
|
114
185
|
if (str_starts_with($trimmed, 'Var ')) { $this->parseVariable($trimmed); continue; }
|
|
115
186
|
if (str_starts_with($trimmed, 'Import:')) {
|
|
@@ -121,24 +192,31 @@ class ThothEngine {
|
|
|
121
192
|
$line = $this->resolveDynamicData($line);
|
|
122
193
|
$trimmed = trim($line);
|
|
123
194
|
|
|
124
|
-
// Raw Injection (CSS/JS)
|
|
195
|
+
// --- 8. Raw Injection (CSS/JS) ---
|
|
125
196
|
if ($inRawMode) {
|
|
126
197
|
if ($indent <= $rawIndent && !empty($trimmed)) { $inRawMode = false; $htmlBody .= "</$rawType>\n"; }
|
|
127
198
|
else { $htmlBody .= $line . "\n"; continue; }
|
|
128
199
|
}
|
|
129
200
|
|
|
130
201
|
$sep = $this->findSeparator($trimmed);
|
|
131
|
-
|
|
132
|
-
// ุงูุฐูุงุก ุงูุงุตุทูุงุนู ูุงูุชุดุงู ุงูุฃุฎุทุงุก ุงูู
ุทุจุนูุฉ
|
|
133
|
-
throw new ThothSyntaxError("ParseError: Invalid syntax or missing separator ':'.", $this->currentLine, $line);
|
|
134
|
-
}
|
|
135
|
-
|
|
202
|
+
|
|
136
203
|
$cmdPart = ($sep !== -1) ? trim(substr($trimmed, 0, $sep)) : $trimmed;
|
|
137
204
|
$val = ($sep !== -1) ? trim(substr($trimmed, $sep + 1)) : "";
|
|
138
205
|
|
|
139
206
|
$spacePos = strpos($cmdPart, ' ');
|
|
140
207
|
$cmd = ($spacePos !== false) ? substr($cmdPart, 0, $spacePos) : $cmdPart;
|
|
141
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
|
+
}
|
|
142
220
|
|
|
143
221
|
if ($cmd === "StyleSheet" || $cmd === "Scripting") {
|
|
144
222
|
$inRawMode = true; $rawType = ($cmd === "StyleSheet") ? "style" : "script";
|
|
@@ -152,12 +230,38 @@ class ThothEngine {
|
|
|
152
230
|
}
|
|
153
231
|
|
|
154
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
|
+
|
|
155
248
|
$cleanAttrs = preg_replace('/Auth="[^"]+"/', '', $attrs);
|
|
156
|
-
$
|
|
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) : "") . ">";
|
|
157
260
|
|
|
158
261
|
if (in_array($tag, $this->voidTags)) {
|
|
159
262
|
$htmlBody .= str_repeat(" ", $indent) . $openingTag . "\n";
|
|
160
263
|
} elseif ($val !== "") {
|
|
264
|
+
$val = $this->injectStateText($val);
|
|
161
265
|
$htmlBody .= str_repeat(" ", $indent) . $openingTag . $val . "</$tag>\n";
|
|
162
266
|
} else {
|
|
163
267
|
$htmlBody .= str_repeat(" ", $indent) . $openingTag . "\n";
|
|
@@ -182,6 +286,31 @@ class ThothEngine {
|
|
|
182
286
|
return (isset($_SESSION['user_role']) && $_SESSION['user_role'] === $role);
|
|
183
287
|
}
|
|
184
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
|
+
|
|
185
314
|
private function processRepeat($key, $linesBuffer) {
|
|
186
315
|
$dataArray = $this->dataContext[$key] ?? [];
|
|
187
316
|
$output = "";
|
|
@@ -193,6 +322,54 @@ class ThothEngine {
|
|
|
193
322
|
}
|
|
194
323
|
return $output;
|
|
195
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
|
+
}
|
|
196
373
|
|
|
197
374
|
private function resolveDynamicData($text) {
|
|
198
375
|
$text = str_replace(array_keys($this->variables), array_values($this->variables), $text);
|
|
@@ -227,10 +404,6 @@ class ThothEngine {
|
|
|
227
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>";
|
|
228
405
|
}
|
|
229
406
|
|
|
230
|
-
/**
|
|
231
|
-
* Python-Style Traceback Overlay
|
|
232
|
-
* ุชุตู
ูู
ููุฏุณู ุฐูู ูุญุฏุฏ ุงูุฎุทุฃ ูุงูู
ูุงู ูุงูู
ูู ุจุงูุชูุตูู
|
|
233
|
-
*/
|
|
234
407
|
private function devErrorOverlay($msg, $line, $lineContent = "") {
|
|
235
408
|
$escapedContent = htmlspecialchars($lineContent);
|
|
236
409
|
return "
|
|
@@ -263,6 +436,32 @@ class ThothEngine {
|
|
|
263
436
|
$title = $this->dataContext['site_title'] ?? "THOTH Compiled System";
|
|
264
437
|
$desc = $this->dataContext['site_desc'] ?? "Architected by Abdelfatah Abdelhamed";
|
|
265
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
|
+
|
|
266
465
|
$liveReload = $this->devMode ? "<script>
|
|
267
466
|
let lastMod = null;
|
|
268
467
|
setInterval(async () => {
|
|
@@ -279,9 +478,9 @@ class ThothEngine {
|
|
|
279
478
|
" <meta charset='UTF-8'>\n" .
|
|
280
479
|
" <meta name='viewport' content='width=device-width, initial-scale=1.0'>\n" .
|
|
281
480
|
" <meta name='description' content='$desc'>\n" .
|
|
282
|
-
" <meta name='generator' content='THOTH Sovereign Engine
|
|
481
|
+
" <meta name='generator' content='THOTH Sovereign Engine 12.0.0'>\n" .
|
|
283
482
|
" <title>$title</title>\n" .
|
|
284
|
-
"</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>";
|
|
285
484
|
}
|
|
286
485
|
}
|
|
287
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,26 @@
|
|
|
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",
|
|
24
37
|
"pulse-edition",
|
|
25
38
|
"python-style-traceback",
|
|
26
39
|
"smart-error-handling",
|
package/thoth.js
CHANGED
|
@@ -1,22 +1,28 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* THOTH Engine
|
|
4
|
+
* THOTH Engine v12.0.0 - The Sovereign Cloud (Intelligence Suite)
|
|
5
5
|
* Lead Developer & Architect: Engineer Abdelfatah Abdelhamed ๐ช๐ฌ
|
|
6
6
|
* ------------------------------------------------------------------
|
|
7
|
-
* ุงูู
ูุฒุงุช
|
|
7
|
+
* ุงูู
ูุฒุงุช ุงูู
ุฏู
ุฌุฉ (ุงููุณุฎุฉ ุงูููุงุฆูุฉ):
|
|
8
8
|
* 1. Strict Identification: ุฅูุฒุงู
ูุฉ ูุฌูุฏ TYPE THOTH ูู ุงูุณุทุฑ ุงูุฃูู.
|
|
9
9
|
* 2. Middleware Support: ูุธุงู
Auth Guard ุงูู
ุชูุฏู
ูุชุตููุฉ ุงูุนูุงุตุฑ.
|
|
10
10
|
* 3. Dynamic Meta Engine: ุชูููุฏ ูุณูู
ุงูู
ูุชุง ุชููุงุฆูุงู ู
ู ุณูุงู ุงูุจูุงูุงุช.
|
|
11
11
|
* 4. Dev Server & Live Reload: ุฎุงุฏู
ู
ุญูู ูู
ุฑุงูุจุฉ ุงูุชุบููุฑุงุช ูุญุธูุงู.
|
|
12
12
|
* 5. Recursive Data Engine: ูุธุงู
ุงูู Loops ูุงูู JSON ูุงูู Variables.
|
|
13
13
|
* 6. Python-Style Traceback: ู
ุชุชุจุน ุฃุฎุทุงุก ุฐูู ูุฏููู ุฌุฏุงู.
|
|
14
|
-
* 7. Ultra-Fast Parser: ุชุณุฑูุน ุฎูุงุฑุฒู
ูุงุช ุงูู Indentation
|
|
14
|
+
* 7. Ultra-Fast Parser: ุชุณุฑูุน ุฎูุงุฑุฒู
ูุงุช ุงูู Indentation.
|
|
15
|
+
* 8. Sovereign Components: ุงููุฏุฑุฉ ุนูู ุชุนุฑูู ูุฅุนุงุฏุฉ ุงุณุชุฎุฏุงู
ุงูู
ูููุงุช.
|
|
16
|
+
* 9. State Management: ุญูู ู
ุชุบูุฑุงุช ุงูุญุงูุฉ ูุฅูุดุงุก ูุงุฌูุงุช ุชูุงุนููุฉ.
|
|
17
|
+
* 10. Layout Engine: ูุธุงู
ุดุจูุงุช ู
ุฏู
ุฌ (Row / Column) ุจุฎูุงุต Flexbox.
|
|
18
|
+
* 11. Smart Routing: ูุธุงู
ุชููู ุฏุงุฎูู ู
ุฏู
ุฌ ูุจูุงุก ุชุทุจููุงุช SPA.
|
|
19
|
+
* 12. API Fetch Engine [NEW]: ู
ุญุฑู ูุงุชุฒุงู
ูู (Async) ูุฌูุจ ุจูุงูุงุช ุงูู APIs.
|
|
15
20
|
*/
|
|
16
21
|
|
|
17
22
|
const fs = require('fs');
|
|
18
23
|
const path = require('path');
|
|
19
24
|
const http = require('http');
|
|
25
|
+
const https = require('https');
|
|
20
26
|
|
|
21
27
|
// --- ููุงุณ ุชุชุจุน ุงูุฃุฎุทุงุก ุงูุฐูู (Python-Style Error Traceback) ---
|
|
22
28
|
class ThothSyntaxError extends Error {
|
|
@@ -36,17 +42,17 @@ const TAG_MAP = {
|
|
|
36
42
|
'Header': 'header', 'Footer': 'footer', 'Article': 'article', 'Aside': 'aside',
|
|
37
43
|
'Link': 'a', 'Image': 'img', 'Button': 'button', 'List': 'ul', 'Item': 'li',
|
|
38
44
|
'Input': 'input', 'Form': 'form', 'Label': 'label', 'Break': 'br', 'Line': 'hr',
|
|
39
|
-
'Main': 'main', 'Layout': 'section'
|
|
45
|
+
'Main': 'main', 'Layout': 'section',
|
|
46
|
+
'Row': 'div', 'Column': 'div'
|
|
40
47
|
};
|
|
41
48
|
|
|
42
49
|
const VOID_ELEMENTS = ['img', 'br', 'hr', 'input', 'meta', 'link'];
|
|
43
50
|
|
|
44
|
-
// --- ุณูุงู ุงูุชุดุบูู ุงูุณูุงุฏู ---
|
|
45
|
-
let
|
|
46
|
-
let config = {
|
|
51
|
+
// --- ุณูุงู ุงูุชุดุบูู ุงูุณูุงุฏู ุงูุนุงู
---
|
|
52
|
+
let globalConfig = {
|
|
47
53
|
devMode: process.argv.includes('--dev') || process.argv.includes('serve'),
|
|
48
54
|
port: 3000,
|
|
49
|
-
currentUserRole: 'admin',
|
|
55
|
+
currentUserRole: 'admin',
|
|
50
56
|
strictMode: true
|
|
51
57
|
};
|
|
52
58
|
|
|
@@ -59,25 +65,38 @@ if (!command || (!target && command !== 'serve')) {
|
|
|
59
65
|
process.exit(1);
|
|
60
66
|
}
|
|
61
67
|
|
|
62
|
-
/**
|
|
63
|
-
* ุนุฑุถ ุฅุฑุดุงุฏุงุช ุงูุงุณุชุฎุฏุงู
ุงูุชูููุฉ
|
|
64
|
-
*/
|
|
65
68
|
function displayUsage() {
|
|
66
69
|
const yellow = '\x1b[33m';
|
|
67
70
|
const cyan = '\x1b[36m';
|
|
68
71
|
const reset = '\x1b[0m';
|
|
69
72
|
console.log(yellow + 'โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ' + reset);
|
|
70
|
-
console.log('\x1b[1m\x1b[32m THOTH INTELLIGENCE SUITE
|
|
73
|
+
console.log('\x1b[1m\x1b[32m THOTH INTELLIGENCE SUITE v12.0.0 (The Sovereign Cloud) \x1b[0m');
|
|
71
74
|
console.log(cyan + ' Lead Architect: Engineer Abdelfatah Abdelhamed' + reset);
|
|
72
75
|
console.log(yellow + 'โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ' + reset);
|
|
73
76
|
console.log(' Usage:');
|
|
74
77
|
console.log(' thoth build [file].thoth (Production Compilation)');
|
|
75
|
-
console.log(' thoth serve [file].thoth (Live
|
|
78
|
+
console.log(' thoth serve [file].thoth (Live SPA Server + Traceback)');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// --- ู
ุญุฑู ุงูุงุชุตุงู ุงูุฎุงุฑุฌู ุงูุณูุงุฏู (ู
ุชูุงูู ู
ุน ูู ูุณุฎ Node) ---
|
|
82
|
+
function fetchJSON(url) {
|
|
83
|
+
return new Promise((resolve, reject) => {
|
|
84
|
+
const client = url.startsWith('https') ? https : http;
|
|
85
|
+
client.get(url, { headers: { 'User-Agent': 'THOTH-Sovereign-Engine/12.0' } }, (res) => {
|
|
86
|
+
let data = '';
|
|
87
|
+
res.on('data', chunk => data += chunk);
|
|
88
|
+
res.on('end', () => {
|
|
89
|
+
if (res.statusCode >= 200 && res.statusCode < 300) {
|
|
90
|
+
try { resolve(JSON.parse(data)); }
|
|
91
|
+
catch (e) { reject(new Error('Invalid JSON response format.')); }
|
|
92
|
+
} else {
|
|
93
|
+
reject(new Error(`HTTP Error: ${res.statusCode}`));
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
}).on('error', reject);
|
|
97
|
+
});
|
|
76
98
|
}
|
|
77
99
|
|
|
78
|
-
/**
|
|
79
|
-
* ู
ุนุงูุฌุฉ ุงูุจูุงูุงุช ุงูุฏููุงู
ูููุฉ @{{key}} ู @Variable (Fast Regex)
|
|
80
|
-
*/
|
|
81
100
|
const DATA_REGEX = /@\{\{([^}]+)\}\}/g;
|
|
82
101
|
function resolveData(text, context, variables = {}) {
|
|
83
102
|
let resolved = text;
|
|
@@ -90,54 +109,138 @@ function resolveData(text, context, variables = {}) {
|
|
|
90
109
|
});
|
|
91
110
|
}
|
|
92
111
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
112
|
+
function injectStateText(text, stateVars) {
|
|
113
|
+
let processedText = text;
|
|
114
|
+
for (const [key, val] of Object.entries(stateVars)) {
|
|
115
|
+
const token = `@{{${key}}}`;
|
|
116
|
+
if (processedText.includes(token)) {
|
|
117
|
+
processedText = processedText.replace(new RegExp(token, 'g'), `<span data-thoth-state="${key}">${val}</span>`);
|
|
118
|
+
}
|
|
99
119
|
}
|
|
120
|
+
return processedText;
|
|
121
|
+
}
|
|
100
122
|
|
|
101
|
-
|
|
102
|
-
const
|
|
123
|
+
function injectStateBindings(attrs) {
|
|
124
|
+
const match = attrs.match(/action="([^"]+)"/);
|
|
125
|
+
if (match) {
|
|
126
|
+
const actionStr = match[1];
|
|
127
|
+
const jsAction = `thothState.dispatch('${actionStr}')`;
|
|
128
|
+
return attrs.replace(/action="[^"]+"/, `onclick="${jsAction}"`);
|
|
129
|
+
}
|
|
130
|
+
return attrs;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* ุงูู
ุญุฑู ุงูุฃุณุงุณู (ุชุญูู ุฅูู Async/Await ูุฏุนู
ุงูุณุญุงุจุฉ ุงูุณูุงุฏูุฉ)
|
|
135
|
+
*/
|
|
136
|
+
async function compileThothEngine(sourceContent, inputPath, isDev = false, isSubCall = false, inheritedContext = {}, inheritedComponents = {}, requestedRoute = '/') {
|
|
137
|
+
const lines = sourceContent.split(/\r?\n/);
|
|
103
138
|
|
|
104
|
-
// --- ุงูุชุญูู ู
ู ุดุฑุท ุงูุณูุงุฏุฉ ุงูุฃูู ---
|
|
105
139
|
if (lines[0].trim() !== "TYPE THOTH") {
|
|
106
|
-
throw new ThothSyntaxError("Architectural Identity Error: Missing 'TYPE THOTH' protocol
|
|
140
|
+
throw new ThothSyntaxError("Architectural Identity Error: Missing 'TYPE THOTH' protocol.", 1, lines[0], inputPath);
|
|
107
141
|
}
|
|
108
142
|
|
|
109
143
|
let htmlContent = "";
|
|
110
144
|
let stack = [];
|
|
111
|
-
|
|
145
|
+
|
|
146
|
+
let dataContext = { ...inheritedContext.dataContext };
|
|
147
|
+
let variables = { ...inheritedContext.variables };
|
|
148
|
+
let stateVars = { ...inheritedContext.stateVars };
|
|
149
|
+
let componentsContext = { ...inheritedComponents };
|
|
150
|
+
|
|
112
151
|
let rawScope = { active: false, type: '', indent: 0 };
|
|
113
152
|
let skipIndent = -1;
|
|
114
153
|
let repeatScope = { active: false, key: '', indent: 0, buffer: [] };
|
|
154
|
+
|
|
155
|
+
let componentScope = { active: false, name: '', indent: 0, buffer: [] };
|
|
115
156
|
|
|
116
157
|
for (let i = 1; i < lines.length; i++) {
|
|
117
158
|
const lineNum = i + 1;
|
|
118
159
|
let line = lines[i];
|
|
119
160
|
|
|
120
|
-
// ุชุณุฑูุน ุงูุชุดุงู ุงูู
ุณุงูุงุช (ุฃุณุฑุน ู
ู Regex search)
|
|
121
161
|
const trimmed = line.trimStart();
|
|
122
162
|
if (!trimmed || trimmed.startsWith('#')) continue;
|
|
123
163
|
const indent = line.length - trimmed.length;
|
|
124
164
|
const fullyTrimmed = trimmed.trimEnd();
|
|
125
165
|
|
|
126
|
-
// --- 1. Middleware / Auth Guard ---
|
|
127
166
|
if (skipIndent !== -1) {
|
|
128
167
|
if (indent > skipIndent) continue;
|
|
129
168
|
else skipIndent = -1;
|
|
130
169
|
}
|
|
131
170
|
|
|
171
|
+
// --- 1. ุงูุชููู ุงูุฐูู (Smart Routing) ---
|
|
172
|
+
if (fullyTrimmed.startsWith('Route "')) {
|
|
173
|
+
const match = fullyTrimmed.match(/Route "([^"]+)"/);
|
|
174
|
+
const routePath = match ? match[1] : '';
|
|
175
|
+
if (routePath !== requestedRoute) {
|
|
176
|
+
skipIndent = indent;
|
|
177
|
+
}
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// --- 2. Middleware / Auth Guard ---
|
|
132
182
|
const authMatch = fullyTrimmed.match(/Auth="([^"]+)"/);
|
|
133
183
|
if (authMatch) {
|
|
134
|
-
if (authMatch[1] !==
|
|
184
|
+
if (authMatch[1] !== globalConfig.currentUserRole && authMatch[1] !== 'guest') {
|
|
135
185
|
skipIndent = indent;
|
|
136
186
|
continue;
|
|
137
187
|
}
|
|
138
188
|
}
|
|
139
189
|
|
|
140
|
-
// ---
|
|
190
|
+
// --- 3. Sovereign Components (Define) ---
|
|
191
|
+
if (componentScope.active) {
|
|
192
|
+
if (indent > componentScope.indent) {
|
|
193
|
+
componentScope.buffer.push(line);
|
|
194
|
+
continue;
|
|
195
|
+
} else {
|
|
196
|
+
componentsContext[componentScope.name] = [...componentScope.buffer];
|
|
197
|
+
componentScope.active = false;
|
|
198
|
+
componentScope.buffer = [];
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (fullyTrimmed.startsWith('Define ')) {
|
|
203
|
+
const colonIdx = fullyTrimmed.indexOf(':');
|
|
204
|
+
if (colonIdx === -1) throw new ThothSyntaxError("ComponentError: Missing ':' in Define statement.", lineNum, line, inputPath);
|
|
205
|
+
const compName = fullyTrimmed.substring(7, colonIdx).trim();
|
|
206
|
+
componentScope.name = compName;
|
|
207
|
+
componentScope.active = true;
|
|
208
|
+
componentScope.indent = indent;
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// --- 4. State Management ---
|
|
213
|
+
if (fullyTrimmed.startsWith('State ')) {
|
|
214
|
+
const colonIdx = fullyTrimmed.indexOf(':');
|
|
215
|
+
if (colonIdx !== -1) {
|
|
216
|
+
const stateKey = fullyTrimmed.substring(6, colonIdx).trim();
|
|
217
|
+
const stateVal = fullyTrimmed.substring(colonIdx + 1).trim();
|
|
218
|
+
stateVars[stateKey] = stateVal;
|
|
219
|
+
variables[`@{{${stateKey}}}`] = stateVal;
|
|
220
|
+
} else {
|
|
221
|
+
throw new ThothSyntaxError(`StateError: Invalid State syntax. Expected 'State name: value'.`, lineNum, line, inputPath);
|
|
222
|
+
}
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// --- 5. API Fetch Engine [NEW] ---
|
|
227
|
+
if (fullyTrimmed.startsWith('API ')) {
|
|
228
|
+
const match = fullyTrimmed.match(/API\s+([a-zA-Z0-9_]+)="([^"]+)"/);
|
|
229
|
+
if (match) {
|
|
230
|
+
const apiKey = match[1];
|
|
231
|
+
const apiUrl = match[2];
|
|
232
|
+
try {
|
|
233
|
+
dataContext[apiKey] = await fetchJSON(apiUrl);
|
|
234
|
+
} catch (err) {
|
|
235
|
+
throw new ThothSyntaxError(`APIError: Failed to fetch external data from '${apiUrl}'. ${err.message}`, lineNum, line, inputPath);
|
|
236
|
+
}
|
|
237
|
+
} else {
|
|
238
|
+
throw new ThothSyntaxError("APIError: Invalid API syntax. Expected 'API name=\"URL\"'.", lineNum, line, inputPath);
|
|
239
|
+
}
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// --- 6. Repeat Logic (Recursive & Async) ---
|
|
141
244
|
if (repeatScope.active) {
|
|
142
245
|
if (indent > repeatScope.indent) {
|
|
143
246
|
repeatScope.buffer.push(line);
|
|
@@ -147,9 +250,10 @@ function compileThoth(inputPath, isDev = false) {
|
|
|
147
250
|
if(!Array.isArray(list)) {
|
|
148
251
|
throw new ThothSyntaxError(`DataMappingError: '${repeatScope.key}' is not a valid Array in Context.`, lineNum, line, inputPath);
|
|
149
252
|
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
253
|
+
for (const item of list) {
|
|
254
|
+
const mergedContext = { dataContext: { ...dataContext, ...item }, variables, stateVars };
|
|
255
|
+
htmlContent += await processBuffer(repeatScope.buffer, mergedContext, componentsContext, inputPath, lineNum, requestedRoute);
|
|
256
|
+
}
|
|
153
257
|
repeatScope.active = false;
|
|
154
258
|
repeatScope.buffer = [];
|
|
155
259
|
}
|
|
@@ -164,15 +268,14 @@ function compileThoth(inputPath, isDev = false) {
|
|
|
164
268
|
continue;
|
|
165
269
|
}
|
|
166
270
|
|
|
167
|
-
// ---
|
|
271
|
+
// --- 7. DataSource & Variables ---
|
|
168
272
|
if (fullyTrimmed.startsWith('DataSource:')) {
|
|
169
273
|
const jsonFileName = fullyTrimmed.split(':')[1].trim();
|
|
170
274
|
const dPath = path.resolve(path.dirname(inputPath), jsonFileName);
|
|
171
|
-
if (!fs.existsSync(dPath)) {
|
|
172
|
-
throw new ThothSyntaxError(`MissingDataError: DataSource '${jsonFileName}' not found.`, lineNum, line, inputPath);
|
|
173
|
-
}
|
|
275
|
+
if (!fs.existsSync(dPath)) throw new ThothSyntaxError(`MissingDataError: DataSource '${jsonFileName}' not found.`, lineNum, line, inputPath);
|
|
174
276
|
try {
|
|
175
|
-
|
|
277
|
+
const parsedData = JSON.parse(fs.readFileSync(dPath, 'utf8'));
|
|
278
|
+
dataContext = { ...dataContext, ...parsedData };
|
|
176
279
|
} catch(e) {
|
|
177
280
|
throw new ThothSyntaxError(`JSONParseError: Invalid JSON format in '${jsonFileName}'.`, lineNum, line, inputPath);
|
|
178
281
|
}
|
|
@@ -182,14 +285,23 @@ function compileThoth(inputPath, isDev = false) {
|
|
|
182
285
|
if (fullyTrimmed.startsWith('Var ')) {
|
|
183
286
|
const vParts = fullyTrimmed.substring(4).split(':');
|
|
184
287
|
if (vParts.length === 2) variables['@' + vParts[0].trim()] = vParts[1].trim();
|
|
185
|
-
else throw new ThothSyntaxError(`VariableError: Invalid Var syntax
|
|
288
|
+
else throw new ThothSyntaxError(`VariableError: Invalid Var syntax.`, lineNum, line, inputPath);
|
|
289
|
+
continue;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
if (fullyTrimmed.startsWith('Import:')) {
|
|
293
|
+
const importFile = fullyTrimmed.substring(7).trim();
|
|
294
|
+
const importPath = path.resolve(path.dirname(inputPath), importFile);
|
|
295
|
+
if (!fs.existsSync(importPath)) throw new ThothSyntaxError(`ImportError: Module '${importFile}' not found.`, lineNum, line, inputPath);
|
|
296
|
+
const importContent = fs.readFileSync(importPath, 'utf8');
|
|
297
|
+
const subCall = await compileThothEngine(importContent, importPath, false, true, { dataContext, variables, stateVars }, componentsContext, requestedRoute);
|
|
298
|
+
htmlContent += subCall.html;
|
|
186
299
|
continue;
|
|
187
300
|
}
|
|
188
301
|
|
|
189
302
|
line = resolveData(line, dataContext, variables);
|
|
190
303
|
const processedTrimmed = line.trim();
|
|
191
304
|
|
|
192
|
-
// --- 4. Raw Code Injection (CSS/JS) ---
|
|
193
305
|
if (rawScope.active) {
|
|
194
306
|
if (indent <= rawScope.indent && processedTrimmed !== "") {
|
|
195
307
|
rawScope.active = false;
|
|
@@ -200,7 +312,6 @@ function compileThoth(inputPath, isDev = false) {
|
|
|
200
312
|
}
|
|
201
313
|
}
|
|
202
314
|
|
|
203
|
-
// --- ุฎูุงุฑุฒู
ูุฉ ุชุญููู ุงููุตู ุงูุฐูู (Strict Parser) ---
|
|
204
315
|
let colonIdx = -1;
|
|
205
316
|
let inQuotes = false;
|
|
206
317
|
for (let j = 0; j < processedTrimmed.length; j++) {
|
|
@@ -213,7 +324,7 @@ function compileThoth(inputPath, isDev = false) {
|
|
|
213
324
|
|
|
214
325
|
const firstSpace = instr.indexOf(' ');
|
|
215
326
|
const tagName = firstSpace !== -1 ? instr.substring(0, firstSpace) : instr;
|
|
216
|
-
|
|
327
|
+
let attrs = firstSpace !== -1 ? instr.substring(firstSpace).trim() : "";
|
|
217
328
|
|
|
218
329
|
if (tagName === "StyleSheet" || tagName === "Scripting") {
|
|
219
330
|
rawScope.active = true;
|
|
@@ -223,74 +334,134 @@ function compileThoth(inputPath, isDev = false) {
|
|
|
223
334
|
continue;
|
|
224
335
|
}
|
|
225
336
|
|
|
226
|
-
//
|
|
337
|
+
// --- 8. Component Instantiation ---
|
|
338
|
+
if (componentsContext[tagName]) {
|
|
339
|
+
let props = {};
|
|
340
|
+
const propMatches = attrs.matchAll(/([a-zA-Z0-9_]+)="([^"]+)"/g);
|
|
341
|
+
for (const match of propMatches) { props[`@${match[1]}`] = match[2]; }
|
|
342
|
+
|
|
343
|
+
let compSource = "TYPE THOTH\n";
|
|
344
|
+
componentsContext[tagName].forEach(l => { compSource += ' '.repeat(indent) + l + '\n'; });
|
|
345
|
+
|
|
346
|
+
const subMergedVars = { ...variables, ...props };
|
|
347
|
+
const subRes = await compileThothEngine(compSource, inputPath, false, true, { dataContext, variables: subMergedVars, stateVars }, componentsContext, requestedRoute);
|
|
348
|
+
htmlContent += subRes.html;
|
|
349
|
+
continue;
|
|
350
|
+
}
|
|
351
|
+
|
|
227
352
|
while (stack.length > 0 && stack[stack.length - 1].indent >= indent) {
|
|
228
353
|
htmlContent += `</${stack.pop().name}>\n`;
|
|
229
354
|
}
|
|
230
355
|
|
|
231
356
|
const tag = TAG_MAP[tagName] || tagName.toLowerCase();
|
|
232
|
-
|
|
357
|
+
|
|
358
|
+
// --- 9. Layout Engine (Row & Column) ---
|
|
359
|
+
let injectedStyle = "";
|
|
360
|
+
if (tagName === 'Row') {
|
|
361
|
+
injectedStyle = "display:flex; flex-wrap:wrap;";
|
|
362
|
+
const gapMatch = attrs.match(/gap="([^"]+)"/);
|
|
363
|
+
if (gapMatch) injectedStyle += ` gap:${gapMatch[1]};`;
|
|
364
|
+
const alignMatch = attrs.match(/align="([^"]+)"/);
|
|
365
|
+
if (alignMatch) injectedStyle += ` align-items:${alignMatch[1]};`;
|
|
366
|
+
attrs = attrs.replace(/(gap|align)="[^"]+"/g, '');
|
|
367
|
+
} else if (tagName === 'Column') {
|
|
368
|
+
injectedStyle = "display:flex; flex-direction:column;";
|
|
369
|
+
const widthMatch = attrs.match(/width="([^"]+)"/);
|
|
370
|
+
if (widthMatch) injectedStyle += ` flex:0 0 ${widthMatch[1]}; max-width:${widthMatch[1]};`;
|
|
371
|
+
else injectedStyle += " flex:1;";
|
|
372
|
+
attrs = attrs.replace(/width="[^"]+"/g, '');
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
let cleanAttrs = attrs.replace(/Auth="[^"]+"/, '').trim();
|
|
376
|
+
cleanAttrs = injectStateBindings(cleanAttrs);
|
|
377
|
+
|
|
378
|
+
if (injectedStyle !== "") {
|
|
379
|
+
if (cleanAttrs.includes('style="')) cleanAttrs = cleanAttrs.replace(/style="([^"]*)"/, `style="$1 ${injectedStyle.trim()}"`);
|
|
380
|
+
else cleanAttrs += ` style="${injectedStyle.trim()}"`;
|
|
381
|
+
}
|
|
382
|
+
|
|
233
383
|
const open = `<${tag}${cleanAttrs ? ' ' + cleanAttrs : ''}>`;
|
|
234
384
|
|
|
235
385
|
if (VOID_ELEMENTS.includes(tag)) {
|
|
236
386
|
htmlContent += ' '.repeat(indent) + open + '\n';
|
|
237
387
|
} else if (val) {
|
|
238
|
-
|
|
388
|
+
const finalVal = injectStateText(val, stateVars);
|
|
389
|
+
htmlContent += ' '.repeat(indent) + `${open}${finalVal}</${tag}>\n`;
|
|
239
390
|
} else {
|
|
240
391
|
htmlContent += ' '.repeat(indent) + open + '\n';
|
|
241
392
|
stack.push({ name: tag, indent: indent });
|
|
242
393
|
}
|
|
243
394
|
}
|
|
244
395
|
|
|
245
|
-
|
|
396
|
+
if (componentScope.active) componentsContext[componentScope.name] = [...componentScope.buffer];
|
|
246
397
|
if (repeatScope.active) {
|
|
247
398
|
const list = dataContext[repeatScope.key] || [];
|
|
248
|
-
|
|
399
|
+
for (const item of list) {
|
|
400
|
+
const mergedContext = { dataContext: { ...dataContext, ...item }, variables, stateVars };
|
|
401
|
+
htmlContent += await processBuffer(repeatScope.buffer, mergedContext, componentsContext, inputPath, lines.length, requestedRoute);
|
|
402
|
+
}
|
|
249
403
|
}
|
|
250
404
|
|
|
251
405
|
while (stack.length > 0) htmlContent += `</${stack.pop().name}>\n`;
|
|
252
406
|
|
|
253
|
-
return
|
|
407
|
+
if (isSubCall) return { html: htmlContent, dataContext, stateVars };
|
|
408
|
+
return generateBoilerplate(htmlContent, dataContext, stateVars, isDev);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* ุฏุงูุฉ ุงูุชุบููู ุงูุนุงู
ุฉ
|
|
413
|
+
*/
|
|
414
|
+
async function compileThoth(inputPath, isDev = false, requestedRoute = '/') {
|
|
415
|
+
if (!fs.existsSync(inputPath)) throw new ThothSyntaxError(`Source Integrity Error: File not found.`, 0, "", inputPath);
|
|
416
|
+
const source = fs.readFileSync(inputPath, 'utf8');
|
|
417
|
+
const result = await compileThothEngine(source, inputPath, isDev, false, {}, {}, requestedRoute);
|
|
418
|
+
return result.html;
|
|
254
419
|
}
|
|
255
420
|
|
|
256
421
|
/**
|
|
257
422
|
* ู
ุนุงูุฌุฉ ุงูู Buffer ุฏุงุฎู ุงูู Loop
|
|
258
423
|
*/
|
|
259
|
-
function processBuffer(buffer,
|
|
260
|
-
let
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
let pLine = resolveData(l, item, variables);
|
|
265
|
-
const t = pLine.trim();
|
|
266
|
-
let cIdx = t.indexOf(':'); // Fast path for loops
|
|
267
|
-
let cmdStr = cIdx !== -1 ? t.substring(0, cIdx).trim() : t;
|
|
268
|
-
let valStr = cIdx !== -1 ? t.substring(cIdx + 1).trim() : "";
|
|
269
|
-
|
|
270
|
-
const space = cmdStr.indexOf(' ');
|
|
271
|
-
const tag = TAG_MAP[cmdStr.substring(0, space === -1 ? cmdStr.length : space)] || cmdStr.toLowerCase();
|
|
272
|
-
|
|
273
|
-
while (bStack.length > 0 && bStack[bStack.length - 1].indent >= ind) res += `</${bStack.pop().name}>\n`;
|
|
274
|
-
|
|
275
|
-
const op = `<${tag}${space !== -1 ? ' ' + cmdStr.substring(space).trim() : ''}>`;
|
|
276
|
-
if (VOID_ELEMENTS.includes(tag)) res += ' '.repeat(ind) + op + '\n';
|
|
277
|
-
else if (valStr) res += ' '.repeat(ind) + `${op}${valStr}</${tag}>\n`;
|
|
278
|
-
else { res += ' '.repeat(ind) + op + '\n'; bStack.push({ name: tag, indent: ind }); }
|
|
279
|
-
});
|
|
280
|
-
while (bStack.length > 0) res += `</${bStack.pop().name}>\n`;
|
|
281
|
-
return res;
|
|
424
|
+
async function processBuffer(buffer, scopeContext, componentsContext, filePath, baseLineNum, requestedRoute) {
|
|
425
|
+
let tempSource = "TYPE THOTH\n";
|
|
426
|
+
buffer.forEach(l => tempSource += l + "\n");
|
|
427
|
+
const res = await compileThothEngine(tempSource, filePath, false, true, scopeContext, componentsContext, requestedRoute);
|
|
428
|
+
return res.html;
|
|
282
429
|
}
|
|
283
430
|
|
|
284
431
|
/**
|
|
285
|
-
* ุชูููุฏ ูููู HTML5 ุงูู
ุนูุงุฑู
|
|
432
|
+
* ุชูููุฏ ูููู HTML5 ุงูู
ุนูุงุฑู
|
|
286
433
|
*/
|
|
287
|
-
function generateBoilerplate(content, isDev) {
|
|
434
|
+
function generateBoilerplate(content, dataContext, stateVars, isDev) {
|
|
288
435
|
const title = dataContext.site_title || "THOTH Sovereign Architecture";
|
|
289
436
|
const desc = dataContext.site_desc || "Engineered by Abdelfatah Abdelhamed";
|
|
437
|
+
const stateJson = JSON.stringify(stateVars);
|
|
290
438
|
|
|
439
|
+
const stateEngineScript = `
|
|
440
|
+
<script>
|
|
441
|
+
const thothState = {
|
|
442
|
+
data: ${stateJson},
|
|
443
|
+
dispatch: function(actionStr) {
|
|
444
|
+
if(actionStr.startsWith('set:')) {
|
|
445
|
+
let logic = actionStr.replace('set:', '').split('=');
|
|
446
|
+
let key = logic[0]; let expr = logic[1];
|
|
447
|
+
if(expr.includes('+1')) this.data[key] = parseInt(this.data[key]) + 1;
|
|
448
|
+
else if(expr.includes('-1')) this.data[key] = parseInt(this.data[key]) - 1;
|
|
449
|
+
else this.data[key] = expr;
|
|
450
|
+
this.render();
|
|
451
|
+
}
|
|
452
|
+
},
|
|
453
|
+
render: function() {
|
|
454
|
+
document.querySelectorAll('[data-thoth-state]').forEach(el => {
|
|
455
|
+
let key = el.getAttribute('data-thoth-state');
|
|
456
|
+
if(this.data[key] !== undefined) el.innerText = this.data[key];
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
};
|
|
460
|
+
</script>`;
|
|
461
|
+
|
|
291
462
|
const liveReload = isDev ? `
|
|
292
463
|
<script>
|
|
293
|
-
console.log('%c THOTH
|
|
464
|
+
console.log('%c THOTH CLOUD DEV MODE: ACTIVE ', 'background:#06b6d4;color:#000;font-weight:bold;');
|
|
294
465
|
let lastMod = null;
|
|
295
466
|
setInterval(async () => {
|
|
296
467
|
try {
|
|
@@ -302,26 +473,24 @@ function generateBoilerplate(content, isDev) {
|
|
|
302
473
|
}, 1500);
|
|
303
474
|
</script>` : "";
|
|
304
475
|
|
|
305
|
-
return `<!DOCTYPE html>
|
|
476
|
+
return { html: `<!DOCTYPE html>
|
|
306
477
|
<html lang="ar" dir="rtl">
|
|
307
478
|
<head>
|
|
308
479
|
<meta charset="UTF-8">
|
|
309
480
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
310
481
|
<meta name="description" content="${desc}">
|
|
311
|
-
<meta name="generator" content="THOTH Sovereign Engine
|
|
482
|
+
<meta name="generator" content="THOTH Sovereign Engine v12.0.0">
|
|
312
483
|
<meta name="author" content="Engineer Abdelfatah Abdelhamed">
|
|
313
484
|
<title>${title}</title>
|
|
314
485
|
</head>
|
|
315
|
-
<body style="margin:0; background:#020617; color:#f8fafc;">
|
|
486
|
+
<body style="margin:0; background:#020617; color:#f8fafc; font-family:sans-serif;">
|
|
316
487
|
${content}
|
|
488
|
+
${stateEngineScript}
|
|
317
489
|
${liveReload}
|
|
318
490
|
</body>
|
|
319
|
-
</html
|
|
491
|
+
</html>`};
|
|
320
492
|
}
|
|
321
493
|
|
|
322
|
-
/**
|
|
323
|
-
* ุฏุงูุฉ ุชูููุฏ ูุงุฌูุฉ ุชุชุจุน ุงูุฃุฎุทุงุก (Browser Overlay)
|
|
324
|
-
*/
|
|
325
494
|
function getBrowserTracebackHTML(e) {
|
|
326
495
|
if (e.name === 'ThothSyntaxError') {
|
|
327
496
|
const escapedContent = e.lineContent.replace(/</g, '<').replace(/>/g, '>');
|
|
@@ -353,12 +522,9 @@ function getBrowserTracebackHTML(e) {
|
|
|
353
522
|
</body>`;
|
|
354
523
|
}
|
|
355
524
|
|
|
356
|
-
/**
|
|
357
|
-
* ุทุจุงุนุฉ ุงูุฃุฎุทุงุก ูู ุงูุชูุฑู
ููุงู
|
|
358
|
-
*/
|
|
359
525
|
function printTerminalError(e) {
|
|
360
526
|
if (e.name === 'ThothSyntaxError') {
|
|
361
|
-
console.error('\x1b[31m%s\x1b[0m', `\nโ ๏ธ THOTH Traceback
|
|
527
|
+
console.error('\x1b[31m%s\x1b[0m', `\nโ ๏ธ THOTH Traceback:`);
|
|
362
528
|
console.error('\x1b[90m%s\x1b[0m', ` File "${e.filePath}", line ${e.lineNum}, in <module>`);
|
|
363
529
|
console.error(` ${e.lineContent}`);
|
|
364
530
|
console.error('\x1b[31m%s\x1b[0m', ` ^`);
|
|
@@ -370,14 +536,17 @@ function printTerminalError(e) {
|
|
|
370
536
|
|
|
371
537
|
// --- ุทุจูุฉ ุงูุชูููุฐ ---
|
|
372
538
|
if (command === 'serve') {
|
|
373
|
-
const server = http.createServer((req, res) => {
|
|
539
|
+
const server = http.createServer(async (req, res) => {
|
|
540
|
+
if (req.url === '/favicon.ico') { res.writeHead(204); return res.end(); }
|
|
541
|
+
|
|
374
542
|
try {
|
|
375
|
-
const
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
543
|
+
const parsedUrl = new URL(req.url, `http://localhost:${globalConfig.port}`);
|
|
544
|
+
const requestedRoute = parsedUrl.pathname;
|
|
545
|
+
|
|
546
|
+
// ุงุณุชุฎุฏุงู
await ุนุดุงู ุงูู
ุญุฑู ููุฏุฑ ูุฌูุจ ุจูุงูุงุช ุงูู API
|
|
547
|
+
const html = await compileThoth(target, true, requestedRoute);
|
|
548
|
+
|
|
549
|
+
res.writeHead(200, { 'Content-Type': 'text/html', 'Cache-Control': 'no-cache', 'ETag': Date.now().toString() });
|
|
381
550
|
res.end(html);
|
|
382
551
|
} catch (e) {
|
|
383
552
|
printTerminalError(e);
|
|
@@ -386,20 +555,25 @@ if (command === 'serve') {
|
|
|
386
555
|
}
|
|
387
556
|
});
|
|
388
557
|
|
|
389
|
-
server.listen(
|
|
558
|
+
server.listen(globalConfig.port, () => {
|
|
390
559
|
console.log('\x1b[36m%s\x1b[0m', `โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ`);
|
|
391
|
-
console.log(` โ SERVER ACTIVE: http://localhost:${
|
|
560
|
+
console.log(` โ SERVER ACTIVE: http://localhost:${globalConfig.port}`);
|
|
392
561
|
console.log(` โ ARCHITECTURE: ${target}`);
|
|
393
|
-
console.log(` โ MODE:
|
|
562
|
+
console.log(` โ MODE: The Sovereign Cloud v12.0.0`);
|
|
394
563
|
console.log('\x1b[36m%s\x1b[0m', `โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ`);
|
|
395
564
|
});
|
|
565
|
+
} else if (command === 'build') {
|
|
566
|
+
// ุงูุชูููุฐ ุบูุฑ ุงูู
ุชุฒุงู
ู ููุจูุงุก
|
|
567
|
+
(async () => {
|
|
568
|
+
try {
|
|
569
|
+
const out = await compileThoth(target, false);
|
|
570
|
+
fs.writeFileSync(target.replace('.thoth', '.html'), out);
|
|
571
|
+
console.log(`\x1b[32m [SUCCESS] Architecture materialized: ${target.replace('.thoth', '.html')}\x1b[0m`);
|
|
572
|
+
} catch (e) {
|
|
573
|
+
printTerminalError(e);
|
|
574
|
+
process.exit(1);
|
|
575
|
+
}
|
|
576
|
+
})();
|
|
396
577
|
} else {
|
|
397
|
-
|
|
398
|
-
const out = compileThoth(target, false);
|
|
399
|
-
fs.writeFileSync(target.replace('.thoth', '.html'), out);
|
|
400
|
-
console.log(`\x1b[32m [SUCCESS] Architecture materialized: ${target.replace('.thoth', '.html')}\x1b[0m`);
|
|
401
|
-
} catch (e) {
|
|
402
|
-
printTerminalError(e);
|
|
403
|
-
process.exit(1);
|
|
404
|
-
}
|
|
578
|
+
displayUsage();
|
|
405
579
|
}
|