gofront 0.0.2 → 0.0.4

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
@@ -46,7 +46,7 @@ highlighting, bracket matching, and indentation rules without any extra configur
46
46
  npm install -g gofront
47
47
  ```
48
48
 
49
- Requires Node.js 25+.
49
+ Requires Node.js 20+.
50
50
 
51
51
  ---
52
52
 
@@ -145,7 +145,7 @@ readable and debuggable — no name mangling, no opaque wrappers.
145
145
  | `for {}` | `while (true) {}` |
146
146
  | `for i, v := range slice` | `for (const [i, v] of arr.entries())` |
147
147
  | `for k, v := range map` | `for (const [k, v] of Object.entries(m))` |
148
- | `for i, ch := range str` | `for (const [i, ch] of Array.from(s).entries())` |
148
+ | `for i, r := range str` | `for (const [i, r] of Array.from(s, (c, i) => [i, c.codePointAt(0)]))` — `r` is a rune integer |
149
149
  | `for i := range n` | `for (let i = 0; i < n; i++)` |
150
150
  | `switch` / `fallthrough` | `switch` / case fall-through |
151
151
  | `switch v := x.(type)` | `if/else if` with `typeof` / `instanceof` checks |
@@ -169,6 +169,12 @@ readable and debuggable — no name mangling, no opaque wrappers.
169
169
  | `clear(x)` | `.length = 0` (slice) or delete-loop (map) |
170
170
  | `print` / `println` | `console.log` |
171
171
  | `fmt.Sprintf` | `__sprintf` tree-shaken helper |
172
+ | `strings.*` | JS string methods (`.includes`, `.startsWith`, `.split`, etc.) |
173
+ | `strconv.*` | `String()`, `parseInt()`, `Number()` |
174
+ | `sort.Slice` | `Array.prototype.sort()` with comparator wrapping |
175
+ | `math.*` | `Math.*` methods and constants |
176
+ | `errors.New` | Identity (returns string) |
177
+ | `time.Now()` | `Date.now()` |
172
178
 
173
179
  ### Type system at runtime
174
180
 
@@ -179,36 +185,71 @@ enforces correctness; JavaScript doesn't need to know.
179
185
 
180
186
  ---
181
187
 
182
- ## Example — Todo App
188
+ ## Examples — Todo App
183
189
 
184
- The only example is a full todo web app in `example/`, split across a
185
- sub-package and four source files to showcase multi-file compilation.
190
+ There are two example apps — both implement the same todo app to show different aspects
191
+ of GoFront.
192
+
193
+ ### Simple (vanilla DOM)
194
+
195
+ The default example. Zero dependencies, clean 1:1 compiled JS output. Showcases GoFront's
196
+ core language features with straightforward DOM manipulation.
186
197
 
187
198
  ```
188
- example/
199
+ example/simple/
189
200
  src/
