- You want bits of programmability in your config language. Else you end up with copy-pasting pieces and adding comments like "must be the same value as foo.bar below!". This sucks enough that you may end up with a config generator for some custom meta-config language, which you need to produce and maintain. You very certainly need symbolic constants, it's great to have simple arithmetics and string concatenation, and ideally you need a way to map a config fragment over a list.
- You don't want a Turing-complete language as your config language. You also don't want to allow any I/O or other effects in that language. You don't want to allow your config parser to do anything but to form a tree of keys and values in memory after reading the config. Javascript is right out. XML is also right out, because entities allow for external resource links, that is, uncontrolled I/O; this was a source of many exploits.
- Nevertheless, you want your configs to be modular when needed, allowing to graft into your main config imported values from some common templates, specific overrides, etc. Direct inclusion is a poor but serviceable approach.
- You want the values in your config be typed. They can be strings by default to save some typing. But you want your config parser to be able to complain when you write a string instead of a number, of a float instead of an integer, or an integer out of representable range (the bane of large numbers in JSON), or a date that cannot be parsed, or a null for a value that cannot be null. This saves you from a ton of nasty surprises when configs are updated.
- You want your config language to have explicit delimiters, so that incompletely copy-pasted constructs would be detected. Hence YAML is a bad choice, JSON5 is a much better choice.
- Of course, you absolutely want comments. JSON is a serialization format, not a human-operated config format.
This is why, I think, CUE, Dhall, and Jsonnet are doing more or less the right thing, but they are a tad large. Maybe something simpler and more compact exists, with some limited programmability and easy syntax.