Jsonnet

Jsonnet is a programming language or rather a templating language for json files. Though jsonnet provides and lot of power and configurability to the user calling jsonnet a programming language like calling a calculator a computer. Even though you can do many things in jsonnet that are similar to other programming languages at the end of the day it is just a templating language for generating json documents.

Syntax

Any json document is a valid jsonnet program, so let's focus on what jsonnet adds to json. Let's start by going over some of the new syntax added by jsonnet:

  • Fields that happen to be valid identifiers have no quotes
  • Trailing commas at the end of arrays and objects
  • Single line and block comments
  • String literals can use both single quotes and double quotes. Single quotes can be used to avoid escaping double quotes from your string and double quotes can be used to avoid escaping single quotes from your string.
  • Text blocks, |||, allow verbatim text across multiple lines.
  • You can also define single line verbatim strings with @

Now let's look at an example from jsonnet.org:

// single line comment

/*
    multiline comment
*/

# as well as python style comment

# define a variable.
# Variables have no effect in the generated JSON without being used.
local num1 = 1;
local num2 = 1 + 1;
local num3 = 5 - 2;
local num4 = 9 % 5;
local num5 = 10 / 2.0;
# jsonnet is a lazy language, if a variable is not used, it is not evaluated.
local num_runtime_error = 1 / 0;

# fields are valid identifiers without quotes
local obj1 = { a: 'letter a', B: 'letter B' };

local arr1 = ['a', 'b', 'c'];

# string literals use " or '.
local str1 = 'a' + 'B';
# multiline text literal in between |||
# Each line must start with a white space.
local str_multiline = |||
  this is a
  multiline string
|||;
# Python-compatible string formatting is available via %
# When combined with ||| this can be used for templating text files.
local str_templating = |||
  %(f1)0.3f
||| % { f1: 1.2345678 };
assert str_templating == '1.235\n';

# if b then e else e. The else branch is optional and defaults to null
local var1 = if 3 < 2 then "YES";
assert var1 == null;

local obj2 = {
  # variable defined inside the object ends with ','
  local var_in_obj = 0,

  local vowels = ['a', 'e', 'i', 'o', 'u'],
  local numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],

  # [num] to look up an array element
  first_vowel: vowels[0],
  # can also slice the array like in Python
  even_numbers: numbers[1::2],

  # python-style list and object comprehensions are also supported
  double_numbers: [x * 2 for x in numbers],
  even_numbers_map: {
      # [ ] syntax in field name is to compute the field name dynamically
      [x + '_is_even']: true for x in numbers if x % 2 == 0
  },

  nested: {
    nested_field1: 'some-value',
    # self refers to the current object
    # ["field-name"] or .field-name can be used to look up a field
    nested_field2: self.nested_field1,
    nested_field3: self.nested_field1,
    # $ refers to outer-most object
    nested_field4: $.first_vowel,

    assert self.nested_field1 == self.nested_field2,
    assert self.nested_field1 == self.nested_field3,
  },

  special_field: 'EVERYTHING FEELS BAD',
};

local obj3 = {
  local var_in_obj = 1.234,
  local var_in_obj2 = { a: { b: 'c' } },

  concat_array: [1, 2, 3] + [4],
  # strings can be concat with +,
  # which implicitly converts one operand to string if needed.
  concat_string: '123' + 4,

  # == tests deep equality
  equals: { a: { b: 'c', d: {} } } == var_in_obj2,

  special_field: 'this feels good',
};

# objects can be merged with + where the right-hand side wins field conflicts
local obj4 = obj2 + obj3;
assert obj4.special_field == 'this feels good';

# define a function
# functions have positional parameters, named parameters, and default arguments
local my_function(x, y, z=1) = x + y - z;
local num6 = my_function(7, 8, 9);
local num7 = my_function(8, z=10, y=9);
local num8 = my_function(4, 5);
# inline anonymous function
local num9 = (function(x) x * x)(3);

local obj5 = {
  # define a method
  # fields defined with :: are hidden, which does not apper in generated JSON
  # function cannot be serialized so need to be hidden
  # if the object is used in the generated JSON.
  is_odd(x):: x % 2 == 1,
};
assert obj5 == {};

# a jsonnet document has to evaluate to something
# be it an object, list, number or just string literal
"FIN"
This page was last updated: 2023-04-12 Wed 20:25. Source