@platforma-sdk/workflow-tengo 3.0.3 → 3.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.
Files changed (51) hide show
  1. package/dist/index.d.ts +1 -1
  2. package/dist/index.js +2 -1
  3. package/dist/index.mjs +2 -1
  4. package/dist/tengo/lib/canonical.lib.tengo +73 -0
  5. package/dist/tengo/lib/exec.lib.tengo +4 -7
  6. package/dist/tengo/lib/exec.limits.lib.tengo +63 -1
  7. package/dist/tengo/lib/exec.monetization.lib.tengo +3 -1
  8. package/dist/tengo/lib/exec.monetization_internal.lib.tengo +2 -1
  9. package/dist/tengo/lib/exec.runcmd.lib.tengo +47 -7
  10. package/dist/tengo/lib/feats.lib.tengo +5 -4
  11. package/dist/tengo/lib/maps.lib.tengo +1 -1
  12. package/dist/tengo/lib/pframes.builder.lib.tengo +5 -1
  13. package/dist/tengo/lib/pframes.bundle.lib.tengo +544 -0
  14. package/dist/tengo/lib/pframes.constants.lib.tengo +5 -1
  15. package/dist/tengo/lib/pframes.lib.tengo +3 -0
  16. package/dist/tengo/lib/pframes.spec.lib.tengo +224 -1
  17. package/dist/tengo/lib/pframes.xsv-import-file.lib.tengo +3 -3
  18. package/dist/tengo/lib/pframes.xsv.lib.tengo +79 -4
  19. package/dist/tengo/lib/sets.lib.tengo +2 -0
  20. package/dist/tengo/lib/slices.lib.tengo +4 -1
  21. package/dist/tengo/lib/smart.lib.tengo +24 -6
  22. package/dist/tengo/lib/tpl.base.lib.tengo +582 -0
  23. package/dist/tengo/lib/tpl.lib.tengo +6 -567
  24. package/dist/tengo/lib/tpl.light.lib.tengo +9 -0
  25. package/dist/tengo/lib/workdir.lib.tengo +1 -1
  26. package/dist/tengo/lib/workdir.proc.lib.tengo +1 -1
  27. package/dist/tengo/lib/workflow.lib.tengo +41 -2
  28. package/dist/tengo/lib/workflow.model.lib.tengo +3 -2
  29. package/dist/tengo/tpl/exec.R.create-renv.plj.gz +0 -0
  30. package/dist/tengo/tpl/exec.exec.plj.gz +0 -0
  31. package/dist/tengo/tpl/exec.monetization_info.plj.gz +0 -0
  32. package/dist/tengo/tpl/exec.monetization_to_json.plj.gz +0 -0
  33. package/dist/tengo/tpl/exec.python.create-venv.plj.gz +0 -0
  34. package/dist/tengo/tpl/exec.python.install-deps.plj.gz +0 -0
  35. package/dist/tengo/tpl/ll.get-field.plj.gz +0 -0
  36. package/dist/tengo/tpl/pframes.export-multiple-pcolumns.plj.gz +0 -0
  37. package/dist/tengo/tpl/pframes.export-pframe-for-ui.plj.gz +0 -0
  38. package/dist/tengo/tpl/pframes.export-pframe.plj.gz +0 -0
  39. package/dist/tengo/tpl/pframes.export-single-pcolumn.plj.gz +0 -0
  40. package/dist/tengo/tpl/pframes.import-dir.plj.gz +0 -0
  41. package/dist/tengo/tpl/pframes.process-pcolumn-data.plj.gz +0 -0
  42. package/dist/tengo/tpl/pframes.remove-nulls.plj.gz +0 -0
  43. package/dist/tengo/tpl/pframes.slice-data.plj.gz +0 -0
  44. package/dist/tengo/tpl/pframes.xsv-export-pframe.plj.gz +0 -0
  45. package/dist/tengo/tpl/pframes.xsv-import-if-not-null.plj.gz +0 -0
  46. package/dist/tengo/tpl/pframes.xsv-import-map.plj.gz +0 -0
  47. package/dist/tengo/tpl/waiter.waiter.plj.gz +0 -0
  48. package/dist/tengo/tpl/workdir.save.plj.gz +0 -0
  49. package/dist/tengo/tpl/workflow.build-ctx.plj.gz +0 -0
  50. package/dist/tengo/tpl/workflow.query-anchored.plj.gz +0 -0
  51. package/package.json +2 -2
