@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.
- package/.claude/skills/cx-core/SKILL.md +38 -20
- package/.claude/skills/cx-core/ref-entity-accounting.md +0 -7
- package/.claude/skills/cx-core/ref-entity-commodity.md +0 -12
- package/.claude/skills/cx-core/ref-entity-contact.md +0 -10
- package/.claude/skills/cx-core/ref-entity-geography.md +0 -9
- package/.claude/skills/cx-core/ref-entity-notification.md +85 -0
- package/.claude/skills/cx-core/ref-entity-order-sub.md +7 -7
- package/.claude/skills/cx-core/ref-entity-order.md +1 -14
- package/.claude/skills/cx-core/ref-entity-rate.md +0 -8
- package/.claude/skills/cx-core/ref-entity-shared.md +20 -9
- package/.claude/skills/cx-core/ref-entity-warehouse.md +0 -5
- package/.claude/skills/cx-module/SKILL.md +28 -103
- package/.claude/skills/cx-module/ref-components-data.md +0 -7
- package/.claude/skills/cx-module/ref-components-display.md +0 -13
- package/.claude/skills/cx-module/ref-components-forms.md +1 -6
- package/.claude/skills/cx-module/ref-components-interactive.md +0 -11
- package/.claude/skills/cx-module/ref-components-layout.md +0 -11
- package/.claude/skills/cx-module/ref-components-specialized.md +0 -50
- package/.claude/skills/cx-workflow/SKILL.md +21 -130
- package/.claude/skills/cx-workflow/ref-communication.md +0 -8
- package/.claude/skills/cx-workflow/ref-entity.md +62 -17
- package/.claude/skills/cx-workflow/ref-expressions.md +272 -0
- package/.claude/skills/cx-workflow/ref-flow.md +5 -11
- package/.claude/skills/cx-workflow/ref-other.md +33 -14
- package/.claude/skills/cx-workflow/ref-utilities.md +111 -14
- package/README.md +34 -34
- package/dist/cli.js +166 -2394
- package/dist/cli.js.map +1 -1
- package/dist/types.d.ts +0 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/validator.d.ts +0 -8
- package/dist/validator.d.ts.map +1 -1
- package/dist/validator.js +2 -54
- package/dist/validator.js.map +1 -1
- package/dist/workflowValidator.d.ts +0 -4
- package/dist/workflowValidator.d.ts.map +1 -1
- package/dist/workflowValidator.js +2 -28
- package/dist/workflowValidator.js.map +1 -1
- package/package.json +2 -3
- package/schemas/actions/all.json +2 -1
- package/schemas/actions/clipboard.json +46 -0
- package/schemas/components/appComponent.json +0 -8
- package/schemas/components/module.json +2 -31
- package/schemas/components/timelineGrid.json +0 -4
- package/schemas/schemas.json +0 -12
- package/schemas/workflows/flow/entity.json +19 -0
- package/schemas/workflows/tasks/all.json +9 -0
- package/schemas/workflows/tasks/authentication.json +12 -26
- package/schemas/workflows/tasks/edi.json +93 -1
- package/schemas/workflows/tasks/httpRequest.json +4 -0
- package/schemas/workflows/tasks/order.json +45 -0
- package/schemas/workflows/tasks/resolve-timezone.json +65 -0
- package/schemas/workflows/tasks/transmission.json +185 -0
- package/schemas/workflows/tasks/unzip-file.json +68 -0
- package/schemas/workflows/variable.json +5 -1
- package/schemas/workflows/workflow.json +4 -0
- package/scripts/postinstall.js +1 -1
- package/templates/module-configuration.yaml +89 -23
- package/templates/module-form.yaml +3 -3
- package/templates/module-grid.yaml +3 -3
- package/templates/module-select.yaml +3 -3
- package/templates/module.yaml +2 -3
- package/templates/workflow-api-tracking.yaml +1 -1
- package/templates/workflow-basic.yaml +1 -1
- package/templates/workflow-document.yaml +1 -1
- package/templates/workflow-entity-trigger.yaml +1 -1
- package/templates/workflow-ftp-edi.yaml +1 -1
- package/templates/workflow-ftp-tracking.yaml +1 -1
- package/templates/workflow-mcp-tool.yaml +1 -1
- package/templates/workflow-public-api.yaml +1 -1
- package/templates/workflow-scheduled.yaml +1 -1
- package/templates/workflow-utility.yaml +1 -1
- package/templates/workflow-webhook.yaml +1 -1
- package/templates/workflow.yaml +1 -1
- package/.claude/skills/cx-core/ref-cli-auth.md +0 -120
- package/.claude/skills/cx-core/ref-graphql-query.md +0 -320
- package/.claude/skills/cx-workflow/ref-expressions-ncalc.md +0 -111
- 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}` |
|