@xnoxs/flux-lang 3.2.0 → 3.2.1

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 CHANGED
@@ -1,74 +1,164 @@
1
- # Flux Lang v3.1.1 — TypeScript Parity Edition
1
+ # Flux Lang v3.2.0
2
2
 
3
- **Flux** adalah bahasa pemrograman modern yang di-transpile ke JavaScript — menggabungkan sintaks bersih ala Python (indentasi berbasis blok), tipe statis ala TypeScript, dan ekspresi kuat ala Rust/Haskell.
3
+ **Flux** is a modern programming language that transpiles to clean JavaScript — combining Python-style indentation, TypeScript-grade type safety, Rust-inspired pattern matching, and a rich standard library all with **zero runtime overhead**.
4
4
 
5
5
  ```
6
- source.flux → [Lexer → Parser → TypeChecker → CodeGen] → output.js
6
+ source.flux → [CSS Pre → JSX Pre → Lexer → Parser → TypeChecker → CodeGen] → output.js
7
7
  ```
8
8
 
9
+ Every Flux file compiles to plain `.js` — no virtual machine, no custom runtime. You get the full JavaScript ecosystem for free.
10
+
9
11
  ---
10
12
 
11
- ## Instalasi & Penggunaan
13
+ ## Installation
12
14
 
13
15
  ```bash
14
- # Jalankan langsung
15
- node bin/flux.js run app.flux
16
+ # Install globally
17
+ npm install -g @xnoxs/flux-lang
16
18
 
17
- # Compile ke JS
18
- node bin/flux.js compile app.flux -o dist/app.js
19
+ # Or locally in a project
20
+ npm install --save-dev @xnoxs/flux-lang
21
+ ```
19
22
 
20
- # Type check (temukan kesalahan tipe sebelum runtime)
21
- node bin/flux.js check app.flux
23
+ **Node.js API** use `require('@xnoxs/flux-lang')` (or `require('@xnoxs/flux-lang/src/transpiler')`) to transpile Flux programmatically:
22
24
 
23
- # Format kode
24
- node bin/flux.js fmt app.flux
25
+ ```js
26
+ const { transpile } = require('@xnoxs/flux-lang');
27
+ const result = transpile('val x = 42\nprint(x)', {});
28
+ console.log(result.output);
29
+ ```
25
30
 
26
- # Jalankan semua test
27
- node bin/flux.js test tests/
31
+ ---
28
32
 
29
- # REPL interaktif
30
- node bin/flux.js repl
33
+ ## CLI Reference
34
+
35
+ | Command | Description |
36
+ |---|---|
37
+ | `flux run file.flux` | Compile and immediately execute |
38
+ | `flux compile file.flux` | Compile to JavaScript |
39
+ | `flux compile file.flux -o out.js` | Compile to specific output file |
40
+ | `flux bundle main.flux -o bundle.js` | Bundle all imports into one file |
41
+ | `flux watch file.flux` | Watch for changes and auto-compile |
42
+ | `flux check file.flux` | Type check + static analysis |
43
+ | `flux lint file.flux` | Lint — unused vars, unreachable code, shadowing |
44
+ | `flux fmt file.flux` | Format source code |
45
+ | `flux test [dir]` | Find and run all `*.test.flux` files |
46
+ | `flux tokens file.flux` | Show lexer token stream |
47
+ | `flux ast file.flux` | Show AST as JSON |
48
+ | `flux repl` | Interactive REPL |
49
+ | `flux version` | Show version |
50
+ | `flux init [name]` | Create new Flux project |
51
+
52
+ ### Flags
31
53
 
32
- # Bundle beberapa file
33
- node bin/flux.js bundle main.flux -o bundle.js
54
+ ```
55
+ --out, -o <file> Output file
56
+ --sourcemap, -m Generate source map (.js.map)
57
+ --stdout Print output to terminal
58
+ --no-color Disable color output
34
59
  ```
35
60
 
36
61
  ---
37
62
 
38
- ## Sintaks Dasar
63
+ ## Quick Start
64
+
65
+ ```flux
66
+ // Immutable and mutable variables
67
+ val name = "Flux"
68
+ var count = 0
69
+
70
+ // Typed function
71
+ fn greet(who: String) -> String:
72
+ return "Hello, {who}!"
73
+
74
+ print(greet(name)) // Hello, Flux!
75
+
76
+ // Arrays + pipe operator
77
+ val result = [1, 2, 3, 4, 5]
78
+ |> filter(n -> n % 2 == 0)
79
+ |> map(n -> n * n)
80
+ |> sum // 20
39
81
 
40
- ### Variabel
82
+ // Algebraic Data Types + pattern matching
83
+ type Result = Ok(value) | Err(message)
84
+
85
+ fn divide(a, b):
86
+ if b == 0: return Err("division by zero")
87
+ return Ok(a / b)
88
+
89
+ match divide(10, 2):
90
+ when Ok(v) -> print("Result: {v}")
91
+ when Err(e) -> print("Error: {e}")
92
+ ```
93
+
94
+ ---
95
+
96
+ ## Variables & Data Types
41
97
 
42
98
  ```flux
43
99
  val x = 42 // immutable (const)
44
100
  var count = 0 // mutable (let)
45
101
 
46
- // Dengan type annotation
102
+ // With type annotation
47
103
  val name: String = "Flux"
48
- val age: Int = 3
49
- val score: Float = 9.5
50
- val active: Bool = true
51
- val nothing: Null = null
104
+ val age: Int = 3
105
+ val pi: Float = 3.14159
106
+ val on: Bool = true
52
107
 
53
- // Tanpa annotation type diinfer otomatis
54
- val items = [1, 2, 3] // infer: Array<Int>
55
- val greeting = "Hello" // infer: String
108
+ // Type is inferred automatically when omitted
109
+ val items = [1, 2, 3] // inferred: Array<Int>
110
+ val greeting = "Hello" // inferred: String
56
111
  ```
57
112
 
58
- ### Print & Template Strings
113
+ ### Primitive Types
114
+
115
+ | Type | Description | Example |
116
+ |---|---|---|
117
+ | `String` | Text | `"Hello"`, `'World'` |
118
+ | `Int` | Integer | `42`, `-7` |
119
+ | `Float` | Decimal | `3.14`, `-0.5` |
120
+ | `Number` | Int or Float | `100`, `3.14` |
121
+ | `Bool` | True or false | `true`, `false` |
122
+ | `Null` | Null value | `null` |
123
+ | `Void` | No return value | empty return |
124
+ | `Never` | Never completes | throw / infinite loop |
125
+ | `Any` | Skip type check | all types |
126
+ | `Unknown` | Needs narrowing first | — |
127
+
128
+ ---
129
+
130
+ ## Strings & Regex
131
+
132
+ Flux has four string literal types:
59
133
 
60
134
  ```flux
61
- print("Hello, World!")
62
- print("Dua ditambah dua: {2 + 2}")
63
- print("Pi: {3.14159:.2f}") // format spec
64
- print("Besar: {n:,}") // separator ribuan
65
- print("Persen: {rate:.1%}") // format persen
135
+ // Double-quoted — interpolation + format specs
136
+ val n = 3.14159
137
+ print("Pi is {n:.2f}") // Pi is 3.14
138
+ print("Big: {5000000:,}") // Big: 5,000,000
139
+ print("Rate: {0.1573:.1%}") // Rate: 15.7%
140
+
141
+ // Single-quoted — no interpolation (safe for CSS/HTML)
142
+ val css = 'color: #38bdf8'
143
+
144
+ // Backtick — multiline, no interpolation
145
+ val html = `
146
+ <div class="card">
147
+ <h2>Hello</h2>
148
+ </div>
149
+ `
150
+
151
+ // Regex literals
152
+ val emailPattern = /^[a-z]+@[a-z]+\.[a-z]+$/i
153
+ val isEmail = emailPattern.test("user@example.com") // true
66
154
  ```
67
155
 
68
- ### Operator
156
+ ---
157
+
158
+ ## Operators
69
159
 
70
160
  ```flux
71
- // Aritmatika
161
+ // Arithmetic
72
162
  val a = 10 + 3 // 13
73
163
  val b = 10 - 3 // 7
74
164
  val c = 10 * 3 // 30
@@ -76,12 +166,12 @@ val d = 10 / 3 // 3.333...
76
166
  val e = 10 % 3 // 1
77
167
  val f = 2 ** 10 // 1024
78
168
 
79
- // Perbandingan
169
+ // Comparison
80
170
  val eq = a == b // false
81
171
  val neq = a != b // true
82
172
  val lt = a < b // false
83
173
 
84
- // Logika
174
+ // Logical
85
175
  val and_ = true && false // false
86
176
  val or_ = true || false // true
87
177
  val not_ = !true // false
@@ -91,16 +181,32 @@ val result = maybeNull ?? "default"
91
181
 
92
182
  // Optional chaining
93
183
  val len = user?.name?.length
184
+
185
+ // Range (exclusive)
186
+ for i in 0..10: print(i) // 0 to 9
187
+
188
+ // Pipe operator
189
+ val total = nums |> filter(n -> n > 0) |> sum
190
+
191
+ // Spread
192
+ val merged = { ...defaults, ...overrides }
193
+
194
+ // Non-null assertion
195
+ val upper = value!.toUpperCase()
196
+
197
+ // Cast and satisfies
198
+ val n = expr as Int
199
+ val config = obj satisfies Config
94
200
  ```
95
201
 
96
202
  ---
97
203
 
98
- ## Fungsi
204
+ ## Functions
99
205
 
100
- ### Deklarasi Dasar
206
+ ### Block & Inline
101
207
 
