@cxtms/cx-schema 1.7.17 → 1.8.1

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 (78) hide show
  1. package/.claude/skills/cx-core/SKILL.md +38 -20
  2. package/.claude/skills/cx-core/ref-entity-accounting.md +0 -7
  3. package/.claude/skills/cx-core/ref-entity-commodity.md +0 -12
  4. package/.claude/skills/cx-core/ref-entity-contact.md +0 -10
  5. package/.claude/skills/cx-core/ref-entity-geography.md +0 -9
  6. package/.claude/skills/cx-core/ref-entity-notification.md +85 -0
  7. package/.claude/skills/cx-core/ref-entity-order-sub.md +7 -7
  8. package/.claude/skills/cx-core/ref-entity-order.md +1 -14
  9. package/.claude/skills/cx-core/ref-entity-rate.md +0 -8
  10. package/.claude/skills/cx-core/ref-entity-shared.md +20 -9
  11. package/.claude/skills/cx-core/ref-entity-warehouse.md +0 -5
  12. package/.claude/skills/cx-module/SKILL.md +28 -103
  13. package/.claude/skills/cx-module/ref-components-data.md +0 -7
  14. package/.claude/skills/cx-module/ref-components-display.md +0 -13
  15. package/.claude/skills/cx-module/ref-components-forms.md +1 -6
  16. package/.claude/skills/cx-module/ref-components-interactive.md +0 -11
  17. package/.claude/skills/cx-module/ref-components-layout.md +0 -11
  18. package/.claude/skills/cx-module/ref-components-specialized.md +0 -50
  19. package/.claude/skills/cx-workflow/SKILL.md +21 -130
  20. package/.claude/skills/cx-workflow/ref-communication.md +0 -8
  21. package/.claude/skills/cx-workflow/ref-entity.md +62 -17
  22. package/.claude/skills/cx-workflow/ref-expressions.md +272 -0
  23. package/.claude/skills/cx-workflow/ref-flow.md +5 -11
  24. package/.claude/skills/cx-workflow/ref-other.md +33 -14
  25. package/.claude/skills/cx-workflow/ref-utilities.md +111 -14
  26. package/README.md +34 -34
  27. package/dist/cli.js +166 -2394
  28. package/dist/cli.js.map +1 -1
  29. package/dist/types.d.ts +0 -2
  30. package/dist/types.d.ts.map +1 -1
  31. package/dist/validator.d.ts +0 -8
  32. package/dist/validator.d.ts.map +1 -1
  33. package/dist/validator.js +2 -54
  34. package/dist/validator.js.map +1 -1
  35. package/dist/workflowValidator.d.ts +0 -4
  36. package/dist/workflowValidator.d.ts.map +1 -1
  37. package/dist/workflowValidator.js +2 -28
  38. package/dist/workflowValidator.js.map +1 -1
  39. package/package.json +2 -3
  40. package/schemas/actions/all.json +2 -1
  41. package/schemas/actions/clipboard.json +46 -0
  42. package/schemas/components/appComponent.json +0 -8
  43. package/schemas/components/module.json +2 -31
  44. package/schemas/components/timelineGrid.json +0 -4
  45. package/schemas/schemas.json +0 -12
  46. package/schemas/workflows/flow/entity.json +19 -0
  47. package/schemas/workflows/tasks/all.json +9 -0
  48. package/schemas/workflows/tasks/authentication.json +12 -26
  49. package/schemas/workflows/tasks/edi.json +93 -1
  50. package/schemas/workflows/tasks/httpRequest.json +4 -0
  51. package/schemas/workflows/tasks/order.json +45 -0
  52. package/schemas/workflows/tasks/resolve-timezone.json +65 -0
  53. package/schemas/workflows/tasks/transmission.json +185 -0
  54. package/schemas/workflows/tasks/unzip-file.json +68 -0
  55. package/schemas/workflows/variable.json +5 -1
  56. package/schemas/workflows/workflow.json +4 -0
  57. package/scripts/postinstall.js +1 -1
  58. package/templates/module-configuration.yaml +89 -23
  59. package/templates/module-form.yaml +3 -3
  60. package/templates/module-grid.yaml +3 -3
  61. package/templates/module-select.yaml +3 -3
  62. package/templates/module.yaml +2 -3
  63. package/templates/workflow-api-tracking.yaml +1 -1
  64. package/templates/workflow-basic.yaml +1 -1
  65. package/templates/workflow-document.yaml +1 -1
  66. package/templates/workflow-entity-trigger.yaml +1 -1
  67. package/templates/workflow-ftp-edi.yaml +1 -1
  68. package/templates/workflow-ftp-tracking.yaml +1 -1
  69. package/templates/workflow-mcp-tool.yaml +1 -1
  70. package/templates/workflow-public-api.yaml +1 -1
  71. package/templates/workflow-scheduled.yaml +1 -1
  72. package/templates/workflow-utility.yaml +1 -1
  73. package/templates/workflow-webhook.yaml +1 -1
  74. package/templates/workflow.yaml +1 -1
  75. package/.claude/skills/cx-core/ref-cli-auth.md +0 -120
  76. package/.claude/skills/cx-core/ref-graphql-query.md +0 -320
  77. package/.claude/skills/cx-workflow/ref-expressions-ncalc.md +0 -111
  78. package/.claude/skills/cx-workflow/ref-expressions-template.md +0 -148
