@servicenow/sdk-build-plugins 4.5.0 → 4.6.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/column-plugin.js +3 -7
- package/dist/column-plugin.js.map +1 -1
- package/dist/flow/flow-logic/flow-logic-diagnostics.js +5 -5
- package/dist/flow/flow-logic/flow-logic-diagnostics.js.map +1 -1
- package/dist/flow/plugins/flow-action-definition-plugin.js +1229 -54
- package/dist/flow/plugins/flow-action-definition-plugin.js.map +1 -1
- package/dist/flow/plugins/flow-data-pill-plugin.js +5 -2
- package/dist/flow/plugins/flow-data-pill-plugin.js.map +1 -1
- package/dist/flow/plugins/flow-definition-plugin.js +16 -42
- package/dist/flow/plugins/flow-definition-plugin.js.map +1 -1
- package/dist/flow/plugins/flow-diagnostics-plugin.d.ts +2 -2
- package/dist/flow/plugins/flow-diagnostics-plugin.js +2 -2
- package/dist/flow/plugins/flow-instance-plugin.js +68 -22
- package/dist/flow/plugins/flow-instance-plugin.js.map +1 -1
- package/dist/flow/plugins/step-definition-plugin.js +2 -1
- package/dist/flow/plugins/step-definition-plugin.js.map +1 -1
- package/dist/flow/plugins/step-instance-plugin.d.ts +9 -1
- package/dist/flow/plugins/step-instance-plugin.js +649 -136
- package/dist/flow/plugins/step-instance-plugin.js.map +1 -1
- package/dist/flow/plugins/wfa-datapill-plugin.js +20 -5
- package/dist/flow/plugins/wfa-datapill-plugin.js.map +1 -1
- package/dist/flow/post-install.js +1 -0
- package/dist/flow/post-install.js.map +1 -1
- package/dist/flow/utils/complex-object-resolver.js +4 -1
- package/dist/flow/utils/complex-object-resolver.js.map +1 -1
- package/dist/flow/utils/complex-objects.js +1 -1
- package/dist/flow/utils/complex-objects.js.map +1 -1
- package/dist/flow/utils/flow-constants.d.ts +66 -2
- package/dist/flow/utils/flow-constants.js +402 -6
- package/dist/flow/utils/flow-constants.js.map +1 -1
- package/dist/flow/utils/flow-io-to-record.d.ts +1 -1
- package/dist/flow/utils/flow-io-to-record.js +37 -16
- package/dist/flow/utils/flow-io-to-record.js.map +1 -1
- package/dist/flow/utils/flow-shapes.js +4 -0
- package/dist/flow/utils/flow-shapes.js.map +1 -1
- package/dist/flow/utils/label-cache-parser.d.ts +9 -2
- package/dist/flow/utils/label-cache-parser.js +32 -4
- package/dist/flow/utils/label-cache-parser.js.map +1 -1
- package/dist/flow/utils/pill-shape-helpers.d.ts +15 -0
- package/dist/flow/utils/pill-shape-helpers.js +35 -0
- package/dist/flow/utils/pill-shape-helpers.js.map +1 -0
- package/dist/flow/utils/pill-string-parser.js +1 -0
- package/dist/flow/utils/pill-string-parser.js.map +1 -1
- package/dist/flow/utils/schema-to-flow-object.d.ts +6 -1
- package/dist/flow/utils/schema-to-flow-object.js +131 -15
- package/dist/flow/utils/schema-to-flow-object.js.map +1 -1
- package/dist/flow/utils/utils.d.ts +1 -0
- package/dist/flow/utils/utils.js +6 -1
- package/dist/flow/utils/utils.js.map +1 -1
- package/dist/form-plugin.js +7 -9
- package/dist/form-plugin.js.map +1 -1
- package/dist/inbound-email-action-plugin.d.ts +10 -0
- package/dist/inbound-email-action-plugin.js +128 -0
- package/dist/inbound-email-action-plugin.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/instance-scan-plugin.js +0 -5
- package/dist/instance-scan-plugin.js.map +1 -1
- package/dist/property-plugin.js +1 -1
- package/dist/property-plugin.js.map +1 -1
- package/dist/record-plugin.d.ts +7 -0
- package/dist/record-plugin.js +10 -2
- package/dist/record-plugin.js.map +1 -1
- package/dist/rest-api-plugin.js +8 -1
- package/dist/rest-api-plugin.js.map +1 -1
- package/dist/schedule-script/scheduled-script-plugin.js +8 -3
- package/dist/schedule-script/scheduled-script-plugin.js.map +1 -1
- package/dist/service-catalog/service-catalog-base.d.ts +18 -18
- package/dist/service-catalog/service-catalog-base.js +22 -22
- package/dist/service-catalog/service-catalog-base.js.map +1 -1
- package/dist/service-portal/header-footer-plugin.d.ts +2 -0
- package/dist/service-portal/header-footer-plugin.js +50 -0
- package/dist/service-portal/header-footer-plugin.js.map +1 -0
- package/dist/service-portal/menu-plugin.js +3 -22
- package/dist/service-portal/menu-plugin.js.map +1 -1
- package/dist/service-portal/page-plugin.js +3 -24
- package/dist/service-portal/page-plugin.js.map +1 -1
- package/dist/service-portal/page-route-map-plugin.d.ts +2 -0
- package/dist/service-portal/page-route-map-plugin.js +114 -0
- package/dist/service-portal/page-route-map-plugin.js.map +1 -0
- package/dist/service-portal/portal-plugin.js +21 -8
- package/dist/service-portal/portal-plugin.js.map +1 -1
- package/dist/service-portal/utils.d.ts +40 -2
- package/dist/service-portal/utils.js +283 -2
- package/dist/service-portal/utils.js.map +1 -1
- package/dist/service-portal/widget-plugin.js +9 -218
- package/dist/service-portal/widget-plugin.js.map +1 -1
- package/dist/static-content-plugin.js +4 -0
- package/dist/static-content-plugin.js.map +1 -1
- package/dist/table-plugin.js +190 -26
- package/dist/table-plugin.js.map +1 -1
- package/dist/ui-action-plugin.js +1 -4
- package/dist/ui-action-plugin.js.map +1 -1
- package/dist/ui-page-plugin.js +68 -13
- package/dist/ui-page-plugin.js.map +1 -1
- package/dist/view-plugin.js +8 -3
- package/dist/view-plugin.js.map +1 -1
- package/dist/workspace-plugin.js +39 -36
- package/dist/workspace-plugin.js.map +1 -1
- package/package.json +5 -4
- package/src/column-plugin.ts +3 -8
- package/src/flow/flow-logic/flow-logic-diagnostics.ts +5 -6
- package/src/flow/plugins/flow-action-definition-plugin.ts +1581 -61
- package/src/flow/plugins/flow-data-pill-plugin.ts +5 -2
- package/src/flow/plugins/flow-definition-plugin.ts +12 -47
- package/src/flow/plugins/flow-diagnostics-plugin.ts +2 -2
- package/src/flow/plugins/flow-instance-plugin.ts +98 -22
- package/src/flow/plugins/step-definition-plugin.ts +2 -1
- package/src/flow/plugins/step-instance-plugin.ts +772 -156
- package/src/flow/plugins/wfa-datapill-plugin.ts +25 -5
- package/src/flow/post-install.ts +1 -0
- package/src/flow/utils/complex-object-resolver.ts +4 -1
- package/src/flow/utils/complex-objects.ts +1 -1
- package/src/flow/utils/flow-constants.ts +421 -5
- package/src/flow/utils/flow-io-to-record.ts +43 -17
- package/src/flow/utils/flow-shapes.ts +4 -0
- package/src/flow/utils/label-cache-parser.ts +33 -4
- package/src/flow/utils/pill-shape-helpers.ts +42 -0
- package/src/flow/utils/pill-string-parser.ts +1 -0
- package/src/flow/utils/schema-to-flow-object.ts +183 -15
- package/src/flow/utils/utils.ts +12 -1
- package/src/form-plugin.ts +1 -3
- package/src/inbound-email-action-plugin.ts +145 -0
- package/src/index.ts +4 -0
- package/src/instance-scan-plugin.ts +0 -5
- package/src/property-plugin.ts +4 -1
- package/src/record-plugin.ts +14 -4
- package/src/rest-api-plugin.ts +7 -1
- package/src/schedule-script/scheduled-script-plugin.ts +14 -3
- package/src/service-catalog/service-catalog-base.ts +22 -22
- package/src/service-portal/header-footer-plugin.ts +57 -0
- package/src/service-portal/menu-plugin.ts +1 -23
- package/src/service-portal/page-plugin.ts +3 -28
- package/src/service-portal/page-route-map-plugin.ts +124 -0
- package/src/service-portal/portal-plugin.ts +33 -10
- package/src/service-portal/utils.ts +404 -3
- package/src/service-portal/widget-plugin.ts +14 -290
- package/src/static-content-plugin.ts +3 -0
- package/src/table-plugin.ts +226 -36
- package/src/ui-action-plugin.ts +1 -8
- package/src/ui-page-plugin.ts +76 -13
- package/src/view-plugin.ts +10 -4
- package/src/workspace-plugin.ts +43 -43
|
@@ -1,16 +1,43 @@
|
|
|
1
1
|
import {
|
|
2
2
|
Plugin,
|
|
3
3
|
CallExpressionShape,
|
|
4
|
+
DurationShape,
|
|
5
|
+
IdentifierShape,
|
|
4
6
|
ObjectShape,
|
|
7
|
+
PropertyAccessShape,
|
|
8
|
+
TemplateExpressionShape,
|
|
9
|
+
TemplateValueShape,
|
|
5
10
|
type Record as BuildRecord,
|
|
6
11
|
type Factory,
|
|
7
12
|
type Shape,
|
|
8
13
|
type Source,
|
|
14
|
+
type Diagnostics,
|
|
9
15
|
} from '@servicenow/sdk-build-core'
|
|
10
|
-
import
|
|
11
|
-
import { sysIdToUuid } from '../utils/utils'
|
|
16
|
+
import { NowIdShape } from '../../now-id-plugin'
|
|
17
|
+
import { getBuiltInStepIdentifier, sysIdToUuid } from '../utils/utils'
|
|
12
18
|
import { COLUMN_API_TO_TYPE } from '../../column/column-helper'
|
|
13
|
-
import {
|
|
19
|
+
import {
|
|
20
|
+
ACTION_STEP_INSTANCE_API_NAME,
|
|
21
|
+
BUILT_IN_STEP_DEFINITIONS,
|
|
22
|
+
BUILT_IN_STEP_NAME_TO_SYSID,
|
|
23
|
+
BUILT_IN_STEP_PREFIX,
|
|
24
|
+
buildExtVarAttributes,
|
|
25
|
+
getVarEntryName,
|
|
26
|
+
getVarEntryType,
|
|
27
|
+
FLOW_OBJECT_API_NAME,
|
|
28
|
+
FLOW_ARRAY_API_NAME,
|
|
29
|
+
} from '../utils/flow-constants'
|
|
30
|
+
import { normalizeInputValue } from './flow-instance-plugin'
|
|
31
|
+
import { ApprovalRulesShape, ApprovalDueDateShape } from '../utils/flow-shapes'
|
|
32
|
+
import { createSdkDocEntry } from '../../utils'
|
|
33
|
+
import {
|
|
34
|
+
generateSchemaFromObject,
|
|
35
|
+
getComplexObjectAttributes,
|
|
36
|
+
formatComplexObjectAttributes,
|
|
37
|
+
} from '../utils/complex-objects'
|
|
38
|
+
|
|
39
|
+
import { PillShape } from '../utils/data-pill-shapes'
|
|
40
|
+
import { findAncestorByCalleeName } from '../utils/utils'
|
|
14
41
|
|
|
15
42
|
// Error handling type mapping: string to number
|
|
16
43
|
const ERROR_HANDLING_TYPE_MAP: Record<string, number> = {
|
|
@@ -18,6 +45,148 @@ const ERROR_HANDLING_TYPE_MAP: Record<string, number> = {
|
|
|
18
45
|
dont_stop_the_action: 2,
|
|
19
46
|
}
|
|
20
47
|
|
|
48
|
+
/**
|
|
49
|
+
* Resolves a TemplateValue field shape to a datapill string (e.g., "{{action.desc|string}}").
|
|
50
|
+
* Handles two cases:
|
|
51
|
+
* 1. Already resolved PillShape — call getValue() directly
|
|
52
|
+
* 2. Unresolved wfa.dataPill() CallExpressionShape — extract pill info from arguments
|
|
53
|
+
* @param cidMap - Optional map of step variable name → CID for direct lookup (avoids AST walking)
|
|
54
|
+
* Returns undefined if the field is not a datapill.
|
|
55
|
+
*/
|
|
56
|
+
function resolveFieldToPillString(fieldShape: Shape, cidMap?: Map<string, string>): string | undefined {
|
|
57
|
+
// Case 1: Already a PillShape (e.g., processed by the datapill plugin)
|
|
58
|
+
if (fieldShape instanceof PillShape) {
|
|
59
|
+
return fieldShape.getValue()
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Case 2: Unresolved wfa.dataPill(expression, type) CallExpressionShape
|
|
63
|
+
if (fieldShape instanceof CallExpressionShape) {
|
|
64
|
+
const callee = fieldShape.getCallee()
|
|
65
|
+
if (callee !== 'wfa.dataPill') {
|
|
66
|
+
return undefined
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const typeArg = fieldShape.getArgument(1)
|
|
70
|
+
|
|
71
|
+
// Extract property path — try Shape API first, then AST node directly
|
|
72
|
+
const propertyNames: string[] = []
|
|
73
|
+
const expressionArg = fieldShape.getArgument(0, false) // 0, false
|
|
74
|
+
if (expressionArg instanceof PropertyAccessShape) {
|
|
75
|
+
expressionArg.getElements().forEach((el: Shape) => {
|
|
76
|
+
if (el instanceof IdentifierShape) {
|
|
77
|
+
propertyNames.push(el.getName())
|
|
78
|
+
}
|
|
79
|
+
})
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (propertyNames.length < 2) {
|
|
83
|
+
return undefined
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
let prefix = 'action'
|
|
87
|
+
let pathParts: string[]
|
|
88
|
+
|
|
89
|
+
if (propertyNames[1] === 'inputs') {
|
|
90
|
+
// params.inputs.xxx → action pill
|
|
91
|
+
const originalNode = fieldShape.getOriginalNode?.()
|
|
92
|
+
if (originalNode) {
|
|
93
|
+
const actionAncestor = findAncestorByCalleeName(originalNode, 'Action')
|
|
94
|
+
prefix = actionAncestor ? 'action' : 'subflow'
|
|
95
|
+
}
|
|
96
|
+
pathParts = propertyNames.slice(2)
|
|
97
|
+
} else {
|
|
98
|
+
// Could be a step variable reference: create_record_step.record.short_description
|
|
99
|
+
// Resolve CID via cidMap lookup (O(1))
|
|
100
|
+
const varName = propertyNames[0]
|
|
101
|
+
const stepCid = varName ? cidMap?.get(varName) : undefined
|
|
102
|
+
if (stepCid) {
|
|
103
|
+
prefix = `step[${stepCid}]`
|
|
104
|
+
pathParts = propertyNames.slice(1)
|
|
105
|
+
} else {
|
|
106
|
+
// Cannot resolve step CID — return undefined so the caller can handle the failure
|
|
107
|
+
return undefined
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const dataType = typeArg?.ifString()?.getValue()
|
|
112
|
+
const typeSuffix = dataType ? `|${dataType}` : ''
|
|
113
|
+
|
|
114
|
+
return `{{${prefix}.${pathParts.join('.')}${typeSuffix}}}`
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Case 3: Already a resolved pill string
|
|
118
|
+
const val = fieldShape.getValue()
|
|
119
|
+
if (typeof val === 'string' && val.startsWith('{{') && val.endsWith('}}')) {
|
|
120
|
+
return val
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return undefined
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Extracts pill type annotations from a pill string and stores them in the pillTypeMap.
|
|
128
|
+
* Captures types from both step pills ({{step[CID].path|type}}) and action pills
|
|
129
|
+
* ({{action.path|type}}). The "|type" portion is captured before it gets stripped
|
|
130
|
+
* for the element_mapping value. The collected types are used later when building the label_cache.
|
|
131
|
+
*/
|
|
132
|
+
const STEP_PILL_TYPE_REGEX = /\{\{step\[([^\]]+)\]\.([^|}]+)(?:\|([^}]+))?\}\}/g
|
|
133
|
+
const ACTION_PILL_TYPE_REGEX = /\{\{action\.([^|}]+)(?:\|([^}]+))?\}\}/g
|
|
134
|
+
function collectPillTypes(pillString: string, pillTypeMap?: Map<string, string>): void {
|
|
135
|
+
if (!pillTypeMap) {
|
|
136
|
+
return
|
|
137
|
+
}
|
|
138
|
+
for (const match of pillString.matchAll(STEP_PILL_TYPE_REGEX)) {
|
|
139
|
+
const [, cid, pillPath, dataType] = match
|
|
140
|
+
if (cid && pillPath && dataType) {
|
|
141
|
+
pillTypeMap.set(`${cid}::${pillPath}`, dataType)
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
for (const match of pillString.matchAll(ACTION_PILL_TYPE_REGEX)) {
|
|
145
|
+
const [, path, dataType] = match
|
|
146
|
+
if (path && dataType) {
|
|
147
|
+
pillTypeMap.set(`action::${path}`, dataType)
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Strips the |type suffix from a pill string.
|
|
154
|
+
* e.g., "{{action.desc|string}}" → "{{action.desc}}"
|
|
155
|
+
*
|
|
156
|
+
* Note: This is called on individual pill strings (from resolveFieldToPillString),
|
|
157
|
+
* never on concatenated multi-pill strings — so no `g` flag is needed.
|
|
158
|
+
*/
|
|
159
|
+
function stripPillType(pill: string): string {
|
|
160
|
+
return pill.replace(/\|[^}]+/, '')
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Resolves a TemplateExpressionShape into a concatenated string, replacing
|
|
165
|
+
* datapill spans with their pill strings (type-stripped) and collecting pill types.
|
|
166
|
+
* Returns the resolved string and whether any pills were found.
|
|
167
|
+
*/
|
|
168
|
+
function resolveTemplateExpression(
|
|
169
|
+
templateShape: TemplateExpressionShape,
|
|
170
|
+
cidMap?: Map<string, string>,
|
|
171
|
+
pillTypeMap?: Map<string, string>
|
|
172
|
+
): { result: string; hasPills: boolean } {
|
|
173
|
+
let result = templateShape.getLiteralText()
|
|
174
|
+
let hasPills = false
|
|
175
|
+
for (const span of templateShape.getSpans()) {
|
|
176
|
+
const expr = span.getExpression()
|
|
177
|
+
const pillStr = resolveFieldToPillString(expr as Shape, cidMap)
|
|
178
|
+
if (pillStr) {
|
|
179
|
+
collectPillTypes(pillStr, pillTypeMap)
|
|
180
|
+
result += stripPillType(pillStr)
|
|
181
|
+
hasPills = true
|
|
182
|
+
} else {
|
|
183
|
+
result += String(expr.getValue?.() ?? '')
|
|
184
|
+
}
|
|
185
|
+
result += span.getLiteralText()
|
|
186
|
+
}
|
|
187
|
+
return { result, hasPills }
|
|
188
|
+
}
|
|
189
|
+
|
|
21
190
|
/**
|
|
22
191
|
* StepInstanceShape represents a step instance within a custom action's body
|
|
23
192
|
* This class handles the shape transformation for step instances
|
|
@@ -29,6 +198,10 @@ export class StepInstanceShape extends CallExpressionShape {
|
|
|
29
198
|
private stepLabel: string
|
|
30
199
|
private inputs: ObjectShape | undefined
|
|
31
200
|
private inputDefinitions: ObjectShape | undefined
|
|
201
|
+
/** Map of step variable name → CID, set by ActionDefinitionPlugin for step pill resolution in Action() bodies */
|
|
202
|
+
private _cidMap?: Map<string, string>
|
|
203
|
+
/** Map of "CID::pillPath" → dataType, populated during toRecord for label_cache type propagation */
|
|
204
|
+
private _pillTypeMap?: Map<string, string>
|
|
32
205
|
|
|
33
206
|
constructor(args: {
|
|
34
207
|
source: Source
|
|
@@ -41,7 +214,7 @@ export class StepInstanceShape extends CallExpressionShape {
|
|
|
41
214
|
inputDefinitions?: ObjectShape
|
|
42
215
|
}) {
|
|
43
216
|
const { source, sysId, config, stepDefinitionSysId, stepLabel, inputs, inputDefinitions } = args
|
|
44
|
-
super({ source, callee: '
|
|
217
|
+
super({ source, callee: 'wfa.actionStep', args: [sysId, config, stepDefinitionSysId] })
|
|
45
218
|
this.config = config
|
|
46
219
|
this.sysId = sysId
|
|
47
220
|
this.stepDefinitionSysId = stepDefinitionSysId
|
|
@@ -73,11 +246,27 @@ export class StepInstanceShape extends CallExpressionShape {
|
|
|
73
246
|
getInputDefinitions(): ObjectShape | undefined {
|
|
74
247
|
return this.inputDefinitions
|
|
75
248
|
}
|
|
249
|
+
|
|
250
|
+
setCidMap(cidMap: Map<string, string>): void {
|
|
251
|
+
this._cidMap = cidMap
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
getCidMap(): Map<string, string> | undefined {
|
|
255
|
+
return this._cidMap
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
setPillTypeMap(pillTypeMap: Map<string, string>): void {
|
|
259
|
+
this._pillTypeMap = pillTypeMap
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
getPillTypeMap(): Map<string, string> | undefined {
|
|
263
|
+
return this._pillTypeMap
|
|
264
|
+
}
|
|
76
265
|
}
|
|
77
266
|
|
|
78
267
|
export const StepInstancePlugin = Plugin.create({
|
|
79
268
|
name: 'StepInstancePlugin',
|
|
80
|
-
docs: [],
|
|
269
|
+
docs: [createSdkDocEntry('wfa.actionStep', ['sys_hub_step_instance'])],
|
|
81
270
|
shapes: [
|
|
82
271
|
{
|
|
83
272
|
shape: CallExpressionShape,
|
|
@@ -99,12 +288,8 @@ export const StepInstancePlugin = Plugin.create({
|
|
|
99
288
|
|
|
100
289
|
const [stepDefinition, stepInstanceConfig, inputs] = args
|
|
101
290
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
!(stepDefinition instanceof CallExpressionShape) ||
|
|
105
|
-
stepDefinition.getCallee() !== 'ActionStepDefinition'
|
|
106
|
-
) {
|
|
107
|
-
diagnostics.error(callExpression, 'Expected first argument to be a ActionStepDefinition')
|
|
291
|
+
if (!stepDefinition) {
|
|
292
|
+
diagnostics.error(callExpression, 'Missing step definition argument')
|
|
108
293
|
return { success: false }
|
|
109
294
|
}
|
|
110
295
|
|
|
@@ -120,7 +305,51 @@ export const StepInstancePlugin = Plugin.create({
|
|
|
120
305
|
return { success: false }
|
|
121
306
|
}
|
|
122
307
|
|
|
123
|
-
|
|
308
|
+
let stepDefinitionSysId: string
|
|
309
|
+
let stepLabel: string
|
|
310
|
+
let inputDefinitions: ObjectShape | undefined
|
|
311
|
+
|
|
312
|
+
// First argument can be a string (built-in step name), IdentifierShape (actionStep.xxx),
|
|
313
|
+
// or ActionStepDefinition() call
|
|
314
|
+
const stepNameValue = stepDefinition.ifString()?.getValue()
|
|
315
|
+
if (stepNameValue) {
|
|
316
|
+
// Built-in step referenced by name string
|
|
317
|
+
stepDefinitionSysId = BUILT_IN_STEP_NAME_TO_SYSID[stepNameValue] ?? ''
|
|
318
|
+
stepLabel = stepNameValue
|
|
319
|
+
if (!stepDefinitionSysId) {
|
|
320
|
+
diagnostics.error(callExpression, `Unknown built-in step type '${stepNameValue}'`)
|
|
321
|
+
return { success: false }
|
|
322
|
+
}
|
|
323
|
+
} else if (stepDefinition instanceof IdentifierShape) {
|
|
324
|
+
// Built-in step referenced via actionStep.xxx identifier
|
|
325
|
+
const identifierName = stepDefinition.getName()
|
|
326
|
+
const prefix = `${BUILT_IN_STEP_PREFIX}.`
|
|
327
|
+
const resolvedName = identifierName.startsWith(prefix)
|
|
328
|
+
? identifierName.slice(prefix.length)
|
|
329
|
+
: identifierName
|
|
330
|
+
stepDefinitionSysId = BUILT_IN_STEP_NAME_TO_SYSID[resolvedName] ?? ''
|
|
331
|
+
stepLabel = resolvedName
|
|
332
|
+
if (!stepDefinitionSysId) {
|
|
333
|
+
diagnostics.error(callExpression, `Unknown built-in step type '${identifierName}'`)
|
|
334
|
+
return { success: false }
|
|
335
|
+
}
|
|
336
|
+
} else if (
|
|
337
|
+
stepDefinition instanceof CallExpressionShape &&
|
|
338
|
+
stepDefinition.getCallee() === 'ActionStepDefinition'
|
|
339
|
+
) {
|
|
340
|
+
// Custom step definition
|
|
341
|
+
const stepConfig = stepDefinition.getArgument(0).asObject()
|
|
342
|
+
stepDefinitionSysId = stepConfig.get('$id')?.getValue() as string
|
|
343
|
+
stepLabel = stepConfig.get('name')?.getValue() as string
|
|
344
|
+
inputDefinitions = stepConfig.get('inputs')?.ifObject()?.asObject()
|
|
345
|
+
} else {
|
|
346
|
+
diagnostics.error(
|
|
347
|
+
callExpression,
|
|
348
|
+
'Expected first argument to be a step type name string, actionStep.xxx identifier, or ActionStepDefinition'
|
|
349
|
+
)
|
|
350
|
+
return { success: false }
|
|
351
|
+
}
|
|
352
|
+
|
|
124
353
|
const shapeArgs: {
|
|
125
354
|
source: Source
|
|
126
355
|
config: ObjectShape
|
|
@@ -133,10 +362,10 @@ export const StepInstancePlugin = Plugin.create({
|
|
|
133
362
|
source: callExpression,
|
|
134
363
|
sysId: stepInstanceConfig.get('$id')?.getValue() as NowIdShape | Shape,
|
|
135
364
|
config: stepInstanceConfig,
|
|
136
|
-
stepDefinitionSysId
|
|
137
|
-
stepLabel
|
|
138
|
-
inputDefinitions: stepConfig.get('inputs')?.asObject(),
|
|
365
|
+
stepDefinitionSysId,
|
|
366
|
+
stepLabel,
|
|
139
367
|
inputs: inputs,
|
|
368
|
+
...(inputDefinitions ? { inputDefinitions } : {}),
|
|
140
369
|
}
|
|
141
370
|
|
|
142
371
|
return {
|
|
@@ -148,10 +377,11 @@ export const StepInstancePlugin = Plugin.create({
|
|
|
148
377
|
{
|
|
149
378
|
shape: StepInstanceShape,
|
|
150
379
|
fileTypes: ['fluent'],
|
|
151
|
-
async toRecord(callExpression, { factory }) {
|
|
380
|
+
async toRecord(callExpression, { factory, diagnostics }) {
|
|
152
381
|
const stepInstanceRecord = await buildStepInstanceRecord({
|
|
153
382
|
callExpression,
|
|
154
383
|
factory,
|
|
384
|
+
diagnostics,
|
|
155
385
|
values: callExpression.getInputs() as ObjectShape,
|
|
156
386
|
sysId: callExpression.getSysId(),
|
|
157
387
|
stepDefinitionSysId: callExpression.getStepDefinitionSysId(),
|
|
@@ -169,6 +399,12 @@ export const StepInstancePlugin = Plugin.create({
|
|
|
169
399
|
sys_hub_step_ext_output: {
|
|
170
400
|
coalesce: ['model', 'element'],
|
|
171
401
|
},
|
|
402
|
+
sys_complex_object: {
|
|
403
|
+
coalesce: ['name'],
|
|
404
|
+
},
|
|
405
|
+
sys_element_mapping: {
|
|
406
|
+
coalesce: ['field', 'id'],
|
|
407
|
+
},
|
|
172
408
|
sys_hub_step_instance: {
|
|
173
409
|
relationships: {
|
|
174
410
|
sys_variable_value: {
|
|
@@ -192,87 +428,137 @@ export const StepInstancePlugin = Plugin.create({
|
|
|
192
428
|
descendant: true,
|
|
193
429
|
},
|
|
194
430
|
},
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
431
|
+
toShape(record, { descendants, logger }) {
|
|
432
|
+
// Skip step instances that belong to an action definition —
|
|
433
|
+
// those are handled by ActionDefinitionPlugin's toShape for Action() definitions
|
|
434
|
+
const actionRef = record.get('action')?.asString()?.getValue()
|
|
435
|
+
if (actionRef) {
|
|
436
|
+
return { success: false }
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
const stepDefinitionRecords = descendants.query('sys_flow_step_definition')
|
|
440
|
+
const variableValues = descendants.query('sys_variable_value')
|
|
441
|
+
const configObj: globalThis.Record<string, unknown> = {}
|
|
442
|
+
|
|
443
|
+
let stepDefinitionShape: CallExpressionShape | IdentifierShape | string
|
|
444
|
+
let stepName: string | undefined
|
|
445
|
+
|
|
446
|
+
if (stepDefinitionRecords.length > 0) {
|
|
447
|
+
// Custom step definition found in descendants
|
|
448
|
+
const stepDefinition = stepDefinitionRecords[0]
|
|
449
|
+
if (!stepDefinition) {
|
|
450
|
+
logger.warn('Step definition is undefined')
|
|
451
|
+
return { success: false }
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
stepName = stepDefinition.get('name')?.asString()?.getValue()
|
|
455
|
+
|
|
456
|
+
// Resolve variable values using input definition records from descendants
|
|
457
|
+
for (const varValue of variableValues) {
|
|
458
|
+
const variableSysId = varValue.get('variable')?.asString()?.getValue()
|
|
459
|
+
const value = varValue.get('value')?.asString()?.getValue()
|
|
460
|
+
|
|
461
|
+
const inputRecords = descendants.query('sys_flow_step_definition_input', {
|
|
462
|
+
sysId: variableSysId,
|
|
463
|
+
})
|
|
464
|
+
if (inputRecords.length > 0) {
|
|
465
|
+
const elementName = inputRecords[0]?.get('element')?.asString()?.getValue()
|
|
466
|
+
if (elementName) {
|
|
467
|
+
try {
|
|
468
|
+
configObj[elementName] = JSON.parse(value || '')
|
|
469
|
+
} catch {
|
|
470
|
+
configObj[elementName] = value
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
stepDefinitionShape = new CallExpressionShape({
|
|
477
|
+
source: stepDefinition,
|
|
478
|
+
callee: 'ActionStepDefinition',
|
|
479
|
+
args: [
|
|
480
|
+
stepDefinition.transform(({ $ }) => ({
|
|
481
|
+
$id: $.val(NowIdShape.from(stepDefinition)),
|
|
482
|
+
name: $,
|
|
483
|
+
})),
|
|
484
|
+
],
|
|
485
|
+
})
|
|
486
|
+
} else {
|
|
487
|
+
// OOB/built-in step definition — not in XML export
|
|
488
|
+
const stepTypeSysId = record.get('step_type')?.asString()?.getValue()
|
|
489
|
+
if (!stepTypeSysId) {
|
|
490
|
+
logger.warn(`Step instance ${record.getId().getValue()} has no step_type reference`)
|
|
491
|
+
return { success: false }
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
const builtInDef = BUILT_IN_STEP_DEFINITIONS[stepTypeSysId]
|
|
495
|
+
if (!builtInDef) {
|
|
496
|
+
logger.warn(
|
|
497
|
+
`Unknown OOB step definition ${stepTypeSysId} for step instance ${record.getId().getValue()}`
|
|
498
|
+
)
|
|
499
|
+
return { success: false }
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
stepName = builtInDef.name
|
|
503
|
+
|
|
504
|
+
// Resolve variable values using the built-in definition's input/output mappings
|
|
505
|
+
for (const varValue of variableValues) {
|
|
506
|
+
const variableSysId = varValue.get('variable')?.asString()?.getValue()
|
|
507
|
+
const value = varValue.get('value')?.asString()?.getValue()
|
|
508
|
+
if (variableSysId) {
|
|
509
|
+
const entry = builtInDef.inputs[variableSysId] ?? builtInDef.outputs[variableSysId]
|
|
510
|
+
const elementName = entry ? getVarEntryName(entry) : undefined
|
|
511
|
+
const uiType = entry ? getVarEntryType(entry) : undefined
|
|
512
|
+
if (elementName && value != null) {
|
|
513
|
+
configObj[elementName] = uiType ? normalizeInputValue(value, uiType, record) : value
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
// Built-in/OOB step: emit actionStep.xxx reference
|
|
519
|
+
const stepIdentifier = getBuiltInStepIdentifier(stepTypeSysId)
|
|
520
|
+
stepDefinitionShape = stepIdentifier
|
|
521
|
+
? new IdentifierShape({ source: record, name: stepIdentifier })
|
|
522
|
+
: builtInDef.name
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
// Build step instance config (2nd arg): $id, label, error_handling_type
|
|
526
|
+
const configProperties: globalThis.Record<string, unknown> = {
|
|
527
|
+
$id: NowIdShape.from(record),
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
const errorHandlingRaw = record.get('error_handling_type')
|
|
531
|
+
const errorHandlingType =
|
|
532
|
+
errorHandlingRaw?.ifNumber()?.getValue() ?? Number(errorHandlingRaw?.ifString()?.getValue())
|
|
533
|
+
if (errorHandlingType && errorHandlingType !== 1 && !Number.isNaN(errorHandlingType)) {
|
|
534
|
+
configProperties['error_handling_type'] = errorHandlingType
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
const label = record.get('label')?.asString()?.getValue()
|
|
538
|
+
if (label && label !== stepName) {
|
|
539
|
+
configProperties['label'] = label
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
const stepInstanceConfig = new ObjectShape({
|
|
543
|
+
source: record,
|
|
544
|
+
properties: configProperties,
|
|
545
|
+
})
|
|
546
|
+
|
|
547
|
+
// Build inputs (3rd arg): resolved variable values only
|
|
548
|
+
const inputsShape = new ObjectShape({
|
|
549
|
+
source: record,
|
|
550
|
+
properties: { ...configObj },
|
|
551
|
+
})
|
|
552
|
+
|
|
553
|
+
return {
|
|
554
|
+
success: true,
|
|
555
|
+
value: new CallExpressionShape({
|
|
556
|
+
source: record,
|
|
557
|
+
callee: 'wfa.actionStep',
|
|
558
|
+
args: [stepDefinitionShape, stepInstanceConfig, inputsShape],
|
|
559
|
+
}),
|
|
560
|
+
}
|
|
561
|
+
},
|
|
276
562
|
},
|
|
277
563
|
},
|
|
278
564
|
})
|
|
@@ -280,6 +566,7 @@ export const StepInstancePlugin = Plugin.create({
|
|
|
280
566
|
async function buildStepInstanceRecord({
|
|
281
567
|
callExpression,
|
|
282
568
|
factory,
|
|
569
|
+
diagnostics,
|
|
283
570
|
values,
|
|
284
571
|
sysId,
|
|
285
572
|
stepDefinitionSysId,
|
|
@@ -288,12 +575,19 @@ async function buildStepInstanceRecord({
|
|
|
288
575
|
}: {
|
|
289
576
|
callExpression: StepInstanceShape
|
|
290
577
|
factory: Factory
|
|
578
|
+
diagnostics: Diagnostics
|
|
291
579
|
values: ObjectShape
|
|
292
580
|
sysId: NowIdShape | Shape
|
|
293
581
|
stepDefinitionSysId: string
|
|
294
582
|
stepLabel: string
|
|
295
583
|
inputs: ObjectShape | undefined
|
|
296
584
|
}): Promise<BuildRecord> {
|
|
585
|
+
// resolve: false — keep PillShapes and other ResolvableShapes intact (same reason as createVariableRecords).
|
|
586
|
+
// Using .getValue() on the parent ObjectShape would deeply resolve nested PillShapes into symbols.
|
|
587
|
+
const valuesArray = values.properties({ resolve: false })
|
|
588
|
+
const cidMap = callExpression.getCidMap()
|
|
589
|
+
const pillTypeMap = callExpression.getPillTypeMap()
|
|
590
|
+
|
|
297
591
|
// Create step instance record
|
|
298
592
|
const stepInstanceRecord = await factory.createRecord({
|
|
299
593
|
source: callExpression,
|
|
@@ -303,7 +597,8 @@ async function buildStepInstanceRecord({
|
|
|
303
597
|
step_type: stepDefinitionSysId,
|
|
304
598
|
order: 1,
|
|
305
599
|
active: true,
|
|
306
|
-
error_handling_type:
|
|
600
|
+
error_handling_type:
|
|
601
|
+
ERROR_HANDLING_TYPE_MAP[valuesArray['errorHandlingType']?.ifString()?.getValue() ?? ''] ?? 1,
|
|
307
602
|
label: stepLabel,
|
|
308
603
|
},
|
|
309
604
|
})
|
|
@@ -312,20 +607,31 @@ async function buildStepInstanceRecord({
|
|
|
312
607
|
})
|
|
313
608
|
const stepInstanceSysId = updatedStepInstanceRecord.getId().getValue()
|
|
314
609
|
// Create sys_variable_value records for each input value
|
|
315
|
-
const
|
|
610
|
+
const stepDataRecords = await createVariableRecords(
|
|
611
|
+
valuesArray,
|
|
612
|
+
inputs,
|
|
613
|
+
factory,
|
|
614
|
+
callExpression,
|
|
615
|
+
stepInstanceSysId,
|
|
616
|
+
stepDefinitionSysId,
|
|
617
|
+
cidMap
|
|
618
|
+
)
|
|
316
619
|
const extendedInputRecords: BuildRecord[] = []
|
|
317
620
|
const extendedOutputRecords: BuildRecord[] = []
|
|
318
621
|
const extendedVariableValueRecords: BuildRecord[] = []
|
|
622
|
+
const inputVariablesShape = valuesArray['inputVariables']
|
|
623
|
+
if (inputVariablesShape) {
|
|
624
|
+
const inputVarObj = inputVariablesShape.asObject()
|
|
625
|
+
const inputVarProps = inputVarObj.properties({ resolve: false })
|
|
626
|
+
|
|
627
|
+
const extInputTableName = `var__m_sys_hub_step_ext_input_${stepInstanceSysId}`
|
|
319
628
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
const
|
|
326
|
-
const mandatory = config.mandatory
|
|
327
|
-
const defaultValue = config.defaultValue ?? ''
|
|
328
|
-
const value = config.value
|
|
629
|
+
for (const [name, configShapeRaw] of Object.entries(inputVarProps)) {
|
|
630
|
+
const configObj = configShapeRaw.asObject()
|
|
631
|
+
const configProps = configObj.properties({ resolve: false })
|
|
632
|
+
const label = (configProps['label']?.ifString?.()?.getValue() ?? name) as string
|
|
633
|
+
const defaultValue = (configProps['defaultValue']?.ifString?.()?.getValue() ?? '') as string
|
|
634
|
+
const valueShape = configProps['value']
|
|
329
635
|
const extInputRecord = await factory.createRecord({
|
|
330
636
|
source: callExpression,
|
|
331
637
|
table: 'sys_hub_step_ext_input',
|
|
@@ -334,89 +640,397 @@ async function buildStepInstanceRecord({
|
|
|
334
640
|
model: stepInstanceSysId,
|
|
335
641
|
model_id: stepInstanceSysId,
|
|
336
642
|
model_table: 'sys_hub_step_instance',
|
|
337
|
-
name:
|
|
643
|
+
name: extInputTableName,
|
|
338
644
|
element: name,
|
|
339
645
|
label: label,
|
|
340
|
-
mandatory: mandatory,
|
|
341
646
|
default_value: defaultValue,
|
|
647
|
+
attributes: buildExtVarAttributes('string'),
|
|
648
|
+
internal_type: 'string',
|
|
342
649
|
},
|
|
343
650
|
})
|
|
344
651
|
extendedInputRecords.push(extInputRecord)
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
652
|
+
|
|
653
|
+
if (!valueShape) {
|
|
654
|
+
// No value provided — still create a sys_variable_value record with empty value
|
|
655
|
+
// so the platform recognizes the ext input variable exists
|
|
656
|
+
extendedVariableValueRecords.push(
|
|
657
|
+
await factory.createRecord({
|
|
658
|
+
source: callExpression,
|
|
659
|
+
table: 'sys_variable_value',
|
|
660
|
+
properties: {
|
|
661
|
+
document: 'sys_hub_step_instance',
|
|
662
|
+
document_key: stepInstanceSysId,
|
|
663
|
+
order: 100,
|
|
664
|
+
value: '',
|
|
665
|
+
variable: extInputRecord.getId().getValue(),
|
|
666
|
+
},
|
|
667
|
+
})
|
|
668
|
+
)
|
|
669
|
+
} else {
|
|
670
|
+
// Check if value is a datapill — if so, create sys_element_mapping instead of sys_variable_value
|
|
671
|
+
const pillString = resolveFieldToPillString(valueShape as Shape, cidMap)
|
|
672
|
+
if (pillString) {
|
|
673
|
+
collectPillTypes(pillString, pillTypeMap)
|
|
674
|
+
extendedVariableValueRecords.push(
|
|
675
|
+
await factory.createRecord({
|
|
676
|
+
source: callExpression,
|
|
677
|
+
table: 'sys_element_mapping',
|
|
678
|
+
properties: {
|
|
679
|
+
field: name,
|
|
680
|
+
id: stepInstanceSysId,
|
|
681
|
+
table: extInputTableName,
|
|
682
|
+
value: stripPillType(pillString),
|
|
683
|
+
},
|
|
684
|
+
})
|
|
685
|
+
)
|
|
686
|
+
} else if (valueShape.is(TemplateExpressionShape)) {
|
|
687
|
+
const { result, hasPills } = resolveTemplateExpression(
|
|
688
|
+
valueShape as TemplateExpressionShape,
|
|
689
|
+
cidMap,
|
|
690
|
+
pillTypeMap
|
|
691
|
+
)
|
|
692
|
+
if (hasPills) {
|
|
693
|
+
extendedVariableValueRecords.push(
|
|
694
|
+
await factory.createRecord({
|
|
695
|
+
source: callExpression,
|
|
696
|
+
table: 'sys_element_mapping',
|
|
697
|
+
properties: {
|
|
698
|
+
field: name,
|
|
699
|
+
id: stepInstanceSysId,
|
|
700
|
+
table: extInputTableName,
|
|
701
|
+
value: result,
|
|
702
|
+
},
|
|
703
|
+
})
|
|
704
|
+
)
|
|
705
|
+
} else {
|
|
706
|
+
extendedVariableValueRecords.push(
|
|
707
|
+
await factory.createRecord({
|
|
708
|
+
source: callExpression,
|
|
709
|
+
table: 'sys_variable_value',
|
|
710
|
+
properties: {
|
|
711
|
+
document: 'sys_hub_step_instance',
|
|
712
|
+
document_key: stepInstanceSysId,
|
|
713
|
+
order: 100,
|
|
714
|
+
value: result,
|
|
715
|
+
variable: extInputRecord.getId().getValue(),
|
|
716
|
+
},
|
|
717
|
+
})
|
|
718
|
+
)
|
|
719
|
+
}
|
|
720
|
+
} else {
|
|
721
|
+
// Simple value → store in sys_variable_value
|
|
722
|
+
const rawVal = valueShape.ifString()?.getValue() ?? valueShape.getValue?.()
|
|
723
|
+
const resolvedValue = typeof rawVal === 'symbol' ? '' : (rawVal ?? '')
|
|
724
|
+
extendedVariableValueRecords.push(
|
|
725
|
+
await factory.createRecord({
|
|
726
|
+
source: callExpression,
|
|
727
|
+
table: 'sys_variable_value',
|
|
728
|
+
properties: {
|
|
729
|
+
document: 'sys_hub_step_instance',
|
|
730
|
+
document_key: stepInstanceSysId,
|
|
731
|
+
order: 100,
|
|
732
|
+
value: resolvedValue,
|
|
733
|
+
variable: extInputRecord.getId().getValue(),
|
|
734
|
+
},
|
|
735
|
+
})
|
|
736
|
+
)
|
|
737
|
+
}
|
|
738
|
+
}
|
|
358
739
|
}
|
|
359
740
|
}
|
|
360
741
|
|
|
361
742
|
const outputVariables = valuesArray['outputVariables']
|
|
743
|
+
const complexObjectRecords: BuildRecord[] = []
|
|
362
744
|
if (outputVariables) {
|
|
363
745
|
const outputItemShape = outputVariables.asObject()
|
|
364
|
-
const outputProperties = outputItemShape.properties()
|
|
746
|
+
const outputProperties = outputItemShape.properties({ resolve: false })
|
|
365
747
|
|
|
366
748
|
for (const [columnName, columnCallExpr] of Object.entries(outputProperties)) {
|
|
367
749
|
const callExpr = columnCallExpr.as(CallExpressionShape)
|
|
368
|
-
const columnType = callExpr.getCallee() // e.g., 'StringColumn', 'IntegerColumn'
|
|
750
|
+
const columnType = callExpr.getCallee() // e.g., 'StringColumn', 'IntegerColumn', 'FlowObject', 'FlowArray'
|
|
369
751
|
const columnConfig = callExpr.getArgument(0)?.asObject()
|
|
370
752
|
const columnLabel = columnConfig?.get('label')?.getValue() as string
|
|
371
753
|
const mandatory = columnConfig?.get('mandatory')?.getValue() as boolean
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
754
|
+
|
|
755
|
+
// Handle FlowObject and FlowArray complex objects
|
|
756
|
+
if (columnType === FLOW_OBJECT_API_NAME || columnType === FLOW_ARRAY_API_NAME) {
|
|
757
|
+
const coTypeName = columnConfig?.get('co_type_name')?.ifString()?.getValue()
|
|
758
|
+
const varSysId = `${stepInstanceSysId}_${columnName}`
|
|
759
|
+
const complexObjectId = coTypeName || `FD${varSysId}`
|
|
760
|
+
const isArray = columnType === FLOW_ARRAY_API_NAME
|
|
761
|
+
|
|
762
|
+
// Generate schema for complex object
|
|
763
|
+
const schemaObj = generateSchemaFromObject(
|
|
764
|
+
columnConfig,
|
|
765
|
+
complexObjectId,
|
|
766
|
+
columnName,
|
|
767
|
+
stepInstanceSysId,
|
|
768
|
+
0,
|
|
769
|
+
isArray,
|
|
770
|
+
diagnostics,
|
|
771
|
+
false
|
|
772
|
+
)
|
|
773
|
+
|
|
774
|
+
// Create sys_complex_object record
|
|
775
|
+
const explicitId = columnConfig?.get('$id')?.ifString()?.getValue()
|
|
776
|
+
const complexRecord = await factory.createRecord({
|
|
777
|
+
source: callExpression,
|
|
778
|
+
table: 'sys_complex_object',
|
|
779
|
+
properties: {
|
|
780
|
+
name: complexObjectId,
|
|
781
|
+
namespace: 'FlowDesigner',
|
|
782
|
+
type: isArray ? 'complex_object_collection' : 'complex_object_schema',
|
|
783
|
+
serialized_content: JSON.stringify(schemaObj),
|
|
784
|
+
...(explicitId ? { sys_id: explicitId } : {}),
|
|
785
|
+
},
|
|
786
|
+
})
|
|
787
|
+
complexObjectRecords.push(complexRecord)
|
|
788
|
+
|
|
789
|
+
// Get complex object attributes
|
|
790
|
+
const systemAttributes = getComplexObjectAttributes(schemaObj, complexObjectId, isArray)
|
|
791
|
+
const attributesStr = formatComplexObjectAttributes(systemAttributes)
|
|
792
|
+
|
|
793
|
+
// Create ext_output record with complex object type
|
|
794
|
+
const extOutputRecord = await factory.createRecord({
|
|
795
|
+
source: callExpression,
|
|
796
|
+
table: 'sys_hub_step_ext_output',
|
|
797
|
+
properties: {
|
|
798
|
+
active: true,
|
|
799
|
+
model: stepInstanceSysId,
|
|
800
|
+
model_id: stepInstanceSysId,
|
|
801
|
+
model_table: 'sys_hub_step_instance',
|
|
802
|
+
name: `var__m_sys_hub_step_ext_output_${stepInstanceSysId}`,
|
|
803
|
+
element: columnName,
|
|
804
|
+
label: columnLabel || columnName,
|
|
805
|
+
internal_type: 'string',
|
|
806
|
+
max_length: 65000,
|
|
807
|
+
mandatory: mandatory,
|
|
808
|
+
attributes: attributesStr,
|
|
809
|
+
},
|
|
810
|
+
})
|
|
811
|
+
extendedOutputRecords.push(extOutputRecord)
|
|
812
|
+
} else {
|
|
813
|
+
// Handle regular column types (StringColumn, IntegerColumn, etc.)
|
|
814
|
+
const internalType = COLUMN_API_TO_TYPE[columnType] || 'string'
|
|
815
|
+
const maxLength = columnConfig?.get('maxLength')?.ifNumber()?.getValue()
|
|
816
|
+
const hint = columnConfig?.get('hint')?.ifString()?.getValue()
|
|
817
|
+
const defaultValue = columnConfig?.get('default')?.ifString()?.getValue()
|
|
818
|
+
const extOutputRecord = await factory.createRecord({
|
|
819
|
+
source: callExpression,
|
|
820
|
+
table: 'sys_hub_step_ext_output',
|
|
821
|
+
properties: {
|
|
822
|
+
active: true,
|
|
823
|
+
model: stepInstanceSysId,
|
|
824
|
+
model_id: stepInstanceSysId,
|
|
825
|
+
model_table: 'sys_hub_step_instance',
|
|
826
|
+
name: `var__m_sys_hub_step_ext_output_${stepInstanceSysId}`,
|
|
827
|
+
element: columnName,
|
|
828
|
+
label: columnLabel || columnName,
|
|
829
|
+
internal_type: internalType,
|
|
830
|
+
mandatory: mandatory,
|
|
831
|
+
...(maxLength != null ? { max_length: maxLength } : {}),
|
|
832
|
+
...(hint ? { hint } : {}),
|
|
833
|
+
...(defaultValue ? { default_value: defaultValue } : {}),
|
|
834
|
+
attributes: buildExtVarAttributes(internalType),
|
|
835
|
+
},
|
|
836
|
+
})
|
|
837
|
+
extendedOutputRecords.push(extOutputRecord)
|
|
838
|
+
}
|
|
389
839
|
}
|
|
390
840
|
}
|
|
391
841
|
|
|
392
842
|
return updatedStepInstanceRecord.with(
|
|
393
|
-
...
|
|
843
|
+
...stepDataRecords,
|
|
394
844
|
...extendedInputRecords,
|
|
395
845
|
...extendedVariableValueRecords,
|
|
396
|
-
...extendedOutputRecords
|
|
846
|
+
...extendedOutputRecords,
|
|
847
|
+
...complexObjectRecords
|
|
397
848
|
)
|
|
398
849
|
}
|
|
399
850
|
async function createVariableRecords(
|
|
400
|
-
|
|
851
|
+
valuesProperties: globalThis.Record<string, Shape>,
|
|
401
852
|
inputs: ObjectShape | undefined,
|
|
402
853
|
factory: Factory,
|
|
403
854
|
callExpression: StepInstanceShape,
|
|
404
|
-
stepInstanceSysId: string
|
|
855
|
+
stepInstanceSysId: string,
|
|
856
|
+
stepDefinitionSysId: string,
|
|
857
|
+
cidMap?: Map<string, string>
|
|
405
858
|
) {
|
|
406
|
-
const properties = values.properties()
|
|
407
859
|
// Filter out inputVariables, outputVariables and errorHandlingType as they are handled separately
|
|
408
|
-
const filteredEntries = Object.entries(
|
|
860
|
+
const filteredEntries = Object.entries(valuesProperties).filter(
|
|
409
861
|
([key]) => key !== 'inputVariables' && key !== 'outputVariables' && key !== 'errorHandlingType'
|
|
410
862
|
)
|
|
411
|
-
|
|
412
|
-
|
|
863
|
+
|
|
864
|
+
// Build reverse lookup (elementName → varSysId) from BUILT_IN_STEP_DEFINITIONS
|
|
865
|
+
const builtInDef = BUILT_IN_STEP_DEFINITIONS[stepDefinitionSysId]
|
|
866
|
+
const elementToVarSysId: globalThis.Record<string, string> = {}
|
|
867
|
+
if (builtInDef) {
|
|
868
|
+
for (const [varSysId, entry] of Object.entries(builtInDef.inputs)) {
|
|
869
|
+
elementToVarSysId[getVarEntryName(entry)] = varSysId
|
|
870
|
+
}
|
|
871
|
+
for (const [varSysId, entry] of Object.entries(builtInDef.outputs)) {
|
|
872
|
+
elementToVarSysId[getVarEntryName(entry)] = varSysId
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
const pillTypeMap = callExpression.getPillTypeMap()
|
|
877
|
+
const allRecords: BuildRecord[] = []
|
|
878
|
+
await Promise.all(
|
|
879
|
+
filteredEntries.map(async ([key, valueShape]) => {
|
|
880
|
+
// Try resolving from inputDefinitions shape first, then fall back to built-in map
|
|
881
|
+
let variableSysId = ''
|
|
413
882
|
const input = inputs?.get(key)
|
|
414
|
-
|
|
415
|
-
input
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
883
|
+
if (input instanceof CallExpressionShape) {
|
|
884
|
+
variableSysId = (input.getArgument(0).asObject().get('sysId')?.getValue() as string) ?? ''
|
|
885
|
+
}
|
|
886
|
+
if (!variableSysId) {
|
|
887
|
+
variableSysId = elementToVarSysId[key] ?? ''
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
// ApprovalDueDateShape: store JSON in sys_element_mapping.value (ServiceNow reads from there)
|
|
891
|
+
// and create sys_variable_value with empty value
|
|
892
|
+
if (valueShape.is(ApprovalDueDateShape)) {
|
|
893
|
+
const jsonValue = (valueShape as ApprovalDueDateShape).toString().getValue()
|
|
894
|
+
const [elementMappingRecord, variableValueRecord] = await Promise.all([
|
|
895
|
+
factory.createRecord({
|
|
896
|
+
source: callExpression,
|
|
897
|
+
table: 'sys_element_mapping',
|
|
898
|
+
properties: {
|
|
899
|
+
field: key,
|
|
900
|
+
id: stepInstanceSysId,
|
|
901
|
+
table: `var__m_sys_flow_step_definition_input_${stepDefinitionSysId}`,
|
|
902
|
+
value: jsonValue,
|
|
903
|
+
},
|
|
904
|
+
}),
|
|
905
|
+
factory.createRecord({
|
|
906
|
+
source: callExpression,
|
|
907
|
+
table: 'sys_variable_value',
|
|
908
|
+
properties: {
|
|
909
|
+
document: 'sys_hub_step_instance',
|
|
910
|
+
document_key: stepInstanceSysId,
|
|
911
|
+
order: 100,
|
|
912
|
+
// value intentionally empty: ServiceNow reads due_date JSON from sys_element_mapping, not here
|
|
913
|
+
value: '',
|
|
914
|
+
variable: variableSysId,
|
|
915
|
+
},
|
|
916
|
+
}),
|
|
917
|
+
])
|
|
918
|
+
allRecords.push(elementMappingRecord, variableValueRecord)
|
|
919
|
+
return
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
// Handle TemplateValueShape specially - serialize to ServiceNow format.
|
|
923
|
+
// When TemplateValue contains datapills, the platform stores the entire encoded string
|
|
924
|
+
// (with pills inline) in a single sys_element_mapping record with field=<parent input name>.
|
|
925
|
+
let actualValue: unknown
|
|
926
|
+
if (valueShape.is(TemplateValueShape)) {
|
|
927
|
+
const templateObj = (valueShape as TemplateValueShape).getTemplateValue()
|
|
928
|
+
const entries: string[] = []
|
|
929
|
+
let hasPills = false
|
|
930
|
+
|
|
931
|
+
for (const [field, fieldShape] of templateObj.entries({ resolve: false })) {
|
|
932
|
+
const pillString = resolveFieldToPillString(fieldShape, cidMap)
|
|
933
|
+
if (pillString) {
|
|
934
|
+
collectPillTypes(pillString, pillTypeMap)
|
|
935
|
+
entries.push(`${field}=${stripPillType(pillString)}`)
|
|
936
|
+
hasPills = true
|
|
937
|
+
} else if (fieldShape.is(TemplateExpressionShape)) {
|
|
938
|
+
const resolved = resolveTemplateExpression(
|
|
939
|
+
fieldShape as TemplateExpressionShape,
|
|
940
|
+
cidMap,
|
|
941
|
+
pillTypeMap
|
|
942
|
+
)
|
|
943
|
+
if (resolved.hasPills) {
|
|
944
|
+
hasPills = true
|
|
945
|
+
}
|
|
946
|
+
const escapedValue = resolved.result.replace(/\^/g, '^^')
|
|
947
|
+
entries.push(`${field}=${escapedValue}`)
|
|
948
|
+
} else {
|
|
949
|
+
const resolved = fieldShape.getValue()
|
|
950
|
+
const escapedValue = String(resolved).replace(/\^/g, '^^')
|
|
951
|
+
entries.push(`${field}=${escapedValue}`)
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
const encodedValue = entries.join('^')
|
|
956
|
+
|
|
957
|
+
if (hasPills) {
|
|
958
|
+
// TemplateValue with datapills → single sys_element_mapping record
|
|
959
|
+
// No sys_variable_value for this field — platform reads from element_mapping only
|
|
960
|
+
allRecords.push(
|
|
961
|
+
await factory.createRecord({
|
|
962
|
+
source: callExpression,
|
|
963
|
+
table: 'sys_element_mapping',
|
|
964
|
+
properties: {
|
|
965
|
+
field: key,
|
|
966
|
+
id: stepInstanceSysId,
|
|
967
|
+
table: `var__m_sys_flow_step_definition_input_${stepDefinitionSysId}`,
|
|
968
|
+
value: encodedValue,
|
|
969
|
+
},
|
|
970
|
+
})
|
|
971
|
+
)
|
|
972
|
+
return
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
// No datapills — standard encoded string in sys_variable_value
|
|
976
|
+
actualValue = encodedValue ? `${encodedValue}^EQ` : ''
|
|
977
|
+
} else if (valueShape.is(DurationShape)) {
|
|
978
|
+
// DurationShape.getValue() returns a symbol, so use toString() instead
|
|
979
|
+
actualValue = (valueShape as DurationShape).toString().getValue()
|
|
980
|
+
} else if (valueShape.is(ApprovalRulesShape)) {
|
|
981
|
+
// ApprovalRulesShape.getValue() returns a JSON object, not a string.
|
|
982
|
+
// Previously fell through to the generic getValue() path which stored a raw [object Object].
|
|
983
|
+
// toString() correctly serializes it to the JSON string ServiceNow expects.
|
|
984
|
+
actualValue = valueShape.toString().getValue()
|
|
985
|
+
} else if (valueShape.is(TemplateExpressionShape)) {
|
|
986
|
+
const { result, hasPills } = resolveTemplateExpression(
|
|
987
|
+
valueShape as TemplateExpressionShape,
|
|
988
|
+
cidMap,
|
|
989
|
+
pillTypeMap
|
|
990
|
+
)
|
|
991
|
+
if (hasPills) {
|
|
992
|
+
allRecords.push(
|
|
993
|
+
await factory.createRecord({
|
|
994
|
+
source: callExpression,
|
|
995
|
+
table: 'sys_element_mapping',
|
|
996
|
+
properties: {
|
|
997
|
+
field: key,
|
|
998
|
+
id: stepInstanceSysId,
|
|
999
|
+
table: `var__m_sys_flow_step_definition_input_${stepDefinitionSysId}`,
|
|
1000
|
+
value: result,
|
|
1001
|
+
},
|
|
1002
|
+
})
|
|
1003
|
+
)
|
|
1004
|
+
return
|
|
1005
|
+
}
|
|
1006
|
+
actualValue = result
|
|
1007
|
+
} else {
|
|
1008
|
+
// Check if it's a wfa.dataPill() CallExpressionShape (step output reference)
|
|
1009
|
+
// that needs to be resolved to a pill string for sys_element_mapping
|
|
1010
|
+
const pillString = resolveFieldToPillString(valueShape as Shape, cidMap)
|
|
1011
|
+
if (pillString) {
|
|
1012
|
+
collectPillTypes(pillString, pillTypeMap)
|
|
1013
|
+
allRecords.push(
|
|
1014
|
+
await factory.createRecord({
|
|
1015
|
+
source: callExpression,
|
|
1016
|
+
table: 'sys_element_mapping',
|
|
1017
|
+
properties: {
|
|
1018
|
+
field: key,
|
|
1019
|
+
id: stepInstanceSysId,
|
|
1020
|
+
table: `var__m_sys_flow_step_definition_input_${stepDefinitionSysId}`,
|
|
1021
|
+
value: stripPillType(pillString),
|
|
1022
|
+
},
|
|
1023
|
+
})
|
|
1024
|
+
)
|
|
1025
|
+
return
|
|
1026
|
+
}
|
|
1027
|
+
const rawValue = valueShape.getValue?.()
|
|
1028
|
+
// Guard against symbol values (e.g., DurationShape, unresolved shapes with { resolve: false })
|
|
1029
|
+
// since factory.createRecord cannot serialize symbols. Fall back to empty string.
|
|
1030
|
+
actualValue = typeof rawValue === 'symbol' ? '' : (rawValue ?? '')
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
const record = await factory.createRecord({
|
|
420
1034
|
source: callExpression,
|
|
421
1035
|
table: 'sys_variable_value',
|
|
422
1036
|
properties: {
|
|
@@ -427,6 +1041,8 @@ async function createVariableRecords(
|
|
|
427
1041
|
variable: variableSysId,
|
|
428
1042
|
},
|
|
429
1043
|
})
|
|
1044
|
+
allRecords.push(record)
|
|
430
1045
|
})
|
|
431
1046
|
)
|
|
1047
|
+
return allRecords
|
|
432
1048
|
}
|