102
208
  ```flux
103
- // Inline (satu baris)
209
+ // Inline single expression
104
210
  fn double(x) -> x * 2
105
211
  fn add(a, b) -> a + b
106
212
  fn greet(name) -> "Hello, {name}!"
@@ -114,134 +220,167 @@ fn factorial(n):
114
220
  ### Type Annotations
115
221
 
116
222
  ```flux
117
- // Parameter dan return type
118
223
  fn greet(name: String) -> String:
119
224
  return "Hello, {name}!"
120
225
 
121
- fn add(a: Int, b: Int) -> Int:
122
- return a + b
123
-
124
226
  fn area(w: Float, h: Float) -> Float:
125
227
  return w * h
126
228
 
127
- // Parameter opsional
229
+ // Optional param (caller may omit it)
128
230
  fn greetUser(name: String, title?: String) -> String:
129
231
  val prefix = title ?? ""
130
- if prefix != "":
131
- return "{prefix} {name}"
232
+ if prefix != "": return "{prefix} {name}"
132
233
  return name
133
- ```
134
-
135
- ### Sintaks Return Type
136
-
137
- Gunakan `-> ReturnType:` sebelum badan blok fungsi:
138
-
139
- ```flux
140
- // Blok body dengan return type annotation
141
- fn multiply(a: Int, b: Int) -> Int:
142
- return a * b
143
234
 
144
- // Inline body (tanpa return type — diinfer otomatis)
145
- fn square(x) -> x * x
146
-
147
- // Nullable return type
148
- fn findUser(id: Int) -> String?:
149
- if id > 0: return "user_{id}"
150
- return null
151
- ```
152
-
153
- ### Tipe Return Khusus
154
-
155
- ```flux
156
- // Void — tidak mengembalikan nilai
235
+ // Void / Never
157
236
  fn logMessage(msg: String) -> Void:
158
237
  print(msg)
159
238
 
160
- // Never — selalu melempar error (tidak pernah selesai)
161
239
  fn crash(msg: String) -> Never:
162
240
  throw new Error(msg)
163
241
  ```
164
242
 
165
- ### Parameter Rest & Default
243
+ ### Default & Rest Parameters
166
244
 
167
245
  ```flux
168
- // Rest parameter
169
- fn sum(...nums):
170
- return nums.reduce((acc, x) -> acc + x, 0)
171
-
172
- // Default value
173
246
  fn repeat(str: String, times: Int = 3) -> String:
174
247
  return str.repeat(times)
248
+
249
+ fn sum(...nums):
250
+ return nums.reduce((acc, x) -> acc + x, 0)
175
251
  ```
176
252
 
177
- ### Fungsi Async
253
+ ### Async Functions
178
254
 
179
255
  ```flux
180
256
  async fn fetchData(url: String) -> String:
181
- val res = await fetch(url)
182
- return await res.text()
257
+ val res = await fetch(url)
258
+ val text = await res.text()
259
+ return text
183
260
 
184
261
  async fn main():
185
- val data = await fetchData("https://api.example.com")
262
+ val data = await fetchData("https://api.example.com/data")
186
263
  print(data)
187
264
  ```
188
265
 
189
- ### Higher-Order Functions & Lambda
266
+ ### Lambda & Higher-Order
190
267
 
191
268
  ```flux
192
- // Lambda ekspresi
193
269
  val square = x -> x * x
194
- val add = (a, b) -> a + b
270
+ val add = (a, b) -> a + b
271
+
272
+ // Multi-statement lambda
273
+ val process = x -> {
274
+ val doubled = x * 2
275
+ return doubled + 1
276
+ }
195
277
 
196
- // Fungsi sebagai argumen
278
+ // Functions as arguments
197
279
  val doubled = [1, 2, 3].map(x -> x * 2) // [2, 4, 6]
198
- val evens = [1, 2, 3, 4, 5].filter(x -> x % 2 == 0) // [2, 4]
199
- val total = [1, 2, 3, 4].reduce((acc, x) -> acc + x, 0) // 10
280
+ val evens = [1..10].filter(x -> x % 2 == 0) // [2, 4, 6, 8, 10]
200
281
 
201
- // Pipe operator — rantai transformasi
282
+ // Pipe operator — chain transformations
202
283
  val result = [1, 2, 3, 4, 5]
203
284
  |> filter(x -> x > 2)
204
285
  |> map(x -> x * 10)
205
- |> sum
286
+ |> sum // 120
206
287
  ```
207
288
 
208
289
  ---
209
290
 
210
- ## Tipe Data (Type System)
291
+ ## Control Flow
211
292
 
212
- Flux v3.0.0 memiliki sistem tipe yang diperiksa saat kompilasi (`flux check`). Tipe dihapus pada output JavaScript — sama seperti TypeScript.
293
+ ### If / Elif / Else
213
294
 
214
- ### Tipe Primitif
295
+ ```flux
296
+ if x > 0:
297
+ print("positive")
298
+ elif x < 0:
299
+ print("negative")
300
+ else:
301
+ print("zero")
215
302
 
216
- | Tipe | Deskripsi | Contoh |
217
- |-----------|------------------------------|-----------------------|
218
- | `String` | Teks | `"Hello"`, `'World'` |
219
- | `Int` | Bilangan bulat | `42`, `-7` |
220
- | `Float` | Bilangan desimal | `3.14`, `-0.5` |
221
- | `Number` | Int atau Float | `100`, `3.14` |
222
- | `Bool` | Benar atau salah | `true`, `false` |
223
- | `Null` | Nilai null | `null` |
224
- | `Void` | Tidak mengembalikan nilai | return kosong |
225
- | `Never` | Tidak pernah selesai | throw / infinite loop |
226
- | `Any` | Lewati type check | semua tipe |
227
- | `Unknown` | Perlu narrowing dulu | — |
303
+ // Ternary
304
+ val label = x > 0 ? "positive" : "non-positive"
305
+ ```
228
306
 
229
- ### Union Types
307
+ ### For / While / Do-While
230
308
 
231
309
  ```flux
232
- val id: Int | String = 42 // Int atau String
233
- val value: Int | String = "hello" // juga valid
310
+ // Iterate array
311
+ for item in items:
312
+ print(item)
234
313
 
235
- fn stringify(x: Int | String | Bool) -> String:
236
- return "{x}"
314
+ // Range
315
+ for i in 0..10:
316
+ print(i) // 0 to 9
317
+
318
+ // for..of — any JS iterable
319
+ for char of "hello":
320
+ print(char)
321
+
322
+ // For with array destructuring
323
+ for [i, v] in enumerate(items):
324
+ print("{i}: {v}")
325
+
326
+ // Labeled break / continue
327
+ outer: for i in 0..5:
328
+ for j in 0..5:
329
+ if j == 2: break outer
330
+
331
+ // While
332
+ var n = 10
333
+ while n > 0:
334
+ print(n)
335
+ n -= 1
336
+
337
+ // Do-while
338
+ do:
339
+ print("runs at least once")
340
+ while false
237
341
  ```
238
342
 
239
- ### Nullable Types
343
+ ### Match (Pattern Matching)
240
344
 
241
345
  ```flux
242
- // String? adalah singkatan dari String | Null
243
- val name: String? = null
244
- val other: String? = "Flux"
346
+ // Literal
347
+ match value:
348
+ when 0 -> print("zero")
349
+ when 1..9 -> print("one digit")
350
+ when 10..99 -> print("two digits")
351
+ when _ -> print("other")
352
+
353
+ // Guards
354
+ match score:
355
+ when s if s >= 90 -> print("A")
356
+ when s if s >= 80 -> print("B")
357
+ when s if s >= 70 -> print("C")
358
+ when _ -> print("D")
359
+
360
+ // ADT destructuring
361
+ match result:
362
+ when Ok(v) -> print("Result: {v}")
363
+ when Err(e) -> print("Error: {e}")
364
+
365
+ // As expression
366
+ val label = match status:
367
+ when "active" -> "Online"
368
+ when "inactive" -> "Offline"
369
+ when _ -> "Unknown"
370
+ ```
371
+
372
+ ---
373
+
374
+ ## Type System
375
+
376
+ ### Union & Nullable
377
+
378
+ ```flux
379
+ val id: Int | String = 42 // Int or String
380
+ val name: String? = null // String | Null shorthand
381
+
382
+ fn stringify(x: Int | String | Bool) -> String:
383
+ return "{x}"
245
384
 
246
385
  fn findById(id: Int) -> String?:
247
386
  if id > 0: return "item_{id}"
@@ -252,18 +391,115 @@ fn findById(id: Int) -> String?:
252
391
 
253
392
  ```flux
254
393
  val names: Array<String> = ["Andi", "Budi", "Cici"]
255
- val nums: Array<Int> = [1, 2, 3, 4, 5]
394
+ val map: Map<String, Int> = new Map()
256
395
 
257
- fn first(items: Array<String>) -> String?:
396
+ fn first<T>(items: Array<T>) -> T?:
258
397
  if items.length == 0: return null
259
398
  return items[0]
260
399
  ```
261
400
 
