gofront 0.0.5 → 0.0.7

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,13 +1,13 @@
1
1
  ## About
2
2
 
3
- I love Go for the backend — simple, type-safe, no nonsense. I like JavaScript for the
4
- frontend — runs everywhere, no setup. What I don't like is JavaScript's loose typing. And
5
- I don't like TypeScript either. I know, controversial. It's fine, I just don't enjoy it.
3
+ Go for the backend: simple, type-safe, no nonsense. JavaScript for the frontend: runs
4
+ everywhere, no setup. The problem is JavaScript's loose typing — and TypeScript never
5
+ quite felt like home either.
6
6
 
7
- So I built GoFront. Go syntax, type safety, compiles to plain ES modules. Same language
7
+ So I built GoFront. Go syntax and type safety, compiling to plain ES modules. One language
8
8
  front and back, no runtime, no framework, no tsconfig.json.
9
9
 
10
- Is this useful? Probably not, but it was fun to build:D
10
+ Probably not useful. Definitely fun to build.
11
11
 
12
12
  ```go
13
13
  package main
@@ -184,7 +184,7 @@ The type checker enforces correctness; JavaScript doesn't need to know.
184
184
 
185
185
  ## Examples — Todo App
186
186
 
187
- There are two example apps — both implement the same todo app to show different aspects
187
+ There are three example apps — all implement the same todo app to show different aspects
188
188
  of GoFront.
189
189
 
190
190
  ### Simple (vanilla DOM)
@@ -202,7 +202,7 @@ example/simple/
202
202
  styles.go ← injectStyles() creates <style> element with all CSS
203
203
  main.go ← createApp() builds DOM shell · setupEvents() · event delegation
204
204
  utils/
205
- utils.go ← Plural() · generic Filter/Map — cross-package import demo
205
+ utils.go ← Plural() · generic Filter — cross-package import demo
206
206
  browser.d.ts ← minimal external type declarations (sleep)
207
207
  index.html ← bare HTML shell, loads app.js as ES module
208
208
  app.js ← generated output
@@ -212,41 +212,99 @@ example/simple/
212
212
 
213
213
  Same app rebuilt with [reactive.js](https://github.com/seriva/microtastic), a tiny
214
214
  signals-based reactive framework. Demonstrates how GoFront integrates with external JS
215
- libraries via `.d.ts` type declarations — the GoFront code uses typed `Signal` values,
216
- `Signals.create()`, `Signals.computed()`, `Signals.batch()`, and `Reactive.bind()`,
217
- all described in a hand-written `browser.d.ts` shim.
215
+ libraries via `.d.ts` type declarations — the entire reactive API surface is typed via a
216
+ hand-written `browser.d.ts` shim and exercised from GoFront source.
218
217
 
219
218
  ```
220
219
  example/reactive/
221
220
  src/
222
221
  types.go ← Todo, Stats, AppElements structs
223
- store.go ← Signal-typed state · Signals.create/computed/batch
224
- render.go ← createAppShell() returns AppElements · ctx.computed/ctx.bind
225
- styles.go ← injectStyles()
226
- main.go ← wires everything together
222
+ store.go ← reactive state: Signals.create/computed/computedAsync/batch/update
223
+ render.go ← Reactive.Component lifecycle · ctx.bind* · setupStatsBar
224
+ styles.go ← per-section cssClass() scoped styles
225
+ main.go ← async boot, Reactive.mount loading placeholder, signal.subscribe/once
227
226
  utils/
228
- utils.go ← Plural() · generic Filter/Map
229
- browser.d.ts ← Signal interface · Signals/Reactive/ComponentContext namespaces
227
+ utils.go ← Plural() · generic Filter
228
+ browser.d.ts ← Signal · ComponentContext · Signals/Reactive namespaces · htmlTag
230
229
  reactive.js ← signals framework (from microtastic)
231
- index.html ← loads reactive.js + app.js
230
+ index.html ← loads reactive.js, exposes helpers, imports app.js
232
231
  app.js ← generated output