@@ -1,320 +0,0 @@
1
- # GraphQL Query Reference
2
-
3
- ## CLI Query Command
4
-
5
- ```bash
6
- npx cxtms query '<graphql-query>' # Inline query
7
- npx cxtms query my-query.graphql # From file
8
- npx cxtms query '<query>' --vars '{"key":"v"}' # With variables
9
- ```
10
-
11
- Requires active login (`npx cxtms login`). Uses the active organization.
12
-
13
- ## Query Arguments
14
-
15
- All root entity queries follow this pattern:
16
-
17
- ```graphql
18
- orders(
19
- organizationId: Int! # Required — active org ID
20
- filter: String # Lucene query syntax (see below)
21
- search: String # Full-text search across key fields
22
- orderBy: String # Comma-separated sort fields
23
- take: Int # Page size (alias: limit)
24
- skip: Int # Offset (alias: offset)
25
- )
26
- ```
27
-
28
- Entity-specific extras:
29
- - `orders` — `includeDraft: Boolean` (default false)
30
-
31
- Available root queries: `orders`, `contacts`, `commodities`, `accountingTransactions`, `jobs`, and others.
32
-
33
- ## Filter Syntax (Lucene Query)
34
-
35
- Filters use **Lucene Query syntax** (not OData, not NCalc).
36
-
37
- ### Basic field matching
38
- ```
39
- filter: "orderId:196596"
40
- filter: "orderType:ParcelShipment"
41
- filter: "status:Active"
42
- ```
43
-
44
- ### Wildcards
45
- ```
46
- filter: "name:*pending*" # Contains
47
- filter: "code:ABC*" # Starts with
48
- filter: "status:*Active" # Ends with
49
- ```
50
-
51
- ### Logical operators
52
- ```
53
- filter: "countryCode:US AND name:Test"
54
- filter: "status:Active OR status:Pending"
55
- filter: "NOT customValues.po:123"
56
- filter: "orderType:ParcelShipment AND (status:Active OR status:Pending)"
57
- ```
58
-
59
- ### Nested paths (dot notation)
60
- ```
61
- filter: "orderEntities.entityType:Consignee"
62
- filter: "orderEntities.contactId:7128"
63
- filter: "jobs.orders.orderNumber:16*"
64
- ```
65
-
66
- ### Range queries
67
- ```
68
- filter: "lastModified:[\"2026-01-01\" TO \"2026-03-15\"]"
69
- filter: "lastModified:[\"2026-01-01\" TO *]" # >= date
70
- filter: "amount:[100 TO 500]"
71
- ```
72
-
73
- ### NULL checks
74
- ```
75
- filter: "customValues.po:NULL"
76
- ```
77
-
78
- ### CustomValues (JSONB fields)
79
- ```
80
- filter: "customValues.fieldName:value"
81
- filter: "customValues.fieldName:\"exact match\""
82
- filter: "customValues.fieldName:NULL"
83
- ```
84
-
85
- ### Filtered collections (bracket notation)
86
- ```
87
- filter: "children[category:CatA].name:test"
88
- ```
89
-
90
- ## OrderBy Syntax
91
-
92
- ```
93
- orderBy: "orderNumber" # Ascending
94
- orderBy: "-orderNumber" # Descending
95
- orderBy: "-created,orderNumber" # Multi-field
96
- orderBy: "customValues.fieldName" # Custom field sort
97
- orderBy: "orderNumber~ToInt32" # Type conversion during sort
98
- ```
99
-
100
- ## Pagination
101
-
102
- ```graphql
103
- {
104
- orders(organizationId: 1, take: 50, skip: 0) {
105
- items { orderId orderNumber }
106
- totalCount
107
- pageInfo { hasNextPage hasPreviousPage }
108
- }
109
- }
110
- ```
111
-
112
- ## Audit Change History
113
-
114
- ### Entity-level: `changeHistory` computed field
115
-
116
- Available on: **Order**, **Contact**, **Commodity**, **AccountingTransaction**
117
-
118
- ```graphql
119
- {
120
- orders(organizationId: 1, filter: "orderId:196596", take: 1) {
121
- items {
122
- orderId
123
- changeHistory(maxResults: 20) {
124
- entityName
125
- hasMoreRecords
126
- continuationToken
127
- changes {
128
- state # "Added" | "Modified" | "Deleted"
129
- userId
130
- timestamp
131
- user {
132
- fullName
133
- email
134
- }
135
- changedFields {
136
- fieldName
137
- originalValue
138
- currentValue
139
- fieldType
140
- }
141
- }
142
- }
143
- }
144
- }
145
- }
146
- ```
147
-
148
- Arguments: `startDate: DateTime`, `endDate: DateTime`, `maxResults: Int` (default 10)
149
-
150
- ### Root-level: `auditChanges` query
151
-
152
- Query audit changes directly without fetching the entity first:
153
-
154
- ```graphql
155
- {
156
- auditChanges(
157
- organizationId: 1
158
- filter: "entityName:Order AND primaryKey:196596"
159
- take: 20
160
- ) {
161
- items {
162
- state
163
- userId
164
- timestamp
165
- user { fullName email }
166
- changedFields {
167
- fieldName
168
- originalValue
169
- currentValue
170
- fieldType
171
- }
172
- }
173
- }
174
- }
175
- ```
176
-
177
- Arguments: `organizationId: Int!`, `filter: String`, `search: String`, `take: Int`, `skip: Int`, `orderBy: String`
178
-
179
- Filter fields: `entityName`, `primaryKey`, `userId`, `state`
180
-
181
- ### Root-level: `auditChangeSummaries` query
182
-
183
- High-level summary of changes (grouped by change event):
184
-
185
- ```graphql
186
- {
187
- auditChangeSummaries(
188
- organizationId: 1
189
- startDate: "2026-03-01T00:00:00Z"
190
- endDate: "2026-03-15T23:59:59Z"
191
- maxResults: 50
192
- ) {
193
- items {
194
- changeId
195
- userId
196
- timestamp
197
- changePaths
198
- organizationId
199
- }
200
- continuationToken
201
- hasMoreRecords
202
- }
203
- }
204
- ```
205
-
206
- ### Root-level: `auditChange` — single change detail
207
-
208
- ```graphql
209
- {
210
- auditChange(filePath: "<s3-file-path>") {
211
- entityName
212
- state
213
- primaryKey
214
- userId
215
- timestamp
216
- originalValues
217
- currentValues
218
- fields {
219
- fieldName
220
- originalValue
221
- currentValue
222
- fieldType
223
- }
224
- }
225
- }
226
- ```
227
-
228
- ## GraphQL Type Reference
229
-
230
- ### EntityAuditHistoryLightResult
231
- | Field | Type |
232
- |-------|------|
233
- | `entityName` | `String` |
234
- | `primaryKey` | `String` |
235
- | `organizationId` | `Int` |
236
- | `changes` | `[AuditChangeEntry!]!` |
237
- | `continuationToken` | `String` |
238
- | `hasMoreRecords` | `Boolean!` |
239
-
240
- ### AuditChangeEntry
241
- | Field | Type | Notes |
242
- |-------|------|-------|
243
- | `state` | `String` | "Added", "Modified", "Deleted" |
244
- | `userId` | `String` | |
245
- | `timestamp` | `DateTime!` | |
246
- | `user` | `AuditUser` | Lazy-loaded resolver |
247
- | `changedFields` | `[AuditChangeField!]!` | Lazy-loaded resolver |
248
-
249
- ### AuditChangeField
250
- | Field | Type |
251
- |-------|------|
252
- | `fieldName` | `String!` |
253
- | `originalValue` | `Any` |
254
- | `currentValue` | `Any` |
255
- | `fieldType` | `String!` |
256
-
257
- ### AuditUser
258
- | Field | Type |
259
- |-------|------|
260
- | `id` | `String` |
261
- | `firstName` | `String` |
262
- | `lastName` | `String` |
263
- | `fullName` | `String` |
264
- | `userName` | `String` |
265
- | `email` | `String` |
266
-
267
- ## Discovering Fields
268
-
269
- **Always discover field names before building a query.** Do not guess field names — use the tools below.
270
-
271
- ### CLI: `cxtms gql` — schema exploration commands
272
-
273
- ```bash
274
- # List all query root fields (what you can query)
275
- npx cxtms gql queries
276
- npx cxtms gql queries --filter order
277
-
278
- # List all mutation root fields
279
- npx cxtms gql mutations
280
- npx cxtms gql mutations --filter order
281
-
282
- # List all types (filter by name)
283
- npx cxtms gql types --filter audit
284
- npx cxtms gql types --filter order
285
-
286
- # Inspect a specific type — shows fields, arguments, input fields, enum values
287
- npx cxtms gql type OrderGqlDto
288
- npx cxtms gql type AuditChangeEntry
289
- npx cxtms gql type EntityAuditHistoryLightResult
290
- npx cxtms gql type CreateOrderInput
291
- ```
292
-
293
- ### TMS MCP: `graphql_schema` / `graphql_type` — equivalent MCP tools
294
-
295
- When TMS MCP is available, the same discovery is available via MCP tools:
296
-
297
- ```
298
- graphql_schema(section: "queries", filter: "order")
299
- graphql_schema(section: "types", filter: "audit")
300
- graphql_type(typeName: "OrderGqlDto")
301
- graphql_execute(query: "{ orders(organizationId: 1, take: 1) { items { orderId } } }")
302
- ```
303
-
304
- ### Workflow: discover → query
305
-
306
- 1. **Find the type** — `cxtms gql types --filter order` to find type names
307
- 2. **Inspect the type** — `cxtms gql type OrderGqlDto` to see all fields and their types
308
- 3. **Check query args** — `cxtms gql queries --filter order` to see arguments
309
- 4. **Build and run** — `cxtms query '<graphql-query>'`
310
-
311
- ### Fallback: error-driven discovery
312
-
313
- GraphQL error messages reveal valid field/type names:
314
- - "The field `foo` does not exist on the type `BarType`" — tells you the type name
315
- - "The argument `bar` does not exist" — tells you valid argument patterns
316
-
317
- ### Other sources
318
-
319
- - `npx cxtms schema <name>` — shows workflow/module JSON schema fields (not GraphQL)
320
- - Entity reference files (`ref-entity-*.md`) — document common fields, computed properties, and enums
@@ -1,111 +0,0 @@
1
- # NCalc Expressions & Functions
2
-
3
- ## Contents
4
- - NCalc expression syntax `[variable]` (in conditions and expression directives)
5
- - Operators (comparison, logical, arithmetic, ternary, membership)
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.)
9
- - Date functions (now, parseDate, addDays, formatDate, dateFromUnix, etc.)
10
- - Math functions (Abs, Ceiling, Floor, Round, Min, Max, etc.)
11
- - Domain functions (convertWeight, convertDimension)
12
-
13
- For template expressions `{{ path }}` used in step inputs, see [ref-expressions-template.md](ref-expressions-template.md).
14
-
15
- ## NCalc Expressions: `[variable]` (in conditions and expression directives)
16
-
17
- Used in `conditions[].expression`, `switch` case `when`, and `expression:` value directives. Variables use **square bracket** `[name]` syntax.
18
-
19
- ```yaml
20
- conditions:
21
- - expression: "[status] = 'Active' AND [amount] > 100"
22
- - expression: "isNullOrEmpty([Data.GetOrder.order?]) = false"
23
- - expression: "any([changes], [each.key] = 'Status') = true"
24
- ```
25
-
26
- **Parameter resolution rules**:
27
- - Empty strings are converted to `null` (so `""` is treated as no value)
28
- - Numeric strings are auto-converted to `decimal` when needed (e.g., `[price] > 100` works even if price is the string `"150"`)
29
- - Dot paths resolve deep: `[Activity.Step.output.nested.field]`
30
- - Optional suffix `?` prevents errors: `[order.customer?.name?]`
31
-
32
- ### Operators
33
-
34
- | Type | Operators |
35
- |------|-----------|
36
- | Comparison | `=`, `!=`, `<>`, `<`, `>`, `<=`, `>=` |
37
- | Logical | `AND`, `OR`, `NOT` (also `&&`, `\|\|`, `!`) |
38
- | Arithmetic | `+`, `-`, `*`, `/`, `%` |
39
- | Ternary | `if(condition, trueVal, falseVal)` |
40
- | Membership | `in(value, val1, val2, ...)` |
41
-
42
- ### Iterator Variables
43
-
44
- Functions use two iterator variable names:
45
- - **`[each.*]`** -- used by: `any`, `all`, `sum`, `join` (3-arg)
46
- - **`[item.*]`** -- used by: `first`, `last`, `groupBy`
47
-
48
- ### Collection Functions
49
-
50
- | Function | Description |
51
- |----------|-------------|
52
- | `any([items], [each.prop] = 'val')` | True if any item matches expression. Without expression: checks if collection contains the value |
53
- | `all([items], [each.prop] > 0)` | True if all items match. Returns `false` for null/empty collections |
54
- | `count([items])` | Count items in list or JToken. Returns `0` for non-collections |
55
- | `sum([items], [each.amount])` | Sum values as `decimal`. Optional `[each.*]` accessor. Skips nulls |
56
- | `first([items])` or `first([items], [item.name])` | First item or evaluate expression on first item. Returns `""` if empty |
57
- | `last([items])` or `last([items], [item.name])` | Last item or evaluate expression on last item. Returns `""` if empty |
58
- | `distinct([items])` | Remove duplicates. Uses deep comparison for dictionaries |
59
- | `reverse([items])` | Reverse collection or string |
60
- | `contains([source], 'needle')` | String contains, JArray contains, list contains, or dict key/value contains |
61
- | `removeEmpty([items])` | Remove null and whitespace-only items |
62
- | `concat([list1], [list2], ...)` | Concatenate multiple collections into flat list. Variadic args. Skips nulls |
63
- | `groupBy([items], [item.cat])` | Group by one or more key expressions. Returns `[{key, items}]`. Multi-key: keys joined with `\|` |
64
- | `join([items], [each.name], ',')` | Join collection with `[each.*]` accessor and separator (3-arg) |
65
- | `join([items], ',')` | Join collection directly with separator (2-arg) |
66
- | `split([str], ' ')` | Split string by first character of separator. Returns `List<string>` |
67
- | `elementAt([items], 0)` | Get element at index (zero-based) from list |
68
-
69
- ### String Functions
70
-
71
- | Function | Description |
72
- |----------|-------------|
73
- | `isNullOrEmpty([var])` | True if null, empty string, or empty list |
74
- | `length([var])` | String length or collection count. `0` for null strings and non-collections |
75
- | `lower([name])` / `upper([code])` | Case conversion. Handles string, JToken, any `.ToString()` |
76
- | `left([code], 3)` / `right([code], 3)` | Left/right N characters. Returns full string if shorter than N |
77
- | `substring([str], 0, 5)` | Extract substring starting at position for given length |
78
- | `replace([str], 'old', 'new')` | String replacement. Returns null if any arg is null |
79
- | `trim([value])` | Trim whitespace. Returns `""` for null |
80
- | `format('{0}-{1}', [prefix], [id])` | String.Format style. Variadic args. Returns null if format is null |
81
- | `base64([value])` / `fromBase64([encoded])` | Base64 encode/decode. Handles string, byte[], JToken |
82
- | `bool([value])` | Convert to boolean: null->`false`, empty string->`false`, "true"/"false"->parsed, non-zero number->`true`, any object->`true` |
83
- | `transliterate([value])` | Unicode to ASCII (Unidecode). Returns `""` for null |
84
- | `transliterateUa([value])` | Ukrainian-specific transliteration. Returns `""` for null |
85
- | `parseAddress([address])` | Parse address -> `{StreetNumber, StreetName}`. Handles US and EU formats |
86
-
87
- ### Date Functions
88
-
89
- | Function | Description |
90
- |----------|-------------|
91
- | `parseDate([str])` | Parse date string to DateTime. Supports common formats (ISO, US, etc.) |
92
- | `now()` | Current UTC `DateTime` |
93
- | `now('yyyy-MM-dd', 'en-US')` | Formatted current time as string |
94
- | `addDays([date], 30)` | Add days (decimal, can be negative). Accepts DateTime, DateTimeOffset, string |
95
- | `addHours([date], 2)` | Add hours (decimal, can be negative). Same type handling |
96
- | `formatDate([date], 'dd/MM/yyyy', 'en-US')` | Format date with culture. Accepts DateTime or string |
97
- | `dateFromUnix([unixTime])` | Unix timestamp (seconds) -> `DateTimeOffset`. Accepts int, long, decimal, string |
98
- | `dateToUtc([date])` or `dateToUtc([date], 'en-US')` | Convert to UTC. Optional culture for string parsing |
99
-
100
- ### Math Functions (NCalc built-in)
101
-
102
- `Abs(x)`, `Ceiling(x)`, `Floor(x)`, `Round(x, decimals)`, `Min(x, y)`, `Max(x, y)`, `Pow(x, y)`, `Sqrt(x)`, `Truncate(x)`
103
-
104
- Custom: `ceiling([value])` -- same as `Ceiling` but handles type conversion to double.
105
-
106
- ### Domain Functions
107
-
108
- | Function | Description |
109
- |----------|-------------|
110
- | `convertWeight([weight], 'Kg', 'Lb')` | Weight unit conversion. Returns `decimal` rounded to 5 places |
111
- | `convertDimension([length], 'Cm', 'In')` | Dimension unit conversion. Returns `decimal` rounded to 3 places |
@@ -1,148 +0,0 @@
1
- # Template Expressions & Value Directives
2
-
3
- ## Contents
4
- - Template expression syntax `{{ path }}` (in step inputs)
5
- - Type converters (int, decimal, bool, fromJson, toJson, etc.)
6
- - Value directives (expression, coalesce, foreach, switch, extends, $raw, $eval, encrypt/decrypt)
7
- - Property path syntax (dot paths, array indexing, wildcards, filters, projections)
8
-
9
- There are **two distinct syntaxes** for referencing variables, used in different contexts. This file covers **template expressions** used in step inputs. For NCalc conditions and functions, see [ref-expressions-ncalc.md](ref-expressions-ncalc.md).
10
-
11
- ## Template Expressions: `{{ path }}` (in step inputs)
12
-
13
- Used in step `inputs` values. Resolves variable paths from scoped variables.
14
-
15
- ```yaml
16
- inputs:
17
- orderId: "{{ inputs.orderId }}" # Simple reference
18
- url: "{{ chopinConfig.baseUrl }}/api/v1" # String interpolation
19
- order: "{{ Data.GetOrder.order }}" # Raw object (single {{ }})
20
- name: "Order {{ Data.GetOrder.order.orderNumber }}" # String interpolation (multiple)
21
- ```
22
-
23
- **Key behavior**: A single `{{ path }}` returns the **raw object** (preserving type). Multiple `{{ }}` in a string returns string interpolation (each resolved value is `.ToString()`).
24
-
25
- ### Type Converters (prefix in {{ }})
26
-
27
- ```yaml
28
- organizationId: "{{ int organizationId }}"
29
- amount: "{{ decimal totalAmount }}"
30
- isActive: "{{ bool isActive }}"
31
- flag: "{{ boolOrFalse someFlag }}" # null -> false
32
- flagOn: "{{ boolOrTrue someFlag }}" # null -> true
33
- notes: "{{ emptyIfNull notes }}" # null -> ""
34
- notes: "{{ nullIfEmpty notes }}" # "" or whitespace -> null
35
- config: "{{ fromJson configJsonString }}" # JSON string -> dict/array
36
- payload: "{{ toJson someObject }}" # object -> JSON string
37
- name: "{{ trim value }}"
38
- search: "{{ luceneString query }}" # escape & quote for Lucene
39
- ```
40
-
41
- | Converter | Returns | Null handling |
42
- |-----------|---------|---------------|
43
- | `string` | `string` | null. Reads `Stream` to string if value is Stream |
44
- | `int` | `int` | Throws on null |
45
- | `decimal` | `decimal` | Throws on null |
46
- | `bool` | `bool` | Throws on null |
47
- | `boolOrFalse` | `bool` | `false` if null |
48
- | `boolOrTrue` | `bool` | `true` if null |
49
- | `datetime` | `DateTime` | Throws on null |
50
- | `emptyIfNull` | same type | `""` if null, `0` for int?, `0m` for decimal? |
51
- | `nullIfEmpty` | same type | `null` if empty/whitespace string or empty collection |
52
- | `luceneString` | `string` | null |
53
- | `transliterate` | `string` | null (Unicode -> ASCII via Unidecode) |
54
- | `transliterateUa` | `string` | null (Ukrainian-specific rules) |
55
- | `fromJson` | `dict` or `array` | null. Empty string -> empty dict |
56
- | `toJson` | `string` | `""` if null |
57
- | `trim` | `string` | null |
58
-
59
- ### Value Directives (in YAML input mappings)
60
-
61
- **`expression`** -- Evaluate NCalc expression as a value:
62
- ```yaml
63
- amount:
64
- expression: "[price] * [quantity]"
65
- ```
66
-
67
- **`coalesce`** -- First non-null value from a list:
68
- ```yaml
69
- displayName:
70
- coalesce:
71
- - "{{ customer.name? }}"
72
- - "{{ customer.email? }}"
73
- - "Unknown"
74
- ```
75
-
76
- **`foreach`** (value context) -- Transform collections inline:
77
- ```yaml
78
- commodities:
79
- foreach: "sourceCommodities"
80
- item: "item" # default: "item"
81
- conditions: "[item.isActive] = true" # optional NCalc filter per item
82
- continueOnError: false # optional, skip errors
83
- mapping: # dict -> List<dict>, string -> List<object>
84
- name: "{{ item.name }}"
85
- quantity: "{{ item.qty }}"
86
- ```
87
-
88
- **`switch`** (value context) -- Value-based switch (case-insensitive match):
89
- ```yaml
90
- perLb:
91
- switch: "{{ contact.commissionTier }}"
92
- cases:
93
- "tier1": "{{ rate.customValues.commission_per_lb_tier1 }}"
94
- "tier2": "{{ rate.customValues.commission_per_lb_tier2 }}"
95
- default: "0"
96
- ```
97
-
98
- **`extends`** -- Extend/merge an existing object or array:
99
- ```yaml
100
- orderData:
101
- extends: "{{ existingOrder }}" # base object or array
102
- defaultIfNull: {} # fallback if extends is null
103
- mapping: # dict: merge overrides. array: append items
104
- status: "Updated"
105
- notes: "{{ newNotes }}"
106
- ```
107
-
108
- **`$raw`** -- Prevent template parsing (pass as-is):
109
- ```yaml
110
- template:
111
- $raw: "This {{ won't }} be parsed"
112
- ```
113
-
114
- **`$eval`** -- Parse JSON string then evaluate as template:
115
- ```yaml
116
- dynamicConfig:
117
- $eval: "{{ configJsonString }}"
118
- ```
119
-
120
- **`decrypt`** / **`encrypt`** -- AES-CBC encryption (optional key/IV, has defaults):
121
- ```yaml
122
- apiKey:
123
- decrypt:
124
- encryptedValue: "{{ encryptedApiKey }}"
125
- key: "{{ encryptionKey }}" # optional Base64 AES key
126
- initializationVector: "{{ iv }}" # optional Base64 IV
127
- ```
128
-
129
- ---
130
-
131
- ## Property Path Syntax (in collection, mapping, variable paths)
132
-
133
- Used in `collection:` (foreach), `mapping:` (outputs), and variable resolution.
134
-
135
- | Pattern | Description | Example |
136
- |---------|-------------|---------|
137
- | `a.b.c` | Dot-separated nested path | `order.customer.name` |
138
- | `prop?` | Optional access (null if missing) | `order.customer?.name?` |
139
- | `list[0]` | Array index | `items[0]` |
140
- | `list[^1]` | Index from end (last item) | `items[^1]` |
141
- | `list[*]` | Flatten/wildcard (all items) | `containers[*].commodities` |
142
- | `list[**]` | Recursive flatten (all depths) | `containerCommodities[**]` |
143
- | `list[-1]` | Depth filter (leaves only) | `tree[**][-1]` |
144
- | `list[condition]` | Filter by condition | `items[status=Active]` |
145
- | `dict['key']` | Dictionary key access | `customValues['myField']` |
146
- | `list[*].{f1 f2}` | Field selector (projection) | `items[*].{name description}` |
147
- | `list[*].{alias:source}` | Field selector with alias | `items[*].{id:commodityId}` |
148
- | `list[*].{alias:_.parent}` | Field selector referencing parent | `items[*].{parentId:_.orderId}` |