-
Notifications
You must be signed in to change notification settings - Fork 538
JSONM
#JSON with macros (JSONM)
JSONM is a JSON extension that allows using macro definitions inside JSON files.
###Why? The main goals of this format are to make configuration files more readable and to get rid of scripts that generate huge configuration files.
###What? 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.
###How? Using a simple preprocessor, we generate standard JSON objects from user-friendly JSONM by processing all macros and substituting all constants. .
###Syntax
JSONM is a JSON object with two special optional keys: consts
and macros
:
{
"consts": [
constDefinition,
constDefinition,
…
},
"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,
…
}
-
paramSubstitution
string 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. -
builtInCall
Basically the same as template call, but has no short form.
{
"type": "if|transform|process",
… params for this call …
}
###Comments 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
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
.
####Macro definition 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%"
}
}
}
####Macro call Given an object with the macros from our previous examples, other properties may include macro calls:
{
"person": "@fullName(John,Doe)",
"car": "@car(Mercedes)"
}
After preprocessing:
{
"person": {
"first": "John",
"last": "Doe"
},
"car": {
"model": "Mercedes",
"color": "green"
}
}
###Consts
Consts are valueWithMacros
that may be substituted everywhere. One may use
only built-in macros and built-in calls in consts.
{
"consts": [
{
"type": "constDef",
"name": "author",
"value": "John Doe"
},
{
"type": "constDef",
"name": "copyright",
"value": "%author% owns it"
}
],
"file": "%copyright%. Some content"
}
After preprocessing:
{
"file": "John Doe owns it. Some content"
}
###Escaping 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.
###Built-in macros These macros perform different operations on JSON values.
####import
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"
}
####int, str, bool
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.
####keys, values
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"]
####merge Usage:
"type": "merge",
"params": [ list1, list2, list3, ... ]
or
"type": "merge",
"params": [ obj1, obj2, obj3, ... ]
or
"type": "merge"
"params": [ str1, str2, str3, ... ]
Combines multiple 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
}
####select
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:
1
####shuffle
Usage: @shuffle(list)
Randomly shuffles a list.
{
"type": "shuffle",
"dictionary": [1, 2, 3, 4]
}
After preprocessing, (one possible example):
[2, 4, 3, 1]
####slice Usage:
"type": "slice",
"dictionary": obj,
"from": string,
"to": string
or
"type": "slice",
"dictionary": list/string,
"from": int,
"to": int
Returns a slice (subrange) of list, object or string.
{
"type": "slice",
"from": 1,
"to": 2,
"dictionary": [1, 2, 3, 4]
}
After preprocessing:
[2, 3]
####range
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]
}
####isArray, isBool, isInt, isObject, isString
Usage: @isArray(value)
; isBool(value)
; etc.
Return true if value is list, bool, int, object or string respectively:
"@isString(abc)"
After preprocessing:
true
####add, sub, mul, div, mod
Usage: @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": 11
####contains
Usage: @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 }
####empty
Usage: @empty(dictionary)
Returns true if object, array or string is empty.
####less Returns true if A is less than B. Can compare any values except objects.
{ "condition": "@less(bcd,abcd)" }
After preprocessing:
{ "condition": false }
####equals
Usage: @equals(A,B)
Returns true if A == B
. Can compare any values.
####and, or
Returns true if A and B
; A or B
respectively. Both A and B should be booleans.
###Built-in calls ####if Usage:
"type": "if",
"condition": bool,
"is_true": any value
"is_false": any value
Conditional 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" }
####transform 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"
}
####process 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"
- Installation
- Common setups
- Concepts
- Features
- Configuration
- Monitoring
- Error Handling
- Announcements