233
232
  ```
234
233
 
234
+ The reactive example covers the full reactive.js API surface:
235
+
236
+ | Category | Features used |
237
+ |---|---|
238
+ | HTML helpers | `html` tagged template (via `htmlTag`), `trusted`, `join` |
239
+ | CSS | `cssClass` scoped styles with nested `&` selectors |
240
+ | Signals | `create`, `computed`, `computedAsync`, `batch`, `get`, `peek`, `set`, `update`, `subscribe`, `once` |
241
+ | Reactive namespace | `mount` (loading placeholder), `createComponent`, `scan` |
242
+ | Component context | `bind`, `bindAttr`, `bindBoolAttr`, `bindClass`, `bindText`, `bindStyle`, `bindMultiple`, `computed` |
243
+ | Component lifecycle | `state`, `template`, `styles`, `mount`, `mountTo`, `appendTo`, `refs` (via `data-ref`) |
244
+ | Component instance | `signal`, `effect`, `on` (auto-cleanup event listeners) |
245
+ | Scan attributes | `data-model`, `data-text`, `data-html`, `data-if`, `data-visible`, `data-class-*`, `data-attr-*`, `data-bool-*`, `data-on-*`, `data-ref` |
246
+
247
+ ### gom (stdlib component library + todo app)
248
+
249
+ Browser-native declarative DOM components inspired by
250
+ [gomponents](https://www.gomponents.com). `gom` is a **built-in stdlib package** — no
251
+ import path needed, available in every GoFront program just like `fmt` or `strings`. It
252
+ uses **methods on named non-struct types** so that plain functions and slices can satisfy
253
+ the `Node` interface without any struct boilerplate.
254
+
255
+ ```
256
+ example/gom/
257
+ src/
258
+ types.go ← Todo struct, filter/priority constants
259
+ store.go ← state, mutations, localStorage persistence
260
+ render.go ← gom node builders (pure node tree, no innerHTML)
261
+ styles.go ← appStyles() CSS string
262
+ main.go ← event setup, submitInput, entry point
263
+ utils/ ← Filter[T], Plural, HasText
264
+ app.js ← generated output
265
+ index.html ← HTML shell
266
+ ```
267
+
268
+ Key types and functions (all accessed as `gom.*`, no import needed):
269
+ - `gom.Node` — interface with a single `Mount(parent any)` method
270
+ - `gom.NodeFunc` — `type NodeFunc func(parent any)` with `Mount` method; any function becomes a `Node`
271
+ - `gom.Group` — `type Group []Node` with `Mount` method; composes children in order
272
+ - `gom.El(tag, children...)` — creates an element node
273
+ - `gom.Text(s)` — creates a text node
274
+ - `gom.Attr(name, val)` — generic attribute node; named shortcuts: `gom.Class`, `gom.Href`, `gom.Type`, etc.
275
+ - `gom.If(cond, node)` — conditionally renders a node
276
+ - `gom.Map(slice, fn)` — maps a slice to a `Group` of nodes
277
+ - `gom.Style(css)` — returns a `Node` that injects a `<style>` element; styles are part of the node tree
278
+ - `gom.Mount(selector, n)` — mounts a node into the DOM, replacing the element's content
279
+ - `gom.MountTo(selector, n)` — appends a node without clearing; used to inject styles into `<head>`
280
+ - HTML element helpers: `gom.Div`, `gom.Span`, `gom.Button`, `gom.Input`, `gom.Ul`, `gom.Li`, … (full HTML element set)
281
+
235
282
  ### Features demonstrated
236
283
 
237
- Both apps cover: structs & methods, iota constants, named return values, closures,
238
- slices, `for range`, `switch`, cross-package imports, multi-file same-package compilation,
239
- `async`/`await`, `defer`/`recover`, localStorage persistence, DOM APIs, and generic
240
- utility functions (`Filter[T]`, `Map[T, U]`).
284
+ The simple and reactive examples cover: structs & methods, iota constants, named return
285
+ values, closures, slices, `for range`, `switch`, cross-package imports, multi-file
286
+ same-package compilation, `async`/`await`, `defer`/`recover`, localStorage persistence,
287
+ DOM APIs, and generic utility functions (`Filter[T]`, `Map[T, U]`).
241
288
 
242
289
  The reactive example additionally demonstrates: external `.d.ts` type imports,
243
- `declare namespace` patterns for typing JS libraries, and reactive UI updates via signals.
290
+ `declare namespace` patterns for typing JS libraries, the full reactive signal graph
291
+ (source signals → computed signals → async computed → DOM bindings), reactive UI with
292
+ no `querySelector` or `getElementById` in application code, and `Reactive.Component`
293
+ as the primary composition unit (state, template, styles, mount lifecycle, `data-ref`
294
+ element refs, auto-cleanup event listeners).
295
+
296
+ The gom example additionally demonstrates: **the `gom` built-in stdlib package**,
297
+ styles as nodes (`gom.Style` + `gom.MountTo`), `gom.Map` for list rendering, the
298
+ declarative node-tree pattern (no `innerHTML`, no `querySelector`), and full feature
299
+ parity with the other examples (priority mode, validation, localStorage persistence,
300
+ sync status, drag-and-drop reordering).
244
301
 
245
302
  ### Build and run
246
303
 
247
304
  ```sh