190
- utils/ ← sub-package: Plural(), Max(), Clamp() — pure utilities
191
- utils.go
192
- types.go ← Todo struct · FilterMode & Priority consts (iota) · filterLabel()
193
- store.go ← state management: add/toggle/remove/clear · visibleTodos()
194
- · stats() with named returns · statusLine() via utils.Plural
195
- render.go ← renderTodo() · renderFilterBar() · renderFooter() · render()
196
- main.go ← priority-toggle state · submitInput() · event wiring · seed data
197
- index.html ← HTML + CSS, loads app.js as an ES module
198
- app.js ← generated output (produced by build)
199
- build.sh ← build script
201
+ types.go ← Todo struct · FilterAll/Active/Completed iota · Priority iota
202
+ store.go ← state as plain variables · add/toggle/remove/clear · visibleTodos()
203
+ · stats() with named returns · defer/recover · async persistence
204
+ render.go ← render() updates DOM via innerHTML · renderTodo() · renderFilterBar()
205
+ styles.go ← injectStyles() creates <style> element with all CSS
206
+ main.go ← createApp() builds DOM shell · setupEvents() · event delegation
207
+ utils/
208
+ utils.go ← Plural() — cross-package import demo
209
+ browser.d.ts ← minimal external type declarations (sleep)
210
+ index.html ← bare HTML shell, loads app.js as ES module
211
+ app.js ← generated output
200
212
  ```
201
213
 
202
- **Features demonstrated:** structs & methods, iota constants, named return values,
203
- closures, slices, maps, `for range`, `switch`, cross-package imports, multi-file
204
- same-package compilation, DOM APIs.
214
+ ### Reactive (signals + d.ts imports)
215
+
216
+ Same app rebuilt with [reactive.js](https://github.com/seriva/microtastic), a tiny
217
+ signals-based reactive framework. Demonstrates how GoFront integrates with external JS
218
+ libraries via `.d.ts` type declarations — the GoFront code uses typed `Signal` values,
219
+ `Signals.create()`, `Signals.computed()`, `Signals.batch()`, and `Reactive.bind()`,
220
+ all described in a hand-written `browser.d.ts` shim.
221
+
222
+ ```
223
+ example/reactive/
224
+ src/
225
+ types.go ← Todo, Stats, AppElements structs
226
+ store.go ← Signal-typed state · Signals.create/computed/batch
227
+ render.go ← createAppShell() returns AppElements · ctx.computed/ctx.bind
228
+ styles.go ← injectStyles()
229
+ main.go ← wires everything together
230
+ utils/
231
+ utils.go ← Plural()
232
+ browser.d.ts ← Signal interface · Signals/Reactive/ComponentContext namespaces
233
+ reactive.js ← signals framework (from microtastic)
234
+ index.html ← loads reactive.js + app.js
235
+ app.js ← generated output
236
+ ```
237
+
238
+ ### Features demonstrated
239
+
240
+ Both apps cover: structs & methods, iota constants, named return values, closures,
241
+ slices, `for range`, `switch`, cross-package imports, multi-file same-package compilation,
242
+ `async`/`await`, `defer`/`recover`, localStorage persistence, and DOM APIs.
205
243
 
206
- **Build and run:**
244
+ The reactive example additionally demonstrates: external `.d.ts` type imports,
245
+ `declare namespace` patterns for typing JS libraries, and reactive UI updates via signals.
246
+
247
+ ### Build and run
207
248
 
208
249
  ```sh
