@platforma-sdk/workflow-tengo 2.9.5 → 2.9.7

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 (64) hide show
  1. package/dist/tengo/lib/assets.lib.tengo +52 -52
  2. package/dist/tengo/lib/assets.swinfo.lib.tengo +45 -45
  3. package/dist/tengo/lib/constants.lib.tengo +32 -32
  4. package/dist/tengo/lib/exec.R.internal.lib.tengo +29 -29
  5. package/dist/tengo/lib/exec.R.lib.tengo +166 -166
  6. package/dist/tengo/lib/exec.constants.lib.tengo +4 -4
  7. package/dist/tengo/lib/exec.descriptor.lib.tengo +31 -31
  8. package/dist/tengo/lib/exec.internal.lib.tengo +297 -297
  9. package/dist/tengo/lib/exec.lib.tengo +815 -815
  10. package/dist/tengo/lib/exec.monetization.lib.tengo +130 -130
  11. package/dist/tengo/lib/exec.package.lib.tengo +212 -212
  12. package/dist/tengo/lib/exec.python.internal.lib.tengo +6 -6
  13. package/dist/tengo/lib/exec.python.lib.tengo +146 -146
  14. package/dist/tengo/lib/exec.runcmd.lib.tengo +371 -371
  15. package/dist/tengo/lib/exec.runenv.lib.tengo +92 -92
  16. package/dist/tengo/lib/exec.stream.lib.tengo +40 -40
  17. package/dist/tengo/lib/file.internal.lib.tengo +77 -77
  18. package/dist/tengo/lib/file.lib.tengo +57 -57
  19. package/dist/tengo/lib/ll.lib.tengo +244 -244
  20. package/dist/tengo/lib/maps.lib.tengo +152 -152
  21. package/dist/tengo/lib/objects.lib.tengo +13 -13
  22. package/dist/tengo/lib/oop.lib.tengo +19 -19
  23. package/dist/tengo/lib/path.lib.tengo +125 -125
  24. package/dist/tengo/lib/pframes.constants.lib.tengo +28 -28
  25. package/dist/tengo/lib/pframes.export-pcolumn.lib.tengo +33 -33
  26. package/dist/tengo/lib/pframes.lib.tengo +43 -43
  27. package/dist/tengo/lib/pframes.ll.lib.tengo +72 -72
  28. package/dist/tengo/lib/pframes.pcolumn.lib.tengo +49 -49
  29. package/dist/tengo/lib/pframes.spec.lib.tengo +96 -96
  30. package/dist/tengo/lib/pframes.util.lib.tengo +288 -288
  31. package/dist/tengo/lib/pframes.xsv.lib.tengo +272 -272
  32. package/dist/tengo/lib/render.lib.tengo +75 -75
  33. package/dist/tengo/lib/sets.lib.tengo +68 -68
  34. package/dist/tengo/lib/slices.lib.tengo +258 -155
  35. package/dist/tengo/lib/smart.lib.tengo +1069 -1069
  36. package/dist/tengo/lib/test.lib.tengo +161 -161
  37. package/dist/tengo/lib/tpl.lib.tengo +515 -515
  38. package/dist/tengo/lib/tpl.state-await.lib.tengo +240 -240
  39. package/dist/tengo/lib/tpl.util.lib.tengo +9 -9
  40. package/dist/tengo/lib/validation.lib.tengo +378 -378
  41. package/dist/tengo/lib/workdir.lib.tengo +331 -331
  42. package/dist/tengo/lib/workdir.proc.lib.tengo +144 -144
  43. package/dist/tengo/lib/workdir.save.lib.tengo +130 -130
  44. package/dist/tengo/lib/workflow.bobject.lib.tengo +26 -26
  45. package/dist/tengo/lib/workflow.bquery.lib.tengo +165 -165
  46. package/dist/tengo/lib/workflow.constants.lib.tengo +2 -2
  47. package/dist/tengo/lib/workflow.context.lib.tengo +32 -32
  48. package/dist/tengo/lib/workflow.lib.tengo +206 -206
  49. package/dist/tengo/tpl/exec.R.create-renv.plj.gz +0 -0
  50. package/dist/tengo/tpl/exec.exec.plj.gz +0 -0
  51. package/dist/tengo/tpl/exec.monetization_to_json.plj.gz +0 -0
  52. package/dist/tengo/tpl/exec.python.create-venv.plj.gz +0 -0
  53. package/dist/tengo/tpl/exec.python.install-deps.plj.gz +0 -0
  54. package/dist/tengo/tpl/pframes.aggregate.plj.gz +0 -0
  55. package/dist/tengo/tpl/pframes.export-multiple-pcolumns.plj.gz +0 -0
  56. package/dist/tengo/tpl/pframes.export-pframe.plj.gz +0 -0
  57. package/dist/tengo/tpl/pframes.export-single-pcolumn.plj.gz +0 -0
  58. package/dist/tengo/tpl/pframes.import-dir.plj.gz +0 -0
  59. package/dist/tengo/tpl/pframes.map-pframe.plj.gz +0 -0
  60. package/dist/tengo/tpl/pframes.xsv-export-pframe.plj.gz +0 -0
  61. package/dist/tengo/tpl/pframes.xsv-import-map.plj.gz +0 -0
  62. package/dist/tengo/tpl/workdir.save.plj.gz +0 -0
  63. package/dist/tengo/tpl/workflow.build-ctx.plj.gz +0 -0
  64. package/package.json +2 -2