248
305
  npm run build:simple # → example/simple/app.js
249
306
  npm run build:reactive # → example/reactive/app.js
307
+ npm run build:gom # → example/gom/app.js
250
308
  # open the respective index.html in a browser
251
309
  ```
252
310
 
@@ -258,16 +316,18 @@ npm run build:reactive # → example/reactive/app.js
258
316
  gofront <file.go> compile single file → stdout
259
317
  gofront <dir> compile all *.go in directory → stdout
260
318
  gofront <input> -o out.js write output to file (prints elapsed compile time e.g. "15ms")
261
- gofront <input> --check type-check only
262
- gofront <input> --watch watch for changes and recompile
263
- gofront <input> --source-map append inline source map to output
264
- gofront <input> --minify minify output (built-in minifier)
265
- gofront <input> --minify --mangle minify and rename local identifiers
266
- gofront <file.go> --ast dump AST (debug)
267
- gofront <file.go> --tokens dump tokens (debug)
268
- gofront init [dir] scaffold a new project
269
- gofront --version / -v print version
270
- gofront --help / -h print this help
319
+ gofront <input> --check type-check only
320
+ gofront <input> --watch watch for changes and recompile
321
+ gofront <input> -o out.js --serve watch + serve with live reload (default port 3000)
322
+ gofront <input> -o out.js --serve --port 8080 use a custom port
323
+ gofront <input> --source-map append inline source map (single file or directory; multi-file packages emit per-file mappings)
324
+ gofront <input> --minify minify output (built-in minifier)
325
+ gofront <input> --minify --mangle minify and rename local identifiers
326
+ gofront <file.go> --ast dump AST (debug)
327
+ gofront <file.go> --tokens dump tokens (debug)
328
+ gofront init [dir] scaffold a new project
329
+ gofront --version / -v print version
330
+ gofront --help / -h print this help
271
331
  ```
272
332
 
273
333
  ---
@@ -365,6 +425,7 @@ signatures into GoFront's internal type representation.
365
425
  | `error` type | ✓ — interface `{ Error() string }`; custom error types, `errors.Is`/`Unwrap`, `%w` wrapping |
366
426
  | Complex numbers (`complex64`, `complex128`, `3i`) | ✓ — `complex()`, `real()`, `imag()` builtins; `__cmul`/`__cdiv` helpers |
367
427
  | Type definitions, type aliases (`type A = B`) | ✓ |
428
+ | Methods on named non-struct types | ✓ — `type T func(...)` or `type T []E` with methods; emitted as ES6 wrapper classes; satisfies interfaces |
368
429
  | Type conversions, type assertions (plain & comma-ok) | ✓ |
369
430
  | Type switch (`switch v := x.(type)`) | ✓ — compiles to `if/else if` with `typeof` / `instanceof` |
