Closed ghost closed 5 months ago
Thanks for the suggestion. Do you have any use cases for this feature?
well the example in the OP
"name": $self.firstName .. $self.lastName,
would be useful
I guess I was more asking: Why do you need this feature? What problem are you trying to solve?
Despite the current downvotes, I think this would actually be a great addition. YAML files support this via &/*/<< operators, so wherever you use such YAML configurations, you could use JSON5 instead. Substitutions are quite useful in configurations, e.g. docker service files: the same configuration needs to be repeated, with slight variations, across many services. It depends what the goal of JSON5 is. Are we just trying to add minor syntactic sugar to plain JSON files? or are we open to adding extra, more powerful features?
// both the following...
{
shared: { a: 10 },
service: $self.shared
}
{
shared: { a: 10 },
service: { $self.shared }
}
// resolve to
{
shared: { a: 10 },
service: { a: 10 }
}
An idea is to allow a deep merge when prefixed by $$. YAML doesn't support deep merges, so would be an improvement over them. This would allow array merges as well, which YAML also doesn't support. For example:
// object deep merge
{
shared: {a:5, b:{c:10}}
service: {b:{d:15}, $$self.shared}
}
{
shared: {a:5, b:{c:10}}
service: {b:{d:15,c:10}, a:5}
}
// array deep merge
{
shared: [0,1,2],
service: [3,4,$$self.shared,5]
}
{
shared: [0,1,2],
service: [3,4,0,1,2,5]
}
One complaint I've had working with YAML is that it isn't possible to override nested values when merging. An override always applies on a shallow level. For example, suppose I have this config:
shared: &shared
parent:
a: 5
b: 9
service:
<< *shared
parent:
b: 6
In this case, service.parent
overwrites that of shared.parent
, rather than merging them in a deep manner. Unfortunately, a deep merge wouldn't really help here: we want non-referenced service
to merge with the referenced shared
, not the other way around.
However, another idea is to support some very basic templating in JSON5. The implementation would be able to reuse the same backend as is used for regular references/substitution. For example:
{
someConstant: 10,
// define the template function
shared:(x,y) {
sibling: $self.someConstant,
parent: {
child: $x,
$$y
}
}
// use template like a regular reference, but pass variables
service: {
$self.shared("foo", {c:6})
}
}
{
// (result trimmed down)
service: {
sibling: 10,
parent: {
child: "foo",
c: 6
}
}
}
Note the simplicity in that $self
references top level JSON paths, while $x
and $$y
in this example reference the variables from the template call stack. So the reference substitution would behave identically, except in where it looks for the variables to be substituted. I think these simple template substitutions would make JSON5 quite powerful and open up a lot more use cases. In the future we could think about adding even more templating features, like repeating some template call N times, mapping over a list of parameters.
Thanks for your input. While this is a very interesting suggestion, one of the things that makes JSON so easy to use and implement is its simplicity. We follow the same principle in JSON5. It's already significantly more complex than JSON, so adding this feature is against the core principles of JSON5.
something like (this allows for self-recursion too)