mirror of
https://github.com/Dadido3/go-typst.git
synced 2025-04-11 12:13:16 +00:00
Add InjectValues function
This will make CompileWithVariables obsolete, as you can use InjectValues in combination with the normal Compile instead. This also introduces a breaking change with CompileWithVariables, as now invalid identifiers will return an error.
This commit is contained in:
parent
112898d1d7
commit
69bd0ed5b5
17
cli.go
17
cli.go
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 David Vogel
|
||||
// Copyright (c) 2024-2025 David Vogel
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
@ -80,22 +80,17 @@ func (c CLI) Compile(input io.Reader, output io.Writer, options *CLIOptions) err
|
||||
return nil
|
||||
}
|
||||
|
||||
// Compile takes a typst document from input, and renders it into the output writer.
|
||||
// CompileWithVariables takes a typst document from input, and renders it into the output writer.
|
||||
// The options parameter is optional.
|
||||
//
|
||||
// Additionally this will inject the given map of variables into the global scope of the typst document.
|
||||
//
|
||||
// Deprecated: You should use InjectValues in combination with the normal Compile method instead.
|
||||
func (c CLI) CompileWithVariables(input io.Reader, output io.Writer, options *CLIOptions, variables map[string]any) error {
|
||||
varBuffer := bytes.Buffer{}
|
||||
|
||||
// TODO: Use io.pipe instead of a bytes.Buffer
|
||||
|
||||
enc := NewVariableEncoder(&varBuffer)
|
||||
for k, v := range variables {
|
||||
varBuffer.WriteString("#let " + CleanIdentifier(k) + " = ")
|
||||
if err := enc.Encode(v); err != nil {
|
||||
return fmt.Errorf("failed to encode variables with key %q: %w", k, err)
|
||||
}
|
||||
varBuffer.WriteRune('\n')
|
||||
if err := InjectValues(&varBuffer, variables); err != nil {
|
||||
return fmt.Errorf("failed to inject values into Typst markup: %w", err)
|
||||
}
|
||||
|
||||
reader := io.MultiReader(&varBuffer, input)
|
||||
|
9
image.go
9
image.go
@ -1,3 +1,8 @@
|
||||
// Copyright (c) 2024-2025 David Vogel
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
package typst
|
||||
|
||||
import (
|
||||
@ -22,8 +27,10 @@ func (i Image) MarshalTypstVariable() ([]byte, error) {
|
||||
|
||||
// TODO: Make image encoding more efficient: Use reader/writer, baseXX encoding
|
||||
|
||||
// TODO: Consider using raw pixel encoding instead of PNG
|
||||
|
||||
var buf bytes.Buffer
|
||||
buf.WriteString("image.decode(bytes((")
|
||||
buf.WriteString("image.decode(bytes((") // TODO: Pass bytes directly to image once Typst 0.12.0 is not supported anymore
|
||||
for _, b := range buffer.Bytes() {
|
||||
buf.WriteString(strconv.FormatUint(uint64(b), 10) + ",")
|
||||
}
|
||||
|
@ -33,18 +33,24 @@ func (p *testImage) Opaque() bool {
|
||||
}
|
||||
|
||||
func TestImage(t *testing.T) {
|
||||
img := &testImage{image.Rect(0, 0, 255, 255)}
|
||||
img := &testImage{image.Rect(0, 0, 256, 256)}
|
||||
|
||||
// Wrap image.
|
||||
typstImage := typst.Image{img}
|
||||
|
||||
cli := typst.CLI{}
|
||||
|
||||
r := bytes.NewBufferString(`= Image test
|
||||
var r bytes.Buffer
|
||||
|
||||
#TestImage`)
|
||||
if err := typst.InjectValues(&r, map[string]any{"TestImage": typstImage}); err != nil {
|
||||
t.Fatalf("Failed to inject values into Typst markup: %v.", err)
|
||||
}
|
||||
|
||||
if err := cli.CompileWithVariables(r, io.Discard, nil, map[string]any{"TestImage": typstImage}); err != nil {
|
||||
r.WriteString(`= Image test
|
||||
|
||||
#TestImage`) // TODO: Add assertion for the image width and height as soon as it's possible to query that
|
||||
|
||||
if err := cli.Compile(&r, io.Discard, nil); err != nil {
|
||||
t.Fatalf("Failed to compile document: %v.", err)
|
||||
}
|
||||
}
|
||||
|
42
util.go
Normal file
42
util.go
Normal file
@ -0,0 +1,42 @@
|
||||
// Copyright (c) 2025 David Vogel
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
package typst
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
// InjectValues will write the given key-value pairs as Typst markup into output.
|
||||
// This can be used to inject Go values into typst documents.
|
||||
//
|
||||
// Every key in values needs to be a valid identifier, otherwise this function will return an error.
|
||||
// Every value in values will be marshaled according to VariableEncoder into equivalent Typst markup.
|
||||
//
|
||||
// Passing {"foo": 1, "bar": 60 * time.Second} as values will produce the following output:
|
||||
//
|
||||
// #let foo = 1
|
||||
// #let bar = duration(seconds: 60)
|
||||
func InjectValues(output io.Writer, values map[string]any) error {
|
||||
enc := NewVariableEncoder(output)
|
||||
|
||||
for k, v := range values {
|
||||
if !IsIdentifier(k) {
|
||||
return fmt.Errorf("%q is not a valid identifier", k)
|
||||
}
|
||||
if _, err := output.Write([]byte("#let " + CleanIdentifier(k) + " = ")); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := enc.Encode(v); err != nil {
|
||||
return fmt.Errorf("failed to encode variables with key %q: %w", k, err)
|
||||
}
|
||||
if _, err := output.Write([]byte("\n")); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
36
util_test.go
Normal file
36
util_test.go
Normal file
@ -0,0 +1,36 @@
|
||||
package typst
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestInjectValues(t *testing.T) {
|
||||
type args struct {
|
||||
values map[string]any
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantOutput string
|
||||
wantErr bool
|
||||
}{
|
||||
{"empty", args{values: nil}, "", false},
|
||||
{"nil", args{values: map[string]any{"foo": nil}}, "#let foo = none\n", false},
|
||||
{"example", args{values: map[string]any{"foo": 1, "bar": 60 * time.Second}}, "#let foo = 1\n#let bar = duration(seconds: 60)\n", false},
|
||||
{"invalid identifier", args{values: map[string]any{"foo😀": 1}}, "", true},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
output := &bytes.Buffer{}
|
||||
if err := InjectValues(output, tt.args.values); (err != nil) != tt.wantErr {
|
||||
t.Errorf("InjectValues() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if gotOutput := output.String(); gotOutput != tt.wantOutput {
|
||||
t.Errorf("InjectValues() = %v, want %v", gotOutput, tt.wantOutput)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user