go-piml is a Go package that provides functionality to marshal and unmarshal data to and from the PIML (Parenthesis Intended Markup Language) format. PIML is a human-readable, indentation-based data serialization format designed for configuration files and simple data structures.
- Intuitive Syntax: Easy-to-read key-value pairs, supporting nested structures.
- Go-like Tagging: Uses
piml:"tag"struct tags for flexible field mapping. - Primitive Types: Supports strings, integers, floats, and booleans.
- Complex Types: Handles structs, slices (arrays), and maps.
- Nil Handling: Explicitly represents
nilfor pointers, empty slices, and empty maps. - Multi-line Strings: Supports multi-line string values with indentation.
- Comments: Allows single-line comments (lines starting with
#). Inline comments are not supported. In multi-line strings, a leading#can be escaped with a backslash (\#) to be treated as a literal character. - Time Support: Marshals and unmarshals
time.Timevalues using RFC3339Nano format.
PIML uses a simple key-value structure. Keys are enclosed in parentheses (), and values follow. Indentation defines nesting.
(site_name) PIML Demo
(port) 8080
(is_production) false
(version) 1.2
(database)
(host) localhost
(port) 5432
(admins)
> (User)
(id) 1
(name) Alice
> (User)
(id) 2
(name) Bob
(features)
> auth
> logging
> metrics
(description)
This is a sample product description.
It spans multiple lines.
With an empty line in between.
(metadata)
(related_ids) nil
To use go-piml in your Go project, simply run:
go get github.com/fezcode/go-pimlDefine your Go struct with piml tags:
package main
import (
"fmt"
"time"
"github.com/fezcode/go-piml"
)
type User struct {
ID int `piml:"id"`
Name string `piml:"name"`
}
type Config struct {
SiteName string `piml:"site_name"`
Port int `piml:"port"`
IsProduction bool `piml:"is_production"`
Admins []*User `piml:"admins"`
LastUpdated time.Time `piml:"last_updated"`
Description string `piml:"description"`
}
func main() {
cfg := Config{
SiteName: "My Awesome Site",
Port: 8080,
IsProduction: true,
Admins: []*User{
{ID: 1, Name: "Admin One"},
{ID: 2, Name: "Admin Two"},
},
LastUpdated: time.Date(2023, time.November, 10, 15, 30, 0, 0, time.UTC),
Description: "This is a multi-line\ndescription for the site.",
}
pimlData, err := piml.Marshal(cfg)
if err != nil {
fmt.Println("Error marshalling:", err)
return
}
fmt.Println(string(pimlData))
}Output:
(site_name) My Awesome Site
(port) 8080
(is_production) true
(admins)
> (User)
(id) 1
(name) Admin One
> (User)
(id) 2
(name) Admin Two
(last_updated) 2023-11-10T15:30:00Z
(description)
This is a multi-line
description for the site.
package main
import (
"fmt"
"time"
"github.com/fezcode/go-piml"
)
type User struct {
ID int `piml:"id"`
Name string `piml:"name"`
}
type Config struct {
SiteName string `piml:"site_name"`
Port int `piml:"port"`
IsProduction bool `piml:"is_production"`
Admins []*User `piml:"admins"`
LastUpdated time.Time `piml:"last_updated"`
Description string `piml:"description"`
}
func main() {
pimlData := []byte(`
(site_name) My Awesome Site
(port) 8080
(is_production) true
(admins)
> (User)
(id) 1
(name) Admin One
> (User)
(id) 2
(name) Admin Two
(last_updated) 2023-11-10T15:30:00Z
(description)
This is a multi-line
description for the site.
`)
var cfg Config
err := piml.Unmarshal(pimlData, &cfg)
if err != nil {
fmt.Println("Error unmarshalling:", err)
return
}
fmt.Printf("%+v\n", cfg)
for _, admin := range cfg.Admins {
fmt.Printf("Admin: ID=%d, Name=%s\n", admin.ID, admin.Name)
}
}Output:
{SiteName:My Awesome Site Port:8080 IsProduction:true Admins:[0xc0000a4000 0xc0000a4020] LastUpdated:2023-11-10 15:30:00 +0000 UTC Description:This is a multi-line
description for the site.}
Admin: ID=1, Name=Admin One
Admin: ID=2, Name=Admin Two
Contributions are welcome! Please open an issue or submit a pull request.
This project is licensed under the MIT License. See the LICENSE file for details.