Welcome to follow the official wechat account: FSA Full Stack Action 👋

Jsonnet: Google’s JSON data template language.

Features: Support for comments, references, arithmetic, conditional operators, array and object inclusion, introduction, functions, local variables, inheritance, etc.

  • Website: jsonnet.org
  • GitHub:github.com/google/json…
  • Example official language: github.com/google/json…

A, install,

brew install jsonnet
Copy the code

Second, the tool

  • VSCode
  • Plug-in:Jsonnet NG: Supports syntax highlighting and saves previews

After installing the plug-in, click the preview button in the upper right corner

The default preview result is yamL. You can search for jsonnet Preview in Settings to find the corresponding setting and select JSON.

Three, characteristics

1, field,

define

Field names can be unquoted, but must be quoted if there are Spaces

{
  field1: 'lxf1',
  "field 2": 'lxf2'
}
Copy the code

Hidden fields

The fields defined are not output to the JSON result

Language :: 'jsonnet', LXF: {lang: $. Language, author: name}}Copy the code

Results:

{
    "lxf": {
        "author": "LXF"."lang": "jsonnet"}}Copy the code

2, comments,

Single line comments// Single-line comments

/* Multi-line comments */
Copy the code

3. String

quotes

Single quotes are no different from double quotes

A single line verbatim string

# Single-line verbatim strings: use @{"single line": @'hello \ lxf'
}
Copy the code

Results:

{
  "single line": "hello \\ lxf"
}
Copy the code

Multiline verbatim string

# multi-line string word by word: use | | | {"multiple line": |||
  	hello
  	lxf
  |||,
}
Copy the code

Results:

{
  "multiple line": "hello\nlxf\n"
}
Copy the code

Joining together

{
  pi:: 3.1415926,
  format: 'Hello, %s' % 'lxf',
  concat: 'Hello, ' + 'lxf',
  format1: |||
    hello
    pi=%(pi)0.2f
  ||| % self,
}
Copy the code

Results:

{
    "concat": "Hello, lxf"."format": "Hello, lxf"."format1": "Hello \ npi = 3.14 \ n"
}
Copy the code

4, variables,

define

  • uselocalThe keyword defines a variable
  • Variables defined next to fields are marked with commas (.), other cases define variables with a semicolon (;) at the end
local github = 'https://github.com/LinXunFeng'; Variables that are not defined next to fields end in a semicolonLanguage :: 'jsonnet', LXF: {target: $. Language, author: name, by: self.author, address: github } }Copy the code

Results:

{
  "lxf": {
    "address": "https://github.com/LinXunFeng"."author": "LinXunFeng"."by": "LinXunFeng"."target": "jsonnet"}}Copy the code

reference

  • Variable name: Proximity principle
  • selfKeyword: Point to the current object
  • $Keyword: Point to the root object
  • [' field name ']: is used to find a field
  • The field name: Fetch a field, but the field name must conform to the normal naming standard (cannot start with a number, cannot contain Spaces, etc.).
  • [number]: Is used to fetch array elements
  • Allowed long path
  • Strings and arrays allow imagespythonUse array slices likearr[10:20:2]
local github = 'https://github.com/LinXunFeng';
{
  local name = 'LXF',
  language:: 'jsonnet',
  lxf: {
    target: $.language,
    author: name,
    by: self.author,
    address: github,
    languages: ['oc', 'swift', 'python'],
    nums: [1.8.11.22.33.44.55],
  },
  lqr: {
    local name = "fsa_fullstackaction",
    languages: ['java', 'kotlin', 'python'],
    scores: $.lxf.nums[1:3],
    organization: name[4:],
    height: $['lxf'].nums[0] + 'm'
  },
}
Copy the code

Results:

{
  "lqr": {
    "height": "1.8 m"."languages": [
      "java"."kotlin"."python"]."organization": "fullstackaction"."scores": [
      11.22]},"lxf": {
    "address": "https://github.com/LinXunFeng"."author": "LXF"."by": "LXF"."languages": [
      "oc"."swift"."python"]."nums": [
      1.8.11.22.33.44.55]."target": "jsonnet"}}Copy the code

5. Four operations

  • Support four operations, bit operations, comparison logic
  • +When a string is encountered in the operation, the numeric value is converted to a string for concatenation
  • Strings can be compared
  • useinKeyword to determine whether a field in the specified object
{
  info: {
    name: 'LinXunFeng'
  },
  ex1: (1 + 2) / 3 * 4,
  ex2: 1 << 2,
  ex3: 'a' <= 'b',
  ex4: 'a' == 'b',
  ex5: 5 + 6 + '1'+1,
  ex6: 'name' in self.info,
}
Copy the code

Results:

{
    "ex1": 4."ex2": 4."ex3": true."ex4": false."ex5": "1111"."ex6": true."info": {
        "name": "LinXunFeng"}}Copy the code

6, functions,

  • Support for positional, named, and default parameters
  • Support closures
  • A number of commonly used functions are already defined in Standard Library