209
- sh example/build.sh
210
- # → writes example/app.js
211
- # open example/index.html in a browser
250
+ npm run build:simple # → example/simple/app.js
251
+ npm run build:reactive # → example/reactive/app.js
252
+ # open the respective index.html in a browser
212
253
  ```
213
254
 
214
255
  ---
@@ -308,6 +349,7 @@ signatures into GoFront's internal type representation.
308
349
  | Variadic parameters | ✓ |
309
350
  | `init()` functions | ✓ |
310
351
  | Structs + methods | ✓ |
352
+ | Anonymous struct types (`struct { Name string }`) | ✓ — compile to plain JS objects (no class emitted) |
311
353
  | Embedded structs | ✓ |
312
354
  | Pointer receivers | ✓ |
313
355
  | Interfaces | ✓ |
@@ -323,11 +365,11 @@ signatures into GoFront's internal type representation.
323
365
  | Type conversions | ✓ |
324
366
  | Type assertions (`x.(T)`) | ✓ |
325
367
  | Type switch (`switch x.(type)`, `switch v := x.(type)`) | ✓ — compiles to `if/else if` with `typeof` / `instanceof` checks |
326
- | Slice expressions (`s[lo:hi]`) | ✓ |
368
+ | Slice expressions (`s[lo:hi]`, `s[lo:hi:max]`) | ✓ — three-index form is parsed; `max` is ignored at runtime (JS has no capacity) |
327
369
  | `break` / `continue` / labeled `break` / labeled `continue` | ✓ |
328
370
  | `cap()`, `copy()`, `panic()` | ✓ |
329
371
  | Variadic spread (`f(slice...)`, `append(a, b...)`) | ✓ |
330
- | Bitwise operators (`&`, `\|`, `^`, `<<`, `>>`) | ✓ |
372
+ | Bitwise operators (`&`, `\|`, `^`, `&^`, `<<`, `>>`) | ✓ — `&^` (bit clear) compiles to `& ~` |
331
373
  | Compound assignment (`+=`, `-=`, `*=`, `/=`, `%=`, `&=`, `\|=`, `^=`, `<<=`, `>>=`) | ✓ |
332
374
  | Increment / decrement (`i++`, `i--`) | ✓ |
333
375
  | Raw string literals (backticks) | ✓ |
@@ -338,7 +380,15 @@ signatures into GoFront's internal type representation.
338
380
  | Pointer operators (`&`, `*`) | ✓ |
339
381
  | `error` type / `error("msg")` / `.Error()` | ✓ |
340
382
  | `async func` / `await` expressions | ✓ |
341
- | `fmt.Sprintf` / `fmt.Printf` / `fmt.Println` / `fmt.Print` / `fmt.Errorf` | ✓ |
383
+ | `fmt.Sprintf` / `fmt.Printf` / `fmt.Println` / `fmt.Print` / `fmt.Errorf` | ✓ — expanded: `%t`, `%x`, `%X`, `%o`, `%b`, `%q`, `%e`, `%g`, width/precision |
384
+ | `strings` package | ✓ — 20 functions: `Contains`, `HasPrefix`, `Split`, `Join`, `ToUpper`, `ToLower`, `TrimSpace`, etc. |
385
+ | `strconv` package | ✓ — `Itoa`, `Atoi`, `FormatBool`, `FormatInt`, `ParseFloat`, `ParseInt`, `ParseBool` |
386
+ | `sort` package | ✓ — `Ints`, `Float64s`, `Strings`, `Slice`, `SliceStable`, `SliceIsSorted` |
387
+ | `math` package | ✓ — `Sqrt`, `Pow`, `Abs`, `Floor`, `Ceil`, `Round`, `Log`, trig functions + `Pi`, `E`, `MaxInt` constants |
388
+ | `errors` package | ✓ — `errors.New` (returns plain string) |
389
+ | `time` package (partial) | ✓ — `Now`, `Since`, `Sleep` + `Millisecond`, `Second`, `Minute`, `Hour` constants |
390
+ | `unicode` package | ✓ — `IsLetter`, `IsDigit`, `IsSpace`, `IsUpper`, `IsLower`, `IsPunct`, `IsControl`, `IsPrint`, `IsGraphic`, `ToUpper`, `ToLower` |
391
+ | `os` package (partial) | ✓ — `Exit`, `Args`, `Getenv` |
342
392
  | External `.d.ts` types | ✓ |
343
393
  | npm package types | ✓ |
344
394
  | Multi-file packages | ✓ |
@@ -350,46 +400,114 @@ signatures into GoFront's internal type representation.
350
400
  | `[]rune(s)` conversion | ✓ — produces Unicode code points via `Array.from` |
351
401
  | `[...]T{...}` array length inference | ✓ |
352
402
  | Side-effect imports (`import _ "pkg"`) | ✓ — dependency code is bundled; package namespace is not exposed |
403
+ | Dot imports (`import . "pkg"`) | ✓ — merges package exports into the current scope (no qualifier needed) |
404
+ | Unused local import detection | ✓ — unused cross-package imports are type errors (matching Go); `import _` exempt |
353
405
  | `min()` / `max()` builtins | ✓ — compiles to `Math.min` / `Math.max` |
354
406
  | `clear()` builtin | ✓ — zeroes slice length or deletes all map keys |
355
407
  | `range` over integer (`for i := range n`) | ✓ — Go 1.22; also supports `for range n` |
356
408
  | Type aliases (`type A = B`) | ✓ — transparent alias; no conversion needed between alias and original |
409
+ | Numeric literal separators (`1_000_000`) | ✓ — underscores stripped at lex time |
410
+ | Binary / octal literals (`0b1010`, `0o777`) | ✓ — passed through to JS which supports them natively |
411
+ | Hex float literals (`0x1.8p1`) | ✓ — evaluated at lex time to a decimal value |
412
+ | Untyped constants | ✓ — `const x = 5` produces an untyped int that coerces to `int` or `float64` on use (Go spec §Constants) |
413
+ | Positional (unkeyed) struct literals (`Point{1, 2}`) | ✓ |
414
+ | Method expressions (`T.Method`) | ✓ — compiles to `(recv, ...args) => recv.Method(...args)` |
415
+ | Method values (`x.Method`) | ✓ — compiles to `x.Method.bind(x)` |
416
+ | Struct and array equality (`a == b`) | ✓ — deep comparison via tree-shaken `__equal` helper |
417
+ | Multi-value function forwarding (`f(g())`) | ✓ — single multi-return call forwarded as spread |
418
+ | Terminating statement analysis | ✓ — missing `return` in non-void functions is a type error |
357
419
 
358
420
  ---
359
421
 
360
- ## What's not implemented, and why
422
+ ## Go Compatibility
423
+
424
+ GoFront implements a practical subset of the
425
+ [Go Language Specification](https://go.dev/ref/spec) (go1.26). It is not aiming for
426
+ byte-level parity — it is a Go-inspired language for the JavaScript platform. This
427
+ section explains exactly where GoFront matches Go, where it intentionally diverges, and
428
+ where JS fundamentally prevents matching Go semantics.
429
+
430
+ ### What matches Go
431
+
432
+ The core language surface is well covered. All of these compile and behave as a Go
433
+ developer would expect:
434
+
435
+ - **Declarations**: `var`, `:=` (with re-declaration), `const` (with `iota`), `type`,
436
+ `func`, methods, `init()`.
437
+ - **Control flow**: `if`/`else` (with init statement), `for` (classic, condition-only,
438
+ infinite, `range`), `switch`/`case`/`default`/`fallthrough`, type switches, labeled
439
+ `break`/`continue`, `defer`, `panic`/`recover`.
440
+ - **Types**: `int`, `float64`, `string`, `bool`, sized integers (`int8`–`int64`,
441
+ `uint8`–`uint64`), `float32`, `byte`, `rune`, `error`, slices, maps, arrays, structs,
442
+ interfaces (with embedding), pointers (`*T`, `&x`), type aliases, function types.
443
+ - **Expressions**: all arithmetic, comparison, logical, and bitwise operators (including
444
+ `&^`), compound assignment, increment/decrement, type conversions, type assertions
445
+ (plain and comma-ok), slice expressions (`a[lo:hi]`, `a[lo:hi:max]`), composite
446
+ literals (keyed and positional), `[...]T{...}` inference, rune literals, raw string
447
+ literals, variadic spread, blank identifier `_`, method expressions (`T.Method`),
448
+ method values (`x.Method`), struct/array equality, multi-value function forwarding.
449
+ - **Builtins**: `len`, `cap`, `append`, `copy`, `make`, `delete`, `new`, `clear`, `min`,
450
+ `max`, `print`, `println`, `panic`, `recover`, `fmt.Sprintf`/`Printf`/`Println`/`Errorf`.
451
+ - **Standard library shims**: `strings` (20 functions), `strconv` (8 functions),
452
+ `sort` (6 functions), `math` (20 functions + 6 constants), `errors.New`,
453
+ `time.Now`/`Since`/`Sleep` + duration constants, `unicode` (11 functions),
454
+ `os.Exit`/`Args`/`Getenv`.
455
+ - **Packages**: multi-file packages, cross-package imports, import aliases,
456
+ dot imports, blank imports, unused import detection.
457
+
458
+ ### GoFront extensions (not in Go)
459
+
460
+ These features are intentional additions for the JavaScript platform:
461
+
462
+ | Feature | Purpose |
463
+ |---|---|
464
+ | `async func` / `await` | First-class async syntax for frontend work. |
465
+ | Browser globals (`document`, `console`, etc.) | Predeclared as `any` for practical DOM access. |
466
+ | `.d.ts` type imports (`import "js:./types.d.ts"`) | Type-safe interop with JavaScript libraries. |
467
+ | npm package resolution | Import types from `node_modules/` and `@types/` automatically. |
361
468
 
362
- GoFront targets the browser. Several Go features don't translate to JavaScript, and
363
- some were intentionally left out to keep the compiler simple.
469
+ ### What's not implemented
364
470
 
365
- ### Fundamental mismatches — can't implement without a runtime
471
+ | Feature | Reason | Prospect |
472
+ |---|---|---|
473
+ | Generics (`[T any]`) | Touches every compiler stage. Large effort, limited runtime payoff on a JS target. | Feasible — highest-priority future feature. |
474
+ | Range over iterator functions (Go 1.23) | `func(yield func(K, V) bool)` protocol. | Feasible. |
475
+ | Complex numbers (`complex64`, `complex128`, `3i`) | Would need a runtime complex type. Rarely used in frontend. | Feasible but low priority. |
476
+ | `goto` | No clean JS translation. Rare in idiomatic Go. | Not planned. |
477
+ | Goroutines / channels / `select` | Go's concurrency model has no JS equivalent. A userland scheduler defeats the "no runtime" goal. | Out of scope. |
478
+ | `unsafe`, `reflect`, `cgo` | Require memory model or runtime type metadata that JS cannot provide. | Out of scope. |
366
479
 
367
- | Feature | Why |
368
- |---|---|
369
- | Goroutines (`go` keyword) | Go's concurrency model has no JS equivalent. Workers are a different abstraction. A userland scheduler would defeat the "no runtime" goal. |
370
- | Channels (`chan`, `<-`) | Channels are the communication primitive for goroutines. Without goroutines, channels have no purpose. |
371
- | `select` statement | Multiplexes channel operations. Same dependency. |
372
- | Generics (Go 1.18+) | Would require monomorphisation or type-erasure strategy. Type parameters (`[T any]`) touch every compiler stage. Possible, but a large effort with limited payoff for a JS target where everything is `any` at runtime. |
480
+ ### Semantic differences
373
481
 
374
- ### Intentionally skipped
482
+ These features are implemented but behave differently due to fundamental JS runtime
483
+ constraints. These are **not bugs** — they are deliberate trade-offs documented here so
484
+ you know exactly what to expect.
375
485
 
376
- | Feature | Why |
377
- |---|---|
378
- | `goto` statement | Unstructured control flow has no clean JS translation. `goto` is rare in idiomatic Go. Not planned. |
486
+ | Feature | GoFront | Go | Why |
487
+ |---|---|---|---|
488
+ | Map iteration order | Insertion-order (`Object.entries`) | Randomised | JS objects preserve insertion order. |
489
+ | Integer overflow | IEEE 754 float64 semantics | Wraps at type boundary (e.g. `int32`) | All JS numbers are float64. |
490
+ | Integer precision | Safe up to 2⁵³ | Full width per type (`int64` = 64 bits) | JS `number` limitation. |
491
+ | `cap()` | Always equals `len()` | May exceed `len()` | JS arrays have no separate capacity. |
492
+ | Fixed-size arrays (`[n]T`) | Plain JS arrays (no length enforcement) | Fixed at compile time | Runtime enforcement adds overhead for no JS benefit. |
493
+ | `nil` | Maps to `null` | Typed nil (distinct per type) | JS has no typed nil concept. |
494
+ | `rune` / `byte` | Treated as `int` | Distinct types with UTF-8 encoding | JS strings are UTF-16. |
495
+ | `range` over string | Rune integers via `.codePointAt()` | Runes (UTF-8 code points) | Close match — indices are byte-sequential, values are code points. |
496
+ | `len()` on strings | JS `.length` (UTF-16 code units) | Byte count (UTF-8) | Matching Go would require `TextEncoder` on every call. |
497
+ | `error` type | Plain string | Interface `{ Error() string }` | Practical simplification for JS. |
498
+ | `defer` | `try`/`finally` with a defer stack | Runtime stack unwinding | Covers most cases but not identical to Go internals. |
499
+ | Struct field tags | Parsed, silently discarded | Available via `reflect` | No reflection = no use for tag values. |
500
+ | Pointers (`&x`, `*p`) | Syntax accepted, semantically transparent | True memory indirection | JS has no pointer model. |
501
+ | Three-index slice (`a[lo:hi:max]`) | `max` is parsed but ignored | Sets result capacity | JS arrays have no capacity. |
502
+ | Exported / unexported | Enforced for GoFront packages; external `.d.ts`/npm namespaces are exempt | Access enforced uniformly | External JS APIs use lowercase names by convention. |
379
503
 
380
- ### Semantic differences — JS can't match Go behaviour
504
+ ---
381
505
 
382
- These features exist but behave differently due to fundamental JS/Go runtime differences:
506
+ ## Roadmap
383
507
 
384
- | Feature | GoFront behaviour | Go behaviour | Why |
385
- |---|---|---|---|
386
- | Map iteration order | Insertion-order (`Object.entries`) | Randomised | JS objects preserve insertion order. Wrapping in a custom `Map` class would add runtime overhead for no practical benefit. |
387
- | Integer overflow | IEEE 754 float64 wrap | Wraps at type boundary (e.g. `int32`) | All JS numbers are float64. Emitting `\|0` or `BigInt` for every arithmetic op would be prohibitively expensive. |
388
- | `cap()` | Always equals `len()` | May exceed `len()` | JS arrays don't expose allocation capacity. |
389
- | Fixed-size arrays (`[n]T`) | Plain JS arrays (no length enforcement) | Fixed at compile time | Could add a length check at construction, but runtime enforcement adds overhead for no safety benefit in JS. |
390
- | `rune` / `byte` types | Treated as `int` | Distinct types with UTF-8 encoding | JS strings are UTF-16. Proper rune handling would require wrapping every string operation. |
391
- | `range` over string | JS characters (UTF-16 code units via `Array.from`) | Go runes (UTF-8 code points) | Same UTF-16 vs UTF-8 mismatch. |
392
- | `len()` on strings | JS `.length` (UTF-16 code units) | Byte count (UTF-8) | Matching Go would require `TextEncoder` on every `len(s)` call. |
508
+ See [`docs/ROADMAP.md`](docs/ROADMAP.md) for the full roadmap and release history.
509
+ Design documents for planned features are organised by release under `docs/v*/`
510
+ (e.g. [`docs/v0.0.5/`](docs/v0.0.5/)).
393
511
 
394
512
  ---
395
513
 
@@ -399,4 +517,7 @@ These features exist but behave differently due to fundamental JS/Go runtime dif
399
517
  npm test
400
518
  ```
