How does my configuration language look?
Hello all! I've been working on my mod-loader, and I've been designing a configuration format for both the loader's components and the plugins it loads. I figured the best place to ask this question was somewhere were people frequently deal with different configuration formats :P
In this short series of messages, I am going to be explaining the issues I see with known configuration formats and how I would resolve them, then, finally, I will propose a syntax in small difficulty increments.
I would love to have feedback on anything here! To note: I am not criticizing the following formats, each of them have a well-defined purpose, however I feel like more could be done :P
5 Replies
Why not yaml/toml/json?
All of the above languages approach the problem in different ways, and while all correct, sometimes they fall short for what is commonly needed when setting up a minecraft server.
Why not yaml?
YAML is a great language if you need a really simple configuration:
However:
- It is indentation based, it does not accept TAB keys and will cause errors when a plugin inevitably loads the file.
- Its error messages are just for the syntax, it is then up to the plugin itself to report errors in a more or less effective way.
- It can get confusing on larger files, and often times repetition or otherwise very large files can lead to headaches.
How has this been addressed so far?
- Some plugins have adopted the use of
import: <id>
to import/merge template files or other sections. While this works, it is inconsistent and up to the plugin author if they'd like to introduce it.
- Some plugins have made their error reporting nicer to look at, filled with info or otherwise try to indicate what went wrong in the most user-friendly way. Though this is not always the case.
- Some editors just replace TAB with spaces in YAML files. Except the Pterodactyl editor, I always have issues with that.
What can we do?
- Standardize a way to reuse configuration formats in a sensible and structured way.
- Standardize and prioritize informational and readable error reporting at a language level.
- Remove the need for indentation-based configuration.
Why not toml?
TOML is a very easy and intuitive language, I mean, just look at this:
It also has a very, very nice list of possible data-types which just aren't present in YAML, so for now, this is a very welcome improvement.
However:
- Nested configurations can be hard to read, even when using indentation:
- It can often times be unclear as to which section a key is parented to.
- Configurations are still very much static, handling plugin input still requires custom handling.
- And just like YAML, duplicated or long configs can be hard to read.
What can we do?
- Make it clearer as to which section is which, as well as which option is under which section.
- Standardize a way to dynamically pass in data.
- Standardize a way to reuse configuration.
Why not JSON?
JSON, while harder to type, solves some of our issues:
- It is not indentation based.
- It is easier to figure out what is a child of what.
- It is still somewhat easy to read, depending on who you ask.
For example:
However:
- Typing could be more convenient, especially because of the repeated ""
- Its types are similar in number to that of YAML, which is a step down from TOML.
- We still can't reuse configuration.
- Error messages still need to be defined by the plugin.
- And most importantly, there are no comments!
How has this been addressed so far?
- JSON5 has cleared up the configuration by removing the repeated ""
in keys, unless they contain characters such as -
- JSON5 has added comments to JSON, // making it much nicer to explain configuration
- JSON5 has also added more types or otherwise more ways to define them, such as hexacedimal numbers: 0xCAFEBABE
What can we do?
- We can adopt JSON5's changes to make JSON nicer to read, take the above example:
- We can expand the type system to include things like colors, durations and dates
- And finally we can standardize error messages and reusability, as we said previously.
My solution
It is based off of JSON5
, with some key changes we'll go over soon. For now, this is the most basic config:
Pretty simple, right? Let's add some data
so far so good, everything looks exactly like json for now, let's see how we handle external data
WOAH! What's going on here? We have two new features:
- String interpolation, defined by {...}
, allows us to put values inside of strings (and yes, this means other config values!)
- External string interpolation, an enhancement of string interpolation which is written like ${...}
, it does the same as string interpolation however using plugin data, in this case the plugin directly passed in the event data.
Let's keep it moving, see what types we have.
That's a lot of types! And they all boil down to:
We got types, we got a nicer format, we got dynamic data, let's now solve:
- Reusability
- Error messages
Templates
You can also scope them:
And we can make custom postfixes for different values:
Error messages
These error messages are certainly nicer (and yes, a sidenote, the loader itself provides offline docs), they give you context, and often times help you in fixing the issue. When they can't, they'll just resort to telling you why it's wrong. These messages are done automatically, and are always in the same format across plugins.
Miscellaneous features
Importing
Interpolation with config values
Interpolation with config values AND fallbacks
Arrays
Escaping interpolation
Overriding
Repeating
Schemas exist, they are defined as .hxcs
(Helix Config Schema
), and they look like this:
As far as I remember, this should be everything! I would really value some feedback from people who know more than me, so thank you!
*PS: This will be fully open-sourced along with a loader-independent library, which means this won't be tied strictly to my loader!
Also, things like multiline strings exist!
I may have missed some syntax features, if you want to know more just ask!its like writing code, but as a config file. thats awesome. definitly much more readable
Thank you! You are also not forced to use all of this, you can just stick to the basic config format and it will work just fine :D
Most of this is for more advanced cases where you have more complex configs or series of configs
Reminds me of pkl
Yeah, I definitely took from pkl a bit! Main difference is that this doesn't translate itself to different formats, that way I can do much nicer error checking, error reporting and parsing