jsonnet icon indicating copy to clipboard operation
jsonnet copied to clipboard

Different behavior of hidden status inheritance between Jsonnet and Go-Jsonnet

Open simu opened this issue 2 years ago • 0 comments

Summary

I've been evaluating switching to Go-Jsonnet for our tooling and stumbled across a difference in how hidden status inheritance (https://jsonnet.org/ref/spec.html#hidden_inheritance) is implemented in Jsonnet and Go-Jsonnet.

Here's an example Jsonnet script which demonstrates the difference:

// `makeMergeable` is taken from our tooling. We use this extensively to make user inputs loaded from YAML mergeable
local makeMergeable(o) = {
  [key]+: makeMergeable(o[key])
  for key in std.objectFields(o)
  if std.isObject(o[key])
} + {
  [key]+: o[key]
  for key in std.objectFields(o)
  if std.isArray(o[key])
} + {
  [key]: o[key]
  for key in std.objectFields(o)
  if !std.isObject(o[key]) && !std.isArray(o[key])

};

local base = { field:: 'data' };

{
  regular: base { field: 'other' }, // hidden status of `field` is inherited in both implementations
  makeMergeable: base + makeMergeable({
    field: 'other',
  }), // hidden status of `field` is inherited through the object comprehension in go-jsonnet, but the hidden status of the field is lost in jsonnet
}

From what I can tell, the go-jsonnet implementation implements the specification correctly.

Example script evaluation and output

I've wrapped the example in Python (because that's what I had readily available) to run both implementations side-by-side:

import _jsonnet
import _gojsonnet

prog = """
// `makeMergeable` is taken from our tooling. We use this extensively to make user inputs mergeable
local makeMergeable(o) = {
  [key]+: makeMergeable(o[key])
  for key in std.objectFields(o)
  if std.isObject(o[key])
} + {
  [key]+: o[key]
  for key in std.objectFields(o)
  if std.isArray(o[key])
} + {
  [key]: o[key]
  for key in std.objectFields(o)
  if !std.isObject(o[key]) && !std.isArray(o[key])

};

local base = { field:: 'data' };

{
  regular: base { field: 'other' }, // hidden status of `field` is inherited in both implementations
  makeMergeable: base + makeMergeable({
    field: 'other',
  }), // hidden status of `field` is inherited through the object comprehension in go-jsonnet, but the hidden status of the field is lost in jsonnet
}
"""

print("Jsonnet:\n" + _jsonnet.evaluate_snippet("test.jsonnet", prog))
print("Go-Jsonnet:\n" + _gojsonnet.evaluate_snippet("test.jsonnet", prog))

This gives the following in a virtualenv (setup with python3 -m venv venv && source venv/bin/activate && pip install jsonnet gojsonnet):

(venv) simon@phoenix:~/tmp/jsonnet-issue $ pip list
Package    Version
---------- -------
gojsonnet  0.20.0
jsonnet    0.20.0
pip        22.0.2
setuptools 59.6.0
(venv) simon@phoenix:~/tmp/jsonnet-issue $ python test.py
Jsonnet:
{
   "makeMergeable": {
      "field": "other"
   },
   "regular": { }
}

Go-Jsonnet:
{
   "makeMergeable": { },
   "regular": { }
}

simu avatar Sep 19 '23 07:09 simu