tools/local-dev: legacy-report-to-json CLI for synthetic UI testing

A Go module under tools/local-dev/legacy-report that converts the
"dg" / "gplus" engine .REP files in tools/local-dev/reports/ into the
JSON shape of pkg/model/report.Report. The output drives a DEV-only
synthetic-mode loader on the UI lobby so the map, inspectors, and
order-overlay can be exercised against rich game states without
playing many turns end-to-end.

Scope is intentionally narrow: only the fields the UI client decodes
today (planets, players, own ship classes, header). Importing
pkg/model/report keeps the parser and the typed contract in lockstep
— any backwards-incompatible schema change breaks the tool's
compilation before it ships. The README spells out the parity rule
for extending the parser alongside future UI decoders.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Ilia Denisov
2026-05-10 11:07:50 +02:00
parent e0e0f00daf
commit 99962b295f
7 changed files with 1033 additions and 0 deletions
@@ -0,0 +1,75 @@
// Command legacy-report-to-json converts a legacy text-format Galaxy
// turn report (the "dg" / "gplus" engines) into the JSON shape of
// pkg/model/report.Report. The resulting file is what the UI client's
// DEV-only synthetic-report loader on the lobby consumes.
package main
import (
"encoding/json"
"flag"
"fmt"
"io"
"os"
legacyreport "galaxy/legacy-report"
)
func main() {
in := flag.String("in", "", "path to legacy .REP file (use - for stdin)")
out := flag.String("out", "", "path to write JSON to (use - or empty for stdout)")
flag.Parse()
if *in == "" {
fmt.Fprintln(os.Stderr, "usage: legacy-report-to-json --in <path|-> [--out <path|->]")
os.Exit(2)
}
r, closeIn, err := openInput(*in)
if err != nil {
fmt.Fprintf(os.Stderr, "open input: %v\n", err)
os.Exit(1)
}
defer closeIn()
rep, err := legacyreport.Parse(r)
if err != nil {
fmt.Fprintf(os.Stderr, "parse: %v\n", err)
os.Exit(1)
}
w, closeOut, err := openOutput(*out)
if err != nil {
fmt.Fprintf(os.Stderr, "open output: %v\n", err)
os.Exit(1)
}
defer closeOut()
enc := json.NewEncoder(w)
enc.SetIndent("", " ")
if err := enc.Encode(rep); err != nil {
fmt.Fprintf(os.Stderr, "encode: %v\n", err)
os.Exit(1)
}
}
func openInput(path string) (io.Reader, func(), error) {
if path == "-" {
return os.Stdin, func() {}, nil
}
f, err := os.Open(path)
if err != nil {
return nil, nil, err
}
return f, func() { _ = f.Close() }, nil
}
func openOutput(path string) (io.Writer, func(), error) {
if path == "" || path == "-" {
return os.Stdout, func() {}, nil
}
f, err := os.Create(path)
if err != nil {
return nil, nil, err
}
return f, func() { _ = f.Close() }, nil
}