forked from bearcove/styx
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathREADME.md.in
More file actions
333 lines (245 loc) · 7.38 KB
/
README.md.in
File metadata and controls
333 lines (245 loc) · 7.38 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
# Styx
At least it's not YAML!
## Styx the straightforward
Imagine JSON
```json
{
"key": "value"
}
```
But you remove everything that's getting in the way: the double quotes,
the colon, even the comma:
```styx
{
key value
}
```
Of course you can have the comma back if you want to put everything in a single line:
```styx
{key value, koi tuvalu}
```
Not far enough? Wanna get rid of the brackets? Okay, but only for the top-level object:
```styx
key value
koi tuvalu
```
What about arrays? They're called sequences and they use parentheses:
```styx
methods (GET POST PUT)
```
They're always whitespace-separated, never comma-separated.
## Styx the typed
```styx
name "John Doe"
age 97
retired true
```
Hey, which type are those values? Any type you want them to.
Scalars are just text atoms, `97` is not any more a number
than `https://example.org/` is.
Types matter at exactly two times:
- Validation via [schemas](https://styx.bearcove.eu/reference/spec/schema/) (which are also Styx documents)
- Deserialization, in either flavor (dynamic or static typing)
In dynamic typing flavor, your Styx document gets parsed into a tree,
and then you get to request "field name as type string" — and if it can't
be coerced into a string, you get an error at that point.
In static typing flavor, you may for example deserialize to:
```rust
#[derive(Facet)]
struct Does {
name: String,
age: number,
retired: bool,
}
```
And then the type mapping is, well, what you'd expect.
This solves the Norway problem:
```styx
country no
```
This `no` is not a boolean, not a string, not a number, it's everything, everywhere,
all at once, until you _need_ it to be something.
## Styx the nerd
Sometimes a value isn't quite enough, and you want to tag it:
```styx
this (is an untagged list)
that @special(list I hold dear)
```
Remember `()` are for sequences. They're not for grouping/precedence/calls.
You can tag objects, too:
```styx
rule @path_prefix{
prefix /api
route_to localhost:9000 // still no need to double-quote anything
// oh yeah also comments just work
}
```
That's because Styx was designed to play nice with sum types,
like Rust enums:
```rust
enum Alternatives {
NoPayload,
TuplePayload(u32, u32),
StructPayload { name: String },
}
```
And so, tags are a natural way to _select_ a variant:
```styx
alts (
@no_payload@
@tuple_payload(3 7)
@struct_payload{name Gisèle}
)
```
Did you notice the `@` at the end of `@no_payload@`? Not a typo:
that's the unit value. It means "nothing", "none", kinda like "null"
but a little superior.
`@` is a value like any other:
```styx
sparse_seq (1 2 @ 8 9)
```
And in fact, wanna know a secret? `@` is not even the canonical form
of unit: `@@` is.
An empty tag degenerates to `@`, and a tag without a paylod defaults to
a payload of `@`.
Therefore:
```styx
@ // tag=@, payload=@ (implied)
@@ // tag=@, payload=@
@tag // tag=tag, payload=@ (implied)
@tag@ // tag=tag, payload=@
@tag"must" // tag=tag, payload=must
@tag() // tag=tag, payload=() aka empty sequence
```
Importantly, there is NEVER ANY SPACE between a tag and its payload.
Spaces separate seq elements or key-value pairs in object context:
```styx
// this is a key-value pair:
@tag () // key(tag=tag, payload=@) value(tag=@, payload=())
// this is a DIFFERENT key-value pair
@tag() // key(tag=tag, payload=()) value(tag=@, payload=@)
```
Is it confusing? Maybe. Little bit.
## Styx the objective
We've just seen this in the last gotcha:
```styx
@tag() // key(tag=tag, payload=()) value(tag=@, payload=@)
```
Which, okay, `@tag()` is the entire key. But where's the value?
It's omitted. It defaults to `@`:
```styx
key @ // explicitly set to unit
koi // implicitly set to unit
```
So, key-value pairs can be missing a value. And dotted keys create nested structure:
```styx
server.host localhost
// equivalent to
server {host localhost}
```
And object attribute syntax provides a compact way to build objects:
```styx
{
web domain>example.org port>9000
api domain>api.example.org port>9001
}
```
And that's /it/ with the weirdness. (Don't worry, there are comprehensive
specifications and test suites).
Some unfamiliar bits, but hopefully not too many, which lets us...
## Styx the schematic
...define Styx schemas in Styx itself.
```styx
schema {
/// The root structure of a schema file.
@ @object{
/// Schema metadata (required).
meta @Meta
/// External schema imports (optional).
imports @optional(@map(@string @string))
/// Type definitions: @ for document root, strings for named types.
schema @map(@union(@string @unit) @Schema)
}
// etc.
}
```
Are those doc comments? Yes. Parsers are taught to keep them and attach them to
the next element. This means your styx documents can be validated against a
schema:
* by a CLI, locally, in CI
* by an LSP, in your code editor
* honestly anytime for any reason
And that your code editor (mine's [Zed](https://zed.dev)) can have the full
code editing experience: autocomplete, documentation on hover, jump to definition
(in schema), hover for field documentation, etc.
It's... so nice.
## Styx the one last thing
Oh! Also, HEREDOCs:
```styx
examples (
{
name hello.rs
source <<SRC,rust
fn main() {
println!("Hello from Rust!")
}
SRC
}
)
```
The `,rust` is just a hint which is used by your editor to inject syntax
highlighting from the embedded language :)
## Implementations
There is a spec for parsing, schema validation, and error reporting,
tracked with [Tracey](https://github.com/bearcove/tracey) and available
on the [styx website](https://styx.bearcove.eu).
The flagship implementation is, of course, the Rust one — across multiple
crates like `facet-styx` and `serde_styx`, but not just.
There's a TypeScript implementation in the repository, and probably more
to come.
## Editor Support
<p>
<a href="https://zed.dev">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./static/sponsors/zed-dark.svg">
<img src="./static/sponsors/zed-light.svg" height="40" alt="Zed">
</picture>
</a>
</p>
Styx has first-class support for [Zed](https://zed.dev) with syntax highlighting, LSP integration, and more.
## Documentation
See [styx.bearcove.eu](https://styx.bearcove.eu) for full documentation.
## Sponsors
Thanks to all individual sponsors:
<p>
<a href="https://github.com/sponsors/fasterthanlime">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./static/sponsors/github-dark.svg">
<img src="./static/sponsors/github-light.svg" height="40" alt="GitHub Sponsors">
</picture>
</a>
<a href="https://patreon.com/fasterthanlime">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./static/sponsors/patreon-dark.svg">
<img src="./static/sponsors/patreon-light.svg" height="40" alt="Patreon">
</picture>
</a>
</p>
...along with corporate sponsors:
<p>
<a href="https://zed.dev">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./static/sponsors/zed-dark.svg">
<img src="./static/sponsors/zed-light.svg" height="40" alt="Zed">
</picture>
</a>
<a href="https://depot.dev?utm_source=styx">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./static/sponsors/depot-dark.svg">
<img src="./static/sponsors/depot-light.svg" height="40" alt="Depot">
</picture>
</a>
</p>
CI runs on [Depot](https://depot.dev/) runners.
## License
MIT OR Apache-2.0