conf

conf - HOCON Parser for Go
Login

A Go parser for HOCON (Human-Optimized Config Object Notation) that returns an Abstract Syntax Tree (AST).

Features

Installation

go get src.d10.dev/conf

Code Generator

The conf CLI tool generates type-safe Go code from HOCON configuration files, similar to sqlc:

Installation

go install src.d10.dev/conf/cmd/conf@latest

Usage

# Generate code with defaults (package=main, output=conf_gen.go, name=Conf)
conf generate config.conf

# Customize output
conf generate -package=config -name=AppConfig -output=config.go app.conf

Example

Input (config.conf):

{
    database: { host: localhost, port: 5432, timeout: 30s }
    cache: { size: 512MB }
    servers: ["host1", "host2"]
    debug: true
}

Generate:

conf generate -name=AppConfig config.conf

Generated (conf_gen.go): ```go package main

import ( "time" "src.d10.dev/conf/ast" )

type Database struct { Host string Port int64 Timeout time.Duration }

type Cache struct { Size int64 }

type AppConfig struct { Database Database Cache Cache Servers []string Debug bool }

func LoadAppConfig(root ast.Root) (AppConfig, error) { // ... unmarshal logic ... } ```

Use: ```go package main

import ( "log" "src.d10.dev/conf" )

func main() { root, err := conf.ParseFile("config.conf") if err != nil { log.Fatal(err) }

config, err := LoadAppConfig(root)
if err != nil {
    log.Fatal(err)
}

// Type-safe access
println(config.Database.Host)
println(config.Database.Timeout.String())

} ```

Parsing Usage

Basic Parsing

package main

import (
	"fmt"
	"log"
	"src.d10.dev/conf"
)

func main() {
	input := `{ name: "example", value: 42 }`

	root, err := conf.ParseString(input)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("Parsed: %v\n", root)
}

Parse from File

root, err := conf.ParseFile("config.conf")
if err != nil {
	log.Fatal(err)
}

Parse with Include Resolution

// Resolves include directives
root, err := conf.ParseWithIncludes("config.conf")
if err != nil {
	log.Fatal(err)
}

Parse with Full Resolution

// Resolves both includes and substitutions
root, err := conf.ParseWithResolution("config.conf")
if err != nil {
	log.Fatal(err)
}

HOCON Syntax Examples

Basic Object

{
	name: "John"
	age: 30
	active: true
}

Or with commas:

{
	name: "John",
	age: 30,
	active: true
}

Unquoted Keys and Values

{
	database.host: localhost,
	database.port: 5432
}

Nested Objects

{
	server: {
		host: 0.0.0.0,
		port: 8080
	}
}

Arrays

{
	items: [1, 2, 3],
	names: ["Alice", "Bob"]
}

Substitutions

{
	name: "example",
	greeting: "Hello, ${name}!",
	optional: ${?missing.value}
}

Comments

{
	# This is a comment
	value: 42  // Another comment
}

Multiline Strings

{
	description: """
		This is a multiline
		string value
	"""
}

Duration Literals

{
	timeout: 30s
	interval: 500ms
	delay: 2h
	period: 7d
}

Supported units: ns, us, ms, s, m, h, d

Size Literals

{
	memory: 512MB
	disk: 2GB
	cache: 64KB
	maxSize: 1.5TB
}

Supported units: B, KB, MB, GB, TB, PB, EB, ZB

Architecture

The parser is built in layers:

  1. Lexer (lexer.go): Tokenizes HOCON input with state management
  2. Parser (parser.go): Generated from yacc grammar (hocon.y)
  3. AST (ast/): Type-safe representation of HOCON structure
  4. Resolvers (resolver/):
    • merge.go: Object merging logic
    • include.go: Include directive resolution
    • substitution.go: Variable substitution resolution

AST Structure

The AST preserves all HOCON constructs:

Building

To regenerate the parser from the grammar:

goyacc -o hocon_gen.go hocon.y

Testing

go test -v

Limitations