@@ -0,0 +1,582 @@
1
+ tx := import("tx")
2
+ ll := import("@platforma-sdk/workflow-tengo:ll")
3
+ render := import("@platforma-sdk/workflow-tengo:render")
4
+ smart := import("@platforma-sdk/workflow-tengo:smart")
5
+ sets := import("@platforma-sdk/workflow-tengo:sets")
6
+ maps := import("@platforma-sdk/workflow-tengo:maps")
7
+ tplutil := import("@platforma-sdk/workflow-tengo:tpl.util")
8
+ constants := import("@platforma-sdk/workflow-tengo:constants")
9
+ stateAwait := import("@platforma-sdk/workflow-tengo:tpl.state-await")
10
+ validation := import("@platforma-sdk/workflow-tengo:validation")
11
+
12
+
13
+
14
+
15
+
16
+
17
+
18
+
19
+
20
+
21
+ _unmarshal := func(resource, preprocessors) {
22
+ ll.assert(smart.isResource(resource), "expected resource, found ", resource)
23
+
24
+
25
+ self := func(resource) { return _unmarshal(resource, preprocessors) }
26
+
27
+ for preproc in preprocessors {
28
+ if preproc.canParse(resource) {
29
+ return preproc.parse(resource, self)
30
+ }
31
+ }
32
+
33
+ if smart.isReference(resource) && resource.hasError() {
34
+ err := resource.getError().getDataAsJson()
35
+ if !is_undefined(err.message) {
36
+ err = err.message
37
+ }
38
+ ll.panic("input resource has errors: %v", err)
39
+ }
40
+
41
+ if smart.isResource(resource) && resource.checkResourceType(constants.RTYPE_NULL) {
42
+ return undefined
43
+ }
44
+
45
+ if smart.isJsonResource(resource) || resource.checkResourceType(constants.RTYPE_BOBJECT_SPEC) {
46
+
47
+
48
+ return resource.getDataAsJson()
49
+ } else if smart.isMapResource(resource) || smart.isLockedEphMapResource(resource) {
50
+
51
+
52
+ result := {}
53
+ for field, value in resource.inputs() {
54
+ if value.isErrorSet() {
55
+ ll.panic("input %v field has error: %v", field, field.getError().getDataAsJson().message)
56
+ } else if value.isSet() {
57
+ result[field] = _unmarshal(value.getValue(), preprocessors)
58
+ } else {
59
+ result[field] = value
60
+ }
61
+
62
+ }
63
+ return result
64
+ } else {
65
+
66
+ return resource
67
+ }
68
+ }
69
+
70
+
71
+
72
+
73
+
74
+
75
+
76
+
77
+
78
+ tpl := func(ops) {
79
+ self := undefined
80
+
81
+ _renderer := smart.resourceBuilder(ll.getCurrentTemplateRenderer())
82
+
83
+ _rendererType := _renderer.info().Type
84
+
85
+ _isEphemeral := _rendererType.Name == constants.RTYPE_RENDER_EPH_TEMPLATE.Name
86
+
87
+ _hasPrepared := _renderer.get(tplutil.INPUTS_MAP_FIELD).hasField(tplutil.PREPARE_MAP_FIELD_NAME)
88
+
89
+ _preparedMap := _hasPrepared ? _renderer.get(tplutil.INPUTS_MAP_FIELD).get(tplutil.PREPARE_MAP_FIELD_NAME) : undefined
90
+
91
+ _templateId := _renderer.get(tplutil.TEMPLATE_FIELD).id
92
+
93
+ _stateRequests := []
94
+ _delegatedOutputs := []
95
+
96
+ self = {
97
+
98
+
99
+
100
+
101
+ renderer: func() {
102
+ return _renderer
103
+ },
104
+
105
+
106
+
107
+
108
+ isEphemeral: func() {
109
+ return _isEphemeral
110
+ },
111
+
112
+
113
+
114
+
115
+ template: func() {
116
+ return smart.resource(_templateId)
117
+ },
118
+
119
+ _unmarshallers: copy(ops.unmarshallers),
120
+
121
+
122
+
123
+
124
+
125
+
126
+ registerUnmarshaller: func(preproc) {
127
+ ll.assert(is_undefined(self._inputs), "input preprocessors must be registered before getting inputs")
128
+ self._unmarshallers = append(self._unmarshallers, preproc)
129
+ },
130
+
131
+
132
+
133
+
134
+ rawInputs: func() {
135
+ return self.renderer().get(tplutil.INPUTS_MAP_FIELD).inputs()
136
+ },
137
+
138
+ _inputs: undefined,
139
+
140
+
141
+
142
+
143
+ inputs: func() {
144
+ if self._inputs == undefined {
145
+ inputs := _unmarshal(self.renderer().get(tplutil.INPUTS_MAP_FIELD), self._unmarshallers)
146
+
147
+
148
+ pp := inputs[tplutil.PREPARE_MAP_FIELD_NAME]
149
+ if !is_undefined(pp) {
150
+ delete(inputs, tplutil.PREPARE_MAP_FIELD_NAME)
151
+ for k, v in pp {
152
+ ll.assert(is_undefined(inputs[k]), k, " key already exists in inputs map")
153
+ inputs[k] = v
154
+ }
155
+ }
156
+
157
+ self._inputs = inputs
158
+ }
159
+ return self._inputs
160
+ },
161
+
162
+
163
+
164
+
165
+ hasInput: func(name) {
166
+ return self.renderer().get(tplutil.INPUTS_MAP_FIELD).hasField(name)
167
+ },
168
+
169
+
170
+ definedOutputs : [],
171
+
172
+
173
+
174
+
175
+
176
+
177
+
178
+ defineOutputs : func(...name) {
179
+ if len(name) == 1 && is_array(name[0]) {
180
+ for v in name[0] {
181
+ self.definedOutputs = append(self.definedOutputs, v)
182
+ }
183
+ } else {
184
+ self.definedOutputs = append(self.definedOutputs, name...)
185
+ }
186
+ },
187
+
188
+
189
+
190
+
191
+
192
+
193
+
194
+
195
+
196
+
197
+
198
+
199
+
200
+
201
+
202
+
203
+
204
+
205
+
206
+
207
+
208
+
209
+
210
+
211
+
212
+
213
+
214
+
215
+
216
+
217
+
218
+
219
+
220
+
221
+ awaitState: func(...pathAndState) {
222
+ if !self.isEphemeral() {
223
+ ll.panic("awaitState allowed only in ephemeral templates")
224
+ }
225
+ self.awaitStateIfEphemeral(pathAndState...)
226
+ },
227
+
228
+
229
+
230
+
231
+
232
+
233
+
234
+
235
+
236
+
237
+
238
+
239
+
240
+
241
+
242
+
243
+
244
+
245
+
246
+
247
+
248
+
249
+
250
+
251
+
252
+
253
+
254
+
255
+
256
+
257
+
258
+
259
+
260
+
261
+ awaitStateIfEphemeral: func(...pathAndState) {
262
+ if !self.isEphemeral() {
263
+ return
264
+ }
265
+ path := pathAndState[:len(pathAndState) - 1]
266
+ state := pathAndState[len(pathAndState) - 1]
267
+ _stateRequests = append(_stateRequests, {
268
+ path: path,
269
+ state: state
270
+ })
271
+ },
272
+
273
+
274
+
275
+
276
+
277
+ ignorePrepare: _hasPrepared,
278
+
279
+
280
+
281
+
282
+ preparedMapResource: func() {
283
+ return _preparedMap
284
+ },
285
+
286
+
287
+
288
+
289
+ prepareQueue : [],
290
+
291
+
292
+
293
+
294
+
295
+
296
+
297
+ prepare : func(codeFn) {
298
+ if self.ignorePrepare {
299
+ return
300
+ }
301
+
302
+ ll.assert(len(self.prepareQueue) == 0, "multiple prepare statements are not supported yet")
303
+
304
+ self.prepareQueue = append(self.prepareQueue, codeFn)
305
+ },
306
+
307
+
308
+
309
+
310
+
311
+ renderPrepare: func() {
312
+ ll.assert(!self.ignorePrepare, "expected !ignorePrepare")
313
+
314
+ inputs := self.inputs()
315
+
316
+
317
+ newInputs := copy(inputs)
318
+
319
+
320
+ builder := undefined
321
+ if self.isEphemeral() {
322
+ builder = smart.ephemeralMapBuilder()
323
+ } else {
324
+ builder = smart.mapBuilder()
325
+ }
326
+
327
+
328
+ self._validateInputs()
329
+ for cb in self.prepareQueue {
330
+
331
+ r := cb(inputs)
332
+
333
+ ll.assert(is_map(r), "expected map, got ", r)
334
+
335
+ for name, ref in r {
336
+ ll.assert(is_undefined(newInputs[name]), "prepare name is already in use: %s", name)
337
+
338
+ builder.add(name, ref)
339
+ }
340
+ }
341
+ newInputs[tplutil.PREPARE_MAP_FIELD_NAME] = builder.build()
342
+
343
+
344
+ renderer := undefined
345
+ if self.isEphemeral() {
346
+ renderer = render.createEphemeral(self.template(), newInputs)
347
+ } else {
348
+ renderer = render.create(self.template(), newInputs)
349
+ }
350
+
351
+ for output in self.definedOutputs {
352
+ self.getOutputField(output).set(renderer.output(output))
353
+ }
354
+ },
355
+
356
+
357
+
358
+
359
+
360
+ setOutputs : func(resultMap) {
361
+ ll.assert(ll.isMap(resultMap), "expected map, got ", resultMap)
362
+
363
+
364
+ for name, value in resultMap {
365
+ f := self.getOutputField(name)
366
+ if !f.isSet() {
367
+ f.setRefOrJson(value)
368
+ }
369
+ }
370
+ },
371
+
372
+
373
+
374
+
375
+ getOutputField: func(name) {
376
+ return self.renderer().getField(tplutil.TEMPLATE_OUTPUT_PREFIX + name)
377
+ },
378
+
379
+
380
+
381
+
382
+ createOutputsAndLock: func(outputs) {
383
+ for name in outputs {
384
+ self.renderer().createOutputField(tplutil.TEMPLATE_OUTPUT_PREFIX + name)
385
+ }
386
+ self.renderer().lockOutputs()
387
+ },
388
+
389
+ _inputsSchema: undefined,
390
+
391
+
392
+
393
+
394
+ validateInputs: func(schema) {
395
+ ll.assert(is_undefined(self._inputsSchema), "validateInputs was already invoked")
396
+ self._inputsSchema = schema
397
+ },
398
+
399
+ _validateInputs: func() {
400
+ schema := self._inputsSchema
401
+ if is_undefined(schema) {
402
+ return
403
+ }
404
+ validation.assertType(self.inputs(), schema)
405
+ },
406
+
407
+
408
+
409
+
410
+ body: func(bodyFn){
411
+ if self.isEphemeral() {
412
+
413
+ self.routeEph(bodyFn)
414
+ } else {
415
+
416
+ self.routePure(bodyFn)
417
+ }
418
+ },
419
+
420
+
421
+
422
+
423
+ routePure: func(bodyFn){
424
+
425
+ if len(self.definedOutputs) == 0 {
426
+ ll.panic("please define outputs before template body")
427
+ }
428
+
429
+
430
+
431
+
432
+
433
+
434
+
435
+
436
+
437
+
438
+
439
+
440
+
441
+ if ll.isInitializing() {
442
+
443
+
444
+ self.createOutputsAndLock(self.definedOutputs)
445
+ } else {
446
+
447
+
448
+ if len(self.prepareQueue) != 0 {
449
+
450
+
451
+ self.renderPrepare()
452
+ } else {
453
+
454
+ self._validateInputs()
455
+ result := bodyFn(self.inputs())
456
+
457
+ ll.assert(ll.isMap(result),
458
+ "expected map from tpl.body() callback. Did you forget 'return' statement?")
459
+
460
+ outputsWithValues := sets.fromMapKeys(result)
461
+ outputsWithValues = sets.add(outputsWithValues, _delegatedOutputs...)
462
+
463
+ ll.assert(sets.fromSlice(self.definedOutputs) == outputsWithValues,
464
+ "tpl.body() callback must return the same list of outputs as were given to 'defineOutputs()'. Want %s, got %s",
465
+ self.definedOutputs, sets.toSlice(outputsWithValues))
466
+
467
+
468
+ self.setOutputs(result)
469
+ }
470
+ }
471
+ },
472
+
473
+
474
+
475
+
476
+ routeEph: func(bodyFn) {
477
+
478
+ if len(_stateRequests) == 0 {
479
+ _stateRequests = [{
480
+ path: [],
481
+ state: "AllInputsSet"
482
+ }]
483
+ }
484
+
485
+ if _hasPrepared {
486
+ _stateRequests = append(_stateRequests, {
487
+ path: [tplutil.PREPARE_MAP_FIELD_NAME],
488
+ state: "ResourceReady"
489
+ })
490
+ }
491
+
492
+ stateReached := stateAwait.await(
493
+ _renderer.getField(tplutil.INPUTS_MAP_FIELD),
494
+ _renderer,
495
+ _stateRequests
496
+ )
497
+
498
+ if stateReached {
499
+
500
+ if len(self.prepareQueue) > 0 {
501
+ ll.assert(len(self.definedOutputs) > 0, "outputs should be defined prior to prepare")
502
+
503
+ self.createOutputsAndLock(self.definedOutputs)
504
+
505
+ self.renderPrepare()
506
+ } else {
507
+
508
+
509
+ self._validateInputs()
510
+ result := bodyFn(self.inputs())
511
+ ll.assert(ll.isMap(result),
512
+ "expected map from tpl-eph.body() callback. Did you forget 'return' statement?")
513
+
514
+ self.createOutputsAndLock(maps.getKeys(result))
515
+
516
+
517
+ self.setOutputs(result)
518
+ }
519
+ }
520
+ },
521
+
522
+
523
+
524
+
525
+
526
+
527
+
528
+
529
+
530
+ routeDelegate: func(tpl, extraInputs, outputs) {
531
+ _delegatedOutputs = outputs
532
+
533
+ inputs := self.rawInputs()
534
+ for k, v in extraInputs {
535
+ inputs[k] = v
536
+ }
537
+
538
+ renderer := undefined
539
+ if self.isEphemeral() {
540
+ renderer = render.createEphemeral(tpl, inputs)
541
+ } else {
542
+ renderer = render.create(tpl, inputs)
543
+ }
544
+
545
+ tplOutputs := {}
546
+ for o in outputs {
547
+ tplOutputs[o] = renderer.output(o)
548
+ }
549
+
550
+ self.createOutputsAndLock(outputs)
551
+ self.setOutputs(tplOutputs)
552
+ },
553
+
554
+
555
+
556
+
557
+
558
+
559
+ api: func() {
560
+ return ll.toStrict({
561
+ renderer : self.renderer,
562
+ registerUnmarshaller : self.registerUnmarshaller,
563
+ rawInputs : self.rawInputs,
564
+ hasInput : self.hasInput,
565
+ inputs : self.inputs,
566
+ defineOutputs : self.defineOutputs,
567
+ prepare : self.prepare,
568
+ awaitState : self.awaitState,
569
+ awaitStateIfEphemeral : self.awaitStateIfEphemeral,
570
+ delegate : self.routeDelegate,
571
+ validateInputs : self.validateInputs,
572
+ body : self.body,
573
+ template : self.template
574
+ })
575
+ }
576
+ }
577
+ return self
578
+ }
579
+
580
+ export ll.toStrict({
581
+ tpl: tpl
582
+ })