401
+ ### Function Types
402
+
403
+ ```flux
404
+ fn mapInts(arr: Array<Int>, f: fn(Int) -> Int) -> Array<Int>:
405
+ return arr.map(f)
406
+
407
+ // In an interface
408
+ interface Handler:
409
+ fn handle(req: String) -> String
410
+ ```
411
+
412
+ ### Inline Object Types & Tuples
413
+
414
+ ```flux
415
+ fn makePoint(x: Float, y: Float) -> { x: Float, y: Float }:
416
+ return { x, y }
417
+
418
+ fn getCoord() -> [Float, Float]:
419
+ return [3.14, 2.71]
420
+
421
+ val [lat, lng] = getCoord()
422
+ ```
423
+
424
+ ### Intersection Types
425
+
426
+ ```flux
427
+ interface Named: name: String
428
+ interface Aged: age: Int
429
+
430
+ class Person implements Named, Aged:
431
+ name: String
432
+ age: Int
433
+
434
+ // Type alias intersection
435
+ type Entity = Named & { id: Int }
436
+ ```
437
+
438
+ ### Conditional Types
439
+
440
+ ```flux
441
+ // T extends U ? A : B
442
+ type IsString<T> = T extends String ? "yes" : "no"
443
+
444
+ // infer — extract a type from inside another
445
+ type Unwrap<T> = T extends Array<infer U> ? U : T
446
+ ```
447
+
448
+ ### Type Narrowing
449
+
450
+ ```flux
451
+ val user = getUser(1) // String?
452
+
453
+ if user != null:
454
+ print(user.toUpperCase()) // narrowed to String here
455
+
456
+ // typeof narrowing
457
+ fn process(x: Int | String | Bool) -> String:
458
+ if typeof x == "number": return "num: {x}"
459
+ if typeof x == "string": return "str: {x}"
460
+ return "bool: {x}"
461
+ ```
462
+
463
+ ### Utility Types
464
+
465
+ ```flux
466
+ Partial<T> // all fields optional
467
+ Required<T> // all fields required
468
+ Readonly<T> // all fields read-only
469
+ Record<K, V> // dictionary type
470
+ Pick<T, K> // keep only specified keys
471
+ Omit<T, K> // remove specified keys
472
+ NonNullable<T> // remove null from union
473
+ ReturnType<T> // extract return type of fn
474
+ Awaited<T> // unwrap Promise<T>
475
+ Parameters<T> // parameter types as tuple
476
+ Exclude<T, U> // remove U from T
477
+ Extract<T, U> // keep only U in T
478
+ ```
479
+
480
+ ### Index Signatures
481
+
482
+ ```flux
483
+ fn buildRegistry() -> { [key: String]: String }:
484
+ return { name: "Flux", version: "3.2.0" }
485
+ ```
486
+
487
+ ### `keyof` & `typeof`
488
+
489
+ ```flux
490
+ fn getField(key: keyof Config) -> String:
491
+ return key
492
+
493
+ val config = new Config("host", "localhost")
494
+ fn cloneConfig(src: typeof config) -> typeof config:
495
+ return new Config(src.key, src.value)
496
+ ```
497
+
262
498
  ---
263
499
 
264
- ## Interface
500
+ ## Interfaces
265
501
 
266
- Interface mendefinisikan kontrak yang harus dipenuhi class. `flux check` melaporkan **error** jika ada anggota yang tidak diimplementasi.
502
+ Interfaces define structural contracts. `flux check` reports an **error** if a required member is missing.
267
503
 
268
504
  ```flux
269
505
  interface Printable:
@@ -271,56 +507,44 @@ interface Printable:
271
507
 
272
508
  interface Shape:
273
509
  name: String
274
- fn area() -> Float
510
+ fn area() -> Float
275
511
  fn perimeter() -> Float
276
512
 
277
- // Interface dengan inheritance
513
+ // Inheritance
278
514
  interface ColoredShape extends Shape:
279
515
  color: String
280
516
  fn setColor(c: String) -> Void
281
517
 
282
- // Generic interface
518
+ // Generic
283
519
  interface Container<T>:
284
- fn get() -> T
285
- fn set(value: T) -> Void
520
+ fn get() -> T
521
+ fn set(v: T) -> Void
522
+ fn isEmpty() -> Bool
286
523
  ```
287
524
 
288
- ### Class Mengimplementasi Interface
525
+ ### Class Implementing Interface
289
526
 
290
527
  ```flux
291
528
  class Rectangle implements Shape:
292
- name: String
293
- width: Float
529
+ name: String
530
+ width: Float
294
531
  height: Float
295
532
 
296
- fn area() -> Float:
297
- return self.width * self.height
298
-
299
- fn perimeter() -> Float:
300
- return 2.0 * (self.width + self.height)
301
-
302
- class Circle implements Shape:
303
- name: String
304
- radius: Float
533
+ fn area() -> Float -> self.width * self.height
534
+ fn perimeter() -> Float -> 2.0 * (self.width + self.height)
305
535
 
306
- fn area() -> Float:
307
- return 3.14159 * self.radius * self.radius
308
-
309
- fn perimeter() -> Float:
310
- return 2.0 * 3.14159 * self.radius
311
-
312
- val r = new Rectangle("Persegi", 5.0, 3.0)
536
+ val r = new Rectangle("rect", 5.0, 3.0)
313
537
  print(r.area()) // 15
314
538
  print(r.perimeter()) // 16
315
539
  ```
316
540
 
317
541
  ---
318
542
 
319
- ## Class
543
+ ## Classes
320
544
 
321
545
  ```flux
322
546
  class Animal:
323
- name: String
547
+ name: String
324
548
  sound: String
325
549
 
326
550
  fn speak() -> String:
@@ -342,8 +566,9 @@ print(dog.info()) // Dog: Rex (Labrador)
342
566
 
343
567
  ```flux
344
568
  class BankAccount:
345
- private balance: Float
346
- readonly owner: String
569
+ private balance: Float
570
+ readonly id: String
571
+ public owner: String
347
572
 
348
573
  fn deposit(amount: Float) -> Void:
349
574
  self.balance += amount
@@ -352,35 +577,130 @@ class BankAccount:
352
577
  return self.balance
353
578
  ```
354
579
 
580
+ > **Private fields** compile to JavaScript `#field` syntax — enforced at the JS engine level, not just TypeScript-style erased annotations.
581
+
582
+ ### Static Methods & Properties
583
+
584
+ ```flux
585
+ class MathUtils:
586
+ static val PI = 3.14159
587
+
588
+ static fn circle(r: Float) -> Float:
589
+ return MathUtils.PI * r * r
590
+ ```
591
+
592
+ ### Getter / Setter
593
+
594
+ ```flux
595
+ class Temperature:
596
+ private celsius: Float
597
+
598
+ get fahrenheit() -> Float:
599
+ return self.celsius * 9.0 / 5.0 + 32.0
600
+
601
+ set fahrenheit(f: Float):
602
+ self.celsius = (f - 32.0) * 5.0 / 9.0
603
+ ```
604
+
605
+ ### Generic Classes
606
+
607
+ ```flux
608
+ class Stack<T>:
609
+ private items: Array<T> = []
610
+
611
+ fn push(item: T) -> Void:
612
+ self.items.push(item)
613
+
614
+ fn pop() -> T?:
615
+ return self.items.pop()
616
+
617
+ get size() -> Int:
618
+ return self.items.length
619
+ ```
620
+
621
+ ---
622
+
623
+ ## Decorators
624
+
625
+ Decorators wrap functions and classes to add behaviour without modifying their source.
626
+
627
+ ```flux
628
+ // @name — apply decorator after definition
629
+ @log
630
+ fn fetchUser(id: Int):
631
+ return fetch("/api/users/{id}")
632
+
633
+ // @name(args) — decorator factory (called with args, returns decorator)
634
+ @deprecated("use fetchUserV2 instead")
635
+ fn fetchUser(id):
636
+ return fetch("/api/users/{id}")
637
+
638
+ // Class decorator
639
+ @injectable
640
+ class UserService:
641
+ var db: Database
642
+
643
+ // Multiple decorators (applied bottom-up)
644
+ @singleton
645
+ @injectable
646
+ class AppService:
647
+ var repo: Repository
648
+ ```
649
+
650
+ **How it compiles:**
651
+
652
+ ```javascript
653
+ // @log fn greet() →
654
+ function greet(name) { ... }
655
+ greet = log(greet);
656
+
657
+ // @deprecated("...") fn foo() →
658
+ function foo() { ... }
659
+ foo = deprecated("use fetchUserV2 instead")(foo);
660
+
661
+ // @injectable class Service →
662
+ class Service { ... }
663
+ Service = injectable(Service);
664
+ ```
665
+
355
666
  ---
356
667
 
357
668
  ## Algebraic Data Types (ADT)
358
669
 
359
670
  ```flux
360
- // Definisi
671
+ // Definition
361
672
  type Option = Some(value) | None
362
- type Result = Ok(value) | Err(message)
673
+ type Result = Ok(value) | Err(message)
363
674
  type Shape = Circle(radius) | Rectangle(w, h) | Triangle(base, height)
675
+
676
+ // Generic ADTs
677
+ type Result<T> = Ok(value) | Err(message)
678
+ type Either<L, R> = Left(value) | Right(value)
364
679
  ```
365
680
 
366
- ### Pattern Matching dengan ADT
681
+ ### Pattern Matching with ADT
367
682
 
368
683
  ```flux
369
684
  fn safeDivide(a: Float, b: Float) -> Result:
370
685
  if b == 0.0: return Err("Division by zero")
371
686
  return Ok(a / b)
372
687
 
373
- val result = safeDivide(10.0, 2.0)
374
-
375
- match result:
376
- when Ok(v) -> print("Result: {v}")
377
- when Err(e) -> print("Error: {e}")
688
+ match safeDivide(10.0, 2.0):
689
+ when Ok(v) -> print("Result: {v}")
690
+ when Err(e) -> print("Error: {e}")
378
691
 
379
- // Dengan guard
380
- match result:
381
- when Ok(v) if v > 0 -> print("Positive: {v}")
692
+ // Guards
693
+ match safeDivide(10.0, 2.0):
694
+ when Ok(v) if v > 0 -> print("Positive: {v}")
382
695
  when Ok(v) -> print("Non-positive: {v}")
383
696
  when Err(e) -> print("Error: {e}")
697
+
698
+ // Shape area using ADT
699
+ fn area(shape: Shape) -> Float:
700
+ match shape:
701
+ when Circle(r) -> 3.14159 * r * r
702
+ when Rectangle(w,h) -> w * h
703
+ when Triangle(b,h) -> 0.5 * b * h
384
704
  ```
