Jsonnet のイディオム

これはJsonnetのイディオム（よくある書き方）を見たときに生まれる疑問「Jsonnetのこの記述は、どういう意味なの？」について、つらつらと列挙するためのノートです。随時更新。
質問や、「もっといい書き方があるよ」等あればコメント欄に残していただけると助かります。


## フィールド定義


### `field:: value` って何？ `field: value` とどう違うの？

`:` ではなく、`::` でフィールドを定義すると、隠しフィールドになり、最終的な出力に含まれなくなる。
出力しようとするとエラーになるオブジェクト（関数など）を定義する際に使われることが多い。
出力されないだけで存在はしているので、下記の `field2` の値のように、値を評価するときには参照可能。

```jsonnet
{
  hidden_field:: 'hidden',

  filed1: 'value1',
  filed2: 'value2' + self.hidden_field,
}
```
↓

```json
{
   "filed1": "value1",
   "filed2": "value2hidden"
}

```


### `field::: value` って何？ `field: value` や `field:: value` とどう違うの？

同盟のフィールドを持つ2つのオブジェクトを `+` などでマージしたとき、ベースとなる左側のオブジェクトに `::` で定義した隠しフィールドがあると、右側のオブジェクトに `:` で定義した通常フィールドがあっても、出力からそのフィールドは取り除かれてしまう。（次の例で `obj4_hidden_normal` が該当）

ここで右側のオブジェクトのフィールドを `:::` で可視フィールドとして定義しておくと、ベースとなるオブジェクトに同一の名前の隠しフィールドがあっても、フィールドが出力される。（`obj6_hidden_visible` が該当）

ただし、可視フィールドを持つオブジェクトをベースに隠しフィールドを持つオブジェクトをマージすると、出力からフィールドは取り除かれる。（`obj8_visible_hidden` が該当）

```jsonnet
{
  local normal = { field: 1 },
  local hidden = { field:: 2 },
  local visible = { field::: 3 },

  obj1_normal_normal: normal + normal,
  obj2_normal_hidden: normal + hidden,
  obj3_normal_visible: normal + visible,

  obj4_hidden_normal: hidden + normal,
  obj5_hidden_hidden: hidden + hidden,
  obj6_hidden_visible: hidden + visible,

  obj7_visible_normal: visible + normal,
  obj8_visible_hidden: visible + hidden,
  obj9_visible_visible: visible + visible,
}
```
↓

```json
{
   "obj1_normal_normal": {
      "field": 1
   },
   "obj2_normal_hidden": { },
   "obj3_normal_visible": {
      "field": 3
   },
   "obj4_hidden_normal": { },
   "obj5_hidden_hidden": { },
   "obj6_hidden_visible": {
      "field": 3
   },
   "obj7_visible_normal": {
      "field": 1
   },
   "obj8_visible_hidden": { },
   "obj9_visible_visible": {
      "field": 3
   }
}
```

### `field+: value` って何？ `field: value` とどう違うの？

オブジェクトをマージする場合に、 `:` ではなく、`+:` でフィールドを定義すると、親オブジェクトの同フィールドの値と '+' した結果に評価される。値がオブジェクトであればマージされ、配列や文字列であれば連結、数字であれば加算される。
`filed: super.field + value` と書いた場合と同じ。

```jsonnet
local parent = {
  field1: {
    field2: 2,
  },
  field3: [3.1, 3.2],
};

{
  obj1: parent {
    field1+: {
      field4: 4,
    },
    field3+: [3.4, 3.5],
  },
  obj2: parent {
    field1: super.field1 {
      field4: 4,
    },
    field3: super.field3 + [3.4, 3.5],
  },
}
```
↓

```json
{
   "obj1": {
      "field1": {
         "field2": 2,
         "field4": 4
      },
      "field3": [
         3.1000000000000001,
         3.2000000000000002,
         3.3999999999999999,
         3.5
      ]
   },
   "obj2": {
      "field1": {
         "field2": 2,
         "field4": 4
      },
      "field3": [
         3.1000000000000001,
         3.2000000000000002,
         3.3999999999999999,
         3.5
      ]
   }
}
```

## 値の定義

### `filed: variable { ... }` って何？ 

オブジェクトをマージする '+' の簡略記法。 `filed: variable + { ... }` と書いた場合と同じ。

```jsonnet
{
  obj:: {
    field1: 1,
  },

  merged1: self.obj {
    field2: 2,
  },
  merged2: self.obj + {
    field2: 2,
  },
}
```
↓

```json
{
   "merged1": {
      "field1": 1,
      "field2": 2
   },
   "merged2": {
      "field1": 1,
      "field2": 2
   }
}
```

## 標準関数

### std.mergePatch って何？

オブジェクトを再帰的にマージするときに使う。