// This is a bconf file
@extends "./base.bconf"
$app_env = env("APP_ENV")
title = "bconf example"
env = $app_env
admins = [
{ name = "John Doe"; email = "john@example.com" },
{ name = "Jane Smith"; email = "jane@example.com" }
]
admins[0] = {
name = "Cooler John Doe"
email = "coolerjohn@example.com"
}
server {
port = env("PORT")
timeout_ms = 30_000
cors {
enabled
allowed_origins = ["https://example.com", "https://${$app_env}.example.com"]
}
}
server.max_connections = 4Composable
bconf is designed with a single objective in mind: make it easy to compose large or complex configurations.
It is trivial to breakdown and organize large objects or arrays into more manageable chunks.
Flexible
Built-in dynamic features such as reading an environment variable, extended files and importing/exporting variables use generic syntax.
This means it is easy to implement custom modifiers and directives to enable common logic specific for your needs.
Simple
At its core, bconf is not inventing anything new. The syntax and features should be familiar to anyone who has programmed.
A Quick Overview
Strings
Strings can either be single-line or multi-line. A multi-line string uses three quotation marks as its delimiter and allows for raw tabs and newline characters
single_line = "The quick brown fox jumps over the lazy dog"
multi_line = """
Roses are red,
Violets are blue
"""Both single- and multi-line support escape sequences and embedded values. Almost any value can be used as an embedded value
$root = "/Users/brody"
path = "${$root}/projects/bconf/src"Variables
Keys that start with a dollar sign ($) are a mutable variable. If they start with two dollar signs ($$) they are a constant and cannot be reassigned. Variables can be used as a value and their value will be deeply copied
$$PORT = 8080
$domain = "https://example.com"
config.domain = $domain
config.port = $$PORTVariable keys will not appear in the resolved hash-map
// $config will not appear in the output
$config = { domain = "https://example.com"; port = 8080 }Resolvers
Resolvers are basically just if-else statements, allowing for a single key to have a different value if certain criteria is met. Branches are evaluated first to last and are lazily evaluated when parsing. They are enclosed in parentheses (()), with branches separated by a pipe (|)
auth.token_expiry = (
| eq(env("APP_ENV"), "prod") => "1hr"
| "6hr"
)Modifiers
Modifiers are simply function calls. They can take any arbitrary number of arguments and must always return a value. They are evaluated when parsing. Arguments are enclosed with parentheses (()) and must have a leading identifier
// The final value will be `trim = "modifier example"`
title = trim(" modifier example ")Directives
Identifiers that start with an at-symbol (@) are a directive. Directives take any number of arguments which are provided as the unevaluated input. Bare identifiers are allowed as arguments. A directive can return a value and/or modify the document
// Will insert the resolved value of the "./base.bconf" file
@extends "./base.bconf"
config.port = 8080More bconf
bconf supports more values, features, syntax, and many built-in modifiers and directives
Read the full spec