thyscript 1.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.
Files changed (49) hide show
  1. package/bin/thy-node.js +332 -0
  2. package/bin/thy.js +828 -0
  3. package/bin/thys.js +25 -0
  4. package/examples/calculator.thy +274 -0
  5. package/examples/calculator.thy.js +628 -0
  6. package/examples/hello.thy +34 -0
  7. package/examples/login.thy +382 -0
  8. package/examples/login.thy.js +710 -0
  9. package/package.json +54 -0
  10. package/scripts/_class.js +18 -0
  11. package/scripts/_class2.js +11 -0
  12. package/scripts/_class3.js +21 -0
  13. package/scripts/_dstruct.js +20 -0
  14. package/scripts/_dstruct2.js +24 -0
  15. package/scripts/_scaffold.js +16 -0
  16. package/scripts/_scaffold2.js +16 -0
  17. package/scripts/_scaffold3.js +26 -0
  18. package/scripts/_tpl_compile.js +13 -0
  19. package/scripts/_tpl_test.js +9 -0
  20. package/scripts/_typeof.js +26 -0
  21. package/scripts/_typeof2.js +25 -0
  22. package/scripts/patch_genmethod.js +44 -0
  23. package/scripts/smoke_test.js +167 -0
  24. package/scripts/smoke_test2.js +151 -0
  25. package/scripts/test_control_panel.js +58 -0
  26. package/src/compiler/CodeGenerator.js +1449 -0
  27. package/src/compiler/JITCompiler.js +325 -0
  28. package/src/database/DatabaseEngine.js +931 -0
  29. package/src/errors/ErrorDetector.js +305 -0
  30. package/src/errors/ErrorMessages.js +497 -0
  31. package/src/index.js +169 -0
  32. package/src/lexer/Lexer.js +342 -0
  33. package/src/lexer/TokenTypes.js +1234 -0
  34. package/src/memory/MemoryManager.js +283 -0
  35. package/src/parser/AST.js +606 -0
  36. package/src/parser/Parser.js +1942 -0
  37. package/src/runtime/ThyRuntime.js +265 -0
  38. package/src/runtime/stdlib/ArrayLib.js +207 -0
  39. package/src/runtime/stdlib/FileLib.js +168 -0
  40. package/src/runtime/stdlib/MathLib.js +411 -0
  41. package/src/runtime/stdlib/StringLib.js +387 -0
  42. package/src/server/ControlPanel.js +1188 -0
  43. package/src/server/HTMLCSSEngine.js +866 -0
  44. package/src/server/SecurityEngine.js +714 -0
  45. package/src/server/ServerEngine.js +738 -0
  46. package/tests/test1_math.thy +82 -0
  47. package/tests/test2_oop.thy +133 -0
  48. package/tests/test3_server.thy +143 -0
  49. package/tests/test4_functions.thy +159 -0
