Styx
A document language for mortals.
styx-is ( a document language )
with-features {
that make
it { easy to-love } // also comments
} Minimal punctuation
Everything is space-separated, except inline object form:
sequences ( look super clean )
an-object {
can be
multi line
}
or { inline style , with commas } Minimal quoting
Of course, you can have spaces and special chars:
one bare-scalar
two "double-quoted"
raw r#"raw quoted a-la Rust"#
finally <<HEREDOCS
they work!
HEREDOCS Minimal typing
Objects and sequences contain scalar key-values. Scalars are just opaque text at this stage.
country : NO # boolean false
version : 3.10 # 3.1
comment : "This is a string for sure" country NO // opaque scalar "NO"
version 3.10 // opaque scalar "3.10"
comment "This is a string for sure" // nope, an opaque scalar Get those types out of your document
and into your schema.
Styx schemas aren't just for objects and arrays — they're for every scalar.
// input
host localhost
port 8080 // schema
host @string
port @int Server {
host : "localhost" ,
port : 8080 ,
} It starts with a tree
At this point, it's all still objects, sequences, and opaque scalars.
server
├─ host: "localhost"
├─ port: "8080" ← still text
└─ tls
├─ cert: "/path/cert.pem"
└─ key: "/path/key.pem"Meaning on tap
Interpret scalars as typed values when you need them.
Durations, integers, dates — the rules are in the spec, not implementation-defined.
let port: u16 = doc[ "server" ][ "port" ]. get () ?;
let timeout: Duration = doc[ "timeout" ]. get () ?;
let created: DateTime = doc[ "created" ]. get () ?; let port = doc . server . port . asInt ()
let timeout = doc . timeout . asDuration ()
let created = doc . created . asDateTime () port = doc ["server" ]["port" ].as_int ()
timeout = doc ["timeout" ].as_duration ()
created = doc ["created" ].as_datetime ()Standardized interpretation
not implementation-defined.
Durations like 30s or 1h30m. Integers like 0xff or 1_000_000. RFC 3339 dates. It's all in the spec.
timeout 30s
retry 1h30m
poll 500ms
ttl 7d Duration :: from_secs ( 30 )
Duration :: from_secs ( 5400 )
Duration :: from_millis ( 500 )
Duration :: from_secs ( 604800 ) count 1_000_000
color 0xff5500
mask 0b1111_0000
mode 0o755 1000000_i64
16733440_u32
240_u8
493_u32 pi 3.141_592_653
avogadro 6.022e23
small 1.5e-10
max inf 3.141592653_f64
6.022e23_f64
1.5e-10_f64
f64 :: INFINITY created 2024-03-15T14:30:00Z
enabled true
debug false DateTime ( 2024 , 3 , 15 , 14 , 30 , 0 , UTC )
true
falseSkip the schema
Using Rust? Derive Facet on your types and deserialize directly.
No schema files, no code generation — your types are the schema.
# [ derive ( Facet )]
struct Server {
host : String ,
port : u16 ,
tls : Option < bool >,
}
let server: Server = facet_styx:: from_str ( input) ?; Live the schema
Generate schemas from Rust types or write them by hand.
Doc comments become hover text in your editor and show up in error messages.
/// A server configuration.
Server @object {
/// Hostname or IP address to bind to.
host @default ( localhost @string )
/// Port number (1-65535).
port @default ( 8080 @int { min 1 , max 65535 })
/// Enable TLS. Defaults to false.
tls @default ( false @bool )
} Love the schema
Dynamically typed languages like JavaScript can get a fully-typed object through the schema:
import { parse } from "@bearcove/styx" ;
const config = parse ( input , schema );
console . log ( config ); $ node index.ts
{
"host" : "localhost" ,
"port" : 8080,
"created" : 2024-03-15T14:30:00.000Z // a Date!
}Offensively nice tooling
because you deserve better.
Errors that actually help. Autocomplete that actually works. From your editor to your CI pipeline.
CLI Validation
Validate in CI. Get actionable errors with "did you mean?" suggestions.
See the CLI →Web Playground
Try Styx in your browser with full syntax highlighting and validation.
CodeMirror | MonacoWhat are you waiting for?