cxtms 1.9.21 → 1.9.22

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cxtms",
3
- "version": "1.9.21",
3
+ "version": "1.9.22",
4
4
  "description": "Schema validation package for CXTMS YAML modules",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -4,8 +4,8 @@
4
4
  - NCalc expression syntax `[variable]` (in conditions and expression directives)
5
5
  - Operators (comparison, logical, arithmetic, ternary, membership)
6
6
  - Iterator variables (`[each.*]` and `[item.*]`)
7
- - Collection functions (any, all, count, sum, first, last, distinct, groupBy, join, etc.)
8
- - String functions (isNullOrEmpty, length, lower, upper, replace, format, base64, etc.)
7
+ - Collection functions (any, all, count, sum, first, last, distinct, select, zip, groupBy, join, etc.)
8
+ - String functions (isNullOrEmpty, length, lower, upper, replace, format, base64, coalesce, etc.)
9
9
  - Date functions (now, parseDate, addDays, formatDate, dateFromUnix, etc.)
10
10
  - Math functions (Abs, Ceiling, Floor, Round, Min, Max, etc.)
11
11
  - Domain functions (convertWeight, convertDimension)
@@ -28,6 +28,7 @@ conditions:
28
28
  - Numeric strings are auto-converted to `decimal` when needed (e.g., `[price] > 100` works even if price is the string `"150"`)
29
29
  - Dot paths resolve deep: `[Activity.Step.output.nested.field]`
30
30
  - Optional suffix `?` prevents errors: `[order.customer?.name?]`
31
+ - Wildcard traversal continues through POCOs, dictionaries, and `JObject` values, for example `[items[*].customValues.chapter_en?]`
31
32
 
32
33
  ### Operators
33
34
 
@@ -42,14 +43,14 @@ conditions:
42
43
  ### Iterator Variables
43
44
 
44
45
  Functions use two iterator variable names:
45
- - **`[each.*]`** -- used by: `any`, `all`, `sum`, `join` (3-arg)
46
+ - **`[each.*]`** -- used by: `any`, `all`, `sum`, `select`, `join` (3-arg), and projections over `zip(...)` output
46
47
  - **`[item.*]`** -- used by: `first`, `last`, `groupBy`
47
48
 
48
49
  ### Collection Functions
49
50
 
50
51
  | Function | Description |
51
52
  |----------|-------------|
52
- | `any([items], [each.prop] = 'val')` | True if any item matches expression. Without expression: checks if collection contains the value |
53
+ | `any([items], [each.prop] = 'val')` | True if any item matches expression. Without expression: checks if collection contains the value. Returns `false` for empty collections |
53
54
  | `all([items], [each.prop] > 0)` | True if all items match. Returns `false` for null/empty collections |
54
55
  | `count([items])` | Count items in list or JToken. Returns `0` for non-collections |
55
56
  | `sum([items], [each.amount])` | Sum values as `decimal`. Optional `[each.*]` accessor. Skips nulls |
@@ -63,6 +64,8 @@ Functions use two iterator variable names:
63
64
  | `groupBy([items], [item.cat])` | Group by one or more key expressions. Returns `[{key, items}]`. Multi-key: keys joined with `\|` |
64
65
  | `join([items], [each.name], ',')` | Join collection with `[each.*]` accessor and separator (3-arg) |
65
66
  | `join([items], ',')` | Join collection directly with separator (2-arg) |
67
+ | `select([items], [each.field])` | Project each item via `[each.*]` accessor. Returns flat `List<object>` of projected values. Empty input → empty list |
68
+ | `zip([a], [b])` | Pair elements from two or more lists into `[{item1, item2}, ...]`. Custom keys: `zip([a], [b], 'name', 'code')`. Variadic: accepts N lists. Truncates to shortest list. Returns empty list if any input is empty/null. Falls back to `item1`, `item2`, ... when custom key count does not match list count |
66
69
  | `split([str], ' ')` | Split string by first character of separator. Returns `List<string>` |
67
70
  | `elementAt([items], 0)` | Get element at index (zero-based) from list |
68
71
 
@@ -82,6 +85,8 @@ Functions use two iterator variable names:
82
85
  | `bool([value])` | Convert to boolean: null->`false`, empty string->`false`, "true"/"false"->parsed, non-zero number->`true`, any object->`true` |
83
86
  | `transliterate([value])` | Unicode to ASCII (Unidecode). Returns `""` for null |
84
87
  | `transliterateUa([value])` | Ukrainian-specific transliteration. Returns `""` for null |
88
+ | `coalesce([a], [b], 'default')` | First non-null, non-empty/whitespace argument. Variadic. `0` and `false` are kept (not skipped). Returns `null` if all args are null/empty |
89
+ | `prop([obj], 'path.to.field')` | Drill into an object by a runtime-computed string path. Supports dotted paths and `?` optional suffix, same as `[obj.path]` but the path is a string argument |
85
90
  | `parseAddress([address])` | Parse address -> `{StreetNumber, StreetName}`. Handles US and EU formats |
86
91
 
87
92
  ### Date Functions
@@ -152,6 +152,7 @@ Used in `collection:` (foreach), `mapping:` (outputs), and variable resolution.
152
152
  | `list[0]` | Array index | `items[0]` |
153
153
  | `list[^1]` | Index from end (last item) | `items[^1]` |
154
154
  | `list[*]` | Flatten/wildcard (all items) | `containers[*].commodities` |
155
+ | `list[*].dictKey` | Wildcard traversal into Dictionary/JObject keys | `items[*].customValues.chapter_en` |
155
156
  | `list[**]` | Recursive flatten (all depths) | `containerCommodities[**]` |
156
157
  | `list[-1]` | Depth filter (leaves only) | `tree[**][-1]` |
157
158
  | `list[condition]` | Filter by condition | `items[status=Active]` |
@@ -159,3 +160,7 @@ Used in `collection:` (foreach), `mapping:` (outputs), and variable resolution.
159
160
  | `list[*].{f1 f2}` | Field selector (projection) | `items[*].{name description}` |
160
161
  | `list[*].{alias:source}` | Field selector with alias | `items[*].{id:commodityId}` |
161
162
  | `list[*].{alias:_.parent}` | Field selector referencing parent | `items[*].{parentId:_.orderId}` |
163
+
164
+ **Wildcard traversal into Dictionary/JObject**: After `[*]`, subsequent path segments drill into Dictionary keys and JObject properties on each item. Dictionary-like values are preserved intact (not flattened) so multi-hop paths work: `items[*].customValues.chapter_en` extracts the `chapter_en` key from each item's `customValues` dictionary. This also works with nested dictionaries (`items[*].meta.locale.name`) and JObject items from JSON payloads.
165
+
166
+ **JArray primitive unwrapping**: When `GetPropertyValue` encounters a JArray where every element is a JValue (primitive), it automatically unwraps the array into a `List<object>` of plain .NET values. This ensures downstream iteration (e.g., `select()`, `zip()`, `foreach`) works with primitives rather than JValue wrappers.