385
705
 
386
706
  ---
@@ -399,63 +719,46 @@ enum Status:
399
719
  Inactive
400
720
  Pending
401
721
 
402
- print(Direction.North) // 0
403
- print(Status.Active) // 0
722
+ enum Color:
723
+ Red // 0
724
+ Green = 10 // 10
725
+ Blue // 11 (auto-increments from explicit value)
726
+
727
+ print(Direction.North) // 0
728
+ print(Status.Active) // 0
729
+
730
+ // Enums in match
731
+ match dir:
732
+ when Direction.North -> print("Going north")
733
+ when Direction.South -> print("Going south")
734
+ when _ -> print("Other direction")
404
735
  ```
405
736
 
406
737
  ---
407
738
 
408
- ## Kontrol Alur
409
-
410
- ### If / Else
411
-
412
- ```flux
413
- if x > 0:
414
- print("positif")
415
- else if x < 0:
416
- print("negatif")
417
- else:
418
- print("nol")
419
- ```
420
-
421
- ### For / While / Do-While
739
+ ## Destructuring & Spread
422
740
 
423
741
  ```flux
424
- // Iterasi array
425
- for item in items:
426
- print(item)
427
-
428
- // Range
429
- for i in 0..10:
430
- print(i)
742
+ // Object destructuring
743
+ val person = { name: "Budi", age: 25, city: "Jakarta" }
744
+ val { name, age } = person
431
745
 
432
- // While
433
- var n = 10
434
- while n > 0:
435
- print(n)
436
- n -= 1
746
+ // With alias
747
+ val { name: personName, age: personAge } = person
437
748
 
438
- // Do-while
439
- do:
440
- print("minimal sekali")
441
- while false
442
- ```
749
+ // Array destructuring
750
+ val [first, second, ...rest] = [1, 2, 3, 4, 5]
443
751
 
444
- ### Match (Pattern Matching)
752
+ // With default value
753
+ val { title = "Untitled", content } = post
445
754
 
446
- ```flux
447
- match nilai:
448
- when 0 -> print("nol")
449
- when 1..9 -> print("satu digit")
450
- when 10..99 -> print("dua digit")
451
- when _ -> print("lainnya")
755
+ // In function params
756
+ fn greet({ name, title = "Mr" }) -> String:
757
+ return "Hello, {title} {name}!"
452
758
 
453
- // Match dengan guard
454
- match score:
455
- when s if s >= 90 -> print("A")
456
- when s if s >= 80 -> print("B")
457
- when s if s >= 70 -> print("C")
458
- when _ -> print("D")
759
+ // Spread shallow merge
760
+ val defaults_ = { role: "viewer", active: true }
761
+ val merged = { ...defaults_, ...overrides }
459
762
  ```
460
763
 
461
764
  ---
@@ -468,317 +771,419 @@ try:
468
771
  val data = JSON.parse(input)
469
772
  print(data)
470
773
  catch(e):
471
- print("Error: {e.message}")
774
+ print("Parse error: {e.message}")
472
775
  finally:
473
- print("Selesai")
776
+ print("Done")
474
777
 
475
778
  // Throw
476
779
  fn validateAge(age: Int) -> Void:
477
780
  if age < 0:
478
- throw new Error("Usia tidak boleh negatif: {age}")
781
+ throw new Error("Age cannot be negative: {age}")
479
782
 
480
- // Dengan ADT Result
783
+ // ADT Result pattern (no exceptions)
481
784
  type Result = Ok(value) | Err(message)
482
785
 
483
786
  fn parseNumber(s: String) -> Result:
484
787
  val n = parseInt(s, 10)
485
- if isNaN(n): return Err("Bukan angka: {s}")
788
+ if isNaN(n): return Err("Not a number: {s}")
486
789
  return Ok(n)
790
+
791
+ match parseNumber("42"):
792
+ when Ok(n) -> print("Got: {n}")
793
+ when Err(e) -> print("Failed: {e}")
487
794
  ```
488
795
 
489
796
  ---
490
797
 
491
- ## Destructuring
798
+ ## Async / Await
492
799
 
493
800
  ```flux
494
- // Object destructuring
495
- val person = { name: "Budi", age: 25, city: "Jakarta" }
496
- val { name, age, city } = person
497
-
498
- // Dengan alias
499
- val { name: personName, age: personAge } = person
500
-
501
- // Array destructuring
502
- val [first, second, ...rest] = [1, 2, 3, 4, 5]
503
-
504
- // Dengan default value
505
- val { title = "Tanpa Judul", content } = post
801
+ async fn fetchUser(id: Int):
802
+ val res = await fetch("/api/users/{id}")
803
+ val user = await res.json()
804
+ return user
805
+
806
+ // Parallel requests
807
+ async fn loadDashboard():
808
+ val [user, posts, config] = await Promise.all([
809
+ fetchUser(1),
810
+ fetchPosts(),
811
+ fetchConfig()
812
+ ])
813
+ print("Loaded: {user.name}, {posts.length} posts")
814
+
815
+ // Error handling in async
816
+ async fn safeLoad(url: String):
817
+ try:
818
+ val res = await fetch(url)
819
+ return await res.json()
820
+ catch(e):
821
+ print("Network error: {e.message}")
822
+ return null
506
823
  ```
507
824
 
508
825
  ---
509
826
 
510
- ## Import / Export
827
+ ## Modules
511
828
 
512
829
  ```flux
513
830
  // Import default
514
831
  import express from 'express'
515
832
 
516
- // Import named
833
+ // Named imports
517
834
  import { readFileSync, writeFileSync } from 'fs'
518
835
 
519
- // Import namespace
836
+ // Namespace import
520
837
  import * as path from 'path'
521
838
 
522
- // Export
839
+ // Aliased import
840
+ import { useState as useLocalState } from 'react'
841
+
842
+ // Export named
523
843
  export fn calculateTax(amount: Float, rate: Float) -> Float:
524
844
  return amount * rate
525
845
 
846
+ export val TAX_RATE = 0.1
847
+
848
+ // Export default
526
849
  export default fn main():
527
850
  print("Hello from main!")
528
851
  ```
529
852
 
530
853
  ---
531
854
 
532
- ## Interop dengan npm
855
+ ## Pipe Operator
533
856
 
534
- Flux di-transpile ke JavaScript semua package npm dapat digunakan langsung:
857
+ The `|>` operator passes the left value as the first argument to the right function. Combine with stdlib for expressive data pipelines.
535
858
 
536
859
  ```flux
537
- import express from 'express'
538
- import { readFileSync } from 'fs'
539
-
540
- val app = express()
541
-
542
- app.get("/", fn(req, res):
543
- res.json({ status: "ok", lang: "Flux" })
544
- )
545
-
546
- app.listen(3000, fn():
547
- print("Server Flux berjalan di port 3000")
548
- )
860
+ // Chained transformations
861
+ val total = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
862
+ |> filter(n -> n % 2 == 0)
863
+ |> map(n -> n * n)
864
+ |> reduce((acc, n) -> acc + n, 0) // 220
865
+
866
+ // String pipeline
867
+ val slug = " Hello World "
868
+ |> trim
869
+ |> s -> s.toLowerCase()
870
+ |> s -> s.replace(/\s+/g, "-") // "hello-world"
871
+
872
+ // With stdlib functions
873
+ val topScorers = students
874
+ |> sortBy(s -> s.score)
875
+ |> s -> s.reverse()
876
+ |> take(3)
877
+ |> map(s -> s.name)
549
878
  ```
550
879
 
551
880
  ---
552
881
 
553
- ## JSX (React)
882
+ ## JSX
883
+
884
+ Configure the target in `flux.config.js`: `jsxTarget: "react"` for React, `jsxTarget: "server"` for server-side string rendering.
554
885
 
555
886
  ```flux
556
- // Server-side JSX
557
- val heading = <h1 class="title">Hello Flux!</h1>
558
- val card = <div class="card">
559
- <h2>{title}</h2>
560
- <p>{description}</p>
561
- </div>
887
+ // React component
888
+ fn Button({ label, onClick, disabled = false }):
889
+ return (
890
+ <button
891
+ onClick={onClick}
892
+ disabled={disabled}
893
+ className={disabled ? 'btn disabled' : 'btn'}
894
+ >
895
+ {label}
896
+ </button>
897
+ )
898
+
899
+ // Conditional rendering
900
+ fn UserCard({ user }):
901
+ return (
902
+ <div className="card">
903
+ <h2>{user.name}</h2>
904
+ {user.email && <p>{user.email}</p>}
905
+ </div>
906
+ )
907
+
908
+ // List rendering
909
+ fn ItemList({ items }):
910
+ return (
911
+ <ul>
912
+ {items.map(item -> <li key={item.id}>{item.name}</li>)}
913
+ </ul>
914
+ )
562
915
  ```
563
916
 
564
917
  ---
565
918
 
566
- ## CSS Preprocessor
919
+ ## CSS-in-Flux
920
+
921
+ The `css {}` block is a Flux-native CSS preprocessor. Supports shorthand properties and standard CSS with Flux sugar.
567
922
 