370
431
  | Sized integers (`int8`–`int64`, `uint8`–`uint64`, `float32`) | ✓ — mapped to `number` at runtime |
@@ -403,16 +464,22 @@ signatures into GoFront's internal type representation.
403
464
 
404
465
  | Package | Functions |
405
466
  |---|---|
406
- | `fmt` | `Sprintf`, `Printf`, `Println`, `Print`, `Errorf` — format verbs: `%v`, `%d`, `%s`, `%t`, `%x`, `%o`, `%b`, `%q`, `%e`, `%g`, `%w`, width/precision |
407
- | `strings` | `Contains`, `HasPrefix`, `HasSuffix`, `Index`, `LastIndex`, `Count`, `Repeat`, `Replace`, `ReplaceAll`, `ToUpper`, `ToLower`, `TrimSpace`, `Trim`, `TrimPrefix`, `TrimSuffix`, `TrimLeft`, `TrimRight`, `Split`, `Join`, `EqualFold` |
408
- | `bytes` | `Contains`, `HasPrefix`, `HasSuffix`, `Index`, `Join`, `Split`, `Replace`, `ToUpper`, `ToLower`, `TrimSpace`, `Equal`, `Count`, `Repeat` |
467
+ | `fmt` | `Sprintf`, `Printf`, `Println`, `Print`, `Errorf`, `Fprintf`, `Fprintln`, `Fprint` — format verbs: `%v`, `%d`, `%s`, `%t`, `%x`, `%o`, `%b`, `%q`, `%e`, `%g`, `%w`, width/precision |
468
+ | `strings` | `Contains`, `HasPrefix`, `HasSuffix`, `Index`, `LastIndex`, `Count`, `Repeat`, `Replace`, `ReplaceAll`, `ToUpper`, `ToLower`, `TrimSpace`, `Trim`, `TrimPrefix`, `TrimSuffix`, `TrimLeft`, `TrimRight`, `Split`, `Join`, `EqualFold`; **`Builder`** type (`WriteString`, `WriteByte`, `WriteRune`, `Write`, `String`, `Len`, `Reset`, `Grow`) |
469
+ | `bytes` | `Contains`, `HasPrefix`, `HasSuffix`, `Index`, `Join`, `Split`, `Replace`, `ToUpper`, `ToLower`, `TrimSpace`, `Equal`, `Count`, `Repeat`; **`Buffer`** type (`WriteString`, `WriteByte`, `Write`, `String`, `Bytes`, `Len`, `Reset`) |
409
470
  | `strconv` | `Itoa`, `Atoi`, `FormatBool`, `FormatInt`, `FormatFloat`, `ParseFloat`, `ParseInt`, `ParseBool` |
410
471
  | `sort` | `Ints`, `Float64s`, `Strings`, `Slice`, `SliceStable`, `SliceIsSorted` |
411
472
  | `math` | `Abs`, `Floor`, `Ceil`, `Round`, `Sqrt`, `Cbrt`, `Pow`, `Log`, `Log2`, `Log10`, trig functions + `Pi`, `E`, `MaxFloat64`, `MaxInt`, `MinInt` |
412
473
  | `errors` | `New`, `Is`, `Unwrap` — custom error types via interface satisfaction |
413
474
  | `time` | `Now`, `Since`, `Sleep` + `Millisecond`, `Second`, `Minute`, `Hour` constants |
475
+ | `html` | `EscapeString`, `UnescapeString` |
476
+ | `maps` | `Keys`, `Values`, `Clone`, `Copy`, `Equal`, `EqualFunc`, `Delete`, `DeleteFunc` |
477
+ | `slices` | `Contains`, `Index`, `Equal`, `Compare`, `Sort`, `SortFunc`, `SortStableFunc`, `IsSorted`, `IsSortedFunc`, `Reverse`, `Max`, `Min`, `MaxFunc`, `MinFunc`, `Clone`, `Compact`, `CompactFunc`, `Concat`, `Delete`, `DeleteFunc`, `Insert`, `Replace`, `Grow`, `Clip` |
478
+ | `regexp` | `MustCompile`, `Compile`, `MatchString`, `QuoteMeta`; **`*Regexp`** methods: `MatchString`, `FindString`, `FindStringIndex`, `FindAllString`, `FindStringSubmatch`, `FindAllStringSubmatch`, `ReplaceAllString`, `ReplaceAllLiteralString`, `Split`, `String`. Inline flags (`(?i)`, `(?m)`, `(?s)`) are extracted automatically into the JS `RegExp` constructor. |
414
479
  | `unicode` | `IsLetter`, `IsDigit`, `IsSpace`, `IsUpper`, `IsLower`, `IsPunct`, `IsControl`, `IsPrint`, `IsGraphic`, `ToUpper`, `ToLower` |
