package ast import ( "encoding/json" "fmt" "sort" "strings" "time" ) // MakeSushi generates a JSON string for an ast Table, which is compatible // with BurntSushi's TOML testing tool (https://github.com/BurntSushi/toml-test) func (t Table) MakeSushi() string { return MakeSushi(NewValue(TypeTable, t)) } // MakeSushi generates a JSON string for an ast Value, which is compatible // with BurntSushi's TOML testing tool (https://github.com/BurntSushi/toml-test) func MakeSushi(value *Value) string { switch value.Type { case TypeString: return renderValue("string", value.Data[0].(string)) case TypeInteger: return renderValue("integer", fmt.Sprintf("%d", value.Data[0].(int64))) case TypeFloat: return renderValue("float", fmt.Sprintf("%v", value.Data[0].(float64))) case TypeBool: return renderValue("bool", fmt.Sprintf("%t", value.Data[0].(bool))) case TypeOffsetDateTime: return renderValue("datetime", value.Data[0].(time.Time).Format(time.RFC3339Nano)) case TypeLocalDateTime: return renderValue("local_datetime", value.Data[0].(time.Time).Format("2006-01-02 15:04:05.999999999")) case TypeLocalDate: return renderValue("local_date", value.Data[0].(time.Time).Format("2006-01-02")) case TypeLocalTime: return renderValue("local_time", value.Data[0].(time.Time).Format("15:04:05.999999999")) case TypeArrayOfTables: fallthrough case TypeArray: // BurntSushi's tests sees [ {inline: "table"}, {array: "definitions"} ] // as an array of tables, so here we accomodate for that situation // by checking for that case and render such inline array definition // as if it were an [[array.of.tables]]. arr := value.Data[0].(*Array) values := make([]string, 0, arr.Length) for i := arr.First; i != nil; i = i.Next { values = append(values, MakeSushi(i.Value)) } if arr.ItemType == TypeTable { return fmt.Sprintf("[%s]", strings.Join(values, ", ")) } return fmt.Sprintf(`{"type": "array", "value": [%s]}`, strings.Join(values, ", ")) case TypeImplicitTable: fallthrough case TypeTable: pairs := value.Data[0].(Table) keys := make([]string, len(pairs)) i := 0 for k := range pairs { keys[i] = k i++ } sort.Strings(keys) values := make([]string, len(pairs)) for i, k := range keys { values[i] = fmt.Sprintf("%q: %s", k, MakeSushi(pairs[k])) } return fmt.Sprintf("{%s}", strings.Join(values, ", ")) default: panic(fmt.Sprintf("Unhandled data type: %s", value.Type)) } } func renderValue(t string, v string) string { return fmt.Sprintf("{%q: %q, %q: %s}", "type", t, "value", toJSON(v)) } func toJSON(s string) string { j, err := json.Marshal(s) if err != nil { panic(fmt.Sprintf("unable to JSON encode %q: %s", s, err)) } return string(j) }