Skip to content

Commit c3876b3

Browse files
committed
Rename Variable* to Value*
- Rename MarshalVariable to MarshalValue - Rename NewVariableEncoder to NewValueEncoder - Rename VariableEncoder to ValueEncoder - Rename VariableMarshaler to ValueMarshaler - Rename MarshalTypstVariable to MarshalTypstValue There are now wrappers which ensure compatibility with code that still uses some of the old functions/types. - Improve image_test.go by adding an assertion - Rename all occurrences of Variable to Value - Remove "TODO: Handle images..." as that's already working with the image wrapper - Update README.md
1 parent 7c87e3f commit c3876b3

File tree

8 files changed

+88
-55
lines changed

8 files changed

+88
-55
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Use at your own discretion for production systems.
2020

2121
- PDF, SVG and PNG generation.
2222
- All Typst parameters are discoverable and documented in [cli-options.go](cli-options.go).
23-
- Go-to-Typst Object Encoder: Seamlessly inject any Go values (Including `image.Image` with a [wrapper](image.go)) into Typst documents via the provided encoder.
23+
- Go-to-Typst Value Encoder: Seamlessly inject any Go values (Including `image.Image` with a [wrapper](image.go)) into Typst documents via the provided encoder.
2424
- Errors from Typst CLI are returned as structured Go error objects with detailed information, such as line numbers and file paths.
2525
- Uses stdio; No temporary files will be created.
2626
- Good unit test coverage.