@@ -0,0 +1,382 @@
1
+ // ═══════════════════════════════════════════════════════════════
2
+ // ThyScript Authentication & Login System
3
+ // Full-stack Auth with Hashing, JWT Tokens & Sessions
4
+ // ═══════════════════════════════════════════════════════════════
5
+
6
+ const table port = 3001
7
+ const table secretKey = "thyscript_super_secret_auth_key_2024"
8
+
9
+ // In-memory database of registered users
10
+ const table users = []
11
+ const table sessions = {}
12
+
13
+ // User Entity Class
14
+ public class(User):
15
+ const table id = ""
16
+ const table username = ""
17
+ const table email = ""
18
+ const table passwordHash = ""
19
+ const table role = "user"
20
+ const table createdAt = ""
21
+ end()
22
+
23
+ // Initialize Web Server
24
+ server(3001):
25
+ print("🔐 Starting ThyScript Auth Server on port 3001...")
26
+ end()
27
+
28
+ // Web UI Route
29
+ route get "/":
30
+ classHtml(login_page):
31
+ <!DOCTYPE html>
32
+ <html lang="id">
33
+ <head>
34
+ <meta charset="UTF-8">
35
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
36
+ <title>ThyScript Secure Auth</title>
37
+ <style>
38
+ * { margin: 0; padding: 0; box-sizing: border-box; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; }
39
+ body {
40
+ background: linear-gradient(135deg, #090919 0%, #151528 50%, #0d1b2a 100%);
41
+ min-height: 100vh;
42
+ display: flex;
43
+ align-items: center;
44
+ justify-content: center;
45
+ color: #fff;
46
+ padding: 20px;
47
+ }
48
+ .container {
49
+ width: 100%;
50
+ max-width: 420px;
51
+ }
52
+ .brand {
53
+ text-align: center;
54
+ margin-bottom: 24px;
55
+ }
56
+ .brand .logo {
57
+ font-size: 42px;
58
+ display: inline-block;
59
+ background: -webkit-linear-gradient(#6366f1, #a855f7);
60
+ -webkit-background-clip: text;
61
+ -webkit-text-fill-color: transparent;
62
+ font-weight: 900;
63
+ }
64
+ .brand p {
65
+ color: rgba(255, 255, 255, 0.5);
66
+ font-size: 14px;
67
+ margin-top: 4px;
68
+ }
69
+ .card {
70
+ background: rgba(255, 255, 255, 0.04);
71
+ backdrop-filter: blur(20px);
72
+ -webkit-backdrop-filter: blur(20px);
73
+ border: 1px solid rgba(255, 255, 255, 0.1);
74
+ border-radius: 24px;
75
+ padding: 32px;
76
+ box-shadow: 0 20px 40px rgba(0, 0, 0, 0.5);
77
+ }
78
+ .tabs {
79
+ display: flex;
80
+ background: rgba(0, 0, 0, 0.3);
81
+ padding: 4px;
82
+ border-radius: 14px;
83
+ margin-bottom: 24px;
84
+ }
85
+ .tab {
86
+ flex: 1;
87
+ padding: 10px;
88
+ border: none;
89
+ background: transparent;
90
+ color: rgba(255, 255, 255, 0.6);
91
+ font-size: 14px;
92
+ font-weight: 600;
93
+ border-radius: 10px;
94
+ cursor: pointer;
95
+ transition: all 0.2s ease;
96
+ }
97
+ .tab.active {
98
+ background: linear-gradient(135deg, #6366f1, #a855f7);
99
+ color: #fff;
100
+ box-shadow: 0 4px 15px rgba(99, 102, 241, 0.35);
101
+ }
102
+ .form-group {
103
+ margin-bottom: 18px;
104
+ }
105
+ label {
106
+ display: block;
107
+ font-size: 13px;
108
+ font-weight: 500;
109
+ margin-bottom: 8px;
110
+ color: rgba(255, 255, 255, 0.8);
111
+ }
112
+ input {
113
+ width: 100%;
114
+ background: rgba(255, 255, 255, 0.06);
115
+ border: 1px solid rgba(255, 255, 255, 0.12);
116
+ border-radius: 12px;
117
+ padding: 14px 16px;
118
+ font-size: 15px;
119
+ color: #fff;
120
+ outline: none;
121
+ transition: all 0.2s;
122
+ }
123
+ input:focus {
124
+ border-color: #818cf8;
125
+ background: rgba(255, 255, 255, 0.09);
126
+ box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.2);
127
+ }
128
+ .btn-submit {
129
+ width: 100%;
130
+ padding: 14px;
131
+ border: none;
132
+ border-radius: 12px;
133
+ background: linear-gradient(135deg, #6366f1, #a855f7);
134
+ color: white;
135
+ font-size: 16px;
136
+ font-weight: 600;
137
+ cursor: pointer;
138
+ margin-top: 10px;
139
+ transition: all 0.2s ease;
140
+ }
141
+ .btn-submit:hover { transform: translateY(-2px); filter: brightness(1.1); }
142
+ .btn-submit:active { transform: translateY(0); }
143
+ .alert {
144
+ padding: 12px 16px;
145
+ border-radius: 12px;
146
+ margin-top: 16px;
147
+ font-size: 14px;
148
+ display: none;
149
+ }
150
+ .alert-success { background: rgba(16, 185, 129, 0.2); border: 1px solid rgba(16, 185, 129, 0.4); color: #34d399; }
151
+ .alert-error { background: rgba(239, 68, 68, 0.2); border: 1px solid rgba(239, 68, 68, 0.4); color: #f87171; }
152
+
153
+ /* Dashboard view */
154
+ .dashboard {
155
+ display: none;
156
+ text-align: center;
157
+ }
158
+ .user-icon {
159
+ width: 80px;
160
+ height: 80px;
161
+ border-radius: 50%;
162
+ background: linear-gradient(135deg, #6366f1, #a855f7);
163
+ display: flex;
164
+ align-items: center;
165
+ justify-content: center;
166
+ font-size: 32px;
167
+ margin: 0 auto 16px;
168
+ color: white;
169
+ }
170
+ .token-box {
171
+ background: rgba(0, 0, 0, 0.4);
172
+ border: 1px solid rgba(255, 255, 255, 0.1);
173
+ border-radius: 12px;
174
+ padding: 14px;
175
+ font-size: 12px;
176
+ font-family: monospace;
177
+ word-break: break-all;
178
+ color: #a78bfa;
179
+ margin: 16px 0;
180
+ text-align: left;
181
+ }
182
+ .btn-logout {
183
+ padding: 10px 24px;
184
+ border-radius: 12px;
185
+ border: 1px solid rgba(239, 68, 68, 0.4);
186
+ background: rgba(239, 68, 68, 0.15);
187
+ color: #fca5a5;
188
+ cursor: pointer;
189
+ font-weight: 600;
190
+ }
191
+ </style>
192
+ </head>
193
+ <body>
194
+ <div class="container">
195
+ <div class="brand">
196
+ <div class="logo">⚡ ThyScript Auth</div>
197
+ <p>High-Security Authentication System</p>
198
+ </div>
199
+
200
+ <div class="card" id="authBox">
201
+ <div class="tabs">
202
+ <button class="tab active" onclick="switchTab('login')">Masuk</button>
203
+ <button class="tab" onclick="switchTab('register')">Daftar</button>
204
+ </div>
205
+
206
+ <div id="loginForm">
207
+ <div class="form-group">
208
+ <label>Username</label>
209
+ <input type="text" id="logUser" placeholder="Masukkan username">
210
+ </div>
211
+ <div class="form-group">
212
+ <label>Password</label>
213
+ <input type="password" id="logPass" placeholder="Masukkan password">
214
+ </div>
215
+ <button class="btn-submit" onclick="doLogin()">🔑 Masuk Sekarang</button>
216
+ </div>
217
+
218
+ <div id="registerForm" style="display:none">
219
+ <div class="form-group">
220
+ <label>Username</label>
221
+ <input type="text" id="regUser" placeholder="Pilih username unik">
222
+ </div>
223
+ <div class="form-group">
224
+ <label>Email</label>
225
+ <input type="email" id="regEmail" placeholder="nama@domain.com">
226
+ </div>
227
+ <div class="form-group">
228
+ <label>Password</label>
229
+ <input type="password" id="regPass" placeholder="Minimal 6 karakter">
230
+ </div>
231
+ <button class="btn-submit" onclick="doRegister()">✨ Buat Akun Baru</button>
232
+ </div>
233
+
234
+ <div id="alertBox" class="alert"></div>
235
+ </div>
236
+
237
+ <div class="card dashboard" id="dashBox">
238
+ <div class="user-icon" id="userInitial">U</div>
239
+ <h2 id="userNameText">Selamat Datang!</h2>
240
+ <p id="userEmailText" style="color: rgba(255,255,255,0.6); margin-top: 4px;"></p>
241
+ <div class="token-box">
242
+ <div style="color: rgba(255,255,255,0.4); margin-bottom: 4px;">ACTIVE AUTH TOKEN (JWT):</div>
243
+ <span id="tokenText"></span>
244
+ </div>
245
+ <button class="btn-logout" onclick="doLogout()">🚪 Keluar</button>
246
+ </div>
247
+ </div>
248
+
249
+ <script>
250
+ function switchTab(t) {
251
+ document.querySelectorAll('.tab').forEach((el, idx) => {
252
+ el.classList.toggle('active', (t === 'login' && idx === 0) || (t === 'register' && idx === 1));
253
+ });
254
+ document.getElementById('loginForm').style.display = t === 'login' ? 'block' : 'none';
255
+ document.getElementById('registerForm').style.display = t === 'register' ? 'block' : 'none';
256
+ hideAlert();
257
+ }
258
+
259
+ function showAlert(msg, isError) {
260
+ const b = document.getElementById('alertBox');
261
+ b.className = 'alert ' + (isError ? 'alert-error' : 'alert-success');
262
+ b.innerText = msg;
263
+ b.style.display = 'block';
264
+ }
265
+
266
+ function hideAlert() {
267
+ document.getElementById('alertBox').style.display = 'none';
268
+ }
269
+
270
+ async function doRegister() {
271
+ const username = document.getElementById('regUser').value.trim();
272
+ const email = document.getElementById('regEmail').value.trim();
273
+ const password = document.getElementById('regPass').value;
274
+
275
+ if (!username || !email || !password) return showAlert('Semua bidang harus diisi!', true);
276
+
277
+ const res = await fetch('/api/register', {
278
+ method: 'POST',
279
+ headers: { 'Content-Type': 'application/json' },
280
+ body: JSON.stringify({ username, email, password })
281
+ });
282
+ const data = await res.json();
283
+ if (data.success) {
284
+ showAlert('Pendaftaran sukses! Silakan masuk.', false);
285
+ switchTab('login');
286
+ } else {
287
+ showAlert(data.message || 'Registrasi gagal', true);
288
+ }
289
+ }
290
+
291
+ async function doLogin() {
292
+ const username = document.getElementById('logUser').value.trim();
293
+ const password = document.getElementById('logPass').value;
294
+
295
+ if (!username || !password) return showAlert('Masukkan username dan password!', true);
296
+
297
+ const res = await fetch('/api/login', {
298
+ method: 'POST',
299
+ headers: { 'Content-Type': 'application/json' },
300
+ body: JSON.stringify({ username, password })
301
+ });
302
+ const data = await res.json();
303
+ if (data.success) {
304
+ document.getElementById('authBox').style.display = 'none';
305
+ document.getElementById('dashBox').style.display = 'block';
306
+ document.getElementById('userNameText').innerText = 'Halo, ' + data.user.username + '!';
307
+ document.getElementById('userEmailText').innerText = data.user.email;
308
+ document.getElementById('userInitial').innerText = data.user.username[0].toUpperCase();
309
+ document.getElementById('tokenText').innerText = data.token;
310
+ } else {
311
+ showAlert(data.message || 'Username atau password salah', true);
312
+ }
313
+ }
314
+
315
+ function doLogout() {
316
+ document.getElementById('dashBox').style.display = 'none';
317
+ document.getElementById('authBox').style.display = 'block';
318
+ document.getElementById('logPass').value = '';
319
+ hideAlert();
320
+ }
321
+ </script>
322
+ </body>
323
+ </html>
324
+ end()
325
+ end()
326
+
327
+ // API Registration
328
+ route post "/api/register":
329
+ const table username = request.body.username
330
+ const table email = request.body.email
331
+ const table password = request.body.password
332
+
333
+ if(not username or not email or not password):
334
+ response.json({ success: false, message: "Field tidak boleh kosong" })
335
+ end()
336
+
337
+ // Check if user exists
338
+ const table found = users.find(u => u.username == username)
339
+ if(found):
340
+ response.json({ success: false, message: "Username sudah terdaftar" })
341
+ else:
342
+ // Hash password with built-in security
343
+ const table hash = security.hashPassword ? await security.hashPassword(password) : security.hash(password)
344
+ const table newUser = {
345
+ id: String(Date.now()),
346
+ username: username,
347
+ email: email,
348
+ passwordHash: hash,
349
+ role: "user",
350
+ createdAt: new Date().toISOString()
351
+ }
352
+ add newUser in users
353
+ print("👤 New user registered: " + username)
354
+ response.json({ success: true, message: "User registered successfully" })
355
+ end()
356
+ end()
357
+
358
+ // API Login
359
+ route post "/api/login":
360
+ const table username = request.body.username
361
+ const table password = request.body.password
362
+
363
+ const table user = users.find(u => u.username == username)
364
+ if(not user):
365
+ response.json({ success: false, message: "User tidak ditemukan" })
366
+ else:
367
+ const table isValid = security.verifyPassword ? await security.verifyPassword(password, user.passwordHash) : (security.hash(password) == user.passwordHash)
368
+ if(not isValid):
369
+ response.json({ success: false, message: "Password salah" })
370
+ else:
371
+ const table token = security.generateToken ? security.generateToken({ username: user.username, email: user.email }, secretKey) : security.hash(user.username + secretKey)
372
+ print("🔑 User logged in: " + username)
373
+ response.json({
374
+ success: true,
375
+ token: token,
376
+ user: { username: user.username, email: user.email, role: user.role }
377
+ })
378
+ end()
379
+ end()
380
+ end()
381
+
382
+ print("🚀 ThyScript Login Server ready on port " + port)