-
Notifications
You must be signed in to change notification settings - Fork 552
JSONM
JSONM is a JSON extension that allows using macro definitions inside JSON files.
The main goals of this format are to make configuration files more readable and to get rid of scripts that generate huge configuration files.
JSONM is superset of JSON. Any JSON object may be treated as JSON with macros. JSON with macros is also a valid JSON object – the difference lies in enhancing some JSON properties to allow reuse of similar parts of large JSON objects.
Using a simple preprocessor, we generate standard JSON objects from user-friendly JSONM by processing all macros and substituting all constants. .
JSONM is a JSON object with a special optional key macros:
{
"macros": {
"macroName1": macroDefinition,
"macroName2": macroDefinition,
…
},
"customProperty1": valueWithMacros,
"customProperty2": valueWithMacros
}
-
value
any JSON value (string, object, number, etc.) -
valueWithMacros
JSON value that may containmacroCall,paramSubstitution,builtInCall -
macroCall
"@macroName(param1,param2,…)"
or
{
"type": "macroName",
"paramName1": valueWithMacros,
"paramName2": valueWithMacros,
…
}
-
paramSubstitutionstring of form %paramName%. Examples: "%paramName%", "a%paramName%b". %paramName% will be replaced with value of the corresponding parameter. If the whole string is a parameter substitution (i.e., "%paramName%") parameter values may be any valueWithParams. Otherwise, it should be a string. -
builtInCallBasically the same as template call, but has no short form.
{
"type": "if|transform|process",
… params for this call …
}
JSONM allows C-style comments, which are removed by the preprocessor. Example:
{
// some comment here
"key": /* and one more comment here */ "value/**/"
}After preprocessing:
{
"key": "value/**/"
}Macro is a reusable piece of JSON. One can think about it as a function that
takes an arbitrary list of values and returns valueWithMacros.
The "macros" property should be an object with macro definitions. Syntax is following:
{
"macros": {
"macroName": {
"type": "macroDef",
"params": macroDefParamList,
"result": valueWithMacros
}
}
}"result" is JSONM that may contain paramSubstitution.
-
macroDefParamList[ macroDefParam, macroDefParam, …] -
macroDefParam"paramName" | { "name": "paramName", "default": value }
Example:
{
"pair": {
"type": "macroDef",
"params": [ "key", "value" ],
"result": {
"%key%": "%value%"
}
},
"fullName": {
"type": "macroDef",
"params": [ "first", "last" ],
"result": [ "@pair(first,%first%)", "@pair(last,%last%)" ]
}
}Parameters may have defaults. Example:
{
"car": {
"type": "macroDef",
"params": [
"model",
// parameter with default
{
"name": "color",
"default": "green"
}
],
"result": {
"model": "%model%",
"color": "%color%"
}
}
}Given an object with the macros from our previous examples, other properties may include macro calls:
{
"person": "@fullName(John, Doe)",
"car": "@car(Mercedes)"
}Trailing and leading spaces are trimmed from arguments. After preprocessing:
{
"person": {
"first": "John",
"last": "Doe"
},
"car": {
"model": "Mercedes",
"color": "green"
}
}Consts are valueWithMacros that may be substituted everywhere. One may use
only built-in macros and built-in calls in consts.
{
"macros": {
"author": {
"type": "constDef",
"result": "John Doe"
},
"copyright": {
"type": "constDef",
"result": "%author% owns it"
}
},
"file": "%copyright%. Some content"
}After preprocessing:
{
"file": "John Doe owns it. Some content"
}These characters have special meaning for the preprocessor: ‘@', ‘%', ‘(', ‘)', ‘,'. Add two backslashes (\) before any character to escape the character. It will then be added to the string 'as is' and will not be interpreted as a preprocessor instruction. To escape a backslash, write \\. Two backslashes are required because JSON uses a single backslash () as an escape character. Example:
{
"email": "fake\\@fake.fake",
"valid": "100\\%",
"backslash": "\\\\"
}After preprocessing:
{
"email": "fake@fake.fake",
"valid": "100%",
"backslash": "\\"
}Note: "backslash" is JSON property, so it will be interpreted as only one backslash.
These macros perform different operations on JSON values.
Usage: @import(path)
Allows loading JSONM from external source. Example:
File: cities.json
{
"cities": [
"New York",
"Washington"
]
}File: city.json
{
"city": {
"type": "select",
"key": 0,
"dictionary": "@import(cities.json) "
}
}After preprocessing, city.json becomes:
{
"city": "New York"
}Usage: @int(5); @str(@int(5)); @bool(true)
@int casts its argument to an integer:
{
"key": "@int(100)"
}After preprocessing:
{
"key": 100
}@str casts its argument to string; @bool to boolean.
Usage: @keys(object); @values(object)
@keys returns list of object keys; @values returns list of object values:
{
"type": "keys",
"dictionary": {"a": 1, "b": 2}
}After preprocessing:
["a", "b"]Usage:
"type": "merge",
"params": [ list1, list2, list3, ... ]or
"type": "merge",
"params": [ obj1, obj2, obj3, ... ]or
"type": "merge"
"params": [ str1, str2, str3, ... ]Combines multiple strings, lists or objects into one.
In case params is a list of strings, merge concatenates them.
{
"type": "merge",
"params": [
[1, 2],
[3, 4]
]
}After preprocessing:
[1, 2, 3, 4]If params is a list of objects, it will also be merged :
{
"type": "merge",
"params": [
{"a": 1, "b": 2},
{"b": 3, "c": 4}
]
}After preprocessing:
{
"a": 1,
"b": 3,
"c": 4
}Note: properties of obj{N} will override properties of obj{N-1}.
Usage: @select(obj,string) or @select(list,int)
Returns element from list or object.
{
"type": "select",
"key": "a",
"dictionary": {
"a": 1,
"b": 2
}
}After preprocessing:
1Usage: @shuffle(list)
Randomly shuffles a list.
{
"type": "shuffle",
"dictionary": [1, 2, 3, 4]
}After preprocessing, (one possible example):
[2, 4, 3, 1]Usage:
"type": "slice",
"dictionary": obj,
"from": string,
"to": stringor
"type": "slice",
"dictionary": list/string,
"from": int,
"to": intReturns a slice (subrange) of list, object or string:
- in case of list range of elements
from <= id <= to. - in case of object range of properties with keys
from <= key <= to. - in case of string substring
[from, to]Note: from and to are inclusive
{
"type": "slice",
"from": 1,
"to": 2,
"dictionary": [1, 2, 3, 4]
}After preprocessing:
[2, 3]Usage:
"type": "size",
"dictionary": list/string/objectReturns size of object/array/string.
{
"type": "size",
"dictionary": [1, 2],
}After preprocessing:
2Usage:
"type": "sort",
"dictionary": list,Sort a list of strings/numbers.
{
"type": "sort",
"dictionary": [2, 1],
}After preprocessing:
[1, 2]Usage: @range(@int(1),@int(2))
Returns list of integers [from, from + 1, ..., to]
{
"myRange": "@range(@int(1),@int(2))"
}After preprocessing:
{
"myRange": [1, 2]
}Usage: @isArray(value); isBool(value); etc.
Return true if value is list, bool, int, object or string respectively:
"@isString(abc)"After preprocessing:
trueUsage: @add(A,B); @sub(A,B); etc.
Perform corresponding operation on integers:
// 2*3 + 5
{ "value": "@add(@mul(@int(2),@int(3)),@int(5))" }After preprocessing:
"value": 11Usage: @contains(dictionary,value)
Returns true if dictionary contains a key; list contains a value; string contains a substring:
{ "condition": "@contains(abacaba,aca)" }After preprocessing:
{ "condition": true }Usage: @empty(dictionary)
Returns true if object, array or string is empty.
Usage:
"type": "split"
"dictionary": string,
"delim": stringSplits input string by delimiter and returns a list of pieces.
{
"type": "split",
"dictionary": "a.b.c.",
"delim": "."
}After preprocessing:
[ "a", "b", "c", "" ]Usage:
"type": "set"
"dictionary": array or object,
"key": string or int,
"value": any valueFor array, returns input array dictionary with item at index key set to value. 0 <= key <= @size(%dictionary%)
For object, returns input object dictionary with property key set to value.
Usage: @defined(name)
Returns true if the name is defined in local context or in consts (i.e. check if macro, variable, parameter or constant with the given name exists.
Returns true if A is less than B. Can compare any values except objects.
{ "condition": "@less(bcd,abcd)" }After preprocessing:
{ "condition": false }Usage: @equals(A,B)
Returns true if A == B. Can compare any values.
Returns true if A and B; A or B respectively. Both A and B should be booleans.
Usage: @not(A)
Returns true if not A.
Usage:
"type": "if",
"condition": bool,
"is_true": any value
"is_false": any valueConditional operator: returns is_true property if condition is true, is_false otherwise:
{
"value": {
"type": "if",
"condition": "@equals(a,a)"
"is_false": "Oops",
"is_true": "Yeah"
}
}After preprocessing:
{ "value": "Yeah" }Usage:
"type": "transform",
"dictionary": obj,
"itemTransform": macro with extended context
"keyTranform": macro with extended context (optional)
"itemName": string (optional, default: item)
"keyName": string (optional, default: key)or
"type": "transform",
"dictionary": list,
"itemTranform": macro with extended context
"keyName": string (optional, default: key)
"itemName": string (optional, default: item)Transforms elements of a list or object, using itemTransform and keyTransform
properties. keyTransform is optional; available only if the dictionary is an
object. itemTransform and keyTransform are valueWithMacros and may use
two additional parameters: key and item (parameter names are configured
with keyName and itemName properties).
{
"type": "transform",
"keyTransform": "%item%",
"itemTransform": "%key%",
"dictionary": {
"a": "b",
"b": "c"
}
}After preprocessing:
{
"b": "a",
"c": "b"
}Usage:
"type": "process",
"initialValue": any value,
"transform": macro with extended context
"keyName": string (optional, default: key)
"itemName": string (optional, default: item)
"valueName": string (optional, default: value)Iterates over an object or array and transforms "value". Literally:
value = initialValue
for each (key, item) in dictionary:
value = transform(key, item, value)
}
return value
transform is valueWithMacros and may use three additional
parameters: key, item and value (parameter names are configured
with keyName, itemName and valueName properties).
{
"type": "process",
"initialValue": "",
"dictionary": ["a", "b", "c", "d"],
"transform": "%item%%value%"
}After preprocessing:
"dcba"Usage:
"type": "foreach",
"key": string (optional, default: key)
"item": string (optional, default: item)
"from": object or list
"where": macro with extended context (optional, %key% and %item%)
"use": macro with extended context (optional, %key% and %item%)
"top": int (optional)
"noMatchResult": any value (optional)foreach (key, item) from where use top for top items from dictionary "from" which satisfy "where" condition merge expansions into one dictionary.
For example, to filter dictionary:
{
"type": "foreach",
"from": <dictionary>,
"where": <condition>
}To convert object to list:
{
"type": "foreach",
"from": <object>,
"use": [ <list item> ]
"noMatchResult": []
}To grab at most 2 items from that satisfy :
{
"type": "foreach",
"from": <dictionary>
"where": <condition>
"top": 2
}- Installation
- Common setups
- Concepts
- Features
- Configuration
- Monitoring
- Error Handling
- Announcements