415
480
  | `os` | `Exit`, `Args`, `Getenv` |
481
+ | `io` | `Writer`, `Reader`, `ReadWriter`, `Closer` interface types — used for accepting `*strings.Builder`, `*bytes.Buffer`, or any compatible writer/reader |
482
+ | `gom` | Browser-native declarative DOM component library. **Types**: `Node` (interface), `NodeFunc`, `Group`. **Core**: `El(tag, children...)`, `Text(s)`, `Mount(sel, node)`, `MountTo(sel, node)`. **Attributes**: `Attr`, `Class`, `Href`, `Type`, `Src`, `Placeholder`, `DataAttr`, `Style`, `For`, `Name`, `Value`, `Target`, `Rel`, `Alt`, `Title`, `Draggable`, `Role`, `AriaLabel`, `StyleAttr`; boolean: `Disabled`, `Checked`, `Selected`, `Readonly`. **Logic**: `If(cond, node)`, `Map(slice, fn)`. **Elements**: full HTML element set (`Div`, `Span`, `Button`, `Input`, `Ul`, `Li`, `Table`, `Form`, `Img`, `A`, `H1`–`H6`, …) |
416
483
 
417
484
  ### Packages & imports
418
485
 
@@ -484,7 +551,7 @@ you know exactly what to expect.
484
551
 
485
552
  See [`docs/ROADMAP.md`](docs/ROADMAP.md) for the full roadmap and release history.
486
553
  Design documents for planned features are organised by release under `docs/v*/`
487
- (e.g. [`docs/v0.0.5/`](docs/v0.0.5/)).
554
+ (e.g. [`docs/v0.0.8/`](docs/v0.0.8/), [`docs/v0.0.9/`](docs/v0.0.9/)).
488
555
 
489
556
  ---
490
557
 
@@ -494,7 +561,7 @@ Design documents for planned features are organised by release under `docs/v*/`
494
561
  npm test
495
562
  ```
496
563
 
497
- 869 tests covering language features, type errors, edge cases, DOM (jsdom), external
564
+ 990 tests covering language features, type errors, edge cases, DOM (jsdom), external
498
565
  `.d.ts`, npm resolver, multi-file compilation, embedded structs, string formatting, map
499
566
  iteration order, integer overflow semantics, unused variable detection, unused import
500
567
  detection, semantic difference verification, stdlib shim packages, generics (type params,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gofront",
3
- "version": "0.0.5",
3
+ "version": "0.0.7",
4
4
  "author": "Luuk van Venrooij",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -33,12 +33,15 @@
33
33
  "scripts": {
34
34
  "build:simple": "node src/index.js example/simple/src -o example/simple/app.js",
35
35
  "build:reactive": "node src/index.js example/reactive/src -o example/reactive/app.js",
36
- "test": "node test/run.js",
36
+ "build:gom": "node src/index.js example/gom/src -o example/gom/app.js",
37
+ "test": "node test/unit/run.js",
37
38
  "format": "biome format --write .",
38
- "check": "biome check ."
39
+ "check": "biome check .",
40
+ "prepare": "husky"
39
41
  },
40
42
  "devDependencies": {
41
- "@biomejs/biome": "^2.4.11",
43
+ "@biomejs/biome": "^2.4.12",
44
+ "husky": "^9.1.7",
42
45
  "jsdom": "^29.0.2"
43
46
  }
44
47
  }