diff --git a/README.md b/README.md
index 3952800..857ae7f 100644
--- a/README.md
+++ b/README.md
@@ -20,22 +20,35 @@ Use at your own discretion for production systems.
## Features
-- PDF, SVG and PNG generation.
+- PDF, SVG, PNG and HTML generation.
- All Typst parameters are discoverable and documented in [options.go](options.go).
- Go-to-Typst Value Encoder: Seamlessly inject any Go values.
- Encode and inject images as a Typst markup simply by [wrapping](image.go) `image.Image` types or byte slices with raw JPEG or PNG data.
- Errors from Typst CLI are returned as structured Go error objects with detailed information, such as line numbers and file paths.
- Uses stdio; No temporary files will be created.
+- Supports native Typst installations and the official Docker image.
- Good unit test coverage.
## Installation
-1. Use `go get github.com/Dadido3/go-typst` inside of your project to add this module to your project.
-2. Install Typst by following [the instructions in the Typst repository].
+Use `go get github.com/Dadido3/go-typst` inside of your project to add this module to your project.
-## Runtime requirements
+## Usage
-This module assumes that the Typst executable is accessible from your system's PATH.
+This module needs either a native installation of Typst, or a working Docker installation.
+The following subsections will show how to use this library in detail.
+
+### Native Typst installation
+
+The basic usage pattern for calling a natively installed Typst executable looks like this:
+
+```go
+typstCaller := typst.CLI{}
+
+err := typstCaller.Compile(input, output, options)
+```
+
+In this case the module assumes that the Typst executable is accessible from your system's PATH.
Ensure that you have [Typst] installed on any machine that your project will be executed.
You can install it by following [the instructions in the Typst repository].
@@ -43,7 +56,7 @@ Alternatively you can pack the Typst executable with your application.
In this case you have to provide the path to the executable when setting up the `typst.CLI` object:
```go
-typstCLI := typst.CLI{
+typstCaller := typst.CLI{
ExecutablePath: "./typst", // Relative path to executable.
}
```
@@ -51,9 +64,75 @@ typstCLI := typst.CLI{
> [!NOTE]
> Make sure to follow the Typst license requirements when you pack and distribute the Typst executable with your software.
-## Usage
+### Docker
-Here we will create a simple PDF document by passing a reader with Typst markup into `typstCLI.Compile` and then let it write the resulting PDF data into a file:
+To use the official Typst docker image ensure that you have a working Docker installation.
+
+This module will automatically pull and run a Docker container with the latest supported Typst image.
+The basic usage pattern is similar to the CLI variant:
+
+```go
+typstCaller := typst.Docker{}
+
+err := typstCaller.Compile(input, output, options)
+```
+
+#### Tips and tricks
+
+As the Typst instance that's running inside the container is fully encapsulated, you have pass through any resources manually.
+This requires a bit more set up than using a native installation.
+
+Let's say you want to compile a document which imports other local Typst markup files.
+In this case you have to ensure that you mount any needed folders and files to the Docker container.
+You also have to set up the root of Typst to that mounted directory, or a parent of it:
+
+```go
+typstCaller := typst.Docker{
+ Volumes: []string{"./test-files:/markup"},
+}
+
+r := bytes.NewBufferString(`#include "hello-world.typ"`)
+
+var w bytes.Buffer
+err := typstCaller.Compile(r, &w, &typst.OptionsCompile{Root: "/markup"})
+```
+
+This will mount `./test-files` to `/markup` inside the Docker container.
+When Typst compiles the input buffer `r`, it expects `./test-files/hello-world.typ` to exist outside of the container.
+
+Another thing is that the Dockerized version of Typst doesn't see your system fonts.
+To get all your system fonts mounted into the container, you can add the volume parameter `/usr/share/fonts:/usr/share/fonts` to your `typst.Docker`.
+For example:
+
+```go
+typstCaller := typst.Docker{
+ Volumes: []string{
+ "./test-files:/markup",
+ "/usr/share/fonts:/usr/share/fonts",
+ },
+}
+```
+
+The same applies when you want to use custom fonts.
+You need to mount the folder containing the fonts, and then you have to tell Typst where the fonts are mounted to inside the container:
+
+```go
+typstCaller := typst.Docker{
+ Volumes: []string{"./test-files:/fonts"},
+}
+
+err := typstCaller.Compile(input, output, &typst.OptionsCompile{FontPaths: []string{"/fonts"}})
+```
+
+## Caller interface
+
+`typst.CLI` and `typst.Docker` both implement the `typst.Caller` interface.
+
+## More examples
+
+### Simple document
+
+Here we will create a simple PDF document by passing a reader with Typst markup into `typstCaller.Compile` and then let it write the resulting PDF data into a file:
```go
func main() {
@@ -70,23 +149,69 @@ A library to generate documents and reports by utilizing the command line versio
- Uses stdio; No temporary files need to be created.
- Test coverage of most features.`)
- typstCLI := typst.CLI{}
+ typstCaller := typst.CLI{}
- f, err := os.Create("output.pdf")
+ f, err := os.Create(filepath.Join(".", "documentation", "images", "readme-example-simple.svg"))
if err != nil {
t.Fatalf("Failed to create output file: %v.", err)
}
defer f.Close()
- if err := typstCLI.Compile(r, f, nil); err != nil {
+ if err := typstCaller.Compile(r, f, &typst.OptionsCompile{Format: typst.OutputFormatSVG}); err != nil {
t.Fatalf("Failed to compile document: %v.", err)
}
}
```
-The resulting document will look like this:
+Output:
-
+
+
+### Value injection
+
+If you need to create documents that rely on data coming from your Go application, you can use `typst.InjectValues` to encode any Go variables, structures, maps, arrays, slices into their respective Typst markup counterparts:
+
+```go
+func main() {
+ var markup bytes.Buffer
+
+ customValues := map[string]any{
+ "time": time.Now(),
+ "customText": "Hey there!",
+ }
+
+ // Inject Go values as Typst markup.
+ if err := typst.InjectValues(&markup, customValues); err != nil {
+ t.Fatalf("Failed to inject values into Typst markup: %v.", err)
+ }
+
+ // Some Typst markup using the previously injected values.
+ markup.WriteString(`#set page(width: 100mm, height: auto, margin: 5mm)
+#customText | Some date and time: #time.display()`)
+
+ f, err := os.Create(filepath.Join(".", "documentation", "images", "readme-example-injection.svg"))
+ if err != nil {
+ t.Fatalf("Failed to create output file: %v.", err)
+ }
+ defer f.Close()
+
+ typstCaller := typst.CLI{}
+ if err := typstCaller.Compile(&markup, f, &typst.OptionsCompile{Format: typst.OutputFormatSVG}); err != nil {
+ t.Fatalf("Failed to compile document: %v.", err)
+ }
+}
+```
+
+Output:
+
+
+
+### Templates
+
+You can also write your own templates and call them with custom data.
+A tutorial for the Typst side can be found in the [Typst documentation: Making a Template](https://typst.app/docs/tutorial/making-a-template/).
+
+An example on how to invoke Typst templates can be found in the [passing-values example package](examples/passing-values).
[the instructions in the Typst repository]: https://github.com/typst/typst?tab=readme-ov-file#installation
[Typst]: https://typst.app/
diff --git a/cli_test.go b/cli_test.go
index c30047c..b314c40 100644
--- a/cli_test.go
+++ b/cli_test.go
@@ -28,9 +28,9 @@ func TestCLI_VersionString(t *testing.T) {
}
func TestCLI_Fonts(t *testing.T) {
- caller := typst.CLI{}
+ typstCaller := typst.CLI{}
- result, err := caller.Fonts(nil)
+ result, err := typstCaller.Fonts(nil)
if err != nil {
t.Fatalf("Failed to get available fonts: %v.", err)
}
@@ -40,9 +40,9 @@ func TestCLI_Fonts(t *testing.T) {
}
func TestCLI_FontsWithOptions(t *testing.T) {
- caller := typst.CLI{}
+ typstCaller := typst.CLI{}
- result, err := caller.Fonts(&typst.OptionsFonts{IgnoreSystemFonts: true})
+ result, err := typstCaller.Fonts(&typst.OptionsFonts{IgnoreSystemFonts: true})
if err != nil {
t.Fatalf("Failed to get available fonts: %v.", err)
}
@@ -52,9 +52,9 @@ func TestCLI_FontsWithOptions(t *testing.T) {
}
func TestCLI_FontsWithFontPaths(t *testing.T) {
- caller := typst.CLI{}
+ typstCaller := typst.CLI{}
- result, err := caller.Fonts(&typst.OptionsFonts{IgnoreSystemFonts: true, FontPaths: []string{filepath.Join(".", "test-files")}})
+ result, err := typstCaller.Fonts(&typst.OptionsFonts{IgnoreSystemFonts: true, FontPaths: []string{filepath.Join(".", "test-files")}})
if err != nil {
t.Fatalf("Failed to get available fonts: %v.", err)
}
diff --git a/docker_test.go b/docker_test.go
index 62060f4..74cbdbe 100644
--- a/docker_test.go
+++ b/docker_test.go
@@ -23,11 +23,11 @@ func typstDockerImage() string {
}
func TestDocker_VersionString(t *testing.T) {
- caller := typst.Docker{
+ typstCaller := typst.Docker{
Image: typstDockerImage(),
}
- v, err := caller.VersionString()
+ v, err := typstCaller.VersionString()
if err != nil {
t.Fatalf("Failed to get typst version: %v.", err)
}
@@ -36,11 +36,11 @@ func TestDocker_VersionString(t *testing.T) {
}
func TestDocker_Fonts(t *testing.T) {
- caller := typst.Docker{
+ typstCaller := typst.Docker{
Image: typstDockerImage(),
}
- result, err := caller.Fonts(nil)
+ result, err := typstCaller.Fonts(nil)
if err != nil {
t.Fatalf("Failed to get available fonts: %v.", err)
}
@@ -50,11 +50,11 @@ func TestDocker_Fonts(t *testing.T) {
}
func TestDocker_FontsWithOptions(t *testing.T) {
- caller := typst.Docker{
+ typstCaller := typst.Docker{
Image: typstDockerImage(),
}
- result, err := caller.Fonts(&typst.OptionsFonts{IgnoreSystemFonts: true})
+ result, err := typstCaller.Fonts(&typst.OptionsFonts{IgnoreSystemFonts: true})
if err != nil {
t.Fatalf("Failed to get available fonts: %v.", err)
}
@@ -64,12 +64,12 @@ func TestDocker_FontsWithOptions(t *testing.T) {
}
func TestDocker_FontsWithFontPaths(t *testing.T) {
- caller := typst.Docker{
+ typstCaller := typst.Docker{
Image: typstDockerImage(),
Volumes: []string{"./test-files:/fonts"},
}
- result, err := caller.Fonts(&typst.OptionsFonts{IgnoreSystemFonts: true, FontPaths: []string{"/fonts"}})
+ result, err := typstCaller.Fonts(&typst.OptionsFonts{IgnoreSystemFonts: true, FontPaths: []string{"/fonts"}})
if err != nil {
t.Fatalf("Failed to get available fonts: %v.", err)
}
diff --git a/documentation/images/readme-1.svg b/documentation/images/readme-1.svg
deleted file mode 100644
index 6b2fb72..0000000
--- a/documentation/images/readme-1.svg
+++ /dev/null
@@ -1,584 +0,0 @@
-
diff --git a/documentation/images/readme-example-injection.svg b/documentation/images/readme-example-injection.svg
new file mode 100644
index 0000000..2cfb81e
--- /dev/null
+++ b/documentation/images/readme-example-injection.svg
@@ -0,0 +1,125 @@
+
diff --git a/documentation/images/readme-example-simple.svg b/documentation/images/readme-example-simple.svg
new file mode 100644
index 0000000..e046513
--- /dev/null
+++ b/documentation/images/readme-example-simple.svg
@@ -0,0 +1,571 @@
+
diff --git a/examples/passing-values/main.go b/examples/passing-values/main.go
index 6c75bd3..0cd7fe3 100644
--- a/examples/passing-values/main.go
+++ b/examples/passing-values/main.go
@@ -46,8 +46,8 @@ func main() {
}
defer f.Close()
- typstCLI := typst.CLI{}
- if err := typstCLI.Compile(&markup, f, nil); err != nil {
+ typstCaller := typst.CLI{}
+ if err := typstCaller.Compile(&markup, f, nil); err != nil {
log.Panicf("Failed to compile document: %v.", err)
}
}
diff --git a/examples/simple/main.go b/examples/simple/main.go
index 2b2f092..964dd32 100644
--- a/examples/simple/main.go
+++ b/examples/simple/main.go
@@ -30,8 +30,8 @@ This document was created at #%s.display() using typst-go.`, date)
}
defer f.Close()
- typstCLI := typst.CLI{}
- if err := typstCLI.Compile(&markup, f, nil); err != nil {
+ typstCaller := typst.CLI{}
+ if err := typstCaller.Compile(&markup, f, nil); err != nil {
log.Panic("failed to compile document: %w", err)
}
}
diff --git a/readme_test.go b/readme_test.go
index 0ae4480..74b257c 100644
--- a/readme_test.go
+++ b/readme_test.go
@@ -8,12 +8,82 @@ package typst_test
import (
"bytes"
"os"
+ "path/filepath"
"testing"
+ "time"
"github.com/Dadido3/go-typst"
)
func TestREADME1(t *testing.T) {
+ input, output, options := new(bytes.Reader), new(bytes.Buffer), new(typst.OptionsCompile)
+ // -----------------------
+ typstCaller := typst.CLI{}
+
+ err := typstCaller.Compile(input, output, options)
+ // -----------------------
+ if err != nil {
+ t.Fatalf("Failed to compile document: %v.", err)
+ }
+}
+
+func TestREADME3(t *testing.T) {
+ input, output, options := new(bytes.Reader), new(bytes.Buffer), new(typst.OptionsCompile)
+ // -----------------------
+ typstCaller := typst.Docker{}
+
+ err := typstCaller.Compile(input, output, options)
+ // -----------------------
+ if err != nil {
+ t.Fatalf("Failed to compile document: %v.", err)
+ }
+}
+
+func TestREADME4(t *testing.T) {
+ // -----------------------
+ typstCaller := typst.Docker{
+ Volumes: []string{"./test-files:/markup"},
+ }
+
+ r := bytes.NewBufferString(`#include "hello-world.typ"`)
+
+ var w bytes.Buffer
+ err := typstCaller.Compile(r, &w, &typst.OptionsCompile{Root: "/markup"})
+ // -----------------------
+ if err != nil {
+ t.Fatalf("Failed to compile document: %v.", err)
+ }
+}
+
+func TestREADME5(t *testing.T) {
+ // -----------------------
+ typstCaller := typst.Docker{
+ Volumes: []string{
+ "./test-files:/markup",
+ "/usr/share/fonts:/usr/share/fonts",
+ },
+ }
+ // -----------------------
+
+ if _, err := typstCaller.Fonts(nil); err != nil {
+ t.Fatalf("Failed to get available fonts: %v.", err)
+ }
+}
+func TestREADME6(t *testing.T) {
+ input, output := new(bytes.Reader), new(bytes.Buffer)
+ // -----------------------
+ typstCaller := typst.Docker{
+ Volumes: []string{"./test-files:/fonts"},
+ }
+
+ err := typstCaller.Compile(input, output, &typst.OptionsCompile{FontPaths: []string{"/fonts"}})
+ // -----------------------
+ if err != nil {
+ t.Fatalf("Failed to compile document: %v.", err)
+ }
+}
+
+func TestREADME7(t *testing.T) {
r := bytes.NewBufferString(`#set page(width: 100mm, height: auto, margin: 5mm)
= go-typst
@@ -27,15 +97,44 @@ A library to generate documents and reports by utilizing the command line versio
- Uses stdio; No temporary files need to be created.
- Test coverage of most features.`)
- typstCLI := typst.CLI{}
+ typstCaller := typst.CLI{}
- f, err := os.Create("output.pdf")
+ f, err := os.Create(filepath.Join(".", "documentation", "images", "readme-example-simple.svg"))
if err != nil {
t.Fatalf("Failed to create output file: %v.", err)
}
defer f.Close()
- if err := typstCLI.Compile(r, f, nil); err != nil {
+ if err := typstCaller.Compile(r, f, &typst.OptionsCompile{Format: typst.OutputFormatSVG}); err != nil {
+ t.Fatalf("Failed to compile document: %v.", err)
+ }
+}
+
+func TestREADME8(t *testing.T) {
+ var markup bytes.Buffer
+
+ customValues := map[string]any{
+ "time": time.Now(),
+ "customText": "Hey there!",
+ }
+
+ // Inject Go values as Typst markup.
+ if err := typst.InjectValues(&markup, customValues); err != nil {
+ t.Fatalf("Failed to inject values into Typst markup: %v.", err)
+ }
+
+ // Some Typst markup using the previously injected values.
+ markup.WriteString(`#set page(width: 100mm, height: auto, margin: 5mm)
+#customText | Some date and time: #time.display()`)
+
+ f, err := os.Create(filepath.Join(".", "documentation", "images", "readme-example-injection.svg"))
+ if err != nil {
+ t.Fatalf("Failed to create output file: %v.", err)
+ }
+ defer f.Close()
+
+ typstCaller := typst.CLI{}
+ if err := typstCaller.Compile(&markup, f, &typst.OptionsCompile{Format: typst.OutputFormatSVG}); err != nil {
t.Fatalf("Failed to compile document: %v.", err)
}
}
diff --git a/value-encoder_test.go b/value-encoder_test.go
index 657a8a8..9d088ea 100644
--- a/value-encoder_test.go
+++ b/value-encoder_test.go
@@ -195,10 +195,10 @@ func TestValueEncoder(t *testing.T) {
// Compile to test parsing.
if !tt.wantErr {
- typstCLI := typst.CLI{}
+ typstCaller := typst.CLI{}
input := strings.NewReader("#" + result.String())
var output bytes.Buffer
- if err := typstCLI.Compile(input, &output, nil); err != nil {
+ if err := typstCaller.Compile(input, &output, nil); err != nil {
t.Errorf("Failed to compile generated Typst markup: %v", err)
}
}