diff --git a/errors.go b/errors.go index c221e3f..9d6b44d 100644 --- a/errors.go +++ b/errors.go @@ -8,7 +8,7 @@ import ( var stderrRegex = regexp.MustCompile(`^error: (?.+)\n ┌─ (?.+):(?\d+):(?\d+)\n`) -// Error represents a typst error. +// Error represents a generic typst error. type Error struct { Inner error diff --git a/variable-encoder.go b/variable-encoder.go index d836e20..325e85f 100644 --- a/variable-encoder.go +++ b/variable-encoder.go @@ -4,6 +4,7 @@ import ( "encoding" "fmt" "io" + "math" "reflect" "slices" "strconv" @@ -44,7 +45,9 @@ func (e *VariableEncoder) WriteIndentationCharacters() { func (e *VariableEncoder) marshal(v reflect.Value) error { if !v.IsValid() { - return fmt.Errorf("invalid reflect.Value %v", v) + e.WriteString("none") + return nil + //return fmt.Errorf("invalid reflect.Value %v", v) } t := v.Type() @@ -89,14 +92,24 @@ func (e *VariableEncoder) marshal(v reflect.Value) error { e.WriteString(strconv.FormatInt(v.Int(), 10)) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: e.WriteString(strconv.FormatUint(v.Uint(), 10)) - case reflect.Float32: - e.WriteString(strconv.FormatFloat(v.Float(), 'e', -1, 32)) - case reflect.Float64: - e.WriteString(strconv.FormatFloat(v.Float(), 'e', -1, 64)) + case reflect.Float32, reflect.Float64: + f := v.Float() + switch { + case math.IsNaN(f): + e.WriteString("float.nan") + case math.IsInf(f, 1): + e.WriteString("float.inf") + case math.IsInf(f, -1): + e.WriteString("-float.inf") + default: + e.WriteString(strconv.FormatFloat(f, 'e', -1, 64)) + } case reflect.String: return e.encodeString(v) case reflect.Interface, reflect.Pointer: return e.marshal(v.Elem()) + case reflect.Map: + return e.encodeMap(v) case reflect.Struct: return e.encodeStruct(v, t) case reflect.Slice: @@ -141,6 +154,11 @@ func (e *VariableEncoder) encodeString(v reflect.Value) error { } func (e *VariableEncoder) encodeStruct(v reflect.Value, t reflect.Type) error { + if v.NumField() == 0 { + e.WriteString("()") + return nil + } + e.WriteString("(\n") e.indentLevel++ @@ -187,6 +205,11 @@ func (e *VariableEncoder) resolveKeyName(v reflect.Value) (string, error) { } func (e *VariableEncoder) encodeMap(v reflect.Value) error { + if v.Len() == 0 { + e.WriteString("()") + return nil + } + e.WriteString("(\n") e.indentLevel++ diff --git a/variable-encoder_test.go b/variable-encoder_test.go index 1d9f66e..4a3141a 100644 --- a/variable-encoder_test.go +++ b/variable-encoder_test.go @@ -39,10 +39,15 @@ func TestVariableEncoder(t *testing.T) { Foo string Bar int }{"Hey!", 12345}, false, "(\n Foo: \"Hey!\",\n Bar: 12345,\n)"}, + {"struct empty", struct{}{}, false, "()"}, + {"struct empty pointer", (*struct{})(nil), false, "none"}, {"map string string", map[string]string{"Foo": "Bar", "Foo2": "Electric Foogaloo"}, false, "(\n Foo: \"Bar\",\n Foo2: \"Electric Foogaloo\",\n)"}, + {"map string string empty", map[string]string{}, false, "()"}, {"map string string nil", map[string]string(nil), false, "()"}, {"string array", [5]string{"Foo", "Bar"}, false, `("Foo", "Bar", "", "", "")`}, {"string slice", []string{"Foo", "Bar"}, false, `("Foo", "Bar")`}, + {"string slice empty", []string{}, false, `()`}, + {"string slice nil", []string(nil), false, `()`}, {"string slice pointer", &[]string{"Foo", "Bar"}, false, `("Foo", "Bar")`}, } for _, tt := range tests {