package main import ( "encoding/json" "flag" "fmt" "os" "path/filepath" "strings" ) func embStructsSubCommand(args []string) { cmdName := "emb-structs" cmd := flag.NewFlagSet(cmdName, flag.ExitOnError) cmd.Usage = func() { _, _ = fmt.Fprintf(cmd.Output(), `Usage of %s: Embed Go structs as compact format in the binary. JSON file format: { "prefix": "html5entities", // prefix for the generated const/var "types": { // struct field types "Name": "string", // struct fields "CodePoints": "[]int", "Characters": "[]byte" }, // array of struct data // all data must be a string "data": [ {"Name": "AElig", "CodePoints": ["198"], "Characters": ["0xc3", "0x86"]}, {"Name": "AMP", "CodePoints": ["38"], "Characters": ["0x26"]}, ] } `, cmdName) cmd.PrintDefaults() } inputJSONPath := cmd.String("i", "", "source JSON file path(required)") outputPath := cmd.String("o", "", "output file path(required)") if err := cmd.Parse(args); err != nil || len(*inputJSONPath) == 0 || len(*outputPath) == 0 { usage(cmd.Usage, err) } var source map[string]any inputJSONSource, err := os.ReadFile(*inputJSONPath) if err != nil { panic(err) } if err := json.Unmarshal(inputJSONSource, &source); err != nil { panic(err) } f, err := os.Create(*outputPath) if err != nil { fmt.Printf("Failed to open %s: %v\n", *outputPath, err) os.Exit(1) } defer f.Close() abs, _ := filepath.Abs(*outputPath) pkg := filepath.Base(filepath.Dir(abs)) write := func(ft string, v ...any) { if len(v) == 0 { _, _ = f.WriteString(ft) return } _, _ = f.WriteString(fmt.Sprintf(ft, v...)) } writeln := func(ft string, v ...any) { write(ft+"\n", v...) } writeln("// Code generated by _tools; DO NOT EDIT.") writeln("package " + pkg) prefix := source["prefix"].(string) types := source["types"].(map[string]any) data := source["data"].([]any) writeln("const _%sLength = %d", prefix, len(data)) for prop, _typ := range types { typ := _typ.(string) if typ == "string" { write("const _%s%s string = \"", prefix, prop) for _, _d := range data { d := _d.(map[string]any) v := d[prop].(string) write(v) } writeln(`"`) write("const _%s%sIndex = \"", prefix, prop) for _, _d := range data { d := _d.(map[string]any) v := d[prop].(string) write("\\x%02x", len(v)) } writeln(`"`) continue } if strings.HasPrefix(typ, "[]") { elmTyp := typ[2:] write("var _%s%s = [...]%s{", prefix, prop, elmTyp) for i, _d := range data { d := _d.(map[string]any) arr := d[prop].([]any) for j, a := range arr { v := a.(string) write(v) if i != len(data)-1 || j != len(arr)-1 { write(", ") } } } writeln("}") write("var _%s%sIndex = \"", prefix, prop) for _, _d := range data { d := _d.(map[string]any) arr := d[prop].([]any) write("\\x%02x", len(arr)) } writeln(`"`) continue } write("var _%s%s = [...]%s{", prefix, prop, typ) for i, _d := range data { d := _d.(map[string]any) v := d[prop].(string) write(v) if i != len(data)-1 { write(", ") } } writeln(`}`) } }