@@ -1,254 +1,254 @@
1
-
2
-
3
-
4
-
1
+ /**
2
+ * Library implementing state machine to await certain resource states in
3
+ * ephemeral templates.
4
+ */
5
5
 
6
6
  tx := import("tx")
7
7
  ll := import("@platforma-sdk/workflow-tengo:ll")
8
8
  text := import("text")
9
9
 
10
10
  createContext := func() {
11
- return {
12
- activeSubscriptions: {},
13
- resolvedStates: {}
14
- }
11
+ return {
12
+ activeSubscriptions: {},
13
+ resolvedStates: {}
14
+ }
15
15
  }
16
16
 
17
17
  awaitOneState := func(field, path, state) {
18
- if field.isErrorSet() && !field.isValueSet() {
19
-
20
-
21
-
22
-
23
- return { type: "Ready" }
24
- }
25
-
26
- if len(path) > 0 {
27
- step := path[0]
28
- rPath := path[1:]
29
-
30
- if !field.isValueSet() {
31
- return {
32
- type: "Subscribe",
33
- subscriptions: [{
34
- resource: field.id.ResourceID,
35
- event: "InputSet"
36
- }]
37
- }
38
- }
39
-
40
- resource := field.getValue()
41
-
42
- if is_string(step) {
43
- nextField := resource.inputs()[step]
44
- if nextField == undefined {
45
- if resource.info().InputsLocked {
46
- ll.panic("field %v not found and inputs locked", step)
47
- }
48
- return {
49
- type: "Subscribe",
50
- subscriptions: [{
51
- resource: resource.id,
52
- event: "FieldCreated"
53
- },{
54
- resource: resource.id,
55
- event: "InputsLocked"
56
- }]
57
- }
58
- }
59
- return awaitOneState(nextField, rPath, state)
60
- } else if is_map(step) {
61
- if is_undefined(step.wildcard) == is_undefined(step.match) {
62
- ll.panic("Unknown step structure: %v", step)
63
- }
64
-
65
- matcher := undefined
66
-
67
- if !is_undefined(step.wildcard) {
68
- if step.wildcard != "*" {
69
- ll.panic("Complex wildcards are not supported, use { match: \"{regexp}\" }: %v", step.wildcard)
70
- }
71
- matcher = func(field) {
72
- return true
73
- }
74
- } else {
75
- regex := text.re_compile(step.match)
76
- if is_error(regex) {
77
- ll.panic("Error parsing regex %v: %v", step.match, regex)
78
- }
79
- matcher = func(field) {
80
- return regex.match(field)
81
- }
82
- }
83
-
84
- if !resource.info().InputsLocked {
85
- return {
86
- type: "Subscribe",
87
- subscriptions: [{
88
- resource: resource.id,
89
- event: "InputsLocked"
90
- }]
91
- }
92
- }
93
-
94
- subscriptions := []
95
- for nextFieldName, nextField in resource.inputs() {
96
- if !matcher(nextFieldName) {
97
- continue
98
- }
99
- res := awaitOneState(nextField, rPath, state)
100
- if res.type == "Ready" {
101
- continue
102
- } else if res.type == "Subscribe" {
103
- subscriptions = append(subscriptions, res.subscriptions...)
104
- } else {
105
- ll.panic("Unknown result type: %v", res.type)
106
- }
107
- }
108
- if len(subscriptions) == 0 {
109
- return { type: "Ready" }
110
- } else {
111
- return {
112
- type: "Subscribe",
113
- subscriptions: subscriptions
114
- }
115
- }
116
- } else {
117
- ll.panic("Malformed state await request path: %v", step)
118
- }
119
- } else {
120
- if state == "Exists" {
121
- return { type: "Ready" }
122
- } else {
123
- if !field.isSet() {
124
- return {
125
- type: "Subscribe",
126
- subscriptions: [{
127
- resource: field.id.ResourceID,
128
- event: "InputSet"
129
- }]
130
- }
131
- }
132
- resource := field.getValue()
133
- if state == "Set" {
134
- return { type: "Ready" }
135
- } else if state == "InputsLocked" {
136
- if resource.info().InputsLocked {
137
- return { type: "Ready" }
138
- } else {
139
- return {
140
- type: "Subscribe",
141
- subscriptions: [{
142
- resource: resource.id,
143
- event: "InputsLocked"
144
- }]
145
- }
146
- }
147
- } else if state == "AllInputsSet" {
148
- if resource.info().AllInputsSet {
149
- return { type: "Ready" }
150
- } else {
151
- return {
152
- type: "Subscribe",
153
- subscriptions: [{
154
- resource: resource.id,
155
- event: "AllInputsSet"
156
- }]
157
- }
158
- }
159
- } else if state == "ResourceReady" {
160
- if resource.info().ResourceReady {
161
- return { type: "Ready" }
162
- } else {
163
- return {
164
- type: "Subscribe",
165
- subscriptions: [{
166
- resource: resource.id,
167
- event: "ResourceReady"
168
- }]
169
- }
170
- }
171
- } else {
172
- ll.panic("Unknown await state: %v", state)
173
- }
174
- }
175
- }
176
- }
177
-
178
-
18
+ if field.isErrorSet() && !field.isValueSet() {
19
+ // Field is in pure error state (just error and no referenced resource).
20
+ // This is a terminal state, so we stop any traversal here, and return value
21
+ // the same as we would return if we achieved the desired state. It is
22
+ // template's body responsibility to correctly handle the error state.
23
+ return { type: "Ready" }
24
+ }
25
+
26
+ if len(path) > 0 {
27
+ step := path[0]
28
+ rPath := path[1:]
29
+
30
+ if !field.isValueSet() {
31
+ return {
32
+ type: "Subscribe",
33
+ subscriptions: [{
34
+ resource: field.id.ResourceID,
35
+ event: "InputSet"
36
+ }]
37
+ }
38
+ }
39
+
40
+ resource := field.getValue()
41
+
42
+ if is_string(step) {
43
+ nextField := resource.inputs()[step]
44
+ if nextField == undefined {
45
+ if resource.info().InputsLocked {
46
+ ll.panic("field %v not found and inputs locked", step)
47
+ }
48
+ return {
49
+ type: "Subscribe",
50
+ subscriptions: [{
51
+ resource: resource.id,
52
+ event: "FieldCreated"
53
+ },{
54
+ resource: resource.id,
55
+ event: "InputsLocked"
56
+ }]
57
+ }
58
+ }
59
+ return awaitOneState(nextField, rPath, state)
60
+ } else if is_map(step) {
61
+ if is_undefined(step.wildcard) == is_undefined(step.match) {
62
+ ll.panic("Unknown step structure: %v", step)
63
+ }
64
+
65
+ matcher := undefined
66
+
67
+ if !is_undefined(step.wildcard) {
68
+ if step.wildcard != "*" {
69
+ ll.panic("Complex wildcards are not supported, use { match: \"{regexp}\" }: %v", step.wildcard)
70
+ }
71
+ matcher = func(field) {
72
+ return true
73
+ }
74
+ } else {
75
+ regex := text.re_compile(step.match)
76
+ if is_error(regex) {
77
+ ll.panic("Error parsing regex %v: %v", step.match, regex)
78
+ }
79
+ matcher = func(field) {
80
+ return regex.match(field)
81
+ }
82
+ }
83
+
84
+ if !resource.info().InputsLocked {
85
+ return {
86
+ type: "Subscribe",
87
+ subscriptions: [{
88
+ resource: resource.id,
89
+ event: "InputsLocked"
90
+ }]
91
+ }
92
+ }
93
+
94
+ subscriptions := []
95
+ for nextFieldName, nextField in resource.inputs() {
96
+ if !matcher(nextFieldName) {
97
+ continue
98
+ }
99
+ res := awaitOneState(nextField, rPath, state)
100
+ if res.type == "Ready" {
101
+ continue
102
+ } else if res.type == "Subscribe" {
103
+ subscriptions = append(subscriptions, res.subscriptions...)
104
+ } else {
105
+ ll.panic("Unknown result type: %v", res.type)
106
+ }
107
+ }
108
+ if len(subscriptions) == 0 {
109
+ return { type: "Ready" }
110
+ } else {
111
+ return {
112
+ type: "Subscribe",
113
+ subscriptions: subscriptions
114
+ }
115
+ }
116
+ } else {
117
+ ll.panic("Malformed state await request path: %v", step)
118
+ }
119
+ } else {
120
+ if state == "Exists" {
121
+ return { type: "Ready" }
122
+ } else {
123
+ if !field.isSet() {
124
+ return {
125
+ type: "Subscribe",
126
+ subscriptions: [{
127
+ resource: field.id.ResourceID,
128
+ event: "InputSet"
129
+ }]
130
+ }
131
+ }
132
+ resource := field.getValue()
133
+ if state == "Set" {
134
+ return { type: "Ready" }
135
+ } else if state == "InputsLocked" {
136
+ if resource.info().InputsLocked {
137
+ return { type: "Ready" }
138
+ } else {
139
+ return {
140
+ type: "Subscribe",
141
+ subscriptions: [{
142
+ resource: resource.id,
143
+ event: "InputsLocked"
144
+ }]
145
+ }
146
+ }
147
+ } else if state == "AllInputsSet" {
148
+ if resource.info().AllInputsSet {
149
+ return { type: "Ready" }
150
+ } else {
151
+ return {
152
+ type: "Subscribe",
153
+ subscriptions: [{
154
+ resource: resource.id,
155
+ event: "AllInputsSet"
156
+ }]
157
+ }
158
+ }
159
+ } else if state == "ResourceReady" {
160
+ if resource.info().ResourceReady {
161
+ return { type: "Ready" }
162
+ } else {
163
+ return {
164
+ type: "Subscribe",
165
+ subscriptions: [{
166
+ resource: resource.id,
167
+ event: "ResourceReady"
168
+ }]
169
+ }
170
+ }
171
+ } else {
172
+ ll.panic("Unknown await state: %v", state)
173
+ }
174
+ }
175
+ }
176
+ }
177
+
178
+ /** Returns true if all requested states are reached */
179
179
  await := func(rootField, ctxStorageResource, requests) {
180
- pssKey := "await:" + string(rootField.id.ResourceID) + ":" + rootField.id.Name
181
- prevSubscriptions := ctxStorageResource.kvGetAsJson(pssKey)
182
-
183
- if !is_undefined(prevSubscriptions) && len(prevSubscriptions) == 0 {
184
-
185
- ll.panic("Unexpected state, desired state was reached in the previous call")
186
- }
187
-
188
- if is_undefined(prevSubscriptions) {
189
-
190
- prevSubscriptions = {}
191
- }
192
-
193
- subscriptions := {}
194
-
195
- addSubscription := func(subscription) {
196
- key := string(subscription.resource) + ":" + subscription.event
197
- if !is_undefined(subscriptions[key]) {
198
- return false
199
- } else {
200
- subscriptions[key] = subscription
201
- return true
202
- }
203
- }
204
-
205
- for _, request in requests {
206
- if !is_map(request) || !is_array(request.path) || !is_string(request.state) {
207
- ll.panic("Malformed state await request: %v", request)
208
- }
209
- res := awaitOneState(rootField, request.path, request.state)
210
- if res.type == "Ready" {
211
- continue
212
- } else if res.type == "Subscribe" {
213
- for subscription in res.subscriptions {
214
- addSubscription(subscription)
215
- }
216
- } else {
217
- ll.panic("Unknown result type %v", res.type)
218
- }
219
- }
220
-
221
-
222
- for key, sub in subscriptions {
223
- if !is_undefined(prevSubscriptions[key]) {
224
-
225
- continue
226
- }
227
- e := {}
228
- e[sub.event] = true
229
- tx.subscribeTo(sub.resource, pssKey + ":" + key, e)
230
- }
231
-
232
-
233
- for key, _ in prevSubscriptions {
234
- if !is_undefined(subscriptions[key]) {
235
-
236
- continue
237
- }
238
- tx.unsubscribeFrom(pssKey + ":" + key)
239
- }
240
-
241
-
242
- newPrevSubscriptions := {}
243
- for key, _ in subscriptions {
244
- newPrevSubscriptions[key] = true
245
- }
246
-
247
- ctxStorageResource.kvSetJson(pssKey, newPrevSubscriptions)
248
-
249
- return len(subscriptions) == 0
180
+ pssKey := "await:" + string(rootField.id.ResourceID) + ":" + rootField.id.Name
181
+ prevSubscriptions := ctxStorageResource.kvGetAsJson(pssKey)
182
+
183
+ if !is_undefined(prevSubscriptions) && len(prevSubscriptions) == 0 {
184
+ // initialization was finished before, in a previous template execution
185
+ ll.panic("Unexpected state, desired state was reached in the previous call")
186
+ }
187
+
188
+ if is_undefined(prevSubscriptions) {
189
+ // initializing previous subscriptions set
190
+ prevSubscriptions = {}
191
+ }
192
+
193
+ subscriptions := {}
194
+
195
+ addSubscription := func(subscription) {
196
+ key := string(subscription.resource) + ":" + subscription.event
197
+ if !is_undefined(subscriptions[key]) {
198
+ return false
199
+ } else {
200
+ subscriptions[key] = subscription
201
+ return true
202
+ }
203
+ }
204
+
205
+ for _, request in requests {
206
+ if !is_map(request) || !is_array(request.path) || !is_string(request.state) {
207
+ ll.panic("Malformed state await request: %v", request)
208
+ }
209
+ res := awaitOneState(rootField, request.path, request.state)
210
+ if res.type == "Ready" {
211
+ continue
212
+ } else if res.type == "Subscribe" {
213
+ for subscription in res.subscriptions {
214
+ addSubscription(subscription)
215
+ }
216
+ } else {
217
+ ll.panic("Unknown result type %v", res.type)
218
+ }
219
+ }
220
+
221
+ // creating new subscriptions
222
+ for key, sub in subscriptions {
223
+ if !is_undefined(prevSubscriptions[key]) {
224
+ // don't create subscription, if it was created in the past
225
+ continue
226
+ }
227
+ e := {}
228
+ e[sub.event] = true
229
+ tx.subscribeTo(sub.resource, pssKey + ":" + key, e)
230
+ }
231
+
232
+ // unsubscribing from subscriptions we don't need anymore
233
+ for key, _ in prevSubscriptions {
234
+ if !is_undefined(subscriptions[key]) {
235
+ // don't unsubscribe from subscriptions, we still need
236
+ continue
237
+ }
238
+ tx.unsubscribeFrom(pssKey + ":" + key)
239
+ }
240
+
241
+ // creating and saving new context; savong only keys
242
+ newPrevSubscriptions := {}
243
+ for key, _ in subscriptions {
244
+ newPrevSubscriptions[key] = true
245
+ }
246
+ // saving the context
247
+ ctxStorageResource.kvSetJson(pssKey, newPrevSubscriptions)
248
+
249
+ return len(subscriptions) == 0
250
250
  }