401
519
 
402
- 468 tests covering language features, type errors, edge cases, DOM (jsdom), external `.d.ts`, npm resolver, multi-file compilation, embedded structs, string formatting, and the example app.
520
+ 655 tests covering language features, type errors, edge cases, DOM (jsdom), external
521
+ `.d.ts`, npm resolver, multi-file compilation, embedded structs, string formatting, map
522
+ iteration order, integer overflow semantics, unused variable detection, unused import
523
+ detection, semantic difference verification, stdlib shim packages, and both example apps.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gofront",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "author": "Luuk van Venrooij",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -21,14 +21,18 @@
21
21
  "type-safe"
22
22
  ],
23
23
  "engines": {
24
- "node": ">=25"
24
+ "node": ">=20"
25
25
  },
26
26
  "type": "module",
27
+ "files": [
28
+ "src/"
29
+ ],
27
30
  "bin": {
28
31
  "gofront": "./src/index.js"
29
32
  },
30
33
  "scripts": {
31
- "build": "node src/index.js",
34
+ "build:simple": "node src/index.js example/simple/src -o example/simple/app.js",
35
+ "build:reactive": "node src/index.js example/reactive/src -o example/reactive/app.js",
32
36
  "test": "node test/run.js",
33
37
  "format": "biome format --write .",
34
38
  "check": "biome check ."