@platforma-sdk/workflow-tengo 2.2.1 → 2.3.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.
- package/dist/tengo/lib/exec.package.lib.tengo +4 -4
- package/dist/tengo/lib/file.internal.lib.tengo +4 -4
- package/dist/tengo/lib/maps.lib.tengo +41 -0
- package/dist/tengo/lib/pframes.spec.lib.tengo +136 -0
- package/dist/tengo/lib/pframes.util.lib.tengo +39 -39
- package/dist/tengo/lib/validation.lib.tengo +26 -4
- package/dist/tengo/lib/workflow.bobject.lib.tengo +7 -7
- package/dist/tengo/lib/workflow.bquery.lib.tengo +5 -5
- package/dist/tengo/tpl/exec.exec.plj.gz +0 -0
- package/dist/tengo/tpl/exec.python.create-venv.plj.gz +0 -0
- package/dist/tengo/tpl/exec.python.install-deps.plj.gz +0 -0
- package/dist/tengo/tpl/pframes.aggregate.plj.gz +0 -0
- package/dist/tengo/tpl/pframes.export-multiple-pcolumns.plj.gz +0 -0
- package/dist/tengo/tpl/pframes.export-pframe.plj.gz +0 -0
- package/dist/tengo/tpl/pframes.export-single-pcolumn.plj.gz +0 -0
- package/dist/tengo/tpl/pframes.import-dir.plj.gz +0 -0
- package/dist/tengo/tpl/pframes.map-pframe.plj.gz +0 -0
- package/dist/tengo/tpl/pframes.xsv-export-pframe.plj.gz +0 -0
- package/dist/tengo/tpl/pframes.xsv-import-map.plj.gz +0 -0
- package/dist/tengo/tpl/workdir.save.plj.gz +0 -0
- package/dist/tengo/tpl/workflow.build-ctx.plj.gz +0 -0
- package/package.json +1 -1
|
@@ -38,10 +38,10 @@ localDescriptorScheme := {
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
descriptorScheme := {
|
|
41
|
-
"isDev
|
|
42
|
-
"binary
|
|
43
|
-
"asset
|
|
44
|
-
"local
|
|
41
|
+
"isDev,?": "bool",
|
|
42
|
+
"binary,?": binaryDescriptorScheme,
|
|
43
|
+
"asset,?": assetDescriptorScheme,
|
|
44
|
+
"local,?": localDescriptorScheme
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
softwareInfoScheme := {
|
|
@@ -33,8 +33,8 @@ RTYPE_BLOB_DOWNLOAD := { Name: "BlobDownload", Version: "2" }
|
|
|
33
33
|
createBlobImportExternal := func(settings) {
|
|
34
34
|
validation.assertJsonSchema(settings, {
|
|
35
35
|
"dataURL": "string",
|
|
36
|
-
"dataHeaders
|
|
37
|
-
"dataVersion
|
|
36
|
+
"dataHeaders,?": [["string"]],
|
|
37
|
+
"dataVersion,?": "string"
|
|
38
38
|
})
|
|
39
39
|
|
|
40
40
|
importer := smart.structBuilder(RTYPE_BLOB_IMPORT_EXTERNAL, json.encode(settings)).lockAndBuild()
|
|
@@ -55,8 +55,8 @@ createBlobImportInternal := func(settings) {
|
|
|
55
55
|
validation.assertJsonSchema(settings, {
|
|
56
56
|
"path": "string",
|
|
57
57
|
"storageId": "string",
|
|
58
|
-
"maxSpeedBytes
|
|
59
|
-
"dataVersion
|
|
58
|
+
"maxSpeedBytes,?": "number",
|
|
59
|
+
"dataVersion,?": "string"
|
|
60
60
|
})
|
|
61
61
|
|
|
62
62
|
importer := smart.structBuilder(RTYPE_BLOB_IMPORT_INTERNAL, json.encode(settings)).lockAndBuild()
|
|
@@ -89,8 +89,49 @@ filterKeysValues := func(map, predicateFnK, predicateFnV) {
|
|
|
89
89
|
return filter(map, func(k, v) { return predicateFnK(k) && predicateFnV(v) })
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
+
/**
|
|
93
|
+
* Do shallow merge of arbitrary number of maps.
|
|
94
|
+
* Add {... key: undefined ...} to remove the "key" from the map collected from maps before.
|
|
95
|
+
*/
|
|
96
|
+
merge := func(...maps) {
|
|
97
|
+
res := {}
|
|
98
|
+
for map in maps {
|
|
99
|
+
for k, v in map {
|
|
100
|
+
if is_undefined(v) {
|
|
101
|
+
delete(res, k)
|
|
102
|
+
} else {
|
|
103
|
+
res[k] = v
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return res
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Do deep merge of arbitrary number of maps.
|
|
112
|
+
* Add {... key: undefined ...} to remove the "key" from the map collected from maps before.
|
|
113
|
+
*/
|
|
114
|
+
deepMerge := undefined
|
|
115
|
+
deepMerge = func(...maps) {
|
|
116
|
+
res := {}
|
|
117
|
+
for map in maps {
|
|
118
|
+
for k, v in map {
|
|
119
|
+
if is_undefined(v) {
|
|
120
|
+
delete(res, k)
|
|
121
|
+
} else if is_map(res[k]) && is_map(v) {
|
|
122
|
+
res[k] = deepMerge(res[k], v)
|
|
123
|
+
} else {
|
|
124
|
+
res[k] = v
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return res
|
|
129
|
+
}
|
|
130
|
+
|
|
92
131
|
export ll.toStrict({
|
|
93
132
|
map : map,
|
|
133
|
+
merge: merge,
|
|
134
|
+
deepMerge: deepMerge,
|
|
94
135
|
mapKeys : mapKeys,
|
|
95
136
|
mapValues : mapValues,
|
|
96
137
|
filter : filter,
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PFrames spec library:
|
|
3
|
+
* - well known domains, annotations and column names.
|
|
4
|
+
* - utility methods to manipulate column and axis spec
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
ll := import("@platforma-sdk/workflow-tengo:ll")
|
|
8
|
+
maps := import("@platforma-sdk/workflow-tengo:maps")
|
|
9
|
+
validation := import("@platforma-sdk/workflow-tengo:validation")
|
|
10
|
+
json := import("json")
|
|
11
|
+
|
|
12
|
+
//
|
|
13
|
+
// Common schemas
|
|
14
|
+
//
|
|
15
|
+
|
|
16
|
+
P_AXIS_SPEC_SCHEMA := {
|
|
17
|
+
// `__options__,closed`: ``, // commented out to keep the room for future schema modifications
|
|
18
|
+
`type`: `string,regex=Int|Long|Float|Double|String`,
|
|
19
|
+
`name`: `string`,
|
|
20
|
+
`domain,?`: { any: `string` },
|
|
21
|
+
`annotations,?`: { any: `string` },
|
|
22
|
+
`parentAxes,?`: `any` // [ `number` ]
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
P_COLUMN_SPEC_SCHEMA := {
|
|
26
|
+
// `__options__,closed`: ``, // commented out to keep the room for future schema modifications
|
|
27
|
+
`kind`: `string,regex=PColumn`,
|
|
28
|
+
`valueType`: `string`,
|
|
29
|
+
`name`: `string`,
|
|
30
|
+
`domain,?`: { any: `string` },
|
|
31
|
+
`annotations,?`: { any: `string` },
|
|
32
|
+
`parentAxes,?`: `any`, // [ `number` ]
|
|
33
|
+
`axesSpec,?`: [ P_AXIS_SPEC_SCHEMA ]
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
KIND_P_COLUMN := "PColumn"
|
|
37
|
+
|
|
38
|
+
//
|
|
39
|
+
// Column / axis names
|
|
40
|
+
//
|
|
41
|
+
|
|
42
|
+
/** Column containing labels for axis keys */
|
|
43
|
+
N_LABEL := "pl7.app/label"
|
|
44
|
+
|
|
45
|
+
//
|
|
46
|
+
// Column / axis domains
|
|
47
|
+
//
|
|
48
|
+
|
|
49
|
+
/** Domain marking column or axis as block-specific, value must contain block id */
|
|
50
|
+
D_BLOCK := "pl7.app/block"
|
|
51
|
+
|
|
52
|
+
//
|
|
53
|
+
// Column / axis annotations
|
|
54
|
+
//
|
|
55
|
+
|
|
56
|
+
/** Annotation with axis or column label */
|
|
57
|
+
A_LABEL := "pl7.app/label"
|
|
58
|
+
/**
|
|
59
|
+
* Annotation containing trace of operations resulting in a corresponding column.
|
|
60
|
+
*
|
|
61
|
+
* Value must containe JSON encoded array of structures:
|
|
62
|
+
* {
|
|
63
|
+
* type: string - type of the step, often equals to block package name (i.e. milaboratories.mixcr-clonotyping)
|
|
64
|
+
* label: string - string representation of the operation often a block title
|
|
65
|
+
* importance: number - higher the number higher the change label from trace step will be used to derive column label
|
|
66
|
+
* id: string - unique identifier of operation, often a block id
|
|
67
|
+
* }
|
|
68
|
+
*/
|
|
69
|
+
A_TRACE := "pl7.app/trace"
|
|
70
|
+
|
|
71
|
+
//
|
|
72
|
+
// Utility methods
|
|
73
|
+
//
|
|
74
|
+
|
|
75
|
+
_TRACE_STEP_SCHEMA := {
|
|
76
|
+
`type`: `string`,
|
|
77
|
+
`label`: `string`,
|
|
78
|
+
`importance,?`: `number`,
|
|
79
|
+
`id,?`: `string`,
|
|
80
|
+
`__options__,closed`: ``
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
_TRACE_SCHEMA := [_TRACE_STEP_SCHEMA]
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Calculates content of pl7.app/trace annotation, given input column spec, or annotations section
|
|
87
|
+
* of specs, or directly content of pl7.app/trace from the input column spec.
|
|
88
|
+
*
|
|
89
|
+
* Basically validates and adds provided steps.
|
|
90
|
+
*/
|
|
91
|
+
makeTrace := func(input, ...steps) {
|
|
92
|
+
// validating input step structure
|
|
93
|
+
validation.assertJsonSchema(steps, _TRACE_SCHEMA)
|
|
94
|
+
|
|
95
|
+
currentTraceContent := undefined
|
|
96
|
+
if is_string(input) {
|
|
97
|
+
currentTraceContent = input
|
|
98
|
+
} else if is_string(input[A_TRACE]) {
|
|
99
|
+
currentTraceContent = input[A_TRACE]
|
|
100
|
+
} else if is_string(input["annotations"][A_TRACE]) {
|
|
101
|
+
currentTraceContent = input["annotations"][A_TRACE]
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
currentTrace := []
|
|
105
|
+
if !is_undefined(currentTraceContent) {
|
|
106
|
+
currentTrace = json.decode(currentTraceContent)
|
|
107
|
+
// validating trace we just parsed
|
|
108
|
+
validation.assertJsonSchema(currentTrace, _TRACE_SCHEMA)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
currentTrace = append(currentTrace, steps...)
|
|
112
|
+
currentTraceStr := string(json.encode(currentTrace))
|
|
113
|
+
|
|
114
|
+
return ll.toStrict({
|
|
115
|
+
value: currentTrace,
|
|
116
|
+
valueStr: currentTraceStr,
|
|
117
|
+
/** Injects trace information into column spec */
|
|
118
|
+
inject: func(spec) {
|
|
119
|
+
validation.assertJsonSchema(spec, P_COLUMN_SPEC_SCHEMA)
|
|
120
|
+
return maps.deepMerge(spec, {annotations: {"pl7.app/trace": currentTraceStr}})
|
|
121
|
+
}
|
|
122
|
+
})
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export ll.toStrict({
|
|
126
|
+
KIND_P_COLUMN: KIND_P_COLUMN,
|
|
127
|
+
|
|
128
|
+
N_LABEL: N_LABEL,
|
|
129
|
+
|
|
130
|
+
D_BLOCK: D_BLOCK,
|
|
131
|
+
|
|
132
|
+
A_LABEL: A_LABEL,
|
|
133
|
+
A_TRACE: A_TRACE,
|
|
134
|
+
|
|
135
|
+
makeTrace: makeTrace
|
|
136
|
+
})
|
|
@@ -54,33 +54,33 @@ _SPEC_AXES_SCHEMA := {
|
|
|
54
54
|
// Regular expression, if matched - whole row would be skipped;
|
|
55
55
|
// Performed just after reading XSV before any other operations;
|
|
56
56
|
// default: no filter
|
|
57
|
-
`filterOutRegex
|
|
57
|
+
`filterOutRegex,?`: `string`,
|
|
58
58
|
// Pre-processing operations to be performed just after filtering out rows
|
|
59
|
-
`preProcess
|
|
59
|
+
`preProcess,?`: [_PRE_PROCESS_STEP_SCHEMA],
|
|
60
60
|
// Regular expression, if matched - value is considered to be N/A;
|
|
61
61
|
// default: Int, Long - check that the value is a valid integer number;
|
|
62
62
|
// Float, Double - check that the value is a valid float number, not a NaN;
|
|
63
63
|
// String - accept anything;
|
|
64
|
-
`naRegex
|
|
64
|
+
`naRegex,?`: `string`,
|
|
65
65
|
// Should the N/A values (or empty rows) be allowed;
|
|
66
66
|
// default: false
|
|
67
|
-
`allowNA
|
|
67
|
+
`allowNA,?`: `bool`,
|
|
68
68
|
// Specification of the axis
|
|
69
69
|
`spec`: {
|
|
70
70
|
// Type of axis values
|
|
71
71
|
`type`: `string,regex=Int|Long|Float|Double|String`,
|
|
72
72
|
// Name of the axis to be used in spec;
|
|
73
73
|
// default: column label
|
|
74
|
-
`name
|
|
74
|
+
`name,?`: `string`,
|
|
75
75
|
// Auxiliary information to the axis name, type and parents to form a unique identifier;
|
|
76
76
|
// default: empty
|
|
77
|
-
`domain
|
|
77
|
+
`domain,?`: { any: `string` },
|
|
78
78
|
// Any additional information attached to the axis that does not affect its identifier;
|
|
79
79
|
// default: "pl7.app/label": Column label from XSV
|
|
80
|
-
`annotations
|
|
80
|
+
`annotations,?`: { any: `string` },
|
|
81
81
|
// A list of zero-based indices of parent axes in the overall axes specification;
|
|
82
82
|
// default: empty
|
|
83
|
-
`parentAxes
|
|
83
|
+
`parentAxes,?`: [`number`]
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
86
|
|
|
@@ -90,36 +90,36 @@ _SPEC_COLUMN_SCHEMA := {
|
|
|
90
90
|
// Regular expression, if matched - whole row would be skipped;
|
|
91
91
|
// Performed just after reading XSV before any other operations;
|
|
92
92
|
// default: no filter
|
|
93
|
-
`filterOutRegex
|
|
93
|
+
`filterOutRegex,?`: `string`,
|
|
94
94
|
// Pre-processing operations to be performed just after filtering out rows
|
|
95
|
-
`preProcess
|
|
95
|
+
`preProcess,?`: [_PRE_PROCESS_STEP_SCHEMA],
|
|
96
96
|
// Regular expression, if matched - value is considered to be N/A;
|
|
97
97
|
// default: Int, Long - check that the value is a valid integer number;
|
|
98
98
|
// Float, Double - check that the value is a valid float number, not a NaN;
|
|
99
99
|
// String - accept anything;
|
|
100
|
-
`naRegex
|
|
100
|
+
`naRegex,?`: `string`,
|
|
101
101
|
// Should the N/A values (or empty rows) be allowed;
|
|
102
102
|
// default: true
|
|
103
|
-
`allowNA
|
|
103
|
+
`allowNA,?`: `bool`,
|
|
104
104
|
// ID of the column to be used in spec and as a saved filename;
|
|
105
105
|
// default: column label with all special characters replaced with '_'
|
|
106
|
-
`id
|
|
106
|
+
`id,?`: `string`,
|
|
107
107
|
// Specification of the column
|
|
108
108
|
`spec`: {
|
|
109
109
|
// Type of column values
|
|
110
110
|
`valueType`: `string,regex=Int|Long|Float|Double|String`,
|
|
111
111
|
// Name of the column to be used in spec;
|
|
112
112
|
// default: column label
|
|
113
|
-
`name
|
|
113
|
+
`name,?`: `string`,
|
|
114
114
|
// Auxiliary information to the column name, type and parents to form a unique identifier;
|
|
115
115
|
// default: empty
|
|
116
|
-
`domain
|
|
116
|
+
`domain,?`: { any: `string` },
|
|
117
117
|
// Any additional information attached to the axis that does not affect its identifier;
|
|
118
118
|
// default: "pl7.app/label": Column label from XSV
|
|
119
|
-
`annotations
|
|
119
|
+
`annotations,?`: { any: `string` },
|
|
120
120
|
// A list of zero-based indices of parent axes in the overall axes specification;
|
|
121
121
|
// default: empty
|
|
122
|
-
`parentAxes
|
|
122
|
+
`parentAxes,?`: [ `number` ]
|
|
123
123
|
}
|
|
124
124
|
}
|
|
125
125
|
|
|
@@ -128,86 +128,86 @@ _SPEC_INDEX_SCHEMA := {
|
|
|
128
128
|
`name`: `string`,
|
|
129
129
|
// Auxiliary information to the column name, type and parents to form a unique identifier;
|
|
130
130
|
// default: empty
|
|
131
|
-
`domain
|
|
131
|
+
`domain,?`: { any: `string` },
|
|
132
132
|
// Any additional information attached to the axis that does not affect its identifier;
|
|
133
133
|
// default: "pl7.app/label": name
|
|
134
|
-
`annotations
|
|
134
|
+
`annotations,?`: { any: `string` },
|
|
135
135
|
// A list of zero-based indices of parent axes in the overall axes specification;
|
|
136
136
|
// default: empty
|
|
137
|
-
`parentAxes
|
|
137
|
+
`parentAxes,?`: [`number`]
|
|
138
138
|
}
|
|
139
139
|
|
|
140
140
|
PFCONV_IMPORT_CFG_SCHEMA := {
|
|
141
141
|
// Single ASCII character to be used as separator;
|
|
142
142
|
// default: ',' for .csv, '\t' for .tsv
|
|
143
|
-
`separator
|
|
143
|
+
`separator,?`: `string`,
|
|
144
144
|
// Single ASCII character, if XSV row begins with this character - the row would be skipped;
|
|
145
145
|
// default: error is thrown if comment lines are found in document
|
|
146
|
-
`commentLinePrefix
|
|
146
|
+
`commentLinePrefix,?`: `string`,
|
|
147
147
|
// Should empty lines be skipped;
|
|
148
148
|
// default: false
|
|
149
|
-
`skipEmptyLines
|
|
149
|
+
`skipEmptyLines,?`: `bool`,
|
|
150
150
|
// Resolve duplicates by adding sequential suffixes to column labels;
|
|
151
151
|
// default: true
|
|
152
|
-
`allowColumnLabelDuplicates
|
|
152
|
+
`allowColumnLabelDuplicates,?`: `bool`,
|
|
153
153
|
// XSV columns to use as PColumn axes, order of axes in resulting columns
|
|
154
154
|
// would match the order of spec entries provided here
|
|
155
155
|
`axes`: [_SPEC_AXES_SCHEMA],
|
|
156
156
|
// Axis of type Long with XSV row numbers (would be the last one);
|
|
157
157
|
// default: do not create additional axis with indexes
|
|
158
|
-
`index
|
|
158
|
+
`index,?`: _SPEC_INDEX_SCHEMA,
|
|
159
159
|
// XSV columns to use as PColumn values, each exported individually
|
|
160
160
|
`columns`: [_SPEC_COLUMN_SCHEMA],
|
|
161
161
|
// When columns spec is provided but no such column was found in XSV - create such column
|
|
162
162
|
// filled with NA values instead of failing;
|
|
163
163
|
// default: false
|
|
164
|
-
`allowArtificialColumns
|
|
164
|
+
`allowArtificialColumns,?`: `bool`,
|
|
165
165
|
// Prefix all column names with given string;
|
|
166
166
|
// default: names would be preserved
|
|
167
|
-
`columnNamePrefix
|
|
167
|
+
`columnNamePrefix,?`: `string`,
|
|
168
168
|
// Columns would be stored using specified format;
|
|
169
169
|
// default: Binary
|
|
170
|
-
`storageFormat
|
|
170
|
+
`storageFormat,?` : `string,regex=Binary|Json`,
|
|
171
171
|
// Partitioning key length;
|
|
172
172
|
// default: 0
|
|
173
|
-
`partitionKeyLength
|
|
173
|
+
`partitionKeyLength,?` : `number`
|
|
174
174
|
}
|
|
175
175
|
|
|
176
176
|
_COLUMN_FILTER_SCHEMA := {
|
|
177
177
|
// Match any of the types listed here;
|
|
178
178
|
// default: type is ignored during matching
|
|
179
|
-
`type
|
|
179
|
+
`type,?`: `string,regex=Int|Long|Float|Double|String|Bytes`,
|
|
180
180
|
// Match any of the names listed here;
|
|
181
181
|
// default: name is ignored during matching
|
|
182
|
-
`name
|
|
182
|
+
`name,?`: `string`,
|
|
183
183
|
// Match requires all the listed annotations to have provided values;
|
|
184
184
|
// default: no annotation equality checks are performed during matching
|
|
185
|
-
`annotationValue
|
|
185
|
+
`annotationValue,?`: { any: `string` },
|
|
186
186
|
// Match requires all the listed annotations to match provided regex patterns;
|
|
187
187
|
// default: no annotation pattern matching is performed during matching
|
|
188
|
-
`annotationPattern
|
|
188
|
+
`annotationPattern,?`: { any: `string` }
|
|
189
189
|
}
|
|
190
190
|
|
|
191
191
|
PFCONV_EXPORT_CFG_SCHEMA := {
|
|
192
192
|
// String representing NA values of types Int, Long, Float, Double;
|
|
193
193
|
// default: NaN
|
|
194
|
-
`naStr
|
|
194
|
+
`naStr,?`: `string`,
|
|
195
195
|
// String representing NA and missing values of types String, Bytes;
|
|
196
196
|
// default: null
|
|
197
|
-
`nullStr
|
|
197
|
+
`nullStr,?`: `string`,
|
|
198
198
|
// Toggle to export or skip axes and columns of type Bytes;
|
|
199
199
|
// default: false
|
|
200
|
-
`exportBytes
|
|
200
|
+
`exportBytes,?`: `bool`,
|
|
201
201
|
// Single ASCII character to be used as separator;
|
|
202
202
|
// default: ',' for .csv, '\t' for .tsv
|
|
203
|
-
`separator
|
|
203
|
+
`separator,?`: `string`,
|
|
204
204
|
// Only columns matching the selector are exported;
|
|
205
205
|
// default: all columns are exported
|
|
206
|
-
`columnSelector
|
|
206
|
+
`columnSelector,?`: [_COLUMN_FILTER_SCHEMA],
|
|
207
207
|
// During export, columns with equal axes specifications would be joined into single table
|
|
208
208
|
// using the join type specified;
|
|
209
209
|
// default: Full
|
|
210
|
-
`joinType
|
|
210
|
+
`joinType,?`: `string,regex=Full|Inner`
|
|
211
211
|
}
|
|
212
212
|
|
|
213
213
|
/**
|
|
@@ -234,22 +234,41 @@ _validateJson := func(js, schema, keyPath, ...stack) {
|
|
|
234
234
|
schemaTags := {}
|
|
235
235
|
// schema.key -> rule
|
|
236
236
|
schemaRules := {}
|
|
237
|
+
// js padded with all keys from schema
|
|
238
|
+
jsFull := {}
|
|
237
239
|
|
|
238
240
|
for k, v in schema {
|
|
239
241
|
p := _parseTags(k)
|
|
240
242
|
schemaTags[p.key] = p
|
|
241
243
|
schemaRules[p.key] = v
|
|
244
|
+
jsFull[p.key] = undefined
|
|
242
245
|
}
|
|
243
246
|
|
|
244
247
|
// tags that should be applied to all elements
|
|
245
248
|
any := schemaTags["any"]
|
|
249
|
+
if !is_undefined(any) {
|
|
250
|
+
if is_undefined(jsFull["any"]) { // in case actual object has field named "any"
|
|
251
|
+
delete(jsFull, "any")
|
|
252
|
+
}
|
|
253
|
+
}
|
|
246
254
|
|
|
247
255
|
options := schemaTags["__options__"]
|
|
248
256
|
if is_undefined(options) {
|
|
249
257
|
options = {}
|
|
258
|
+
} else {
|
|
259
|
+
delete(schemaTags, "__options__")
|
|
260
|
+
delete(schemaRules, "__options__")
|
|
261
|
+
if is_undefined(jsFull["__options__"]) { // in case actual object has field named "__options__"
|
|
262
|
+
delete(jsFull, "__options__")
|
|
263
|
+
}
|
|
250
264
|
}
|
|
251
265
|
|
|
252
|
-
|
|
266
|
+
// transferring fields from input map into padded map
|
|
267
|
+
for k, v in js {
|
|
268
|
+
jsFull[k] = v
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
for _key, elem in jsFull {
|
|
253
272
|
if any {
|
|
254
273
|
r := _validateJson(elem, schemaRules["any"], _formatKeyPath(keyPath, "%s.%s", _key), js, stack...)
|
|
255
274
|
if isFail(r) {
|
|
@@ -284,8 +303,11 @@ _validateJson := func(js, schema, keyPath, ...stack) {
|
|
|
284
303
|
}
|
|
285
304
|
}
|
|
286
305
|
|
|
287
|
-
if
|
|
288
|
-
|
|
306
|
+
if is_undefined(elem) {
|
|
307
|
+
if key.tags["omitempty"] || key.tags["optional"] || key.tags["?"] {
|
|
308
|
+
continue
|
|
309
|
+
}
|
|
310
|
+
return fail(keyPath, "value %q does not contain key %q", js, _key)
|
|
289
311
|
}
|
|
290
312
|
|
|
291
313
|
r := _validateJson(elem, schemaRules[_key], _formatKeyPath(keyPath, "%s.%s", _key), js, stack...)
|
|
@@ -356,7 +378,7 @@ resource := func(...args) {
|
|
|
356
378
|
}
|
|
357
379
|
|
|
358
380
|
assertJsonSchema(ops, {
|
|
359
|
-
`type
|
|
381
|
+
`type,?`: {
|
|
360
382
|
Name: `string`,
|
|
361
383
|
Version: `string`
|
|
362
384
|
}
|
|
@@ -15,20 +15,20 @@ _pObjectSpecSchema := {
|
|
|
15
15
|
|
|
16
16
|
"kind": "string",
|
|
17
17
|
|
|
18
|
-
"valueType
|
|
18
|
+
"valueType,?": `string,regex=json|File|DynamicFile|String|Double|Long|Int`,
|
|
19
19
|
|
|
20
|
-
"name
|
|
20
|
+
"name,?": {",any": "string"},
|
|
21
21
|
|
|
22
|
-
"domain
|
|
22
|
+
"domain,?": {",any": "string"},
|
|
23
23
|
|
|
24
|
-
"axesSpec
|
|
24
|
+
"axesSpec,?": [{
|
|
25
25
|
"type": "string,regex=String",
|
|
26
26
|
"name": "string",
|
|
27
|
-
"domain
|
|
28
|
-
"annotations
|
|
27
|
+
"domain,?": {",any": "string"},
|
|
28
|
+
"annotations,?": {",any": "string"}
|
|
29
29
|
}],
|
|
30
30
|
|
|
31
|
-
"annotations
|
|
31
|
+
"annotations,?": {",any": "string"}
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
|
|
@@ -9,11 +9,11 @@ _CONTEXT_FIELD_NAME := "ctx"
|
|
|
9
9
|
|
|
10
10
|
// options scheme for query
|
|
11
11
|
_OPTIONS_SCHEME := {
|
|
12
|
-
"spec
|
|
13
|
-
"data
|
|
14
|
-
"single
|
|
15
|
-
"first
|
|
16
|
-
"errIfMissing
|
|
12
|
+
"spec,?": `bool`,
|
|
13
|
+
"data,?": `bool`,
|
|
14
|
+
"single,?": `bool`,
|
|
15
|
+
"first,?": `bool`,
|
|
16
|
+
"errIfMissing,?": `bool`
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
// default query options
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|