jsonnet 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,206 @@
1
+ #include <libjsonnet.h>
2
+ #include <ruby/ruby.h>
3
+ #include <ruby/intern.h>
4
+
5
+ #include "ruby_jsonnet.h"
6
+
7
+ static struct JsonnetJsonValue *protect_obj_to_json(struct JsonnetVm *vm, VALUE obj,
8
+ struct JsonnetJsonValue *parent);
9
+
10
+ /**
11
+ * Converts a Jsonnet JSON value into a Ruby object.
12
+ *
13
+ * Arrays and objects in JSON are not supported due to the limitation of
14
+ * libjsonnet API.
15
+ */
16
+ VALUE
17
+ rubyjsonnet_json_to_obj(struct JsonnetVm *vm, const struct JsonnetJsonValue *value)
18
+ {
19
+ union {
20
+ const char *str;
21
+ double num;
22
+ } typed_value;
23
+
24
+ if ((typed_value.str = jsonnet_json_extract_string(vm, value))) {
25
+ return rb_enc_str_new_cstr(typed_value.str, rb_utf8_encoding());
26
+ }
27
+ if (jsonnet_json_extract_number(vm, value, &typed_value.num)) {
28
+ return DBL2NUM(typed_value.num);
29
+ }
30
+
31
+ switch (jsonnet_json_extract_bool(vm, value)) {
32
+ case 0:
33
+ return Qfalse;
34
+ case 1:
35
+ return Qtrue;
36
+ case 2:
37
+ break;
38
+ default:
39
+ /* never happens */
40
+ rb_raise(rb_eRuntimeError, "unrecognized json bool value");
41
+ }
42
+ if (jsonnet_json_extract_null(vm, value)) {
43
+ return Qnil;
44
+ }
45
+
46
+ /* TODO: support arrays and objects when they get accessible */
47
+ rb_raise(rb_eArgError, "unsupported type of JSON value");
48
+ }
49
+
50
+ static struct JsonnetJsonValue *
51
+ string_to_json(struct JsonnetVm *vm, VALUE str)
52
+ {
53
+ rubyjsonnet_assert_asciicompat(str);
54
+ return jsonnet_json_make_string(vm, RSTRING_PTR(str));
55
+ }
56
+
57
+ static struct JsonnetJsonValue *
58
+ num_to_json(struct JsonnetVm *vm, VALUE n)
59
+ {
60
+ return jsonnet_json_make_number(vm, NUM2DBL(n));
61
+ }
62
+
63
+ static struct JsonnetJsonValue *
64
+ ary_to_json(struct JsonnetVm *vm, VALUE ary)
65
+ {
66
+ struct JsonnetJsonValue *const json_array = jsonnet_json_make_array(vm);
67
+
68
+ int i;
69
+ for (i = 0; i < RARRAY_LEN(ary); ++i) {
70
+ struct JsonnetJsonValue *const v = protect_obj_to_json(vm, RARRAY_AREF(ary, i), json_array);
71
+ jsonnet_json_array_append(vm, json_array, v);
72
+ }
73
+ return json_array;
74
+ }
75
+
76
+ struct hash_to_json_params {
77
+ struct JsonnetVm *vm;
78
+ struct JsonnetJsonValue *obj;
79
+ };
80
+
81
+ static int
82
+ hash_item_to_json(VALUE key, VALUE value, VALUE paramsval)
83
+ {
84
+ const struct hash_to_json_params *const params = (const struct hash_to_json_params *)paramsval;
85
+
86
+ StringValue(key);
87
+ rubyjsonnet_assert_asciicompat(key);
88
+
89
+ jsonnet_json_object_append(params->vm, params->obj, StringValueCStr(key),
90
+ protect_obj_to_json(params->vm, value, params->obj));
91
+
92
+ return ST_CONTINUE;
93
+ }
94
+
95
+ static struct JsonnetJsonValue *
96
+ hash_to_json(struct JsonnetVm *vm, VALUE hash)
97
+ {
98
+ struct JsonnetJsonValue *const json_obj = jsonnet_json_make_object(vm);
99
+ const struct hash_to_json_params args = {vm, json_obj};
100
+ rb_hash_foreach(hash, hash_item_to_json, (VALUE)&args);
101
+ return json_obj;
102
+ }
103
+
104
+ /**
105
+ * Converts a Ruby object into a Jsonnet JSON value
106
+ *
107
+ * TODO(yugui): Safely destorys an intermediate object on exception.
108
+ */
109
+ static struct JsonnetJsonValue *
110
+ obj_to_json(struct JsonnetVm *vm, VALUE obj)
111
+ {
112
+ VALUE converted;
113
+
114
+ switch (obj) {
115
+ case Qnil:
116
+ return jsonnet_json_make_null(vm);
117
+ case Qtrue:
118
+ return jsonnet_json_make_bool(vm, 1);
119
+ case Qfalse:
120
+ return jsonnet_json_make_bool(vm, 0);
121
+ }
122
+
123
+ converted = rb_check_string_type(obj);
124
+ if (converted != Qnil) {
125
+ return string_to_json(vm, converted);
126
+ }
127
+
128
+ converted = rb_check_to_float(obj);
129
+ if (converted != Qnil) {
130
+ return num_to_json(vm, converted);
131
+ }
132
+
133
+ converted = rb_check_array_type(obj);
134
+ if (converted != Qnil) {
135
+ return ary_to_json(vm, converted);
136
+ }
137
+
138
+ converted = rb_check_hash_type(obj);
139
+ if (converted != Qnil) {
140
+ return hash_to_json(vm, converted);
141
+ }
142
+
143
+ converted = rb_any_to_s(obj);
144
+ return string_to_json(vm, converted);
145
+ }
146
+
147
+ struct protect_args {
148
+ struct JsonnetVm *vm;
149
+ VALUE obj;
150
+ };
151
+
152
+ static VALUE
153
+ protect_obj_to_json_block(VALUE paramsval)
154
+ {
155
+ const struct protect_args *const params = (const struct protect_args *)paramsval;
156
+ return (VALUE)obj_to_json(params->vm, params->obj);
157
+ }
158
+
159
+ /**
160
+ * Safely converts a Ruby object into a JSON value.
161
+ *
162
+ * It automatically destroys \a parent on exception.
163
+ * @param[in] vm a Jsonnet VM
164
+ * @param[in] obj a Ruby object to be converted
165
+ * @param[in] parent destroys this value on failure
166
+ * @throws can throw \c TypeError or other exceptions
167
+ */
168
+ static struct JsonnetJsonValue *
169
+ protect_obj_to_json(struct JsonnetVm *vm, VALUE obj, struct JsonnetJsonValue *parent)
170
+ {
171
+ const struct protect_args args = {vm, obj};
172
+ int state = 0;
173
+
174
+ VALUE result = rb_protect(protect_obj_to_json_block, (VALUE)&args, &state);
175
+ if (!state) {
176
+ return (struct JsonnetJsonValue *)result;
177
+ }
178
+
179
+ jsonnet_json_destroy(vm, parent);
180
+ rb_jump_tag(state);
181
+ }
182
+
183
+ /**
184
+ * Converts a Ruby object into a JSON value.
185
+ * Returns an error message on failure.
186
+ *
187
+ * @param[in] vm a Jsonnet VM
188
+ * @param[in] obj a Ruby object to be converted
189
+ * @param[out] success set to 1 on success, set to 0 on failure.
190
+ * @returns the converted value on success, an error message on failure.
191
+ */
192
+ struct JsonnetJsonValue *
193
+ rubyjsonnet_obj_to_json(struct JsonnetVm *vm, VALUE obj, int *success)
194
+ {
195
+ int state = 0;
196
+ const struct protect_args args = {vm, obj};
197
+ VALUE result = rb_protect(protect_obj_to_json_block, (VALUE)&args, &state);
198
+ if (state) {
199
+ const VALUE msg = rubyjsonnet_format_exception(rb_errinfo());
200
+ rb_set_errinfo(Qnil);
201
+ *success = 0;
202
+ return string_to_json(vm, msg);
203
+ }
204
+ *success = 1;
205
+ return (struct JsonnetJsonValue *)result;
206
+ }
@@ -0,0 +1,39 @@
1
+ #ifndef RUBY_JSONNET_RUBY_JSONNET_H_
2
+ #define RUBY_JSONNET_RUBY_JSONNET_H_
3
+
4
+ #include <ruby/ruby.h>
5
+ #include <ruby/encoding.h>
6
+
7
+ extern const rb_data_type_t jsonnet_vm_type;
8
+
9
+ struct native_callback_ctx {
10
+ VALUE callback;
11
+ long arity;
12
+ VALUE vm;
13
+ };
14
+
15
+ struct jsonnet_vm_wrap {
16
+ struct JsonnetVm *vm;
17
+
18
+ VALUE import_callback;
19
+ struct {
20
+ long len;
21
+ struct native_callback_ctx **contexts;
22
+ } native_callbacks;
23
+ };
24
+
25
+ void rubyjsonnet_init_vm(VALUE mod);
26
+ void rubyjsonnet_init_callbacks(VALUE cVM);
27
+ void rubyjsonnet_init_helpers(VALUE mod);
28
+
29
+ struct jsonnet_vm_wrap *rubyjsonnet_obj_to_vm(VALUE vm);
30
+
31
+ VALUE rubyjsonnet_json_to_obj(struct JsonnetVm *vm, const struct JsonnetJsonValue *value);
32
+ struct JsonnetJsonValue *rubyjsonnet_obj_to_json(struct JsonnetVm *vm, VALUE obj, int *success);
33
+
34
+ rb_encoding *rubyjsonnet_assert_asciicompat(VALUE str);
35
+ char *rubyjsonnet_str_to_cstr(struct JsonnetVm *vm, VALUE str);
36
+ VALUE rubyjsonnet_format_exception(VALUE exc);
37
+ int rubyjsonnet_jump_tag(const char *exc_mesg);
38
+
39
+ #endif /* RUBY_JSONNET_RUBY_JSONNET_H_ */
@@ -0,0 +1,351 @@
1
+ #include <libjsonnet.h>
2
+ #include <ruby/ruby.h>
3
+ #include <ruby/intern.h>
4
+
5
+ #include "ruby_jsonnet.h"
6
+
7
+ /*
8
+ * defines the core part of Jsonnet::VM
9
+ */
10
+
11
+ /*
12
+ * Jsonnet evaluator
13
+ *
14
+ * call-seq:
15
+ * Jsonnet::VM
16
+ */
17
+ static VALUE cVM;
18
+
19
+ /*
20
+ * Raised on evaluation errors in a Jsonnet VM.
21
+ */
22
+ static VALUE eEvaluationError;
23
+
24
+ static void raise_eval_error(struct JsonnetVm *vm, char *msg, rb_encoding *enc);
25
+ static VALUE str_new_json(struct JsonnetVm *vm, char *json, rb_encoding *enc);
26
+ static VALUE fileset_new(struct JsonnetVm *vm, char *buf, rb_encoding *enc);
27
+
28
+ static void vm_free(void *ptr);
29
+ static void vm_mark(void *ptr);
30
+
31
+ const rb_data_type_t jsonnet_vm_type = {
32
+ "JsonnetVm",
33
+ {
34
+ /* dmark = */ vm_mark,
35
+ /* dfree = */ vm_free,
36
+ /* dsize = */ 0,
37
+ },
38
+ /* parent = */ 0,
39
+ /* data = */ 0,
40
+ /* flags = */ RUBY_TYPED_FREE_IMMEDIATELY,
41
+ };
42
+
43
+ struct jsonnet_vm_wrap *
44
+ rubyjsonnet_obj_to_vm(VALUE wrap)
45
+ {
46
+ struct jsonnet_vm_wrap *vm;
47
+ TypedData_Get_Struct(wrap, struct jsonnet_vm_wrap, &jsonnet_vm_type, vm);
48
+
49
+ return vm;
50
+ }
51
+
52
+ static VALUE
53
+ vm_s_new(int argc, const VALUE *argv, VALUE klass)
54
+ {
55
+ struct jsonnet_vm_wrap *vm;
56
+ VALUE self = TypedData_Make_Struct(cVM, struct jsonnet_vm_wrap, &jsonnet_vm_type, vm);
57
+ vm->vm = jsonnet_make();
58
+ vm->import_callback = Qnil;
59
+ vm->native_callbacks.len = 0;
60
+ vm->native_callbacks.contexts = NULL;
61
+
62
+ rb_obj_call_init(self, argc, argv);
63
+ return self;
64
+ }
65
+
66
+ static void
67
+ vm_free(void *ptr)
68
+ {
69
+ int i;
70
+ struct jsonnet_vm_wrap *vm = (struct jsonnet_vm_wrap *)ptr;
71
+ jsonnet_destroy(vm->vm);
72
+
73
+ for (i = 0; i < vm->native_callbacks.len; ++i) {
74
+ struct native_callback_ctx *ctx = vm->native_callbacks.contexts[i];
75
+ RB_REALLOC_N(ctx, struct native_callback_ctx, 0);
76
+ }
77
+ RB_REALLOC_N(vm->native_callbacks.contexts, struct native_callback_ctx *, 0);
78
+
79
+ RB_REALLOC_N(vm, struct jsonnet_vm_wrap, 0);
80
+ }
81
+
82
+ static void
83
+ vm_mark(void *ptr)
84
+ {
85
+ int i;
86
+ struct jsonnet_vm_wrap *vm = (struct jsonnet_vm_wrap *)ptr;
87
+
88
+ rb_gc_mark(vm->import_callback);
89
+ for (i = 0; i < vm->native_callbacks.len; ++i) {
90
+ rb_gc_mark(vm->native_callbacks.contexts[i]->callback);
91
+ }
92
+ }
93
+
94
+ static VALUE
95
+ vm_evaluate_file(VALUE self, VALUE fname, VALUE encoding, VALUE multi_p)
96
+ {
97
+ int error;
98
+ char *result;
99
+ rb_encoding *const enc = rb_to_encoding(encoding);
100
+ struct jsonnet_vm_wrap *vm = rubyjsonnet_obj_to_vm(self);
101
+
102
+ FilePathValue(fname);
103
+ if (RTEST(multi_p)) {
104
+ result = jsonnet_evaluate_file_multi(vm->vm, StringValueCStr(fname), &error);
105
+ } else {
106
+ result = jsonnet_evaluate_file(vm->vm, StringValueCStr(fname), &error);
107
+ }
108
+
109
+ if (error) {
110
+ raise_eval_error(vm->vm, result, rb_enc_get(fname));
111
+ }
112
+ return RTEST(multi_p) ? fileset_new(vm->vm, result, enc) : str_new_json(vm->vm, result, enc);
113
+ }
114
+
115
+ static VALUE
116
+ vm_evaluate(VALUE self, VALUE snippet, VALUE fname, VALUE multi_p)
117
+ {
118
+ int error;
119
+ char *result;
120
+ struct jsonnet_vm_wrap *vm = rubyjsonnet_obj_to_vm(self);
121
+
122
+ rb_encoding *enc = rubyjsonnet_assert_asciicompat(StringValue(snippet));
123
+ FilePathValue(fname);
124
+ if (RTEST(multi_p)) {
125
+ result = jsonnet_evaluate_snippet_multi(vm->vm, StringValueCStr(fname),
126
+ StringValueCStr(snippet), &error);
127
+ } else {
128
+ result = jsonnet_evaluate_snippet(vm->vm, StringValueCStr(fname), StringValueCStr(snippet),
129
+ &error);
130
+ }
131
+
132
+ if (error) {
133
+ raise_eval_error(vm->vm, result, rb_enc_get(fname));
134
+ }
135
+ return RTEST(multi_p) ? fileset_new(vm->vm, result, enc) : str_new_json(vm->vm, result, enc);
136
+ }
137
+
138
+ #define vm_bind_variable(type, self, key, val) \
139
+ do { \
140
+ struct jsonnet_vm_wrap *vm; \
141
+ \
142
+ rubyjsonnet_assert_asciicompat(StringValue(key)); \
143
+ rubyjsonnet_assert_asciicompat(StringValue(val)); \
144
+ TypedData_Get_Struct(self, struct jsonnet_vm_wrap, &jsonnet_vm_type, vm); \
145
+ jsonnet_##type(vm->vm, StringValueCStr(key), StringValueCStr(val)); \
146
+ } while (0)
147
+
148
+ /*
149
+ * Binds an external variable to a value.
150
+ * @param [String] key name of the variable
151
+ * @param [String] val the value
152
+ */
153
+ static VALUE
154
+ vm_ext_var(VALUE self, VALUE key, VALUE val)
155
+ {
156
+ vm_bind_variable(ext_var, self, key, val);
157
+ return Qnil;
158
+ }
159
+
160
+ /*
161
+ * Binds an external variable to a code fragment.
162
+ * @param [String] key name of the variable
163
+ * @param [String] code Jsonnet expression
164
+ */
165
+ static VALUE
166
+ vm_ext_code(VALUE self, VALUE key, VALUE code)
167
+ {
168
+ vm_bind_variable(ext_code, self, key, code);
169
+ return Qnil;
170
+ }
171
+
172
+ /*
173
+ * Binds a top-level argument to a value.
174
+ * @param [String] key name of the variable
175
+ * @param [String] val the value
176
+ */
177
+ static VALUE
178
+ vm_tla_var(VALUE self, VALUE key, VALUE val)
179
+ {
180
+ vm_bind_variable(tla_var, self, key, val);
181
+ return Qnil;
182
+ }
183
+
184
+ /*
185
+ * Binds a top-level argument to a code fragment.
186
+ * @param [String] key name of the variable
187
+ * @param [String] code Jsonnet expression
188
+ */
189
+ static VALUE
190
+ vm_tla_code(VALUE self, VALUE key, VALUE code)
191
+ {
192
+ vm_bind_variable(tla_code, self, key, code);
193
+ return Qnil;
194
+ }
195
+
196
+ /*
197
+ * Adds library search paths
198
+ */
199
+ static VALUE
200
+ vm_jpath_add_m(int argc, const VALUE *argv, VALUE self)
201
+ {
202
+ int i;
203
+ struct jsonnet_vm_wrap *vm = rubyjsonnet_obj_to_vm(self);
204
+
205
+ for (i = 0; i < argc; ++i) {
206
+ VALUE jpath = argv[i];
207
+ FilePathValue(jpath);
208
+ jsonnet_jpath_add(vm->vm, StringValueCStr(jpath));
209
+ }
210
+ return Qnil;
211
+ }
212
+
213
+ static VALUE
214
+ vm_set_max_stack(VALUE self, VALUE val)
215
+ {
216
+ struct jsonnet_vm_wrap *vm = rubyjsonnet_obj_to_vm(self);
217
+ jsonnet_max_stack(vm->vm, NUM2UINT(val));
218
+ return Qnil;
219
+ }
220
+
221
+ static VALUE
222
+ vm_set_gc_min_objects(VALUE self, VALUE val)
223
+ {
224
+ struct jsonnet_vm_wrap *vm = rubyjsonnet_obj_to_vm(self);
225
+ jsonnet_gc_min_objects(vm->vm, NUM2UINT(val));
226
+ return Qnil;
227
+ }
228
+
229
+ static VALUE
230
+ vm_set_gc_growth_trigger(VALUE self, VALUE val)
231
+ {
232
+ struct jsonnet_vm_wrap *vm = rubyjsonnet_obj_to_vm(self);
233
+ jsonnet_gc_growth_trigger(vm->vm, NUM2DBL(val));
234
+ return Qnil;
235
+ }
236
+
237
+ /*
238
+ * Let #evaluate and #evaluate_file return a raw String instead of JSON-encoded string if val is
239
+ * true
240
+ * @param [Boolean] val
241
+ */
242
+ static VALUE
243
+ vm_set_string_output(VALUE self, VALUE val)
244
+ {
245
+ struct jsonnet_vm_wrap *vm = rubyjsonnet_obj_to_vm(self);
246
+ jsonnet_string_output(vm->vm, RTEST(val));
247
+ return Qnil;
248
+ }
249
+
250
+ static VALUE
251
+ vm_set_max_trace(VALUE self, VALUE val)
252
+ {
253
+ struct jsonnet_vm_wrap *vm = rubyjsonnet_obj_to_vm(self);
254
+ jsonnet_max_trace(vm->vm, NUM2UINT(val));
255
+ return Qnil;
256
+ }
257
+
258
+ void
259
+ rubyjsonnet_init_vm(VALUE mJsonnet)
260
+ {
261
+ cVM = rb_define_class_under(mJsonnet, "VM", rb_cData);
262
+ rb_define_singleton_method(cVM, "new", vm_s_new, -1);
263
+ rb_define_private_method(cVM, "eval_file", vm_evaluate_file, 3);
264
+ rb_define_private_method(cVM, "eval_snippet", vm_evaluate, 3);
265
+ rb_define_method(cVM, "ext_var", vm_ext_var, 2);
266
+ rb_define_method(cVM, "ext_code", vm_ext_code, 2);
267
+ rb_define_method(cVM, "tla_var", vm_tla_var, 2);
268
+ rb_define_method(cVM, "tla_code", vm_tla_code, 2);
269
+ rb_define_method(cVM, "jpath_add", vm_jpath_add_m, -1);
270
+ rb_define_method(cVM, "max_stack=", vm_set_max_stack, 1);
271
+ rb_define_method(cVM, "gc_min_objects=", vm_set_gc_min_objects, 1);
272
+ rb_define_method(cVM, "gc_growth_trigger=", vm_set_gc_growth_trigger, 1);
273
+ rb_define_method(cVM, "string_output=", vm_set_string_output, 1);
274
+ rb_define_method(cVM, "max_trace=", vm_set_max_trace, 1);
275
+
276
+ rubyjsonnet_init_callbacks(cVM);
277
+
278
+ eEvaluationError = rb_define_class_under(mJsonnet, "EvaluationError", rb_eRuntimeError);
279
+ }
280
+
281
+ /**
282
+ * raises an EvaluationError whose message is \c msg.
283
+ * @param[in] vm a JsonnetVM
284
+ * @param[in] msg must be a NUL-terminated string returned by \c vm.
285
+ * @return never returns
286
+ * @throw EvaluationError
287
+ * @sa rescue_callback
288
+ */
289
+ static void
290
+ raise_eval_error(struct JsonnetVm *vm, char *msg, rb_encoding *enc)
291
+ {
292
+ VALUE ex;
293
+ const int state = rubyjsonnet_jump_tag(msg);
294
+ if (state) {
295
+ /*
296
+ * This is not actually an exception but another type of long jump
297
+ * with the state, temporarily caught by rescue_callback().
298
+ */
299
+ jsonnet_realloc(vm, msg, 0);
300
+ rb_jump_tag(state);
301
+ }
302
+
303
+ ex = rb_exc_new3(eEvaluationError, rb_enc_str_new_cstr(msg, enc));
304
+ jsonnet_realloc(vm, msg, 0);
305
+ rb_exc_raise(ex);
306
+ }
307
+
308
+ /**
309
+ * Returns a String whose contents is equal to \c json.
310
+ * It automatically frees \c json just after constructing the return value.
311
+ *
312
+ * @param[in] vm a JsonnetVM
313
+ * @param[in] json must be a NUL-terminated string returned by \c vm.
314
+ * @return Ruby string equal to \c json.
315
+ */
316
+ static VALUE
317
+ str_new_json(struct JsonnetVm *vm, char *json, rb_encoding *enc)
318
+ {
319
+ VALUE str = rb_enc_str_new_cstr(json, enc);
320
+ jsonnet_realloc(vm, json, 0);
321
+ return str;
322
+ }
323
+
324
+ /**
325
+ * Returns a Hash, whose keys are file names in the multi-mode of Jsonnet,
326
+ * and whose values are corresponding JSON values.
327
+ * It automatically frees \c json just after constructing the return value.
328
+ *
329
+ * @param[in] vm a JsonnetVM
330
+ * @param[in] buf NUL-separated and double-NUL-terminated sequence of strings returned by \c vm.
331
+ * @return Hash
332
+ */
333
+ static VALUE
334
+ fileset_new(struct JsonnetVm *vm, char *buf, rb_encoding *enc)
335
+ {
336
+ VALUE fileset = rb_hash_new();
337
+ char *ptr, *json;
338
+ for (ptr = buf; *ptr; ptr = json + strlen(json) + 1) {
339
+ json = ptr + strlen(ptr) + 1;
340
+ if (!*json) {
341
+ VALUE ex = rb_exc_new3(eEvaluationError,
342
+ rb_enc_sprintf(enc, "output file %s without body", ptr));
343
+ jsonnet_realloc(vm, buf, 0);
344
+ rb_exc_raise(ex);
345
+ }
346
+
347
+ rb_hash_aset(fileset, rb_enc_str_new_cstr(ptr, enc), rb_enc_str_new_cstr(json, enc));
348
+ }
349
+ jsonnet_realloc(vm, buf, 0);
350
+ return fileset;
351
+ }