package main import ( "bytes" "fmt" "io" "log" "net/http" "os" "path/filepath" "strings" ) func main() { if len(os.Args) <= 1 || os.Args[1] == "serve" { serve() return } switch os.Args[1] { case "build": out := "dist/xjs.js" if len(os.Args) >= 3 && strings.TrimSpace(os.Args[2]) != "" { out = os.Args[2] } if err := build(out); err != nil { log.Fatal(err) } log.Printf("Built %s\n", out) default: fmt.Println("Usage:") fmt.Println(" go run main.go serve # dev server (default)") fmt.Println(" go run main.go build [out.js] # bundle animal.js + layer.js into dist/xjs.js (or out.js)") os.Exit(2) } } func serve() { // Serve files from the current directory fs := http.FileServer(http.Dir(".")) http.Handle("/", fs) log.Println("Listening on :8080...") if err := http.ListenAndServe(":8080", nil); err != nil { log.Fatal(err) } } func readFile(path string) ([]byte, error) { f, err := os.Open(path) if err != nil { return nil, err } defer f.Close() return io.ReadAll(f) } func ensureDirForFile(out string) error { dir := filepath.Dir(out) if dir == "." || dir == "/" { return nil } return os.MkdirAll(dir, 0o755) } func build(out string) error { animal, err := readFile("animal.js") if err != nil { return fmt.Errorf("read animal.js: %w", err) } layer, err := readFile("layer.js") if err != nil { return fmt.Errorf("read layer.js: %w", err) } var buf bytes.Buffer buf.WriteString("// xjs.js - combined single-file build (animal + layer)\n") buf.WriteString("// Generated by `go run main.go build`.\n") buf.WriteString("// NOTE: Do not edit this file directly in development.\n") buf.WriteString("// Edit animal.js / layer.js instead.\n\n") // Keep layer first to match previous bundled layout; runtime lookups are lazy anyway. buf.WriteString("/* --- layer.js --- */\n") buf.Write(layer) if !bytes.HasSuffix(layer, []byte("\n")) { buf.WriteByte('\n') } buf.WriteString("\n/* --- animal.js --- */\n") buf.Write(animal) if !bytes.HasSuffix(animal, []byte("\n")) { buf.WriteByte('\n') } // Export globals expected by docs/users. buf.WriteString("\n;(function(g){\n") buf.WriteString(" try { if (g && g.animal && !g.xjs) g.xjs = g.animal; } catch {}\n") buf.WriteString(" try { if (g && g.XJS_GLOBAL_DOLLAR && !g.$ && g.xjs) g.$ = g.xjs; } catch {}\n") buf.WriteString("})(typeof window !== 'undefined' ? window : (typeof globalThis !== 'undefined' ? globalThis : this));\n") if err := ensureDirForFile(out); err != nil { return fmt.Errorf("mkdir %s: %w", filepath.Dir(out), err) } if err := os.WriteFile(out, buf.Bytes(), 0o644); err != nil { return fmt.Errorf("write %s: %w", out, err) } return nil }