568
923
  ```flux
569
- val styles = css`
570
- .button {
571
- background: var(--primary);
572
- border-radius: 8px;
573
- padding: 8px 16px;
924
+ val styles = css {
925
+ .card {
926
+ flex; center; bold
927
+ bg: #0f172a
928
+ radius: 12px
929
+ p: 20px
930
+ border: 1px solid #1e3a5f
574
931
 
575
932
  &:hover {
576
- opacity: 0.9;
933
+ border-color: #38bdf8
577
934
  }
578
935
  }
579
- `
580
- ```
581
-
582
- ---
583
936
 
584
- ## Perintah CLI
585
-
586
- | Perintah | Deskripsi |
587
- |---------------------------------|------------------------------------------------------|
588
- | `flux init [nama]` | Buat project Flux baru |
589
- | `flux compile file.flux` | Compile ke JavaScript |
590
- | `flux compile file.flux -o out` | Compile ke file output tertentu |
591
- | `flux bundle main.flux` | Bundle semua import menjadi satu file |
592
- | `flux run file.flux` | Compile dan langsung jalankan |
593
- | `flux watch file.flux` | Pantau perubahan dan compile otomatis |
594
- | `flux check file.flux` | **Type check** + analisis statis |
595
- | `flux lint file.flux` | **Lint** — unused vars, unreachable code, shadowing |
596
- | `flux fmt file.flux` | Format kode sumber |
597
- | `flux test [dir]` | Temukan dan jalankan file `*.test.flux` |
598
- | `flux tokens file.flux` | Tampilkan daftar token dari lexer |
599
- | `flux ast file.flux` | Tampilkan AST dalam format JSON |
600
- | `flux repl` | Mode REPL interaktif |
601
- | `flux version` | Tampilkan versi |
602
-
603
- ### Flag
937
+ .button {
938
+ bg: linear-gradient(135deg, #38bdf8, #818cf8)
939
+ radius: 8px
940
+ p: 10px 20px
941
+ color: white
942
+ bold
604
943
 
944
+ &:hover { opacity: 0.85 }
945
+ }
946
+ }
605
947
  ```
606
- --out, -o <file> File output
607
- --sourcemap, -m Hasilkan source map (.js.map)
608
- --stdout Cetak output ke terminal
609
- --no-color Nonaktifkan warna
610
- ```
948
+
949
+ **Shorthand properties:** `flex` → `display:flex`, `bold` → `font-weight:700`, `center` → `text-align:center`, `bg` → `background`, `radius` → `border-radius`, `p` → `padding`, `m` `margin`.
611
950
 
612
951
  ---
613
952
 
614
- ## Sistem Tipe — TypeScript Parity
953
+ ## Standard Library
615
954
 
616
- Flux v3.1.0 memiliki sistem tipe yang setara dengan TypeScript. Berikut fitur lengkapnya:
955
+ All stdlib functions are **tree-shaken** only symbols actually used in compiled output are injected.
617
956
 
618
- ### Intersection Types (`A & B`)
957
+ ### Sequences
619
958
 
620
959
  ```flux
621
- interface Named:
622
- name: String
623
-
624
- interface Aged:
625
- age: Int
626
-
627
- // Intersection: class harus memenuhi SEMUA interface
628
- class Person implements Named, Aged:
629
- name: String
630
- age: Int
960
+ range(end) // range(5) → [0,1,2,3,4]
961
+ range(start, end) // range(1, 4) → [1,2,3]
962
+ range(start, end, step) // range(0, 10, 2) → [0,2,4,6,8]
963
+ zip(...arrays) // zip([1,2],[3,4]) → [[1,3],[2,4]]
964
+ unzip(pairs) // unzip([[1,"a"]]) → [[1],["a"]]
965
+ enumerate(arr, start?) // enumerate(["a","b"]) → [[0,"a"],[1,"b"]]
966
+ flatten(arr, depth?) // flatten([[1,[2]],3]) → [1,2,3]
967
+ chunk(arr, size) // chunk([1..5], 2) → [[1,2],[3,4],[5]]
968
+ unique(arr) // unique([1,2,2,3]) → [1,2,3]
969
+ groupBy(arr, fn|key) // groupBy(items, "type") → { fruit:[...], veg:[...] }
970
+ sortBy(arr, fn|key) // sortBy(users, "age")
971
+ countBy(arr, fn|key) // countBy(words, w -> w[0]) → { a:3, b:2 }
972
+ partition(arr, fn) // partition(nums, n -> n>0) → [[pos],[neg]]
973
+ toPairs(obj) // toPairs({a:1}) → [["a",1]]
631
974
  ```
632
975
 
633
- ### Tuple Types
976
+ ### Arrays (pipe-compatible)
634
977
 
635
978
  ```flux
636
- fn getCoord() -> [Float, Float]:
637
- return [3.14, 2.71]
638
-
639
- fn parseKV(pair: String) -> [String, String]:
640
- val parts = pair.split("=")
641
- return [parts[0], parts[1]]
642
-
643
- val [lat, lng] = getCoord() // destructure tuple
644
- val [key, val_] = parseKV("a=b")
979
+ // Pipe helpers designed for |>
980
+ map(arr, fn) // [1,2,3] |> map(x -> x*2)
981
+ filter(arr, fn) // nums |> filter(x -> x > 0)
982
+ reduce(arr, fn, init?) // nums |> reduce((a,n) -> a+n, 0)
983
+ forEach(arr, fn) // items |> forEach(print)
984
+ find(arr, fn) // users |> find(u -> u.id == id)
985
+ findIndex(arr, fn) // arr |> findIndex(x -> x == 5)
986
+ some(arr, fn) // arr |> some(x -> x > 10)
987
+ every(arr, fn) // arr |> every(x -> x > 0)
988
+ join(arr, sep?) // words |> join(", ")
989
+ sort(arr, fn?) // nums |> sort()
990
+ flat(arr, depth?) // nested |> flat()
991
+ flatMap(arr, fn) // arrs |> flatMap(x -> x)
992
+ includes(arr, val) // arr |> includes(5)
993
+
994
+ // Array extras
995
+ first(arr) / head(arr) // first([1,2,3]) → 1
996
+ last(arr) // last([1,2,3]) → 3
997
+ tail(arr) // tail([1,2,3]) → [2,3]
998
+ nth(arr, n) // nth([1,2,3], -1) → 3
999
+ take(arr, n) // take([1,2,3,4], 2) → [1,2]
1000
+ drop(arr, n) // drop([1,2,3,4], 2) → [3,4]
1001
+ takeWhile(arr, fn) // takeWhile([1,2,5,3], n -> n<4) → [1,2]
1002
+ dropWhile(arr, fn) // dropWhile([1,2,5,3], n -> n<4) → [5,3]
1003
+ compact(arr) // compact([0,1,null,2,""]) → [1,2]
1004
+ intersection(a, b) // intersection([1,2,3],[2,3,4]) → [2,3]
1005
+ difference(a, b) // difference([1,2,3],[2,3]) → [1]
1006
+ arrayUnion(a, b) // arrayUnion([1,2],[2,3]) → [1,2,3]
1007
+ count(arr, fn?) // count(arr, x -> x > 0)
1008
+ minBy(arr, fn|key) // minBy(users, u -> u.age)
1009
+ maxBy(arr, fn|key) // maxBy(products, p -> p.price)
1010
+ rotate(arr, n) // rotate([1,2,3,4], 1) → [2,3,4,1]
1011
+ sliding(arr, size, step?) // sliding([1,2,3,4], 2) → [[1,2],[2,3],[3,4]]
645
1012
  ```
646
1013
 
647
- ### Inline Object Types
1014
+ ### Math & Random
648
1015
 
649
1016
  ```flux
650
- fn makePoint(x: Float, y: Float) -> { x: Float, y: Float }:
651
- return { x, y }
652
-
653
- fn distance(p1: { x: Float, y: Float }, p2: { x: Float, y: Float }) -> Float:
654
- val dx = p1.x - p2.x
655
- val dy = p1.y - p2.y
656
- return Math.sqrt(dx * dx + dy * dy)
1017
+ clamp(val, min, max) // clamp(150, 0, 100) → 100
1018
+ sum(arr) // sum([1,2,3,4]) → 10
1019
+ product(arr) // product([1,2,3,4]) → 24
1020
+ min(arr) / min(a, b, ...) // min([3,1,4]) 1
1021
+ max(arr) / max(a, b, ...) // max([3,1,4]) → 4
1022
+ abs(n) // abs(-5) → 5
1023
+ floor(n) // floor(3.7) → 3
1024
+ ceil(n) // ceil(3.2) → 4
1025
+ round(n, decimals?) // round(3.14159, 2) → 3.14
1026
+ mean(arr) // mean([1,2,3,4,5]) → 3
1027
+ median(arr) // median([1,3,5]) → 3
1028
+ stdDev(arr) // stdDev([2,4,4,4,5]) → ~0.97
1029
+ lerp(a, b, t) // lerp(0, 100, 0.5) → 50
1030
+ randInt(min, max) // randInt(1, 6) → dice roll
1031
+ sample(arr) // sample(["a","b","c"]) → random element
1032
+ shuffle(arr) // shuffle(range(1, 53)) → shuffled deck
657
1033
  ```
658
1034
 
659
- ### Structural Typing
1035
+ > **`Math` object** — all JS `Math` functions are also directly available: `Math.sqrt`, `Math.pow`, `Math.log`, `Math.sin`, `Math.cos`, `Math.PI`, etc.
660
1036
 
661
- ```flux
662
- interface Printable:
663
- fn toString() -> String
1037
+ ### Objects
664
1038
 
665
- // Tidak perlu implements jika shape cocok (duck typing)
666
- class Config implements Printable:
667
- key: String
668
- fn toString() -> String -> "Config({self.key})"
1039
+ ```flux
1040
+ keys(obj) // keys({a:1,b:2}) → ["a","b"]
1041
+ values(obj) // values({a:1,b:2}) → [1,2]
1042
+ entries(obj) // entries({a:1}) → [["a",1]]
1043
+ pick(obj, keys) // pick(user, ["name","role"])
1044
+ omit(obj, keys) // omit(user, ["password"])
1045
+ merge(obj, ...sources) // merge(defaults, overrides)
1046
+ defaults(obj, ...sources) // fill null/undefined only
1047
+ invert(obj) // invert({ok:200}) → {"200":"ok"}
1048
+ mapValues(obj, fn) // mapValues(scores, v -> v*2)
1049
+ filterValues(obj, fn) // filterValues(obj, v -> v > 0)
1050
+ fromEntries(entries) // fromEntries([["x",1]]) → {x:1}
1051
+ deepEqual(a, b) // deepEqual({a:1}, {a:1}) → true
1052
+ deepClone(v) // deep copy via JSON round-trip
669
1053
  ```
670
1054
 
671
- ### Type Narrowing via Control Flow
1055
+ ### Strings
672
1056
 
673
1057
  ```flux
674
- fn getUser(id: Int) -> String?:
675
- if id > 0: return "User_{id}"
676
- return null
1058
+ capitalize(s) // capitalize("hello") "Hello"
1059
+ camelCase(s) // camelCase("hello world") → "helloWorld"
1060
+ snakeCase(s) // snakeCase("helloWorld") → "hello_world"
1061
+ kebabCase(s) // kebabCase("helloWorld") → "hello-world"
1062
+ truncate(s, len, suffix?) // truncate("long text", 8) → "long ..."
1063
+ pad(s, len, char?) // pad("hi", 6) → " hi "
1064
+ padStart(s, len, char?) // padStart("42", 5, "0") → "00042"
1065
+ padEnd(s, len, char?) // padEnd("hi", 5) → "hi "
1066
+ trim(s) // trim(" hi ") → "hi"
1067
+ trimStart(s) // trimStart(" hi") → "hi"
1068
+ trimEnd(s) // trimEnd("hi ") → "hi"
1069
+ words(s) // words("hello world") → ["hello","world"]
1070
+ lines(s) // lines("a\nb\nc") → ["a","b","c"]
1071
+ startsWith(s, prefix) // startsWith("flux", "fl") → true
1072
+ endsWith(s, suffix) // endsWith("flux", "ux") → true
1073
+ repeat(s, n) // repeat("ab", 3) → "ababab"
1074
+ replaceAll(s, find, rep) // replaceAll("aabba", "a", "x") → "xxbbx"
1075
+ reverseStr(s) // reverseStr("flux") → "xulf"
1076
+ ```
677
1077
 
678
- val user = getUser(1)
1078
+ > **Native string methods** also available: `.toUpperCase()`, `.toLowerCase()`, `.split()`, `.replace()`, `.includes()`, `.slice()`, `.indexOf()`, `.match()`.
679
1079
 
680
- // Flux mengecilkan tipe di dalam blok null-check
681
- if user != null:
682
- print(user.toUpperCase()) // OK — user adalah String di sini, bukan String?
1080
+ ### Functional
683
1081
 
684
- // typeof narrowing
685
- fn process(x: Int | String | Bool) -> String:
686
- if typeof x == "number": return "num: {x}"
687
- if typeof x == "string": return "str: {x}"
688
- return "bool: {x}"
1082
+ ```flux
1083
+ pipe(f1, f2, ...) // compose left-to-right new function
1084
+ compose(f1, f2, ...) // compose right-to-left new function
1085
+ partial(fn, ...args) // pre-fill first N arguments
1086
+ curry(fn) // auto-curry — one arg at a time
1087
+ memoize(fn) // cache results by JSON-serialized args
1088
+ once(fn) // execute only on first call; cache result
1089
+ flip(fn) // swap first two arguments
1090
+ complement(fn) // negate fn's boolean result
1091
+ identity(v) // return v unchanged
1092
+ noop() // do nothing
689
1093
  ```
690
1094
 
691
- ### Function Types
692
-
693
1095
  ```flux
694
- // Anotasi tipe fungsi sebagai parameter
695
- fn mapInts(arr: Array<Int>, f: fn(Int) -> Int) -> Array<Int>:
696
- return arr.map(f)
697
-
698
- fn double(x: Int) -> Int:
699
- return x * 2
700
-
701
- val results = mapInts([1, 2, 3], double)
702
-
703
- // Tipe fungsi di interface
704
- interface Handler:
705
- fn handle(req: String) -> String
1096
+ // pipe example
1097
+ val process = pipe(
1098
+ s -> s.trim(),
1099
+ s -> s.toLowerCase(),
1100
+ capitalize
1101
+ )
1102
+ process(" hello WORLD ") // "Hello world"
1103
+
1104
+ // once — run initialization only once
1105
+ val init = once(() -> {
1106
+ print("connecting...")
1107
+ return connectDB()
1108
+ })
1109
+ init() // "connecting..." → connection
1110
+ init() // silent → same connection
1111
+
1112
+ // complement — negate a predicate
1113
+ val isEven = n -> n % 2 == 0
1114
+ val isOdd = complement(isEven)
1115
+ [1,2,3,4] |> filter(isOdd) // [1,3]
1116
+
1117
+ // curry
1118
+ val add = curry((a, b) -> a + b)
1119
+ val addFive = add(5)
1120
+ addFive(3) // 8
706
1121
  ```
707
1122
 
708
- ### `keyof` & `typeof` di Tipe
1123
+ ### Type Checks
709
1124
 
710
1125
  ```flux
711
- // keyof T union dari semua key interface
712
- fn getField(key: keyof Config) -> String:
713
- return key
714
-
715
- // typeof x tipe dari variabel
716
- val config = new Config("host", "localhost")
717
- fn cloneConfig(src: typeof config) -> typeof config:
718
- return new Config(src.key, src.value)
1126
+ isNil(v) // true if null or undefined
1127
+ isString(v) // true if typeof v === "string"
1128
+ isNumber(v) // true if finite number (excludes NaN)
1129
+ isArray(v) // true if Array.isArray(v)
1130
+ isObject(v) // true if plain object (not array/null)
1131
+ isFunction(v) // true if typeof v === "function"
1132
+ isBool(v) // true if typeof v === "boolean"
719
1133
  ```
720
1134
 
721
- ### Utility Types
722
-
723
1135
  ```flux
724
- // Semua utility type TypeScript tersedia:
725
- fn setPartial(opts: Partial<Config>) -> Void:
726
- // semua field optional
727
- pass
728
-
729
- fn setRequired(opts: Required<Config>) -> Void:
730
- // semua field wajib
731
- pass
732
-
733
- fn makeReadonly(opts: Readonly<Config>) -> Void:
734
- // tidak bisa diubah
735
- pass
736
-
737
- // Record<K, V> — dictionary type
738
- fn buildMap(keys: Array<String>) -> Record<String, Int>:
739
- return {}
740
-
741
- // NonNullable<T> — hapus null dari union
742
- fn safeGet(x: NonNullable<String?>) -> String:
743
- return x
744
-
745
- // ReturnType<T> — extract return type
746
- // Pick<T, K>, Omit<T, K>, Exclude<T, U>, Extract<T, U>
747
- // Awaited<T>, Parameters<T>, InstanceType<T>
1136
+ fn safeLength(v) -> Int:
1137
+ if isString(v): return v.length
1138
+ if isArray(v): return v.length
1139
+ return 0
748
1140
  ```
749
1141
 
750
- ### Index Signatures
1142
+ ### Async Utils
751
1143
 
752
1144
  ```flux
753
- // { [key: String]: T } — map arbitrary keys to type
754
- fn buildRegistry() -> { [key: String]: String }:
755
- return { name: "Flux", version: "3.1.0" }
1145
+ sleep(ms) // Promise that resolves after ms
1146
+ retry(fn, attempts?, delay?) // retry up to N times with exponential back-off
1147
+ timeout(fn|promise, ms) // reject with Error if exceeds ms
1148
+ allSettled(promises) // like Promise.allSettled — never rejects
1149
+ debounce(fn, ms) // delay until ms of inactivity (trailing edge)
1150
+ throttle(fn, ms) // fire at most once per ms
1151
+ memoize(fn) // cache async results too
756
1152
  ```
757
1153
 
758
- ### Generic Type Parameters di ADT
759
-
760
1154
  ```flux
761
- // Type parameter <T> di ADT declarations
762
- type Result<T> = Ok(value) | Err(message)
763
- type Option<T> = Some(value) | None
764
- type Either<L, R> = Left(value) | Right(value)
1155
+ // sleep non-blocking delay
1156
+ await sleep(2000) // wait 2 seconds
1157
+
1158
+ // retry — defaults: 3 attempts, 300ms base delay, exponential back-off
1159
+ val data = await retry(
1160
+ () -> fetchDataFromAPI(),
1161
+ 5, // max attempts
1162
+ 200 // base delay ms (doubles each retry)
1163
+ )
765
1164
 
766
- fn safeDivide(a: Float, b: Float) -> Result:
767
- if b == 0.0: return Err("Division by zero")
768
- return Ok(a / b)
1165
+ // timeout fail if too slow
1166
+ val res = await timeout(fetchFromSlowAPI(), 5000)
1167
+
1168
+ // debounce — fire after user stops typing
1169
+ val onSearch = debounce(q -> search(q), 300)
1170
+
1171
+ // allSettled — collect every outcome without throwing
1172
+ val results = await allSettled([fetchUser(), fetchPosts()])
1173
+ for r in results:
1174
+ if r.status == "fulfilled": print("ok: {r.value}")
1175
+ else: print("err: {r.reason}")
769
1176
  ```
770
1177
 
771
1178
  ---
772
1179
 
773
1180
  ## `flux check` — Type Checker
774
1181
 
775
- Perintah `flux check` menjalankan tiga lapisan:
776
-
777
- 1. **Syntax check** — pastikan kode bisa diparse
778
- 2. **Val immutability** — cegah reassignment `val`
779
- 3. **Type checker** — periksa tipe annotations, return types, interface implementations, dan type narrowing
1182
+ `flux check` runs three layers:
780
1183
 
781
- ### Contoh Output
1184
+ 1. **Syntax check** — ensure code is parseable
1185
+ 2. **Val immutability** — prevent reassignment of `val`
1186
+ 3. **Type checker** — validate type annotations, return types, interface implementations, and type narrowing
782
1187
 
783
1188
  ```
784
1189
  $ flux check app.flux
@@ -792,251 +1197,138 @@ $ flux check app.flux
792
1197
 
793
1198
  [TypeError]:28:1 Class 'Cat' does not implement method 'area()' required by interface 'Shape'
794
1199
  hint: Add 'fn area()' to the class
795
-
796
- ✗ app.flux — 2 type errors
797
- Functions: 5 | Classes: 2 | JS output: 47 lines
798
1200
  ```
799
1201
 
800
- ### Hal yang Diperiksa
1202
+ ### What is Checked
801
1203
 
802
- | Pemeriksaan | Contoh yang ditangkap |
803
- |-------------------------------|-----------------------------------------------------------|
804
- | Mismatch tipe variabel | `val name: String = 42` → error |
805
- | Return type mismatch | `fn f() -> Int: return "hello"` → error |
806
- | Interface tidak diimplementasi| class tidak punya method yang diwajibkan interface |
807
- | Val reassignment | `val x = 1; x = 2` → error |
808
- | Nullable / union assignability| `val x: Int = null` → error |
1204
+ | Check | Example caught |
1205
+ |---|---|
1206
+ | Variable type mismatch | `val name: String = 42` → error |
1207
+ | Return type mismatch | `fn f() -> Int: return "hello"` → error |
1208
+ | Interface not implemented | class missing a required method |
1209
+ | Val reassignment | `val x = 1; x = 2` → error |
1210
+ | Nullable assignability | `val x: Int = null` → error |
809
1211
 
810
1212
  ---
811
1213
 
812
1214
  ## `flux lint` — Linter
813
1215
 
814
- Perintah `flux lint` menjalankan **semua** lapisan pemeriksaan `flux check`, ditambah tiga aturan AST-level yang menangkap masalah logika tanpa melihat tipe:
815
-
816
- | Lapisan | Aturan | Keparahan |
817
- |---------|--------|-----------|
818
- | Syntax | Parse errors | Error (fatal) |
819
- | Immutability | Reassignment `val` | Error |
820
- | Type checker | Mismatch tipe, interface | Error |
821
- | **unused-var** | `val`/`var` dideklarasi tapi tidak pernah dibaca | Warning |
822
- | **unreachable** | Statement setelah `return`/`throw`/`break` | Error |
823
- | **shadow-val** | `val x` di scope dalam menutupi `val x` di scope luar | Warning |
824
- | Format | File tidak terformat | Warning |
825
- | Style | Baris terlalu panjang (>120 karakter), TODO/FIXME | Info |
826
-
827
- ### Perbedaan `flux check` vs `flux lint`
1216
+ `flux lint` runs everything `flux check` does, plus three AST-level rules:
828
1217
 
829
- | | `flux check` | `flux lint` |
830
- |-|---|---|
831
- | Type errors | | |
832
- | Immutability | | |
833
- | **Unused variables** | | |
834
- | **Unreachable code** | | |
835
- | **Variable shadowing** | | |
836
- | Format check | | |
837
-
838
- ### Contoh Output
1218
+ | Layer | Rule | Severity |
1219
+ |---|---|---|
1220
+ | Syntax | Parse errors | Error (fatal) |
1221
+ | Immutability | `val` reassignment | Error |
1222
+ | Type checker | Type mismatches, interface | Error |
1223
+ | **unused-var** | `val`/`var` declared but never read | Warning |
1224
+ | **unreachable** | Statement after `return`/`throw`/`break` | Error |
1225
+ | **shadow-val** | Inner `val x` hides outer `val x` | Warning |
1226
+ | Format | File is not formatted | Warning |
1227
+ | Style | Line > 120 chars, TODO/FIXME | Info |
839
1228
 
840
1229
  ```
841
1230
  $ flux lint app.flux
842
1231
 
843
- ⊛ Linting: app.flux
844
-
845
1232
  [E] unreachable:15:5 Unreachable code after 'return'
846
- hint: Remove or move the unreachable statement
847
1233
  15 │ val dead = 99
848
- │ ^
849
1234
 
850
1235
  [W] unused-var:8:5 'temp' is declared but never used
851
- hint: Prefix with '_' (e.g. '_temp') to silence this warning, or remove the declaration
1236
+ hint: Prefix with '_' to silence
852
1237
  8 │ val temp = calculate()
853
- │ ^
854
1238
 
855
1239
  [W] shadow-val:22:9 'x' shadows an outer declaration
856
- hint: Rename one of the 'x' variables to avoid confusion
857
1240
  22 │ val x = 0
858
- │ ^
859
1241
 
860
1242
  ──────────────────────────────────────────────────
861
- ✗ app.flux — 3 issue(s) (45 lines)
862
- ```
863
-
864
- ### Cara Menonaktifkan Warning Tertentu
865
-
866
- Prefiks nama variabel dengan `_` untuk menonaktifkan `unused-var` dan `shadow-val`:
867
-
868
- ```flux
869
- val _ignored = sideEffect() // tidak dilaporkan unused
870
- fn process(_unused, value): // param tidak dilaporkan unused
871
- return value * 2
872
- ```
873
-
874
- ---
875
-
876
- ## Bug Fixes & Riwayat Perubahan
877
-
878
- ### v3.1.1 — Perbaikan Bug (Juni 2026)
879
-
880
- Empat bug ditemukan melalui analisis statis dan dibuktikan dengan test sebelum diperbaiki. Semua perubahan diverifikasi dengan suite test penuh (71 test, 0 gagal).
881
-
882
- ---
883
-
884
- #### Bug #1 — `codegen.js`: Wildcard arm pertama menghasilkan `else {` tanpa `if`
885
-
886
- **Dampak:** `SyntaxError` runtime di JavaScript — kode tidak bisa dijalankan sama sekali.
887
-
888
- **Penyebab:** `genMatch` di `src/codegen.js` menghasilkan `else {` untuk arm wildcard, tetapi jika wildcard adalah arm *pertama*, tidak ada `if` sebelumnya → JS tidak valid.
889
-
890
- **Sebelum:**
891
- ```javascript
892
- // Jika wildcard adalah arm pertama, menghasilkan:
893
- else { // ← SyntaxError: tidak ada `if` sebelumnya
894
- return "matched";
895
- }
896
- ```
897
-
898
- **Sesudah:** Ditambahkan flag `hasOpenIf` — arm wildcard pertama menghasilkan `if (true) {` sehingga JS tetap valid.
899
-
900
- ```flux
901
- // Kode Flux ini sekarang berfungsi benar:
902
- fn classify(x):
903
- match x:
904
- when _ -> "default"
905
- when 1 -> "one"
906
- ```
907
-
908
- ---
909
-
910
- #### Bug #2 — `stdlib.js`: `truncate` menghasilkan string terlalu panjang jika suffix ≥ len
911
-
912
- **Dampak:** Hasil `truncate` melebihi panjang yang diminta.
913
-
914
- **Penyebab:** `slice(0, len - suffix.length)` menghasilkan indeks negatif jika `suffix.length >= len`, yang diinterpretasi JavaScript sebagai `slice(0, negatif)` → mengembalikan karakter dari akhir string alih-alih awal.
915
-
916
- **Sebelum:**
917
- ```javascript
918
- return str.slice(0, len - suffix.length) + suffix;
919
- // truncate("hello world", 3, "......") → hasil > 3 karakter ❌
1243
+ ✗ app.flux — 3 issue(s)
920
1244
  ```
921
1245
 
922
- **Sesudah:** Ditambahkan guard jika `suffix.length >= len`, kembalikan `suffix.slice(0, len)`:
923
- ```javascript
924
- const cut = len - suffix.length;
925
- if (cut <= 0) return suffix.slice(0, len);
926
- return str.slice(0, cut) + suffix;
927
- // truncate("hello world", 3, "......") → "..." (3 karakter) ✓
928
- ```
929
-
930
- ---
931
-
932
- #### Bug #3 — `parser.js`: `(a, b, c)` tanpa `->` diam-diam membuang nilai
1246
+ Prefix any name with `_` to suppress `unused-var` and `shadow-val`:
933
1247
 
934
- **Dampak:** Nilai di posisi 1, 2, ... dalam ekspresi kurung banyak diam-diam hilang tanpa pesan error apapun — sangat sulit di-debug.
935
-
936
- **Penyebab:** Parser membangun `items[]` dari ekspresi berkoma di dalam `(...)`, tetapi jika tidak ada `->` (bukan lambda), ia mengembalikan `items[0]` saja.
937
-
938
- **Sebelum:**
939
1248
  ```flux
940
- val x = (10, 20, 30)
941
- // Dikompilasi menjadi: const x = 10; ← 20 dan 30 hilang diam-diam
942
- ```
943
-
944
- **Sesudah:** Jika `items.length > 1` tanpa `->`, ParseError yang jelas dilempar:
945
- ```
946
- ParseError: Unexpected comma in expression — did you mean a lambda?
947
- Write (p0, p1, p2) -> expr
1249
+ val _ignored = sideEffect()
1250
+ fn process(_unused, value): return value * 2
948
1251
  ```
949
1252
 
950
1253
  ---
951
1254
 
952
- #### Bug #4 — `parser.js`: Auto-index enum tidak direset setelah nilai eksplisit
953
-
954
- **Dampak:** Member enum setelah nilai eksplisit mendapat indeks yang salah.
955
-
956
- **Penyebab:** `autoIndex` hanya dimulai dari 0 dan naik +1, tanpa pernah mengambil nilai dari assignment eksplisit `member = N`.
957
-
958
- **Sebelum:**
959
- ```flux
960
- enum Color:
961
- Red // 0 ✓
962
- Green = 10 // 10 ✓
963
- Blue // 2 ❌ (seharusnya 11)
964
- ```
965
-
966
- **Sesudah:** Setelah nilai eksplisit `N`, `autoIndex` diatur ke `N` sehingga member berikutnya mendapat `N + 1`:
967
- ```flux
968
- enum Color:
969
- Red // 0 ✓
970
- Green = 10 // 10 ✓
971
- Blue // 11 ✓
972
- ```
973
-
974
- ---
975
-
976
- #### Regresi
977
-
978
- Semua 4 perbaikan diverifikasi tidak merusak test yang ada:
979
-
980
- | Suite | Test | Hasil |
981
- |-------|------|-------|
982
- | `01_basics` — `09_ts_compat` | 53 test | ✅ Semua lulus |
983
- | `10_bugfixes` (baru) | 18 test | ✅ Semua lulus |
984
- | `prove_bugs.js` (bukti bug) | 7 test | ✅ Semua lulus |
985
-
986
- ---
987
-
988
- ## Arsitektur Transpiler
1255
+ ## Transpiler Architecture
989
1256
 
990
1257
  ```
991
1258
  Flux Source (.flux)
992
1259
 
993
1260
 
994
- [CSS Preprocessor] css`...` → string template
1261
+ [CSS Preprocessor] css{} / css`...` → string template
995
1262
 
996
1263
 
997
- [JSX Preprocessor] <div>...</div> → createElement(...)
1264
+ [JSX Preprocessor] <div>...</div> → createElement(...)
998
1265
 
999
1266
 
1000
- [Lexer] Source → Token stream
1267
+ [Lexer] Source → Token stream
1001
1268
 
1002
1269
 
1003
- [Parser] Tokens → AST (Abstract Syntax Tree)
1270
+ [Parser] Tokens → AST (Abstract Syntax Tree)
1004
1271
 
1005
1272
  ├──▶ [Val Checker] AST → immutability errors
1006
1273
 
1007
1274
  ├──▶ [Type Checker] AST → type errors & warnings
1008
1275
 
1009
1276
 
1010
- [Code Generator] AST → JavaScript output
1277
+ [Code Generator] AST → JavaScript output
1011
1278
 
1012
1279
 
1013
- JavaScript (.js) Siap dijalankan di Node.js / browser
1280
+ JavaScript (.js) Ready to run in Node.js / browser
1281
+ ```
1282
+
1283
+ ---
1284
+
1285
+ ## Self-Hosting
1286
+
1287
+ Flux v3 is **100% self-hosted** — the compiler is written in Flux itself. The canonical source lives in `src/self/`:
1288
+
1289
+ ```
1290
+ src/self/lexer.flux → compiled → src/lexer.js
1291
+ src/self/parser.flux → compiled → src/parser.js
1292
+ src/self/codegen.flux → compiled → src/codegen.js
1293
+ src/self/type-checker.flux → compiled → src/type-checker.js
1294
+ src/self/transpiler.flux → compiled → src/transpiler.js
1295
+ ...
1014
1296
  ```
1015
1297
 
1298
+ Bootstrap the self-hosted compiler:
1299
+
1300
+ ```bash
1301
+ node scripts/bootstrap.js
1302
+ ```
1303
+
1304
+ This compiles all `.flux` source files into their `.js` counterparts using the existing JS stage of the compiler.
1305
+
1016
1306
  ---
1017
1307
 
1018
- ## Perbedaan dengan TypeScript
1019
-
1020
- | Fitur | TypeScript | Flux Lang |
1021
- |--------------------------|--------------------|---------------------------------|
1022
- | Sintaks | C-style `{}` | Indentasi (Python-style) |
1023
- | Type annotations | `x: string` | `x: String` |
1024
- | Return type | `(): string {}` | `() -> String:` |
1025
- | Union types | `string \| number` | `String \| Int` |
1026
- | Nullable | `string \| null` | `String?` |
1027
- | Pattern matching | Tidak ada | `match / when` |
1028
- | ADT | Tidak ada | `type Result = Ok(v) \| Err(e)` |
1029
- | Pipe operator | Tidak ada | `\|>` (F# style) |
1030
- | Template strings | `` `${x}` `` | `"{x}"` |
1031
- | Format spec | Tidak ada | `"{n:.2f}"`, `"{n:,}"` |
1032
- | Val (immutable) | `const` | `val` |
1033
- | Var (mutable) | `let` | `var` |
1034
- | npm interop | Ya | Ya (100% kompatibel) |
1035
- | Transpiler output | `.js` | `.js` |
1308
+ ## Differences from TypeScript
1309
+
1310
+ | Feature | TypeScript | Flux Lang |
1311
+ |---|---|---|
1312
+ | Syntax | C-style `{}` blocks | Indentation (Python-style) |
1313
+ | Type annotations | `x: string` | `x: String` |
1314
+ | Return type | `(): string {}` | `() -> String:` |
1315
+ | Union types | `string \| number` | `String \| Int` |
1316
+ | Nullable | `string \| null` | `String?` |
1317
+ | Pattern matching | none | `match / when` |
1318
+ | ADT | none | `type Result = Ok(v) \| Err(e)` |
1319
+ | Pipe operator | none | `\|>` (F# style) |
1320
+ | Template strings | `` `${x}` `` | `"{x}"` |
1321
+ | Format specs | none | `"{n:.2f}"`, `"{n:,}"` |
1322
+ | Decorators | `@decorator` (experimental) | `@decorator` (stable) |
1323
+ | Private fields | `#field` (manual) | `private var field` → `#field` |
1324
+ | Immutable binding | `const` | `val` |
1325
+ | Mutable binding | `let` | `var` |
1326
+ | npm interop | Yes | Yes (100% compatible) |
1327
+ | Output | `.js` | `.js` |
1036
1328
 
1037
1329
  ---
1038
1330
 
1039
- ## Contoh Lengkap — Server HTTP
1331
+ ## Full ExampleHTTP Server
1040
1332
 
1041
1333
  ```flux
1042
1334
  import express from 'express'
@@ -1044,8 +1336,8 @@ import express from 'express'
1044
1336
  type Result = Ok(data) | Err(message)
1045
1337
 
1046
1338
  interface User:
1047
- id: Int
1048
- name: String
1339
+ id: Int
1340
+ name: String
1049
1341
  email: String
1050
1342
 
1051
1343
  fn validateEmail(email: String) -> Bool:
@@ -1053,13 +1345,13 @@ fn validateEmail(email: String) -> Bool:
1053
1345
 
1054
1346
  fn createUser(id: Int, name: String, email: String) -> Result:
1055
1347
  if !validateEmail(email):
1056
- return Err("Email tidak valid: {email}")
1348
+ return Err("Invalid email: {email}")
1057
1349
  return Ok({ id, name, email })
1058
1350
 
1059
1351
  val app = express()
1060
1352
  app.use(express.json())
1061
1353
 
1062
- var users = []
1354
+ var users: Array<User> = []
1063
1355
 
1064
1356
  app.post("/users", fn(req, res):
1065
1357
  val { id, name, email } = req.body
@@ -1078,12 +1370,38 @@ app.get("/users", fn(req, res):
1078
1370
  )
1079
1371
 
1080
1372
  app.listen(3000, fn():
1081
- print("Server Flux berjalan di port 3000")
1373
+ print("Flux server running on port 3000")
1082
1374
  )
1083
1375
  ```
1084
1376
 
1085
1377
  ---
1086
1378
 
1087
- ## Lisensi
1379
+ ## Changelog
1380
+
1381
+ ### v3.2.0 — June 2026
1382
+ - **Decorators** — `@name` and `@name(args)` on `fn` and `class`
1383
+ - **Private fields** — `private var x` → JS `#x` syntax
1384
+ - **+58 stdlib functions** — array extras, math, objects, strings, type checks, async, functional
1385
+ - **Tree-shaking** — stdlib injects only what's used in each compiled file
1386
+ - Transpiler version header bumped to v3.2.0
1387
+
1388
+ ### v3.1.0 — June 2026
1389
+ - Multiline arrow block bodies
1390
+ - `for..of` loops, computed property keys
1391
+ - Class getter / setter, labeled break / continue
1392
+ - For-loop array destructuring
1393
+ - esbuild bundle (`dist/flux.cjs.js`, `dist/flux.esm.js`, `dist/flux.min.js`)
1394
+ - Test suite: 81 tests across 11 files
1395
+
1396
+ ### v3.0.0 — June 2026
1397
+ - TypeScript-parity type system
1398
+ - Self-hosting (compiler written in Flux)
1399
+ - Pattern matching, ADT, enums
1400
+ - Pipe operator, JSX, CSS preprocessor
1401
+ - `flux check`, `flux lint`, `flux fmt`
1402
+
1403
+ ---
1404
+
1405
+ ## License
1088
1406
 
1089
- MIT Flux Lang v3.0.0
1407
+ MIT © Flux Lang Contributors