local addNumber(number) = function(x) number + x;
local add2 = addNumber(2);
local add3 = addNumber(3); {# closures: closures: [add2(2),
    add3(5Local sayHello(name) =' hello %s' % name, sum(x, y):: x + y, newPerson(name=' LXF ', age=18, gender='male'):: {name: name, age: age, gender: gender,}, # call call_say_hello: sayHello(' LXF '), call_sum: $.sum(1, 2),
  lxf: $.newPerson(age=3),
  standard_lib: std.join(' ', std.split('foo/bar', '/')),
  len: [
    std.length('hello'),
    std.length([1.2.3])],}Copy the code

Results:

{
    "call_say_hello": "hello lxf"."call_sum": 3."closures": [
        4.8]."len": [
        5.3]."lxf": {
        "age": 3."gender": "male"."name": "lxf"
    },
    "standard_lib": "foo bar"
}
Copy the code

7. Conditional statements

Expression: if a then b else C, else is optional, returns null by default

local Person(isFemale) = {
  name: 'lxf',
  age: 18,
  gender: if isFemale then 'female' else 'male',
  [if isFemale then 'clothing']: 'dress',
};

{
  condition1: if 2 > 1 then 'true' else 'false',
  condition2: if 2 < 1 then 'true',
  male: Person(false),
  female: Person(true),}Copy the code

Results:

{
    "condition1": "true"."condition2": null."female": {
        "age": 18."clothing": "dress"."gender": "female"."name": "lxf"
    },
    "male": {
        "age": 18."gender": "male"."name": "lxf"}}Copy the code

8. Object merge

  • use+Operator to combine two objects, and if a field conflict is encountered, the fields in the object on the right are used
  • Right object can be usedsuperKeywords refer to fields in the left object
  • use+ :When the operator combines two objects, the right object overwrites the existing fields in the left object, and the missing fields are added
# +
local base = {
    f: 2,
    g: self.f + 100}; base + { f:5,
    old_f: super.f,
    old_g: super.g,
}

##################################

# +:
local base = {
    override: {
        x: 1,
    },
    composite+: {
        x: 1,}}; { override: { y:2, 
      z: 3 
    },
    composite: { 
      y: 4, 
      z: 5 
    },
} + base
Copy the code

Results:

# +
{
    "f": 5."g": 105."old_f": 2."old_g": 105
}

##################################

# +:

{
    "composite": {
        "x": 1."y": 4."z": 5
    },
    "override": {
        "x": 1}}Copy the code

9. Import the template

  • Similar to copy/paste code
  • It can also be used to importjsonThe original data
  • The suffix of a template file must be.libsonnet
  • useimportKeyword to import the template content and store it using the specified variable

Content of the template

{
  newPerson(
    name,
    country='China',
    age=18
  ):: {
    name: name,
    country: country,
    age: age,
    belly: [],
    eat(food):: self + {
      belly+: [food],
    },
  },
}
Copy the code

Use the template

Localpersontemplate = import 'libs/lxflib.libsonnet'; libsonnet = libsonnet; personTemplate .newPerson(name='lxf', age=3)
  .eat('rice')
  .eat('pear')
Copy the code

Results:

{
    "age": 3."belly": [
        "rice"."pear"]."country": "China"."name": "lxf"
}
Copy the code

Four, terminal use

1, basic use

#Simple code can be run directly using -e
jsonnet -e '{key: 1+2}'
Copy the code

View the conversion results of the Jsonnet file

jsonnet shuttle.jsonnet
Copy the code

2. Specify the library path

If there is an imported template file in the Jsonnet file, but only write the name of the template file, not the path

Libsonnet local personTemplate = import 'lxflib.libsonnet';Copy the code

In this case, direct execution of the command will report an error

RUNTIME ERROR: couldn't open import "lxflib.libsonnet": no match locally or in the Jsonnet library paths.
Copy the code

At this point you have two choices

Option 1: Honestly write the full relative path when importing

local personTemplate = import 'libs/lxflib.libsonnet';
Copy the code

Option 2: Use the -j


parameter

 jsonnet -J ./libs shuttle.jsonnet
Copy the code

3. Export the result to a file

Export json files using jsonnet files

jsonnet shuttle.jsonnet -o shuttle.json
Copy the code

4. Multiple file output

Jsonnet also supports scenarios where multiple JSON files are generated using a single Jsonnet file, such as both A.JAXon and B.JAXon

{
  "a.json": {
    x: 1,
    y: $["b.json"].y,
  },
  "b.json": {
    x: $["a.json"].x,
    y: 2,}}Copy the code

The command

#Jsonnet -m 
      
        Jsonnet file
      
jsonnet -m . multiple_output.jsonnet
Copy the code

Results:

$ cat a.json 
{
   "x": 1,
   "y": 2
}

$ cat b.json 
{
   "x": 1,
   "y": 2
}
Copy the code

Five, the application of

In order to improve our work efficiency, it is often to organize and save some commonly used commands.

I do, for example, and use it with Shuttle, a shortcut menu that uses JSON to configure terminal commands.

As shown in the figure below, I added the command that triggers the remote Jenkins to package, but the remote build machine for some reason switches between two fixed IP addresses, so I added two, only the IP is different

However, in addition to the packaging function, other functions are related to the build machine IP, so once we add an IP, we have to change a lot of things, and also find that the command is the same, if one day the command is changed… 😭

So in cases like this, we need the help of Jsonnet to simplify things.

On the left of the image below, I’ve defined some common templates under the libs directory and put some constant configurations into the constant.libsonnet template file

In the shuttle. Jsonnet file, the entire shuttle configuration is defined

The good thing about this is that when the new person comes in and you need them to be able to step in immediately to pack and distribute, you just need to configure the Shuttle.

Configuring the Shuttle simply requires adjusting the constant.libsonnet file and executing one line of command!

jsonnet . shuttle.jsonnet -o ~/.shuttle.json
Copy the code