examples/simple/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import (
1212

1313
func main() {
1414
// Convert a time.Time value into Typst markup.
15-
date, err := typst.MarshalVariable(time.Now())
15+
date, err := typst.MarshalValue(time.Now())
1616
if err != nil {
1717
log.Panicf("Failed to marshal date into Typst markup: %v", err)
1818
}

image.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ import (
1515

1616
// Image can be used to encode any image.Image into a typst image.
1717
//
18-
// For this, just wrap any image.Image with this type before passing it to MarshalVariable or a VariableEncoder.
18+
// For this, just wrap any image.Image with this type before passing it to MarshalValue or a ValueEncoder.
1919
type Image struct{ image.Image }
2020

21-
func (i Image) MarshalTypstVariable() ([]byte, error) {
21+
func (i Image) MarshalTypstValue() ([]byte, error) {
2222
var buffer bytes.Buffer
2323

2424
if err := png.Encode(&buffer, i); err != nil {

image_test.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,9 @@ func TestImage(t *testing.T) {
4848

4949
r.WriteString(`= Image test
5050
51-
#TestImage`) // TODO: Add assertion for the image width and height as soon as it's possible to query that
51+
#TestImage
52+
53+
#assert(type(TestImage) == content, message: "TestImage is not of expected type: got " + str(type(TestImage)) + ", want content")`) // TODO: Add another assertion for the image width and height as soon as it's possible to query that
5254

5355
if err := cli.Compile(&r, io.Discard, nil); err != nil {
5456
t.Fatalf("Failed to compile document: %v.", err)

util.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,14 @@ import (
1616
// This can be used to inject Go values into typst documents.
1717
//
1818
// Every key in values needs to be a valid identifier, otherwise this function will return an error.
19-
// Every value in values will be marshaled according to VariableEncoder into equivalent Typst markup.
19+
// Every value in values will be marshaled according to ValueEncoder into equivalent Typst markup.
2020
//
2121
// Passing {"foo": 1, "bar": 60 * time.Second} as values will produce the following output:
2222
//
2323
// #let foo = 1
2424
// #let bar = duration(seconds: 60)
2525
func InjectValues(output io.Writer, values map[string]any) error {
26-
enc := NewVariableEncoder(output)
26+
enc := NewValueEncoder(output)
2727

2828
// We will have to iterate over the sorted list of map keys.
2929
// Otherwise the output is not deterministic, and tests will fail randomly.
@@ -36,7 +36,7 @@ func InjectValues(output io.Writer, values map[string]any) error {
3636
return err
3737
}
3838
if err := enc.Encode(v); err != nil {
39-
return fmt.Errorf("failed to encode variables with key %q: %w", k, err)
39+
return fmt.Errorf("failed to encode values with key %q: %w", k, err)
4040
}
4141
if _, err := output.Write([]byte("\n")); err != nil {
4242
return err

variable-encoder.go renamed to value-encoder.go

Lines changed: 38 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) 2024 David Vogel
1+
// Copyright (c) 2024-2025 David Vogel
22
//
33
// This software is released under the MIT License.
44
// https://opensource.org/licenses/MIT
@@ -18,49 +18,49 @@ import (
1818
"time"
1919
)
2020

21-
// MarshalVariable takes any go type and returns a typst markup representation as a byte slice.
22-
func MarshalVariable(v any) ([]byte, error) {
21+
// MarshalValue takes any go type and returns a typst markup representation as a byte slice.
22+
func MarshalValue(v any) ([]byte, error) {
2323
var buf bytes.Buffer
2424

25-
enc := NewVariableEncoder(&buf)
25+
enc := NewValueEncoder(&buf)
2626
if err := enc.Encode(v); err != nil {
2727
return nil, err
2828
}
2929

3030
return buf.Bytes(), nil
3131
}
3232

33-
// VariableMarshaler can be implemented by types to support custom typst marshaling.
34-
type VariableMarshaler interface {
35-
MarshalTypstVariable() ([]byte, error)
33+
// ValueMarshaler can be implemented by types to support custom Typst marshaling.
34+
type ValueMarshaler interface {
35+
MarshalTypstValue() ([]byte, error)
3636
}
3737

38-
type VariableEncoder struct {
38+
type ValueEncoder struct {
3939
indentLevel int
4040

4141
writer io.Writer
4242
}
4343

44-
// NewVariableEncoder returns a new encoder that writes into w.
45-
func NewVariableEncoder(w io.Writer) *VariableEncoder {
46-
return &VariableEncoder{
44+
// NewValueEncoder returns a new encoder that writes into w.
45+
func NewValueEncoder(w io.Writer) *ValueEncoder {
46+
return &ValueEncoder{
4747
writer: w,
4848
}
4949
}
5050

51-
func (e *VariableEncoder) Encode(v any) error {
51+
func (e *ValueEncoder) Encode(v any) error {
5252
return e.marshal(reflect.ValueOf(v))
5353
}
5454

55-
func (e *VariableEncoder) writeString(s string) error {
55+
func (e *ValueEncoder) writeString(s string) error {
5656
return e.writeBytes([]byte(s))
5757
}
5858

59-
func (e *VariableEncoder) writeRune(r rune) error {
59+
func (e *ValueEncoder) writeRune(r rune) error {
6060
return e.writeBytes([]byte{byte(r)})
6161
}
6262

63-
func (e *VariableEncoder) writeStringLiteral(s []byte) error {
63+
func (e *ValueEncoder) writeStringLiteral(s []byte) error {
6464
dst := make([]byte, 0, len(s)+5)
6565

6666
dst = append(dst, '"')
@@ -85,19 +85,19 @@ func (e *VariableEncoder) writeStringLiteral(s []byte) error {
8585
return e.writeBytes(dst)
8686
}
8787

88-
func (e *VariableEncoder) writeBytes(b []byte) error {
88+
func (e *ValueEncoder) writeBytes(b []byte) error {
8989
if _, err := e.writer.Write(b); err != nil {
9090
return fmt.Errorf("failed to write into writer: %w", err)
9191
}
9292

9393
return nil
9494
}
9595

96-
func (e *VariableEncoder) writeIndentationCharacters() error {
96+
func (e *ValueEncoder) writeIndentationCharacters() error {
9797
return e.writeBytes(slices.Repeat([]byte{' ', ' '}, e.indentLevel))
9898
}
9999

100-
func (e *VariableEncoder) marshal(v reflect.Value) error {
100+
func (e *ValueEncoder) marshal(v reflect.Value) error {
101101
if !v.IsValid() {
102102
return e.writeString("none")
103103
//return fmt.Errorf("invalid reflect.Value %v", v)
@@ -134,8 +134,18 @@ func (e *VariableEncoder) marshal(v reflect.Value) error {
134134
return nil
135135
}
136136

137-
// TODO: Handle images, maybe create a wrapper type that does this
137+
if t.Implements(reflect.TypeFor[ValueMarshaler]()) {
138+
if m, ok := v.Interface().(ValueMarshaler); ok {
139+
bytes, err := m.MarshalTypstValue()
140+
if err != nil {
141+
return fmt.Errorf("error calling MarshalTypstValue for type %s: %w", t.String(), err)
142+
}
143+
return e.writeBytes(bytes)
144+
}
145+
return e.writeString("none")
146+
}
138147

148+
// TODO: Remove this in a future update, it's only here for compatibility reasons
139149
if t.Implements(reflect.TypeFor[VariableMarshaler]()) {
140150
if m, ok := v.Interface().(VariableMarshaler); ok {
141151
bytes, err := m.MarshalTypstVariable()
@@ -222,11 +232,11 @@ func (e *VariableEncoder) marshal(v reflect.Value) error {
222232
return err
223233
}
224234

225-
func (e *VariableEncoder) encodeString(v reflect.Value) error {
235+
func (e *ValueEncoder) encodeString(v reflect.Value) error {
226236
return e.writeStringLiteral([]byte(v.String()))
227237
}
228238

229-
func (e *VariableEncoder) encodeStruct(v reflect.Value, t reflect.Type) error {
239+
func (e *ValueEncoder) encodeStruct(v reflect.Value, t reflect.Type) error {
230240
if v.NumField() == 0 {
231241
return e.writeString("()")
232242
}
@@ -276,7 +286,7 @@ func (e *VariableEncoder) encodeStruct(v reflect.Value, t reflect.Type) error {
276286
return e.writeRune(')')
277287
}
278288

279-
func (e *VariableEncoder) resolveKeyName(v reflect.Value) (string, error) {
289+
func (e *ValueEncoder) resolveKeyName(v reflect.Value) (string, error) {
280290
// From encoding/json/encode.go.
281291
if v.Kind() == reflect.String {
282292
return v.String(), nil
@@ -297,7 +307,7 @@ func (e *VariableEncoder) resolveKeyName(v reflect.Value) (string, error) {
297307
return "", fmt.Errorf("unsupported map key type %q", v.Type().String())
298308
}
299309

300-
func (e *VariableEncoder) encodeMap(v reflect.Value) error {
310+
func (e *ValueEncoder) encodeMap(v reflect.Value) error {
301311
if v.Len() == 0 {
302312
return e.writeString("()")
303313
}
@@ -357,7 +367,7 @@ func (e *VariableEncoder) encodeMap(v reflect.Value) error {
357367
return e.writeRune(')')
358368
}
359369

360-
func (e *VariableEncoder) EncodeByteSlice(bb []byte) error {
370+
func (e *ValueEncoder) EncodeByteSlice(bb []byte) error {
361371
if err := e.writeString("bytes(("); err != nil {
362372
return err
363373
}
@@ -385,7 +395,7 @@ func (e *VariableEncoder) EncodeByteSlice(bb []byte) error {
385395
return e.writeString("))")
386396
}
387397

388-
func (e *VariableEncoder) encodeSlice(v reflect.Value, t reflect.Type) error {
398+
func (e *ValueEncoder) encodeSlice(v reflect.Value, t reflect.Type) error {
389399

390400
// Special case for byte slices.
391401
if t.Elem().Kind() == reflect.Uint8 {
@@ -417,7 +427,7 @@ func (e *VariableEncoder) encodeSlice(v reflect.Value, t reflect.Type) error {
417427
return e.writeRune(')')
418428
}
419429

420-
func (e *VariableEncoder) encodeArray(v reflect.Value) error {
430+
func (e *ValueEncoder) encodeArray(v reflect.Value) error {
421431
if err := e.writeRune('('); err != nil {
422432
return err
423433
}
@@ -443,7 +453,7 @@ func (e *VariableEncoder) encodeArray(v reflect.Value) error {
443453
return e.writeRune(')')
444454
}
445455

446-
func (e *VariableEncoder) encodeTime(t time.Time) error {
456+
func (e *ValueEncoder) encodeTime(t time.Time) error {
447457
return e.writeString(fmt.Sprintf("datetime(year: %d, month: %d, day: %d, hour: %d, minute: %d, second: %d)",
448458
t.Year(),
449459
t.Month(),
@@ -454,6 +464,6 @@ func (e *VariableEncoder) encodeTime(t time.Time) error {
454464
))
455465
}
456466

457-
func (e *VariableEncoder) encodeDuration(d time.Duration) error {
467+
func (e *ValueEncoder) encodeDuration(d time.Duration) error {
458468
return e.writeString(fmt.Sprintf("duration(seconds: %d)", int(math.Round(d.Seconds()))))
459469
}

variable-encoder_test.go renamed to value-encoder_test.go

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) 2024 David Vogel
1+
// Copyright (c) 2024-2025 David Vogel
22
//
33
// This software is released under the MIT License.
44
// https://opensource.org/licenses/MIT
@@ -18,7 +18,7 @@ import (
1818
"github.com/google/go-cmp/cmp"
1919
)
2020

21-
func TestMarshalVariable(t *testing.T) {
21+
func TestMarshalValue(t *testing.T) {
2222
tests := []struct {
2323
name string
2424
arg any
@@ -31,33 +31,33 @@ func TestMarshalVariable(t *testing.T) {
3131
}
3232
for _, tt := range tests {
3333
t.Run(tt.name, func(t *testing.T) {
34-
got, err := typst.MarshalVariable(tt.arg)
34+
got, err := typst.MarshalValue(tt.arg)
3535
if (err != nil) != tt.wantErr {
36-
t.Errorf("MarshalVariable() error = %v, wantErr %v", err, tt.wantErr)
36+
t.Errorf("MarshalValue() error = %v, wantErr %v", err, tt.wantErr)
3737
return
3838
}
3939
if !reflect.DeepEqual(got, tt.want) {
40-
t.Errorf("MarshalVariable() = %v, want %v", got, tt.want)
40+
t.Errorf("MarshalValue() = %v, want %v", got, tt.want)
4141
}
4242
})
4343
}
4444
}
4545

46-
type VariableMarshalerType []byte
46+
type ValueMarshalerType []byte
4747

48-
func (v VariableMarshalerType) MarshalTypstVariable() ([]byte, error) {
48+
func (v ValueMarshalerType) MarshalTypstValue() ([]byte, error) {
4949
result := append([]byte{'"'}, v...)
5050
result = append(result, '"')
5151

5252
return result, nil
5353
}
5454

55-
type VariableMarshalerTypePointer []byte
55+
type ValueMarshalerTypePointer []byte
5656

57-
var variableMarshalerTypePointer = VariableMarshalerTypePointer("test")
58-
var variableMarshalerTypePointerNil = VariableMarshalerTypePointer(nil)
57+
var valueMarshalerTypePointer = ValueMarshalerTypePointer("test")
58+
var valueMarshalerTypePointerNil = ValueMarshalerTypePointer(nil)
5959

60-
func (v *VariableMarshalerTypePointer) MarshalTypstVariable() ([]byte, error) {
60+
func (v *ValueMarshalerTypePointer) MarshalTypstValue() ([]byte, error) {
6161
if v != nil {
6262
result := append([]byte{'"'}, *v...)
6363
result = append(result, '"')
@@ -87,7 +87,7 @@ func (v *TextMarshalerTypePointer) MarshalText() ([]byte, error) {
8787
return nil, fmt.Errorf("no data")
8888
}
8989

90-
func TestVariableEncoder(t *testing.T) {
90+
func TestValueEncoder(t *testing.T) {
9191

9292
tests := []struct {
9393
name string
@@ -156,11 +156,11 @@ func TestVariableEncoder(t *testing.T) {
156156
{"byte slice 1", []byte{1}, false, `bytes((1,))`},
157157
{"byte slice empty", []byte{}, false, `bytes(())`},
158158
{"byte slice nil", []byte(nil), false, `bytes(())`},
159-
{"MarshalTypstVariable value", VariableMarshalerType("test"), false, `"test"`},
160-
{"MarshalTypstVariable value nil", VariableMarshalerType(nil), false, `""`},
161-
{"MarshalTypstVariable pointer", &variableMarshalerTypePointer, false, `"test"`},
162-
{"MarshalTypstVariable pointer nil", &variableMarshalerTypePointerNil, false, `""`},
163-
{"MarshalTypstVariable nil pointer", struct{ A *VariableMarshalerTypePointer }{nil}, true, ``},
159+
{"MarshalTypstValue value", ValueMarshalerType("test"), false, `"test"`},
160+
{"MarshalTypstValue value nil", ValueMarshalerType(nil), false, `""`},
161+
{"MarshalTypstValue pointer", &valueMarshalerTypePointer, false, `"test"`},
162+
{"MarshalTypstValue pointer nil", &valueMarshalerTypePointerNil, false, `""`},
163+
{"MarshalTypstValue nil pointer", struct{ A *ValueMarshalerTypePointer }{nil}, true, ``},
164164
{"MarshalText value", TextMarshalerType("test"), false, `"test"`},
165165
{"MarshalText value nil", TextMarshalerType(nil), false, `""`},
166166
{"MarshalText pointer", &textMarshalerTypePointer, false, `"test"`},
@@ -179,12 +179,12 @@ func TestVariableEncoder(t *testing.T) {
179179
t.Parallel()
180180

181181
var result bytes.Buffer
182-
vEnc := typst.NewVariableEncoder(&result)
182+
vEnc := typst.NewValueEncoder(&result)
183183

184184
err := vEnc.Encode(tt.params)
185185
switch {
186186
case err != nil && !tt.wantErr:
187-
t.Fatalf("Failed to encode typst variables: %v", err)
187+
t.Fatalf("Failed to encode typst values: %v", err)
188188
case err == nil && tt.wantErr:
189189
t.Fatalf("Expected error, but got none")
190190
}

variable-encoder-compat.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright (c) 2025 David Vogel
2+
//
3+
// This software is released under the MIT License.
4+
// https://opensource.org/licenses/MIT
5+
6+
package typst
7+
8+
import "io"
9+
10+
// This exists for compatibility reasons.
11+
12+
// Deprecated: Use NewValueEncoder instead, as this will be removed in a future version.
13+
func NewVariableEncoder(w io.Writer) *ValueEncoder { return NewValueEncoder(w) }
14+
15+
// Deprecated: Use MarshalValue instead, as this will be removed in a future version.
16+
func MarshalVariable(v any) ([]byte, error) { return MarshalValue(v) }
17+
18+
// Deprecated: Use ValueMarshaler interface instead, as this will be removed in a future version.
19+
type VariableMarshaler interface {
20+
MarshalTypstVariable() ([]byte, error)
21+
}

0 commit comments

Comments
 (0)