251
251
 
252
252
  export ll.toStrict({
253
- await: await
253
+ await: await
254
254
  })
@@ -1,19 +1,19 @@
1
-
1
+ /* Templates/renderers utils */
2
2
 
3
3
  ll := import("@platforma-sdk/workflow-tengo:ll")
4
4
 
5
-
5
+ // template field name in renderer resource
6
6
  TEMPLATE_FIELD := "template"
7
-
7
+ // field name of a resource map with the inputs in renderer resource
8
8
  INPUTS_MAP_FIELD := "inputs"
9
-
9
+ // prefix of output fields template results in renderer resource
10
10
  TEMPLATE_OUTPUT_PREFIX := "outputs/"
11
-
11
+ // input field containing a map with resources to prepare for the body
12
12
  PREPARE_MAP_FIELD_NAME := "__prepare__"
13
13
 
14
14
  export ll.toStrict({
15
- TEMPLATE_FIELD : TEMPLATE_FIELD,
16
- INPUTS_MAP_FIELD : INPUTS_MAP_FIELD,
17
- TEMPLATE_OUTPUT_PREFIX : TEMPLATE_OUTPUT_PREFIX,
18
- PREPARE_MAP_FIELD_NAME : PREPARE_MAP_FIELD_NAME
15
+ TEMPLATE_FIELD : TEMPLATE_FIELD,
16
+ INPUTS_MAP_FIELD : INPUTS_MAP_FIELD,
17
+ TEMPLATE_OUTPUT_PREFIX : TEMPLATE_OUTPUT_PREFIX,
18
+ PREPARE_MAP_FIELD_NAME : PREPARE_MAP_FIELD_NAME
19
19
  })