frontmatter

repository·master·Indexed 41 days ago

https://github.com/adrg/frontmatter

A Go library to detect and decode front matter formats such as YAML, JSON, and TOML from content files. It provides functions like Parse and MustParse to extract metadata into structs and return the remaining document body, with support for custom delimiters and unmarshaling logic via the Format struct.

Tokens
2K
Snippets
9
Records
9
Agent score
46%

What's inside frontmatter

  1. Parse front matter using default formats

    master

    Use frontmatter.Parse to detect and decode front matter from an io.Reader. The function returns the remaining content (the 'rest' of the document) and an error. You must provide a pointer to a struct where the fields match the front matter keys (using appropriate struct tags like yaml:, json:, or toml:).

    If the presence of front matter is mandatory for your application, use frontmatter.MustParse instead, which will panic if no front matter is found.

    package main
    
    import (
    	"fmt"
    	"strings"
    
    	"github.com/adrg/frontmatter"
    )
    
    var input = `
    ---
    name: "frontmatter"
    tags: ["go", "yaml", "json", "toml"]
    ---
    rest of the content`
    
    func main() {
    	var matter struct {
    		Name string   ` + "`yaml:" + "`name`" + `
    		Tags []string ` + "`yaml:" + "`tags`" + `
    	}
    
    	// Parse returns the content after the front matter and an error
    	rest, err := frontmatter.Parse(strings.NewReader(input), &matter)
    	if err != nil {
    		// Handle error
    	}
    
    	fmt.Printf("%+v\n", matter)
    	fmt.Println(string(rest))
    }
  2. Define custom front matter formats

    master

    If the default supported formats are not suitable, you can provide a custom list of *frontmatter.Format objects to the frontmatter.Parse function.

    To create a custom format, use frontmatter.NewFormat(prefix, suffix, unmarshalFunc). The unmarshalFunc should be a function compatible with the standard unmarshaling pattern (e.g., yaml.Unmarshal).

    package main
    
    import (
    	"fmt"
    	"strings"
    
    	"github.com/adrg/frontmatter"
    	"gopkg.in/yaml.v2"
    )
    
    var input = `
    ...
    name: "frontmatter"
    tags: ["go", "yaml", "json", "toml"]
    ...
    rest of the content`
    
    func main() {
    	var matter struct {
    		Name string   ` + "`yaml:" + "`name`" + `
    		Tags []string ` + "`yaml:" + "`tags`" + `
    	}
    
    	// Define custom formats with specific delimiters and an unmarshaler
    	formats := []*frontmatter.Format{
    		frontmatter.NewFormat("...", "...", yaml.Unmarshal),
    	}
    
    	// Pass the custom formats as variadic arguments to Parse
    	rest, err := frontmatter.Parse(strings.NewReader(input), &matter, formats...)
    	if err != nil {
    		// Handle error
    	}
    
    	fmt.Printf("%+v\n", matter)
    	fmt.Println(string(rest))
    }
  3. Parse front matter using MustParse()

    master

    The MustParse function behaves like Parse, but it treats the absence of front matter as an error. If no front matter is found in the reader, it returns ErrNotFound.

    Use MustParse when your application logic requires that front matter must be present for the content to be valid.

    // Example usage of MustParse
    // Returns ErrNotFound if no front matter is detected
    data, err := frontmatter.MustParse(reader, &myConfigStruct)
    if errors.Is(err, frontmatter.ErrNotFound) {
        // handle missing front matter
    }
  4. Create a new front matter format with NewFormat

    master

    Use NewFormat to quickly create a Format instance with standard settings. It initializes UnmarshalDelims and RequiresNewLine to false by default.

    Signature: func NewFormat(start, end string, unmarshal UnmarshalFunc) *Format

    import (
        "encoding/json"
        "github.com/adrg/adrg/frontmatter"
    )
    
    // Creates a format using '---' as start/end delimiters and JSON unmarshaling
    format := frontmatter.NewFormat("---", "---", json.Unmarshal)
  5. Parse front matter using Parse()

    master

    The Parse function decodes front matter from an io.Reader into the provided interface v and returns the remaining content as a byte slice.

    If no front matter is detected, Parse returns the original data unchanged and leaves v untouched. You can specify custom formats by passing *Format arguments; if none are provided, the library uses default supported formats (YAML, TOML, and JSON).

    Supported default formats:

    • YAML: Identified by --- / --- or ---yaml / ---.
    • TOML: Identified by +++ / +++ or ---toml / ---.
    • JSON: Identified by ;;; / ;;;, ---json / ---, or a single JSON object followed by an empty line.
    // Example usage of Parse
    // data is the remaining content after the front matter
    // err is returned if decoding fails
    data, err := frontmatter.Parse(reader, &myConfigStruct)
  6. Handle missing front matter with ErrNotFound

    master

    When using MustParse, if the input reader does not contain any detectable front matter, the function returns the ErrNotFound error. You can check for this specific error using errors.Is.

    if errors.Is(err, frontmatter.ErrNotFound) {
        // The front matter was not found
    }
  7. Define a custom front matter format with Format

    master

    The Format struct defines how to detect and decode front matter within a document. You can use it to specify the delimiters and the unmarshaling logic required for a specific format.

    Fields:

    • Start: The starting delimiter (e.g., --- or ---yaml).
    • End: The ending delimiter (e.g., ---).
    • Unmarshal: An UnmarshalFunc used to decode the data once detected.
    • UnmarshalDelims: A boolean indicating if the delimiters themselves should be included in the data passed to the unmarshaler. Usually false.
    • RequiresNewLine: A boolean indicating if an empty line is required immediately after the front matter block. Usually false.
    import "encoding/json"
    
    // Example of a custom format definition
    myFormat := &frontmatter.Format{
        Start:           "<!--meta-->",
        End:             "<!--/meta-->",
        Unmarshal:       json.Unmarshal,
        UnmarshalDelims: false,
        RequiresNewLine: false,
    }
  8. Use UnmarshalFunc for decoding data

    master

    The UnmarshalFunc type is a function signature used to decode raw bytes into a provided value. It must match the following signature:

    type UnmarshalFunc func(data []byte, v interface{}) error

    // Example of a compatible function signature
    func myCustomDecoder(data []byte, v interface{}) error {
        // custom decoding logic
        return nil
    }