@servicenow/sdk-build-plugins 4.2.0 → 4.4.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/acl-plugin.js +11 -0
- package/dist/acl-plugin.js.map +1 -1
- package/dist/applicability-plugin.d.ts +2 -0
- package/dist/applicability-plugin.js +72 -0
- package/dist/applicability-plugin.js.map +1 -0
- package/dist/atf/test-plugin.js +5 -2
- package/dist/atf/test-plugin.js.map +1 -1
- package/dist/basic-syntax-plugin.js +7 -1
- package/dist/basic-syntax-plugin.js.map +1 -1
- package/dist/business-rule-plugin.js +1 -0
- package/dist/business-rule-plugin.js.map +1 -1
- package/dist/call-expression-plugin.js +1 -107
- package/dist/call-expression-plugin.js.map +1 -1
- package/dist/column/column-to-record.d.ts +10 -3
- package/dist/column/column-to-record.js +44 -7
- package/dist/column/column-to-record.js.map +1 -1
- package/dist/column-plugin.d.ts +3 -1
- package/dist/column-plugin.js +12 -12
- package/dist/column-plugin.js.map +1 -1
- package/dist/dashboard/dashboard-component-property-defaults.d.ts +152 -0
- package/dist/dashboard/dashboard-component-property-defaults.js +264 -0
- package/dist/dashboard/dashboard-component-property-defaults.js.map +1 -0
- package/dist/dashboard/dashboard-component-resolver.d.ts +13 -0
- package/dist/dashboard/dashboard-component-resolver.js +69 -0
- package/dist/dashboard/dashboard-component-resolver.js.map +1 -0
- package/dist/dashboard/dashboard-plugin.d.ts +12 -0
- package/dist/dashboard/dashboard-plugin.js +397 -0
- package/dist/dashboard/dashboard-plugin.js.map +1 -0
- package/dist/data-plugin.d.ts +3 -0
- package/dist/data-plugin.js +61 -113
- package/dist/data-plugin.js.map +1 -1
- package/dist/email-notification-plugin.d.ts +2 -0
- package/dist/email-notification-plugin.js +541 -0
- package/dist/email-notification-plugin.js.map +1 -0
- package/dist/flow/constants/flow-plugin-constants.d.ts +58 -0
- package/dist/flow/constants/flow-plugin-constants.js +70 -0
- package/dist/flow/constants/flow-plugin-constants.js.map +1 -0
- package/dist/flow/flow-logic/flow-logic-constants.d.ts +38 -0
- package/dist/flow/flow-logic/flow-logic-constants.js +118 -0
- package/dist/flow/flow-logic/flow-logic-constants.js.map +1 -0
- package/dist/flow/flow-logic/flow-logic-diagnostics.d.ts +19 -0
- package/dist/flow/flow-logic/flow-logic-diagnostics.js +503 -0
- package/dist/flow/flow-logic/flow-logic-diagnostics.js.map +1 -0
- package/dist/flow/flow-logic/flow-logic-plugin-helpers.d.ts +62 -0
- package/dist/flow/flow-logic/flow-logic-plugin-helpers.js +2092 -0
- package/dist/flow/flow-logic/flow-logic-plugin-helpers.js.map +1 -0
- package/dist/flow/flow-logic/flow-logic-plugin.d.ts +52 -0
- package/dist/flow/flow-logic/flow-logic-plugin.js +283 -0
- package/dist/flow/flow-logic/flow-logic-plugin.js.map +1 -0
- package/dist/flow/flow-logic/flow-logic-shapes.d.ts +104 -0
- package/dist/flow/flow-logic/flow-logic-shapes.js +201 -0
- package/dist/flow/flow-logic/flow-logic-shapes.js.map +1 -0
- package/dist/flow/plugins/approval-rules-plugin.d.ts +2 -0
- package/dist/flow/plugins/approval-rules-plugin.js +49 -0
- package/dist/flow/plugins/approval-rules-plugin.js.map +1 -0
- package/dist/flow/plugins/flow-action-definition-plugin.d.ts +2 -0
- package/dist/flow/plugins/flow-action-definition-plugin.js +286 -0
- package/dist/flow/plugins/flow-action-definition-plugin.js.map +1 -0
- package/dist/flow/plugins/flow-data-pill-plugin.d.ts +9 -0
- package/dist/flow/plugins/flow-data-pill-plugin.js +212 -0
- package/dist/flow/plugins/flow-data-pill-plugin.js.map +1 -0
- package/dist/flow/plugins/flow-definition-plugin.d.ts +2 -0
- package/dist/flow/plugins/flow-definition-plugin.js +1668 -0
- package/dist/flow/plugins/flow-definition-plugin.js.map +1 -0
- package/dist/flow/plugins/flow-diagnostics-plugin.d.ts +26 -0
- package/dist/flow/plugins/flow-diagnostics-plugin.js +217 -0
- package/dist/flow/plugins/flow-diagnostics-plugin.js.map +1 -0
- package/dist/flow/plugins/flow-instance-plugin.d.ts +12 -0
- package/dist/flow/plugins/flow-instance-plugin.js +1205 -0
- package/dist/flow/plugins/flow-instance-plugin.js.map +1 -0
- package/dist/flow/plugins/flow-trigger-instance-plugin.d.ts +2 -0
- package/dist/flow/plugins/flow-trigger-instance-plugin.js +338 -0
- package/dist/flow/plugins/flow-trigger-instance-plugin.js.map +1 -0
- package/dist/flow/plugins/inline-script-plugin.d.ts +39 -0
- package/dist/flow/plugins/inline-script-plugin.js +80 -0
- package/dist/flow/plugins/inline-script-plugin.js.map +1 -0
- package/dist/flow/plugins/step-definition-plugin.d.ts +5 -0
- package/dist/flow/plugins/step-definition-plugin.js +71 -0
- package/dist/flow/plugins/step-definition-plugin.js.map +1 -0
- package/dist/flow/plugins/step-instance-plugin.d.ts +31 -0
- package/dist/flow/plugins/step-instance-plugin.js +339 -0
- package/dist/flow/plugins/step-instance-plugin.js.map +1 -0
- package/dist/flow/plugins/trigger-plugin.d.ts +2 -0
- package/dist/flow/plugins/trigger-plugin.js +96 -0
- package/dist/flow/plugins/trigger-plugin.js.map +1 -0
- package/dist/flow/plugins/wfa-datapill-plugin.d.ts +15 -0
- package/dist/flow/plugins/wfa-datapill-plugin.js +178 -0
- package/dist/flow/plugins/wfa-datapill-plugin.js.map +1 -0
- package/dist/flow/utils/approval-rules-processor.d.ts +13 -0
- package/dist/flow/utils/approval-rules-processor.js +267 -0
- package/dist/flow/utils/approval-rules-processor.js.map +1 -0
- package/dist/flow/utils/built-in-complex-objects.d.ts +19 -0
- package/dist/flow/utils/built-in-complex-objects.js +62 -0
- package/dist/flow/utils/built-in-complex-objects.js.map +1 -0
- package/dist/flow/utils/complex-object-resolver.d.ts +8 -0
- package/dist/flow/utils/complex-object-resolver.js +614 -0
- package/dist/flow/utils/complex-object-resolver.js.map +1 -0
- package/dist/flow/utils/complex-objects.d.ts +36 -0
- package/dist/flow/utils/complex-objects.js +481 -0
- package/dist/flow/utils/complex-objects.js.map +1 -0
- package/dist/flow/utils/data-pill-shapes.d.ts +58 -0
- package/dist/flow/utils/data-pill-shapes.js +135 -0
- package/dist/flow/utils/data-pill-shapes.js.map +1 -0
- package/dist/flow/utils/datapill-transformer.d.ts +110 -0
- package/dist/flow/utils/datapill-transformer.js +503 -0
- package/dist/flow/utils/datapill-transformer.js.map +1 -0
- package/dist/flow/utils/flow-constants.d.ts +72 -0
- package/dist/flow/utils/flow-constants.js +230 -0
- package/dist/flow/utils/flow-constants.js.map +1 -0
- package/dist/flow/utils/flow-io-to-record.d.ts +44 -0
- package/dist/flow/utils/flow-io-to-record.js +409 -0
- package/dist/flow/utils/flow-io-to-record.js.map +1 -0
- package/dist/flow/utils/flow-shapes.d.ts +161 -0
- package/dist/flow/utils/flow-shapes.js +255 -0
- package/dist/flow/utils/flow-shapes.js.map +1 -0
- package/dist/flow/utils/flow-to-xml.d.ts +16 -0
- package/dist/flow/utils/flow-to-xml.js +237 -0
- package/dist/flow/utils/flow-to-xml.js.map +1 -0
- package/dist/flow/utils/flow-variable-processor.d.ts +51 -0
- package/dist/flow/utils/flow-variable-processor.js +69 -0
- package/dist/flow/utils/flow-variable-processor.js.map +1 -0
- package/dist/flow/utils/label-cache-parser.d.ts +7 -0
- package/dist/flow/utils/label-cache-parser.js +24 -0
- package/dist/flow/utils/label-cache-parser.js.map +1 -0
- package/dist/flow/utils/label-cache-processor.d.ts +119 -0
- package/dist/flow/utils/label-cache-processor.js +719 -0
- package/dist/flow/utils/label-cache-processor.js.map +1 -0
- package/dist/flow/utils/pill-string-parser.d.ts +88 -0
- package/dist/flow/utils/pill-string-parser.js +306 -0
- package/dist/flow/utils/pill-string-parser.js.map +1 -0
- package/dist/flow/utils/schema-to-flow-object.d.ts +22 -0
- package/dist/flow/utils/schema-to-flow-object.js +318 -0
- package/dist/flow/utils/schema-to-flow-object.js.map +1 -0
- package/dist/flow/utils/service-catalog.d.ts +47 -0
- package/dist/flow/utils/service-catalog.js +137 -0
- package/dist/flow/utils/service-catalog.js.map +1 -0
- package/dist/flow/utils/utils.d.ts +117 -0
- package/dist/flow/utils/utils.js +345 -0
- package/dist/flow/utils/utils.js.map +1 -0
- package/dist/index.d.ts +20 -1
- package/dist/index.js +21 -1
- package/dist/index.js.map +1 -1
- package/dist/list-plugin.js +1 -1
- package/dist/list-plugin.js.map +1 -1
- package/dist/now-attach-plugin.d.ts +1 -0
- package/dist/now-attach-plugin.js +10 -10
- package/dist/now-attach-plugin.js.map +1 -1
- package/dist/now-ref-plugin.js +1 -1
- package/dist/now-ref-plugin.js.map +1 -1
- package/dist/record-plugin.d.ts +29 -0
- package/dist/record-plugin.js +66 -7
- package/dist/record-plugin.js.map +1 -1
- package/dist/repack/index.d.ts +2 -0
- package/dist/repack/index.js +8 -0
- package/dist/repack/index.js.map +1 -1
- package/dist/rest-api-plugin.js +54 -44
- package/dist/rest-api-plugin.js.map +1 -1
- package/dist/server-module-plugin/index.d.ts +10 -0
- package/dist/server-module-plugin/index.js +83 -59
- package/dist/server-module-plugin/index.js.map +1 -1
- package/dist/service-catalog/catalog-clientscript-plugin.d.ts +2 -0
- package/dist/service-catalog/catalog-clientscript-plugin.js +117 -0
- package/dist/service-catalog/catalog-clientscript-plugin.js.map +1 -0
- package/dist/service-catalog/catalog-item-plugin.d.ts +2 -0
- package/dist/service-catalog/catalog-item-plugin.js +115 -0
- package/dist/service-catalog/catalog-item-plugin.js.map +1 -0
- package/dist/service-catalog/catalog-ui-policy-plugin.d.ts +2 -0
- package/dist/service-catalog/catalog-ui-policy-plugin.js +266 -0
- package/dist/service-catalog/catalog-ui-policy-plugin.js.map +1 -0
- package/dist/service-catalog/index.d.ts +5 -0
- package/dist/service-catalog/index.js +22 -0
- package/dist/service-catalog/index.js.map +1 -0
- package/dist/service-catalog/record-to-shape.d.ts +6 -0
- package/dist/service-catalog/record-to-shape.js +93 -0
- package/dist/service-catalog/record-to-shape.js.map +1 -0
- package/dist/service-catalog/sc-record-producer-plugin.d.ts +2 -0
- package/dist/service-catalog/sc-record-producer-plugin.js +140 -0
- package/dist/service-catalog/sc-record-producer-plugin.js.map +1 -0
- package/dist/service-catalog/service-catalog-base.d.ts +311 -0
- package/dist/service-catalog/service-catalog-base.js +542 -0
- package/dist/service-catalog/service-catalog-base.js.map +1 -0
- package/dist/service-catalog/service-catalog-diagnostics.d.ts +45 -0
- package/dist/service-catalog/service-catalog-diagnostics.js +172 -0
- package/dist/service-catalog/service-catalog-diagnostics.js.map +1 -0
- package/dist/service-catalog/shape-to-record.d.ts +8 -0
- package/dist/service-catalog/shape-to-record.js +235 -0
- package/dist/service-catalog/shape-to-record.js.map +1 -0
- package/dist/service-catalog/utils.d.ts +323 -0
- package/dist/service-catalog/utils.js +1216 -0
- package/dist/service-catalog/utils.js.map +1 -0
- package/dist/service-catalog/variable-helper.d.ts +43 -0
- package/dist/service-catalog/variable-helper.js +92 -0
- package/dist/service-catalog/variable-helper.js.map +1 -0
- package/dist/service-catalog/variable-set-plugin.d.ts +2 -0
- package/dist/service-catalog/variable-set-plugin.js +175 -0
- package/dist/service-catalog/variable-set-plugin.js.map +1 -0
- package/dist/service-catalog/variables-transform.d.ts +139 -0
- package/dist/service-catalog/variables-transform.js +403 -0
- package/dist/service-catalog/variables-transform.js.map +1 -0
- package/dist/sla/sla-validators.d.ts +61 -0
- package/dist/sla/sla-validators.js +224 -0
- package/dist/sla/sla-validators.js.map +1 -0
- package/dist/sla-plugin.d.ts +5 -0
- package/dist/sla-plugin.js +280 -0
- package/dist/sla-plugin.js.map +1 -0
- package/dist/static-content-plugin.js +25 -2
- package/dist/static-content-plugin.js.map +1 -1
- package/dist/table-plugin.js +32 -15
- package/dist/table-plugin.js.map +1 -1
- package/dist/ui-page-plugin.js +832 -19
- package/dist/ui-page-plugin.js.map +1 -1
- package/dist/ui-policy-plugin.js +5 -7
- package/dist/ui-policy-plugin.js.map +1 -1
- package/dist/utils.d.ts +10 -1
- package/dist/utils.js +16 -0
- package/dist/utils.js.map +1 -1
- package/dist/ux-list-menu-config-plugin.d.ts +2 -0
- package/dist/ux-list-menu-config-plugin.js +292 -0
- package/dist/ux-list-menu-config-plugin.js.map +1 -0
- package/dist/workspace-plugin/chrome-tab.d.ts +2 -0
- package/dist/workspace-plugin/chrome-tab.js +46 -0
- package/dist/workspace-plugin/chrome-tab.js.map +1 -0
- package/dist/workspace-plugin/constants.d.ts +52 -0
- package/dist/workspace-plugin/constants.js +56 -0
- package/dist/workspace-plugin/constants.js.map +1 -0
- package/dist/workspace-plugin/fluent-utils.d.ts +9 -0
- package/dist/workspace-plugin/fluent-utils.js +60 -0
- package/dist/workspace-plugin/fluent-utils.js.map +1 -0
- package/dist/workspace-plugin/page.d.ts +8 -0
- package/dist/workspace-plugin/page.js +108 -0
- package/dist/workspace-plugin/page.js.map +1 -0
- package/dist/workspace-plugin/screen.d.ts +1 -0
- package/dist/workspace-plugin/screen.js +38 -0
- package/dist/workspace-plugin/screen.js.map +1 -0
- package/dist/workspace-plugin/templates/index.d.ts +10 -0
- package/dist/workspace-plugin/templates/index.js +20 -0
- package/dist/workspace-plugin/templates/index.js.map +1 -0
- package/dist/workspace-plugin/templates/record-page-composition.d.ts +1 -0
- package/dist/workspace-plugin/templates/record-page-composition.js +4043 -0
- package/dist/workspace-plugin/templates/record-page-composition.js.map +1 -0
- package/dist/workspace-plugin/templates/record-page-data.d.ts +1 -0
- package/dist/workspace-plugin/templates/record-page-data.js +527 -0
- package/dist/workspace-plugin/templates/record-page-data.js.map +1 -0
- package/dist/workspace-plugin/templates/record-page-interalEventMappings.d.ts +1 -0
- package/dist/workspace-plugin/templates/record-page-interalEventMappings.js +39 -0
- package/dist/workspace-plugin/templates/record-page-interalEventMappings.js.map +1 -0
- package/dist/workspace-plugin/templates/record-page-layoutModel.d.ts +1 -0
- package/dist/workspace-plugin/templates/record-page-layoutModel.js +55 -0
- package/dist/workspace-plugin/templates/record-page-layoutModel.js.map +1 -0
- package/dist/workspace-plugin/templates/record-page-properties.d.ts +1 -0
- package/dist/workspace-plugin/templates/record-page-properties.js +135 -0
- package/dist/workspace-plugin/templates/record-page-properties.js.map +1 -0
- package/dist/workspace-plugin/templates/record-page.d.ts +3 -0
- package/dist/workspace-plugin/templates/record-page.js +8 -0
- package/dist/workspace-plugin/templates/record-page.js.map +1 -0
- package/dist/workspace-plugin.d.ts +2 -0
- package/dist/workspace-plugin.js +453 -0
- package/dist/workspace-plugin.js.map +1 -0
- package/package.json +10 -12
- package/src/acl-plugin.ts +16 -1
- package/src/applicability-plugin.ts +82 -0
- package/src/atf/test-plugin.ts +6 -3
- package/src/basic-syntax-plugin.ts +10 -1
- package/src/business-rule-plugin.ts +2 -1
- package/src/call-expression-plugin.ts +2 -130
- package/src/column/column-to-record.ts +54 -8
- package/src/column-plugin.ts +29 -13
- package/src/dashboard/dashboard-component-property-defaults.ts +277 -0
- package/src/dashboard/dashboard-component-resolver.ts +69 -0
- package/src/dashboard/dashboard-plugin.ts +450 -0
- package/src/data-plugin.ts +67 -139
- package/src/email-notification-plugin.ts +850 -0
- package/src/flow/constants/flow-plugin-constants.ts +79 -0
- package/src/flow/flow-logic/flow-logic-constants.ts +120 -0
- package/src/flow/flow-logic/flow-logic-diagnostics.ts +591 -0
- package/src/flow/flow-logic/flow-logic-plugin-helpers.ts +2550 -0
- package/src/flow/flow-logic/flow-logic-plugin.ts +337 -0
- package/src/flow/flow-logic/flow-logic-shapes.ts +215 -0
- package/src/flow/plugins/approval-rules-plugin.ts +48 -0
- package/src/flow/plugins/flow-action-definition-plugin.ts +295 -0
- package/src/flow/plugins/flow-data-pill-plugin.ts +258 -0
- package/src/flow/plugins/flow-definition-plugin.ts +2173 -0
- package/src/flow/plugins/flow-diagnostics-plugin.ts +280 -0
- package/src/flow/plugins/flow-instance-plugin.ts +1499 -0
- package/src/flow/plugins/flow-trigger-instance-plugin.ts +444 -0
- package/src/flow/plugins/inline-script-plugin.ts +83 -0
- package/src/flow/plugins/step-definition-plugin.ts +67 -0
- package/src/flow/plugins/step-instance-plugin.ts +431 -0
- package/src/flow/plugins/trigger-plugin.ts +95 -0
- package/src/flow/plugins/wfa-datapill-plugin.ts +213 -0
- package/src/flow/utils/approval-rules-processor.ts +298 -0
- package/src/flow/utils/built-in-complex-objects.ts +81 -0
- package/src/flow/utils/complex-object-resolver.ts +875 -0
- package/src/flow/utils/complex-objects.ts +656 -0
- package/src/flow/utils/data-pill-shapes.ts +165 -0
- package/src/flow/utils/datapill-transformer.ts +632 -0
- package/src/flow/utils/flow-constants.ts +285 -0
- package/src/flow/utils/flow-io-to-record.ts +533 -0
- package/src/flow/utils/flow-shapes.ts +296 -0
- package/src/flow/utils/flow-to-xml.ts +318 -0
- package/src/flow/utils/flow-variable-processor.ts +100 -0
- package/src/flow/utils/label-cache-parser.ts +37 -0
- package/src/flow/utils/label-cache-processor.ts +870 -0
- package/src/flow/utils/pill-string-parser.ts +375 -0
- package/src/flow/utils/schema-to-flow-object.ts +385 -0
- package/src/flow/utils/service-catalog.ts +174 -0
- package/src/flow/utils/utils.ts +395 -0
- package/src/index.ts +20 -1
- package/src/list-plugin.ts +1 -1
- package/src/now-attach-plugin.ts +14 -11
- package/src/now-ref-plugin.ts +1 -1
- package/src/record-plugin.ts +76 -11
- package/src/repack/index.ts +14 -0
- package/src/rest-api-plugin.ts +62 -50
- package/src/server-module-plugin/index.ts +112 -86
- package/src/service-catalog/catalog-clientscript-plugin.ts +140 -0
- package/src/service-catalog/catalog-item-plugin.ts +162 -0
- package/src/service-catalog/catalog-ui-policy-plugin.ts +324 -0
- package/src/service-catalog/index.ts +5 -0
- package/src/service-catalog/record-to-shape.ts +109 -0
- package/src/service-catalog/sc-record-producer-plugin.ts +201 -0
- package/src/service-catalog/service-catalog-base.ts +600 -0
- package/src/service-catalog/service-catalog-diagnostics.ts +254 -0
- package/src/service-catalog/shape-to-record.ts +279 -0
- package/src/service-catalog/utils.ts +1455 -0
- package/src/service-catalog/variable-helper.ts +135 -0
- package/src/service-catalog/variable-set-plugin.ts +197 -0
- package/src/service-catalog/variables-transform.ts +438 -0
- package/src/sla/sla-validators.ts +331 -0
- package/src/sla-plugin.ts +358 -0
- package/src/static-content-plugin.ts +25 -2
- package/src/table-plugin.ts +49 -16
- package/src/ui-page-plugin.ts +1063 -20
- package/src/ui-policy-plugin.ts +5 -9
- package/src/utils.ts +24 -1
- package/src/ux-list-menu-config-plugin.ts +312 -0
- package/src/workspace-plugin/chrome-tab.ts +44 -0
- package/src/workspace-plugin/constants.ts +53 -0
- package/src/workspace-plugin/fluent-utils.ts +60 -0
- package/src/workspace-plugin/page.ts +139 -0
- package/src/workspace-plugin/screen.ts +34 -0
- package/src/workspace-plugin/templates/index.ts +17 -0
- package/src/workspace-plugin/templates/record-page-composition.ts +4051 -0
- package/src/workspace-plugin/templates/record-page-data.ts +523 -0
- package/src/workspace-plugin/templates/record-page-interalEventMappings.ts +35 -0
- package/src/workspace-plugin/templates/record-page-layoutModel.ts +51 -0
- package/src/workspace-plugin/templates/record-page-properties.ts +131 -0
- package/src/workspace-plugin/templates/record-page.ts +6 -0
- package/src/workspace-plugin.ts +574 -0
|
@@ -0,0 +1,1499 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CallExpressionShape,
|
|
3
|
+
type Database,
|
|
4
|
+
type Diagnostics,
|
|
5
|
+
DurationShape,
|
|
6
|
+
type Factory,
|
|
7
|
+
IdentifierShape,
|
|
8
|
+
type Logger,
|
|
9
|
+
ObjectShape,
|
|
10
|
+
Plugin,
|
|
11
|
+
PropertyAccessShape,
|
|
12
|
+
Record,
|
|
13
|
+
type RecordContext,
|
|
14
|
+
type Result,
|
|
15
|
+
Shape,
|
|
16
|
+
type Source,
|
|
17
|
+
StringShape,
|
|
18
|
+
TemplateExpressionShape,
|
|
19
|
+
TemplateValueShape,
|
|
20
|
+
TimeShape,
|
|
21
|
+
type Transform,
|
|
22
|
+
ts,
|
|
23
|
+
VariableStatementShape,
|
|
24
|
+
} from '@servicenow/sdk-build-core'
|
|
25
|
+
import { NowIdShape } from '../../now-id-plugin'
|
|
26
|
+
import { gunzipSync } from 'node:zlib'
|
|
27
|
+
import { resolveComplexInput as _resolveComplexInput } from '../utils/complex-object-resolver'
|
|
28
|
+
import {
|
|
29
|
+
getCoreActionIdentifier,
|
|
30
|
+
getDirectVariableIdentifier,
|
|
31
|
+
getIdentifierFromRecord,
|
|
32
|
+
getIdentifierFromShape,
|
|
33
|
+
resolveDataPillShape,
|
|
34
|
+
sysIdToUuid,
|
|
35
|
+
} from '../utils/utils'
|
|
36
|
+
import {
|
|
37
|
+
convertSlushBucketToCatalogVariableArray,
|
|
38
|
+
createTemplateExpressionFromIdentifier,
|
|
39
|
+
findCatalogItemBySysId,
|
|
40
|
+
isCatalogAction,
|
|
41
|
+
} from '../utils/service-catalog'
|
|
42
|
+
import { getAttributeValue } from '../utils/schema-to-flow-object'
|
|
43
|
+
import {
|
|
44
|
+
ActionSubflowInstanceShape,
|
|
45
|
+
ApprovalRulesShape,
|
|
46
|
+
ApprovalDueDateShape,
|
|
47
|
+
InlineScriptShape,
|
|
48
|
+
} from '../utils/flow-shapes'
|
|
49
|
+
import { FDInlineScriptCallShape } from './inline-script-plugin'
|
|
50
|
+
|
|
51
|
+
import {
|
|
52
|
+
ACTION_DEF_COLUMN_NAME,
|
|
53
|
+
ACTION_INSTANCE_API_NAME,
|
|
54
|
+
APPROVAL_RULES_DATA_TYPE_VALUE,
|
|
55
|
+
APPROVAL_DUE_DATE_DATA_TYPE_VALUE,
|
|
56
|
+
CORE_ACTIONS_SYS_ID_NAME_MAP,
|
|
57
|
+
DURATION_DATA_TYPE_VALUE,
|
|
58
|
+
SUBFLOW_INSTANCE_API_NAME,
|
|
59
|
+
TEMPLATE_DATA_TYPE_VALUE,
|
|
60
|
+
TIME_DATA_TYPE_VALUE,
|
|
61
|
+
UNSUPPORTED_DATA_TYPES,
|
|
62
|
+
UTC_TIMEZONE_VALUE,
|
|
63
|
+
APPROVAL_DUE_DATE_INPUT_FIELD_ACTIONS,
|
|
64
|
+
ACTION_TYPE_KEY_NAME,
|
|
65
|
+
CATALOG_VARIABLE_TABLE,
|
|
66
|
+
CATALOG_VARIABLE_SET_TABLE,
|
|
67
|
+
} from '../utils/flow-constants'
|
|
68
|
+
|
|
69
|
+
import type { ApprovalDueDateType, ApprovalRulesType } from '@servicenow/sdk-core/runtime/flow'
|
|
70
|
+
import type { Duration } from '@servicenow/sdk-core/runtime/db'
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Helper function to check if a field is hidden based on visible or visible_in_fd attributes
|
|
74
|
+
* @param attributes The attributes string from the field definition
|
|
75
|
+
* @returns true if the field has visible='false' or visible_in_fd='false'
|
|
76
|
+
*/
|
|
77
|
+
function isHiddenField(attributes: string | undefined): boolean {
|
|
78
|
+
if (!attributes) {
|
|
79
|
+
return false
|
|
80
|
+
}
|
|
81
|
+
const visibleAttr = getAttributeValue(attributes, 'visible')
|
|
82
|
+
const visibleInFdAttr = getAttributeValue(attributes, 'visible_in_fd')
|
|
83
|
+
return visibleAttr === 'false' || visibleInFdAttr === 'false'
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Parses a complex object format where values are nested under $cv.$v
|
|
88
|
+
* @param obj The complex object to parse
|
|
89
|
+
* @returns A simplified object with direct values
|
|
90
|
+
*/
|
|
91
|
+
function parseComplexObjectValues(obj: unknown): unknown {
|
|
92
|
+
/**
|
|
93
|
+
* Recursively parse a value that may contain Flow Designer complex-object wrappers.
|
|
94
|
+
* Handles:
|
|
95
|
+
* • Primitive values – returned as-is
|
|
96
|
+
* • Objects with `$cv` – unwrap to `$cv.$v`
|
|
97
|
+
* • Objects with `$COCollectionField` – treat as an array and recurse
|
|
98
|
+
* • Arrays – recurse over each element
|
|
99
|
+
* • Plain objects – recurse over each property
|
|
100
|
+
*/
|
|
101
|
+
const parseValue = (val: unknown): unknown => {
|
|
102
|
+
if (val === null || val === undefined) {
|
|
103
|
+
return val
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Arrays – recurse element-wise
|
|
107
|
+
if (Array.isArray(val)) {
|
|
108
|
+
return val.map(parseValue)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Objects
|
|
112
|
+
if (typeof val === 'object') {
|
|
113
|
+
const obj = val as globalThis.Record<string, unknown>
|
|
114
|
+
// Direct complex-value wrapper
|
|
115
|
+
if ('$cv' in obj) {
|
|
116
|
+
const cv = obj['$cv'] as globalThis.Record<string, unknown> | undefined
|
|
117
|
+
return parseValue(cv?.['$v'])
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Flow Designer collection array wrapper
|
|
121
|
+
if ('$COCollectionField' in obj) {
|
|
122
|
+
return parseValue(obj['$COCollectionField'])
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Plain object – recurse on each property
|
|
126
|
+
const out: { [k: string]: unknown } = {}
|
|
127
|
+
for (const [k, v] of Object.entries(val)) {
|
|
128
|
+
out[k] = parseValue(v)
|
|
129
|
+
}
|
|
130
|
+
return out
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Primitive
|
|
134
|
+
return val
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return parseValue(obj)
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Normalize raw input value based on uiType.
|
|
142
|
+
* - Attempts to JSON.parse strings.
|
|
143
|
+
* - Resolves FlowDesigner complexObject structures via parseComplexObjectValues.
|
|
144
|
+
* - For array uiTypes, ensures the result is an array (falling back to raw).
|
|
145
|
+
* - For glide_time, parses the time string and returns a TimeShape object.
|
|
146
|
+
* - For glide_duration, parses the duration string and returns a DurationShape object.
|
|
147
|
+
* - For template_value, parses the time string and returns a TemplateValueShape object.
|
|
148
|
+
*/
|
|
149
|
+
export function normalizeInputValue(value: string, uiType?: string, source?: Source, logger?: Logger): unknown {
|
|
150
|
+
// Handle glide_time type specially - parse the time string and return TimeShape
|
|
151
|
+
if (source) {
|
|
152
|
+
try {
|
|
153
|
+
if (uiType === TIME_DATA_TYPE_VALUE) {
|
|
154
|
+
// Create a StringShape from the value and use TimeShape.from() to parse it.
|
|
155
|
+
// Uses UTC timezone value to show in fluent flow to be in sync with Flow designer UI
|
|
156
|
+
return TimeShape.from(source, Shape.from(source, value).asString(), UTC_TIMEZONE_VALUE)
|
|
157
|
+
} else if (uiType === DURATION_DATA_TYPE_VALUE) {
|
|
158
|
+
// Create a StringShape from the value and use DurationShape.from() to parse it
|
|
159
|
+
return DurationShape.from(source, Shape.from(source, value).asString())
|
|
160
|
+
} else if (uiType === TEMPLATE_DATA_TYPE_VALUE) {
|
|
161
|
+
// Create a StringShape from the value and use TemplateValueShape.from() to parse it
|
|
162
|
+
return TemplateValueShape.from(source, Shape.from(source, value).asString())
|
|
163
|
+
} else if (uiType === APPROVAL_RULES_DATA_TYPE_VALUE) {
|
|
164
|
+
// Create a StringShape from the value and use ApprovalRulesShape.from() to parse it
|
|
165
|
+
return ApprovalRulesShape.from(source, Shape.from(source, value).asString())
|
|
166
|
+
} else if (uiType === APPROVAL_DUE_DATE_DATA_TYPE_VALUE) {
|
|
167
|
+
// Check if source is a Record before accessing action_type
|
|
168
|
+
if (source instanceof Record) {
|
|
169
|
+
const actionType = source.get(ACTION_TYPE_KEY_NAME)?.ifDefined()?.asString()?.getValue()
|
|
170
|
+
if (APPROVAL_DUE_DATE_INPUT_FIELD_ACTIONS.includes(actionType as string)) {
|
|
171
|
+
// Create a StringShape from the value and use ApprovalDueDateShape.from() to parse it
|
|
172
|
+
return ApprovalDueDateShape.from(source, Shape.from(source, value).asString())
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
} catch (e) {
|
|
177
|
+
// If parsing fails, fall through to normal handling
|
|
178
|
+
logger?.error(
|
|
179
|
+
`Failed to parse value ${value} for ${uiType} in record ${source}: ${e instanceof Error ? e.message : e}`
|
|
180
|
+
)
|
|
181
|
+
return value
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
let parsed: unknown = value
|
|
186
|
+
try {
|
|
187
|
+
if (uiType !== 'string') {
|
|
188
|
+
parsed = JSON.parse(value)
|
|
189
|
+
}
|
|
190
|
+
} catch {
|
|
191
|
+
// handle internal string types
|
|
192
|
+
if (uiType === 'glide_list') {
|
|
193
|
+
// comma separated sys_ids – return [] if empty
|
|
194
|
+
return value && value.trim() !== '' ? value.split(',') : []
|
|
195
|
+
}
|
|
196
|
+
return value // any string literal value (other than a valid stringified JSON)
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (parsed && typeof parsed === 'object' && 'complexObject' in parsed) {
|
|
200
|
+
return parseComplexObjectValues(parsed.complexObject)
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (uiType?.startsWith('array')) {
|
|
204
|
+
return Array.isArray(parsed) ? parsed : value
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Handle internal non-string types for primitive data types
|
|
209
|
+
* Ex. Instances store boolean values as '1' or '0' instead of true or false. But we show it as true/false in UI/fluent
|
|
210
|
+
*/
|
|
211
|
+
if (uiType === 'boolean') {
|
|
212
|
+
parsed = Boolean(parsed) // 1 or true = true, 0 or false = false
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return parsed
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function buildInstanceToShape({
|
|
219
|
+
defColumn, // e.g. "action_type" | "subflow"
|
|
220
|
+
inputsTableName, // e.g. "sys_hub_action_input" | "sys_hub_flow_input"
|
|
221
|
+
zippedColumn, // e.g. "values" | "subflow_inputs"
|
|
222
|
+
callee, // "wfa.action" | "wfa.subflow"
|
|
223
|
+
}: {
|
|
224
|
+
defColumn: string
|
|
225
|
+
inputsTableName: string
|
|
226
|
+
zippedColumn: string
|
|
227
|
+
callee: typeof ACTION_INSTANCE_API_NAME | typeof SUBFLOW_INSTANCE_API_NAME
|
|
228
|
+
}) {
|
|
229
|
+
return function toShape(record: Record, { database, logger }: RecordContext): Result<Shape> {
|
|
230
|
+
// Resolve the instance definition - either from the source shape or from the database record
|
|
231
|
+
const source = record.getSource()
|
|
232
|
+
const instanceDef =
|
|
233
|
+
source instanceof ActionSubflowInstanceShape
|
|
234
|
+
? source.getInstanceDefinition()
|
|
235
|
+
: record.get(defColumn)?.ifDefined()?.asString()
|
|
236
|
+
|
|
237
|
+
const definitionInputs =
|
|
238
|
+
instanceDef instanceof Record
|
|
239
|
+
? instanceDef.flat().filter((v) => v.getTable() === inputsTableName)
|
|
240
|
+
: undefined
|
|
241
|
+
|
|
242
|
+
const zippedInputs = record.get(zippedColumn)?.ifString()?.getValue() ?? ''
|
|
243
|
+
|
|
244
|
+
// ── Identifier discovery ────────────────────────────────────────────────
|
|
245
|
+
let identifierShapeOrSysId: Shape | undefined = instanceDef
|
|
246
|
+
if (instanceDef instanceof Record) {
|
|
247
|
+
// check for core actions in existing fluent code, if so below condition will keep the existing identifier.
|
|
248
|
+
// Otherwise action.core.log will be replaced with the log.
|
|
249
|
+
const sysId = instanceDef.getId().getValue()
|
|
250
|
+
const coreActionIdentifier = getCoreActionIdentifier(sysId)
|
|
251
|
+
if (coreActionIdentifier) {
|
|
252
|
+
identifierShapeOrSysId = new IdentifierShape({
|
|
253
|
+
source: record,
|
|
254
|
+
name: coreActionIdentifier,
|
|
255
|
+
})
|
|
256
|
+
} else {
|
|
257
|
+
const original = instanceDef.getOriginalSource()
|
|
258
|
+
if (ts.Node.isNode(original)) {
|
|
259
|
+
const varDecl = original.getFirstAncestorByKind(ts.SyntaxKind.VariableDeclaration)
|
|
260
|
+
const idNode = varDecl?.getNameNode()
|
|
261
|
+
if (idNode) {
|
|
262
|
+
identifierShapeOrSysId = new IdentifierShape({
|
|
263
|
+
source: idNode,
|
|
264
|
+
name: idNode.getText(),
|
|
265
|
+
})
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
} else {
|
|
270
|
+
// When definition is not a Record, try to resolve from database by sys_id
|
|
271
|
+
if (defColumn === ACTION_DEF_COLUMN_NAME) {
|
|
272
|
+
const sysId = instanceDef?.ifString()?.getValue()
|
|
273
|
+
if (!sysId) {
|
|
274
|
+
return { success: false }
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const coreActionIdentifier = getCoreActionIdentifier(sysId)
|
|
278
|
+
if (callee === ACTION_INSTANCE_API_NAME && !coreActionIdentifier) {
|
|
279
|
+
logger.warn(`Custom actions are not supported, action = ${sysId}`)
|
|
280
|
+
return { success: false }
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const action = database
|
|
284
|
+
.query('sys_hub_action_type_definition')
|
|
285
|
+
.find((v) => v.getId().getValue() === sysId)
|
|
286
|
+
|
|
287
|
+
const actionSource = action?.getSource()
|
|
288
|
+
if (actionSource instanceof CallExpressionShape) {
|
|
289
|
+
const identifierName = getIdentifierFromShape(actionSource)
|
|
290
|
+
if (identifierName) {
|
|
291
|
+
identifierShapeOrSysId = new IdentifierShape({
|
|
292
|
+
source: actionSource.getOriginalSource(),
|
|
293
|
+
name: identifierName,
|
|
294
|
+
})
|
|
295
|
+
}
|
|
296
|
+
} else if (coreActionIdentifier) {
|
|
297
|
+
//Special case handling for core actions
|
|
298
|
+
identifierShapeOrSysId = new IdentifierShape({ source: record, name: coreActionIdentifier })
|
|
299
|
+
}
|
|
300
|
+
} else if (defColumn === 'subflow') {
|
|
301
|
+
const sysId = instanceDef?.getValue()
|
|
302
|
+
const subflow = database.query('sys_hub_flow').find((v) => v.getId().getValue() === sysId)
|
|
303
|
+
|
|
304
|
+
const actionSource = subflow?.getSource()
|
|
305
|
+
if (actionSource instanceof CallExpressionShape) {
|
|
306
|
+
const identifierName = getIdentifierFromShape(actionSource)
|
|
307
|
+
if (identifierName) {
|
|
308
|
+
identifierShapeOrSysId = new IdentifierShape({
|
|
309
|
+
source: actionSource.getOriginalSource(),
|
|
310
|
+
name: identifierName,
|
|
311
|
+
})
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
let inputsShape = buildInputsShapeFromZipped({
|
|
318
|
+
zippedInputs,
|
|
319
|
+
definitionInputs,
|
|
320
|
+
actionDefinition: instanceDef,
|
|
321
|
+
record,
|
|
322
|
+
logger,
|
|
323
|
+
database,
|
|
324
|
+
})
|
|
325
|
+
if (inputsShape === undefined) {
|
|
326
|
+
return { success: false as const }
|
|
327
|
+
}
|
|
328
|
+
const waitForCompletion =
|
|
329
|
+
record.get('wait_for_completion')?.getValue() === true ||
|
|
330
|
+
record.get('wait_for_completion')?.getValue() === 'true'
|
|
331
|
+
if (waitForCompletion) {
|
|
332
|
+
inputsShape = inputsShape
|
|
333
|
+
? inputsShape.merge({ waitForCompletion })
|
|
334
|
+
: Shape.from(record, { waitForCompletion }).asObject()
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
const configArg = new ObjectShape({
|
|
338
|
+
source: record,
|
|
339
|
+
properties: record.transform(({ $ }) => ({
|
|
340
|
+
$id: $.val(NowIdShape.from(record)),
|
|
341
|
+
annotation: $.from('comment').def(''),
|
|
342
|
+
uuid: $.from('ui_id').def(''),
|
|
343
|
+
})),
|
|
344
|
+
})
|
|
345
|
+
|
|
346
|
+
// Create the CallExpressionShape for the action/subflow instance
|
|
347
|
+
const callExpression = new CallExpressionShape({
|
|
348
|
+
source: record,
|
|
349
|
+
callee,
|
|
350
|
+
args: [identifierShapeOrSysId, configArg, inputsShape],
|
|
351
|
+
})
|
|
352
|
+
|
|
353
|
+
// Generate variable name from existing source or fallback to callee + ID
|
|
354
|
+
const order = record.get('order')?.getValue()
|
|
355
|
+
let identifierPrefix = ''
|
|
356
|
+
if (callee.toLowerCase() === ACTION_INSTANCE_API_NAME) {
|
|
357
|
+
identifierPrefix = 'action'
|
|
358
|
+
} else if (callee.toLowerCase() === SUBFLOW_INSTANCE_API_NAME) {
|
|
359
|
+
identifierPrefix = 'subflow'
|
|
360
|
+
}
|
|
361
|
+
// Use getDirectVariableIdentifier to only check direct parent VariableDeclaration
|
|
362
|
+
// This prevents actions inside Subflows from inheriting the parent Subflow's variable name
|
|
363
|
+
const variableName =
|
|
364
|
+
getDirectVariableIdentifier(record.getOriginalSource()) ?? `${identifierPrefix}Instance_${order}` // _${instanceId.slice(0, 8)}`
|
|
365
|
+
|
|
366
|
+
// Wrap in VariableStatementShape with isExported: false
|
|
367
|
+
return {
|
|
368
|
+
success: true,
|
|
369
|
+
value: new VariableStatementShape({
|
|
370
|
+
source: record,
|
|
371
|
+
variableName,
|
|
372
|
+
initializer: callExpression,
|
|
373
|
+
isExported: false,
|
|
374
|
+
}),
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* Validates that all property accesses on a getCatalogVariables action output variable
|
|
381
|
+
* are declared in its catalog_variables input.
|
|
382
|
+
*
|
|
383
|
+
* Runs once per getCatalogVariables action instance (forward search from declaration to usages)
|
|
384
|
+
* rather than once per template expression (backward search from usage to declaration).
|
|
385
|
+
*/
|
|
386
|
+
function validateCatalogVariableOutputReferences(
|
|
387
|
+
callExpression: ActionSubflowInstanceShape,
|
|
388
|
+
instanceInputs: ObjectShape,
|
|
389
|
+
diagnostics: Diagnostics
|
|
390
|
+
): void {
|
|
391
|
+
// Extract allowed variable names from the catalog_variables input
|
|
392
|
+
const catalogVarsShape = instanceInputs.get('catalog_variables')
|
|
393
|
+
if (!catalogVarsShape) {
|
|
394
|
+
return
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
const allowedVariables: string[] = []
|
|
398
|
+
if (catalogVarsShape.isArray()) {
|
|
399
|
+
for (const el of catalogVarsShape.asArray().getElements(false)) {
|
|
400
|
+
if (el instanceof PropertyAccessShape) {
|
|
401
|
+
const propElements = el.getElements()
|
|
402
|
+
const lastEl = propElements[propElements.length - 1]
|
|
403
|
+
if (lastEl instanceof IdentifierShape) {
|
|
404
|
+
allowedVariables.push(lastEl.getName())
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
if (allowedVariables.length === 0) {
|
|
411
|
+
return
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// Navigate from the wfa.action(...) call to its parent variable declaration
|
|
415
|
+
const originalNode = callExpression.getOriginalNode()
|
|
416
|
+
if (!ts.Node.isCallExpression(originalNode)) {
|
|
417
|
+
return
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
const parent = originalNode.getParent()
|
|
421
|
+
if (!ts.Node.isVariableDeclaration(parent)) {
|
|
422
|
+
return
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
const nameNode = parent.getNameNode()
|
|
426
|
+
if (!ts.Node.isIdentifier(nameNode)) {
|
|
427
|
+
return
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
// Find all references to the action output variable and validate each property access
|
|
431
|
+
for (const ref of nameNode.findReferencesAsNodes()) {
|
|
432
|
+
const refParent = ref.getParent()
|
|
433
|
+
if (!ts.Node.isPropertyAccessExpression(refParent)) {
|
|
434
|
+
continue
|
|
435
|
+
}
|
|
436
|
+
if (refParent.getExpression() !== ref) {
|
|
437
|
+
continue
|
|
438
|
+
} // ref must be the object base, not the property name
|
|
439
|
+
|
|
440
|
+
const propertyName = refParent.getName()
|
|
441
|
+
if (propertyName && !allowedVariables.includes(propertyName)) {
|
|
442
|
+
diagnostics.error(
|
|
443
|
+
catalogVarsShape,
|
|
444
|
+
`Property '${propertyName}' is not available in the getCatalogVariables output. ` +
|
|
445
|
+
`Only the following variables are accessible: ${allowedVariables.join(', ')}. ` +
|
|
446
|
+
`Please add '${propertyName}' to the catalog_variables input if you need to access it.`
|
|
447
|
+
)
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
export const FlowInstancePlugin = Plugin.create({
|
|
453
|
+
name: 'FlowInstancePlugin',
|
|
454
|
+
records: {
|
|
455
|
+
sys_hub_action_instance_v2: {
|
|
456
|
+
toShape: buildInstanceToShape({
|
|
457
|
+
defColumn: ACTION_DEF_COLUMN_NAME,
|
|
458
|
+
inputsTableName: 'sys_hub_action_input',
|
|
459
|
+
zippedColumn: 'values',
|
|
460
|
+
callee: ACTION_INSTANCE_API_NAME,
|
|
461
|
+
}),
|
|
462
|
+
},
|
|
463
|
+
sys_hub_sub_flow_instance_v2: {
|
|
464
|
+
toShape: buildInstanceToShape({
|
|
465
|
+
defColumn: 'subflow',
|
|
466
|
+
inputsTableName: 'sys_hub_flow_input',
|
|
467
|
+
zippedColumn: 'subflow_inputs',
|
|
468
|
+
callee: SUBFLOW_INSTANCE_API_NAME,
|
|
469
|
+
}),
|
|
470
|
+
},
|
|
471
|
+
},
|
|
472
|
+
shapes: [
|
|
473
|
+
{
|
|
474
|
+
// Look for FDInstanceShape and return instance records as needed for Flow plugin
|
|
475
|
+
shape: ActionSubflowInstanceShape,
|
|
476
|
+
fileTypes: ['fluent'],
|
|
477
|
+
async toRecord(callExpression, { factory, transform, diagnostics, logger }) {
|
|
478
|
+
const instanceType = callExpression.getInstanceType()
|
|
479
|
+
|
|
480
|
+
// Shortcut for unsupported instance types
|
|
481
|
+
if (instanceType !== ACTION_INSTANCE_API_NAME && instanceType !== SUBFLOW_INSTANCE_API_NAME) {
|
|
482
|
+
return { success: false }
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
const instanceParentDef = callExpression.getInstanceDefinition()
|
|
486
|
+
const instanceSysId = callExpression.getSysId()
|
|
487
|
+
const instanceInputs = callExpression.getInstanceProps()
|
|
488
|
+
const instanceAnnotation = callExpression.getAnnotation()?.getValue()
|
|
489
|
+
const instanceUUID = callExpression.getInstanceUUID()?.getValue()
|
|
490
|
+
|
|
491
|
+
if (!instanceInputs || !instanceSysId || !instanceParentDef) {
|
|
492
|
+
diagnostics.error(
|
|
493
|
+
callExpression,
|
|
494
|
+
`Failed to extract inputs, sysId, or definition from ${instanceType}`
|
|
495
|
+
)
|
|
496
|
+
return { success: false }
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
let instanceRecord: Record | undefined
|
|
500
|
+
|
|
501
|
+
if (instanceType === ACTION_INSTANCE_API_NAME) {
|
|
502
|
+
// Validate getCatalogVariables output references once, from the declaration
|
|
503
|
+
if (instanceParentDef?.isRecord()) {
|
|
504
|
+
const actionSysId = instanceParentDef.as(Record).getId().getValue()
|
|
505
|
+
const actionName = CORE_ACTIONS_SYS_ID_NAME_MAP[actionSysId]
|
|
506
|
+
if (actionName === 'getCatalogVariables') {
|
|
507
|
+
validateCatalogVariableOutputReferences(callExpression, instanceInputs, diagnostics)
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
instanceRecord = await buildActionInstance({
|
|
512
|
+
actionDef: instanceParentDef,
|
|
513
|
+
inputs: instanceInputs,
|
|
514
|
+
sysId: instanceSysId,
|
|
515
|
+
annotation: instanceAnnotation,
|
|
516
|
+
uuid: instanceUUID,
|
|
517
|
+
factory,
|
|
518
|
+
source: callExpression,
|
|
519
|
+
transform,
|
|
520
|
+
logger,
|
|
521
|
+
})
|
|
522
|
+
} else if (instanceType === SUBFLOW_INSTANCE_API_NAME) {
|
|
523
|
+
instanceRecord = await buildSubflowInstance({
|
|
524
|
+
subflowDef: instanceParentDef,
|
|
525
|
+
inputs: instanceInputs,
|
|
526
|
+
sysId: instanceSysId,
|
|
527
|
+
annotation: instanceAnnotation,
|
|
528
|
+
uuid: instanceUUID,
|
|
529
|
+
factory,
|
|
530
|
+
source: callExpression,
|
|
531
|
+
transform,
|
|
532
|
+
})
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
return instanceRecord ? { success: true, value: instanceRecord } : { success: false }
|
|
536
|
+
},
|
|
537
|
+
},
|
|
538
|
+
],
|
|
539
|
+
})
|
|
540
|
+
|
|
541
|
+
// -------------------------
|
|
542
|
+
// Shared helpers
|
|
543
|
+
// -------------------------
|
|
544
|
+
|
|
545
|
+
/**
|
|
546
|
+
* Builds an FDInlineScriptCallShape from XML inline script data.
|
|
547
|
+
*
|
|
548
|
+
* **Inline Script Detection:**
|
|
549
|
+
* Detects inputs with `scriptActive: true` and extracts the script content from
|
|
550
|
+
* the `script[fieldName].script` property. Creates an FDInlineScriptCallShape that represents
|
|
551
|
+
* `wfa.inlineScript('script content')` in Fluent code.
|
|
552
|
+
*
|
|
553
|
+
* @param fieldName - The name of the input field
|
|
554
|
+
* @param scriptActive - Whether this field contains an active script
|
|
555
|
+
* @param script - The script object containing script content keyed by field name
|
|
556
|
+
* @param source - The source Record for creating the shape
|
|
557
|
+
* @returns FDInlineScriptCallShape if this is an inline script, undefined otherwise
|
|
558
|
+
*/
|
|
559
|
+
function buildInlineScriptShapeFromXml(
|
|
560
|
+
fieldName: string,
|
|
561
|
+
scriptActive: boolean | undefined,
|
|
562
|
+
script: { [key: string]: { scriptActive: boolean; script: string } } | undefined,
|
|
563
|
+
source: Record
|
|
564
|
+
): FDInlineScriptCallShape | undefined {
|
|
565
|
+
if (scriptActive === true && script && script[fieldName]?.script) {
|
|
566
|
+
const scriptContent = script[fieldName].script
|
|
567
|
+
|
|
568
|
+
return new FDInlineScriptCallShape({
|
|
569
|
+
source,
|
|
570
|
+
scriptContent,
|
|
571
|
+
})
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
return undefined
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
/**
|
|
578
|
+
* Build an ObjectShape representing instance inputs from a base64-zipped JSON payload.
|
|
579
|
+
* This is used by both subflow and action instances.
|
|
580
|
+
* Supports bi-directional conversion for inline scripts (XML ↔ Fluent).
|
|
581
|
+
*/
|
|
582
|
+
function buildInputsShapeFromZipped({
|
|
583
|
+
zippedInputs,
|
|
584
|
+
definitionInputs,
|
|
585
|
+
actionDefinition,
|
|
586
|
+
record,
|
|
587
|
+
logger,
|
|
588
|
+
database,
|
|
589
|
+
}: {
|
|
590
|
+
zippedInputs: string
|
|
591
|
+
definitionInputs: Record[] | undefined
|
|
592
|
+
actionDefinition: Shape | undefined
|
|
593
|
+
record: Record
|
|
594
|
+
logger: Logger
|
|
595
|
+
database?: Database
|
|
596
|
+
}): ObjectShape | undefined {
|
|
597
|
+
if (!zippedInputs) {
|
|
598
|
+
return undefined
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
const props: { [key: string]: unknown } = {}
|
|
602
|
+
|
|
603
|
+
try {
|
|
604
|
+
const unzipped = gunzipSync(Buffer.from(zippedInputs, 'base64')).toString()
|
|
605
|
+
const values: Array<{
|
|
606
|
+
name: string
|
|
607
|
+
value: unknown
|
|
608
|
+
scriptActive?: boolean
|
|
609
|
+
script?: { [key: string]: { scriptActive: boolean; script: string } }
|
|
610
|
+
parameter: { type: string; attributes: { [key: string]: unknown } }
|
|
611
|
+
}> = JSON.parse(unzipped)
|
|
612
|
+
|
|
613
|
+
// Check if this is a catalog-related action (getCatalogVariables or createCatalogTask)
|
|
614
|
+
const catalogAction = isCatalogAction(actionDefinition)
|
|
615
|
+
let catalogItemRecord: Record | undefined
|
|
616
|
+
if (catalogAction) {
|
|
617
|
+
// Find the catalog item record
|
|
618
|
+
const templateCatalogItemValue = values.find((v) => v.name === 'template_catalog_item')
|
|
619
|
+
catalogItemRecord = findCatalogItemBySysId(templateCatalogItemValue?.value as string, database)
|
|
620
|
+
if (!catalogItemRecord) {
|
|
621
|
+
logger.warn(
|
|
622
|
+
`Catalog item not found for sys_id '${templateCatalogItemValue?.value}'. ` +
|
|
623
|
+
`template_catalog_item and catalog_variables will fall back to raw string values.`
|
|
624
|
+
)
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
for (const { name, value, scriptActive, script, parameter } of values) {
|
|
629
|
+
const attributes = definitionInputs
|
|
630
|
+
?.find((v) => v.get('element').asString()?.getValue() === name)
|
|
631
|
+
?.get('attributes')
|
|
632
|
+
?.ifString()
|
|
633
|
+
?.getValue()
|
|
634
|
+
const uiType = attributes ? getAttributeValue(attributes, 'uiType') : undefined
|
|
635
|
+
// Skip hidden fields during transformation
|
|
636
|
+
// Convert parameter.attributes object to string format (key=value,key=value)
|
|
637
|
+
const paramAttributesStr = parameter?.attributes
|
|
638
|
+
? Object.entries(parameter.attributes)
|
|
639
|
+
.map(([key, value]) => `${key}=${value}`)
|
|
640
|
+
.join(',')
|
|
641
|
+
: undefined
|
|
642
|
+
if (isHiddenField(attributes) || isHiddenField(paramAttributesStr)) {
|
|
643
|
+
continue
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
try {
|
|
647
|
+
if (UNSUPPORTED_DATA_TYPES.includes(parameter?.type)) {
|
|
648
|
+
logger.warn(`input ${name} has unsupported data type ${parameter?.type}`)
|
|
649
|
+
return undefined
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
// Check if this is an inline script and convert to wfa.inlineScript() format
|
|
653
|
+
const inlineScriptShape = buildInlineScriptShapeFromXml(name, scriptActive, script, record)
|
|
654
|
+
|
|
655
|
+
// Determine the appropriate shape for this input
|
|
656
|
+
let inputShape: Shape | undefined
|
|
657
|
+
|
|
658
|
+
if (inlineScriptShape) {
|
|
659
|
+
props[name] = inlineScriptShape
|
|
660
|
+
} else {
|
|
661
|
+
if (catalogAction) {
|
|
662
|
+
if (name === 'template_catalog_item' && catalogItemRecord) {
|
|
663
|
+
// Create template expression: `${catalogItemIdentifier}`
|
|
664
|
+
const catalogItemIdentifier = getIdentifierFromRecord(catalogItemRecord)
|
|
665
|
+
inputShape = catalogItemIdentifier
|
|
666
|
+
? createTemplateExpressionFromIdentifier(catalogItemIdentifier, record)
|
|
667
|
+
: undefined
|
|
668
|
+
} else if (name === 'catalog_variables' && catalogItemRecord) {
|
|
669
|
+
// Convert slushbucket to array of catalog variable references
|
|
670
|
+
inputShape = convertSlushBucketToCatalogVariableArray(
|
|
671
|
+
value as string,
|
|
672
|
+
catalogItemRecord,
|
|
673
|
+
record
|
|
674
|
+
)
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
// Use the specialized shape or fallback to normalized value
|
|
678
|
+
props[name] =
|
|
679
|
+
inputShape ?? normalizeInputValue(value as string, uiType ?? parameter.type, record, logger)
|
|
680
|
+
}
|
|
681
|
+
} catch (e) {
|
|
682
|
+
const recordInfo = `${record.getTable()}.${record.getId().getValue()}`
|
|
683
|
+
logger.warn(
|
|
684
|
+
`Failed to parse value for ${name} in record ${recordInfo}: ${e instanceof Error ? e.message : e}`
|
|
685
|
+
)
|
|
686
|
+
props[name] = value
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
return new ObjectShape({ source: record, properties: props })
|
|
691
|
+
} catch (error) {
|
|
692
|
+
logger.error(`Malformed/unsupported input payload in subflow_inputs: ${error}`)
|
|
693
|
+
return undefined
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
// -------------------------
|
|
698
|
+
// Helper builders
|
|
699
|
+
// -------------------------
|
|
700
|
+
|
|
701
|
+
async function buildActionInstance({
|
|
702
|
+
actionDef,
|
|
703
|
+
inputs,
|
|
704
|
+
sysId,
|
|
705
|
+
annotation,
|
|
706
|
+
uuid,
|
|
707
|
+
factory,
|
|
708
|
+
source,
|
|
709
|
+
transform,
|
|
710
|
+
logger,
|
|
711
|
+
}: {
|
|
712
|
+
actionDef: Record | StringShape | undefined
|
|
713
|
+
inputs: ObjectShape
|
|
714
|
+
sysId: NowIdShape
|
|
715
|
+
annotation: string | undefined
|
|
716
|
+
uuid: string | undefined
|
|
717
|
+
factory: Factory
|
|
718
|
+
source: Source
|
|
719
|
+
transform: Transform
|
|
720
|
+
logger: Logger
|
|
721
|
+
}): Promise<Record | undefined> {
|
|
722
|
+
const values = actionDef ? await prepareActionInstanceValueJson(inputs, actionDef, transform, logger) : undefined
|
|
723
|
+
const actionDefRecord = actionDef instanceof Record ? actionDef : undefined
|
|
724
|
+
const instanceProps = inputs.transform(({ $ }) => ({
|
|
725
|
+
active: $.val(true),
|
|
726
|
+
// if actionDef is not a Record (sysId fallback cases), actionDef?.getValue() should get get the string value (sysId) as is
|
|
727
|
+
action_type: $.val(actionDefRecord?.getId()?.getValue() || actionDef?.getValue() || ''),
|
|
728
|
+
action_type_parent: $.val(actionDefRecord?.getId()?.getValue() || actionDef?.getValue() || ''),
|
|
729
|
+
comment: $.val(annotation || actionDefRecord?.get('comment')?.getValue() || ''),
|
|
730
|
+
display_text: $.val(''),
|
|
731
|
+
generation_source: $.val(''),
|
|
732
|
+
sys_class_name: $.val('sys_hub_action_instance_v2'),
|
|
733
|
+
updation_source: $.val(''),
|
|
734
|
+
values: $.val(values),
|
|
735
|
+
parent_ui_id: $.val(''),
|
|
736
|
+
}))
|
|
737
|
+
|
|
738
|
+
if (!instanceProps) {
|
|
739
|
+
return undefined
|
|
740
|
+
}
|
|
741
|
+
const record = await factory.createRecord({
|
|
742
|
+
source,
|
|
743
|
+
explicitId: sysId,
|
|
744
|
+
table: 'sys_hub_action_instance_v2',
|
|
745
|
+
properties: instanceProps,
|
|
746
|
+
})
|
|
747
|
+
|
|
748
|
+
// UUID can come from either instance uuid property (for fd ui authored actions) or generated from sysid (for fluent authored actions).
|
|
749
|
+
const instanceUUID = uuid ? uuid : sysIdToUuid(record.getId().getValue())
|
|
750
|
+
return record.merge({ ui_id: instanceUUID })
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
async function buildSubflowInstance({
|
|
754
|
+
subflowDef,
|
|
755
|
+
inputs,
|
|
756
|
+
sysId,
|
|
757
|
+
annotation,
|
|
758
|
+
factory,
|
|
759
|
+
uuid,
|
|
760
|
+
source,
|
|
761
|
+
transform,
|
|
762
|
+
}: {
|
|
763
|
+
subflowDef: Record | StringShape | undefined
|
|
764
|
+
inputs: ObjectShape
|
|
765
|
+
sysId: NowIdShape
|
|
766
|
+
annotation: string | undefined
|
|
767
|
+
factory: Factory
|
|
768
|
+
uuid: string | undefined
|
|
769
|
+
source: Source
|
|
770
|
+
transform: Transform
|
|
771
|
+
}): Promise<Record | undefined> {
|
|
772
|
+
const values = subflowDef ? await prepareSubflowInstanceValueJson(inputs, subflowDef, transform) : undefined
|
|
773
|
+
|
|
774
|
+
const subflowDefRecord = subflowDef instanceof Record ? subflowDef : undefined
|
|
775
|
+
const instanceProps = inputs.transform(({ $ }) => ({
|
|
776
|
+
order: $.val(1 as number),
|
|
777
|
+
flow: $.val(''),
|
|
778
|
+
attributes: $.val(''),
|
|
779
|
+
comment: $.val(annotation || subflowDefRecord?.get('comment')?.getValue() || ''),
|
|
780
|
+
display_text: $.val(''),
|
|
781
|
+
generation_source: $.val(''),
|
|
782
|
+
subflow: $.val(subflowDefRecord?.getId()?.getValue() || subflowDef?.getValue() || ''),
|
|
783
|
+
subflow_inputs: $.val(values),
|
|
784
|
+
wait_for_completion: $.from('waitForCompletion').def(false),
|
|
785
|
+
sys_class_name: $.val('sys_hub_sub_flow_instance_v2'),
|
|
786
|
+
parent_ui_id: $.def(''),
|
|
787
|
+
}))
|
|
788
|
+
|
|
789
|
+
if (!instanceProps) {
|
|
790
|
+
return undefined
|
|
791
|
+
}
|
|
792
|
+
const record = await factory.createRecord({
|
|
793
|
+
source,
|
|
794
|
+
explicitId: sysId,
|
|
795
|
+
table: 'sys_hub_sub_flow_instance_v2',
|
|
796
|
+
properties: instanceProps,
|
|
797
|
+
})
|
|
798
|
+
|
|
799
|
+
// UUID can come from either instance uuid property (for fd ui authored subflows) or generated from sysid (for fluent authored subflows).
|
|
800
|
+
const instanceUUID = uuid ? uuid : sysIdToUuid(record.getId().getValue())
|
|
801
|
+
return record.merge({ ui_id: instanceUUID })
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
/**
|
|
805
|
+
* Checks for inline script patterns in the input properties and resolves them
|
|
806
|
+
* to their appropriate format (either script format or primitive value).
|
|
807
|
+
*
|
|
808
|
+
* Supports inline scripts via wfa.inlineScript('script') (detected as CallExpressionShape/FDInlineScriptCallShape).
|
|
809
|
+
*
|
|
810
|
+
* Architecture note:
|
|
811
|
+
* This function detects inline scripts based on context - only template literals and Now.include()
|
|
812
|
+
* calls used as Action/Subflow inputs are treated as inline scripts. This avoids incorrectly
|
|
813
|
+
* converting template literals used elsewhere in the codebase (logging, formatting, etc.).
|
|
814
|
+
*
|
|
815
|
+
* Similar to data pills processing, this function:
|
|
816
|
+
* - Uses .entries({ resolve: false }) to preserve shape types
|
|
817
|
+
* - Checks if each shape is a TemplateExpressionShape or Now.include() call
|
|
818
|
+
* - Returns special serialization format for inline scripts
|
|
819
|
+
* - Falls back to regular getValue() for non-script shapes
|
|
820
|
+
*
|
|
821
|
+
* @param instanceInputs - The ObjectShape containing input properties
|
|
822
|
+
* @param transform - Transform context for shape conversion
|
|
823
|
+
* @returns Array of [name, value] tuples where inline scripts are serialized appropriately
|
|
824
|
+
*/
|
|
825
|
+
async function checkAndResolveInlineScripts(
|
|
826
|
+
instanceInputs: ObjectShape,
|
|
827
|
+
_transform: Transform
|
|
828
|
+
): Promise<Array<[string, unknown]>> {
|
|
829
|
+
const entries = instanceInputs.entries({ resolve: false })
|
|
830
|
+
const results: [string, unknown][] = []
|
|
831
|
+
|
|
832
|
+
for (const [key, shape] of entries) {
|
|
833
|
+
// Handle wfa.inlineScript() calls - they should already be FDInlineScriptCallShape after plugin processing
|
|
834
|
+
if (shape instanceof FDInlineScriptCallShape) {
|
|
835
|
+
const scriptContent = shape.getValue()
|
|
836
|
+
if (typeof scriptContent === 'string') {
|
|
837
|
+
// Wrap the script content in a TemplateExpressionShape
|
|
838
|
+
const templateShape = new TemplateExpressionShape({
|
|
839
|
+
source: shape,
|
|
840
|
+
literalText: scriptContent,
|
|
841
|
+
})
|
|
842
|
+
// Create InlineScriptShape for Flow Designer serialization
|
|
843
|
+
const inlineScript = new InlineScriptShape({
|
|
844
|
+
source: templateShape,
|
|
845
|
+
scriptContent,
|
|
846
|
+
})
|
|
847
|
+
const scriptValue = inlineScript.toFlowDesignerJson(key)
|
|
848
|
+
results.push([key, scriptValue])
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
return results
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
/**
|
|
857
|
+
* Resolves complex object input values for subflow/action instance preparation.
|
|
858
|
+
* @param name - Input field name
|
|
859
|
+
* @param value - Raw input value
|
|
860
|
+
* @param parentDef - Record containing input and complex object definitions
|
|
861
|
+
* @param inputTableName - Table name to look up input definitions (e.g. 'sys_hub_flow_input' or 'sys_hub_action_input')
|
|
862
|
+
*/
|
|
863
|
+
// Deprecated: kept for backward-compat but delegates to shared resolver
|
|
864
|
+
function resolveComplexInput(
|
|
865
|
+
name: string,
|
|
866
|
+
value: unknown,
|
|
867
|
+
parentDef: Record,
|
|
868
|
+
inputTableName: string,
|
|
869
|
+
logger?: Logger
|
|
870
|
+
): { value: unknown; internalType: unknown } {
|
|
871
|
+
return _resolveComplexInput(name, value, parentDef, inputTableName, undefined, logger)
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
/**
|
|
875
|
+
* Checks if a given value is a serialized inline script object.
|
|
876
|
+
* This is used to identify inputs that have already been processed into the final
|
|
877
|
+
* Flow Designer JSON format for scripts.
|
|
878
|
+
*
|
|
879
|
+
* @param value - The value to check.
|
|
880
|
+
* @returns `true` if the value is a script object, `false` otherwise.
|
|
881
|
+
*/
|
|
882
|
+
function isInlineScriptValue(value: unknown): boolean {
|
|
883
|
+
return typeof value === 'object' && value !== null && (value as { scriptActive?: boolean }).scriptActive === true
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
/**
|
|
887
|
+
* Processes an input value from objShape and returns the appropriate result object.
|
|
888
|
+
* Handles inline scripts by returning them as-is, or creates a standard input object.
|
|
889
|
+
*
|
|
890
|
+
* @param inputName - The name of the input field
|
|
891
|
+
* @param objShape - The ObjectShape containing all input values
|
|
892
|
+
* @param options - Optional processing options
|
|
893
|
+
* @param options.type - The parameter type to use (defaults to 'string' if not provided)
|
|
894
|
+
* @param options.actionDefRecord - Action definition record for complex input resolution
|
|
895
|
+
* @param options.inputTableName - Table name for input definitions (e.g., 'sys_hub_action_input')
|
|
896
|
+
* @returns The processed input object
|
|
897
|
+
*/
|
|
898
|
+
function processInputValue(
|
|
899
|
+
inputName: string,
|
|
900
|
+
objShape: ObjectShape,
|
|
901
|
+
options?: {
|
|
902
|
+
type?: unknown
|
|
903
|
+
actionDefRecord?: Record
|
|
904
|
+
inputTableName?: string
|
|
905
|
+
logger?: Logger
|
|
906
|
+
},
|
|
907
|
+
displayValues?: Map<string, string>
|
|
908
|
+
): unknown {
|
|
909
|
+
const value = objShape.get(inputName)
|
|
910
|
+
const primitiveValue = value.getValue()
|
|
911
|
+
|
|
912
|
+
// If it's an inline script object, return it as-is
|
|
913
|
+
if (isInlineScriptValue(primitiveValue)) {
|
|
914
|
+
return primitiveValue
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
let finalValue: unknown = primitiveValue
|
|
918
|
+
let finalType: unknown = options?.type ?? 'string'
|
|
919
|
+
|
|
920
|
+
// If action definition is provided, resolve complex input
|
|
921
|
+
if (options?.actionDefRecord && options?.inputTableName) {
|
|
922
|
+
const resolvedValue = resolveComplexInput(
|
|
923
|
+
inputName,
|
|
924
|
+
primitiveValue,
|
|
925
|
+
options.actionDefRecord,
|
|
926
|
+
options.inputTableName,
|
|
927
|
+
options?.logger
|
|
928
|
+
)
|
|
929
|
+
finalValue = resolvedValue.value
|
|
930
|
+
finalType = resolvedValue.internalType
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
// Return standard input object
|
|
934
|
+
return {
|
|
935
|
+
name: inputName,
|
|
936
|
+
value: finalValue,
|
|
937
|
+
displayValue: displayValues && displayValues.has(inputName) ? displayValues.get(inputName) : finalValue,
|
|
938
|
+
scriptActive: false,
|
|
939
|
+
parameter: {
|
|
940
|
+
type: finalType,
|
|
941
|
+
},
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
/**
|
|
946
|
+
* Processes a definition input that was not provided by the user.
|
|
947
|
+
* Handles hidden fields and default values by creating appropriate input objects.
|
|
948
|
+
*
|
|
949
|
+
* @param inputDef - The input definition record from the action/subflow definition
|
|
950
|
+
* @param inputName - The name of the input field
|
|
951
|
+
* @returns The processed input object if the field is hidden or has a default value, undefined otherwise
|
|
952
|
+
*/
|
|
953
|
+
function processDefaultOrHiddenInput(inputDef: Record, inputName: string): unknown | undefined {
|
|
954
|
+
// Get attributes and check if hidden
|
|
955
|
+
const attributes = inputDef.get('attributes')?.ifString()?.getValue()
|
|
956
|
+
const visibleAttr = attributes ? getAttributeValue(attributes, 'visible') : undefined
|
|
957
|
+
const visibleInFdAttr = attributes ? getAttributeValue(attributes, 'visible_in_fd') : undefined
|
|
958
|
+
const isHidden = visibleAttr === 'false' || visibleInFdAttr === 'false'
|
|
959
|
+
|
|
960
|
+
// Get default value and internal type
|
|
961
|
+
const defaultValue = inputDef.get('default_value')?.getValue()
|
|
962
|
+
const hasDefaultValue = defaultValue !== undefined && defaultValue !== null && defaultValue !== ''
|
|
963
|
+
const internalType = inputDef.get('internal_type')?.asString()?.getValue() || 'string'
|
|
964
|
+
|
|
965
|
+
// For hidden fields or fields with default values, add them to result
|
|
966
|
+
if (isHidden || hasDefaultValue) {
|
|
967
|
+
const valueToUse = hasDefaultValue ? defaultValue : ''
|
|
968
|
+
const paramAttributes: { visible?: boolean; visible_in_fd?: boolean } = {}
|
|
969
|
+
if (visibleAttr === 'false') {
|
|
970
|
+
paramAttributes.visible = false
|
|
971
|
+
}
|
|
972
|
+
if (visibleInFdAttr === 'false') {
|
|
973
|
+
paramAttributes.visible_in_fd = false
|
|
974
|
+
}
|
|
975
|
+
return {
|
|
976
|
+
name: inputName,
|
|
977
|
+
value: valueToUse,
|
|
978
|
+
displayValue: valueToUse,
|
|
979
|
+
scriptActive: false,
|
|
980
|
+
parameter: {
|
|
981
|
+
type: internalType,
|
|
982
|
+
...(Object.keys(paramAttributes).length > 0 && { attributes: paramAttributes }),
|
|
983
|
+
},
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
return undefined
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
/**
|
|
990
|
+
* Resolve a catalog item record from a Shape (direct Record, TemplateExpressionShape, or IdentifierShape).
|
|
991
|
+
*/
|
|
992
|
+
function resolveCatalogItemRecord(shape: Shape): Record | undefined {
|
|
993
|
+
// Handle direct record reference (e.g., softwareInstallationCatalogItem)
|
|
994
|
+
if (shape?.isRecord && shape.isRecord()) {
|
|
995
|
+
return shape.as(Record)
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
// Handle template expression (e.g., `${softwareInstallationCatalogItem}`)
|
|
999
|
+
if (shape instanceof TemplateExpressionShape) {
|
|
1000
|
+
const spans = shape.getSpans()
|
|
1001
|
+
if (spans[0]) {
|
|
1002
|
+
const expr = spans[0].getExpression()
|
|
1003
|
+
const resolved = expr instanceof IdentifierShape ? expr.resolve() : undefined
|
|
1004
|
+
if (resolved?.isRecord()) {
|
|
1005
|
+
return resolved.as(Record)
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
// Handle identifier (e.g., variable reference)
|
|
1011
|
+
if (shape instanceof IdentifierShape) {
|
|
1012
|
+
const resolved = shape.resolve()
|
|
1013
|
+
if (resolved?.isRecord()) {
|
|
1014
|
+
return resolved.as(Record)
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
return undefined
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
/**
|
|
1022
|
+
* Convert comma-separated variable names to SlushBucket format with sys_ids.
|
|
1023
|
+
* Input: "html,email" + catalog item record
|
|
1024
|
+
* Output: "sys_id1:item_option_new,sys_id2:item_option_new"
|
|
1025
|
+
*/
|
|
1026
|
+
function convertVariableNamesToSlushBucket(variableNames: string, catalogItemRecord: Record, logger: Logger): string {
|
|
1027
|
+
const names = variableNames
|
|
1028
|
+
.split(',')
|
|
1029
|
+
.map((n) => n.trim())
|
|
1030
|
+
.filter(Boolean)
|
|
1031
|
+
if (names.length === 0) {
|
|
1032
|
+
return ''
|
|
1033
|
+
}
|
|
1034
|
+
// Create a map of variable name to sys_id for quick lookup
|
|
1035
|
+
const variableMap = new Map<string, string>()
|
|
1036
|
+
|
|
1037
|
+
// Single loop: flatten records and build the map
|
|
1038
|
+
for (const rec of catalogItemRecord.flat()) {
|
|
1039
|
+
// Check direct record
|
|
1040
|
+
if (rec.getTable() === CATALOG_VARIABLE_TABLE) {
|
|
1041
|
+
const varName = rec.get('name')?.asString()?.getValue()
|
|
1042
|
+
if (varName && !variableMap.has(varName)) {
|
|
1043
|
+
const sysId = rec.getId().getValue()
|
|
1044
|
+
if (sysId && typeof sysId === 'string') {
|
|
1045
|
+
variableMap.set(varName, sysId)
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
// Check variable set records and their nested variables
|
|
1050
|
+
if (rec.getTable() === CATALOG_VARIABLE_SET_TABLE) {
|
|
1051
|
+
const variableSetRef = rec.get('variable_set')
|
|
1052
|
+
if (!variableSetRef?.isRecord()) {
|
|
1053
|
+
continue
|
|
1054
|
+
}
|
|
1055
|
+
for (const nestedRec of variableSetRef.flat().filter((r) => r.getTable() === CATALOG_VARIABLE_TABLE)) {
|
|
1056
|
+
const varName = nestedRec.get('name')?.asString()?.getValue()
|
|
1057
|
+
if (varName && !variableMap.has(varName)) {
|
|
1058
|
+
const sysId = nestedRec.getId().getValue()
|
|
1059
|
+
if (sysId) {
|
|
1060
|
+
variableMap.set(varName, sysId)
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
// Generate entries in the same order as input names
|
|
1068
|
+
const entries: string[] = []
|
|
1069
|
+
for (const name of names) {
|
|
1070
|
+
const variableSysId = variableMap.get(name)
|
|
1071
|
+
if (variableSysId) {
|
|
1072
|
+
entries.push(`${variableSysId}:${CATALOG_VARIABLE_TABLE}`)
|
|
1073
|
+
} else {
|
|
1074
|
+
logger.warn(`Catalog variable '${name}' not found in catalog item. It will be skipped.`)
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
return entries.join(',')
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
/**
|
|
1082
|
+
* Process getCatalogVariables action inputs to extract sys_ids and display values.
|
|
1083
|
+
* Handles:
|
|
1084
|
+
* - template_catalog_item: extracts catalog item sys_id and name
|
|
1085
|
+
* - catalog_variables: converts variable names to slushbucket format
|
|
1086
|
+
*/
|
|
1087
|
+
function processGetCatalogVariablesInputs(
|
|
1088
|
+
instanceInputs: ObjectShape,
|
|
1089
|
+
logger: Logger
|
|
1090
|
+
): {
|
|
1091
|
+
overrideValues: Map<string, string>
|
|
1092
|
+
displayValues: Map<string, string>
|
|
1093
|
+
} {
|
|
1094
|
+
const overrideValues = new Map<string, string>()
|
|
1095
|
+
const displayValues = new Map<string, string>()
|
|
1096
|
+
|
|
1097
|
+
// Get catalog item record from template_catalog_item input
|
|
1098
|
+
const templateShape = instanceInputs.get('template_catalog_item')
|
|
1099
|
+
const catalogItemRecord = resolveCatalogItemRecord(templateShape)
|
|
1100
|
+
|
|
1101
|
+
if (!catalogItemRecord) {
|
|
1102
|
+
return { overrideValues, displayValues }
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
// Extract sys_id and name for template_catalog_item
|
|
1106
|
+
const sysId = catalogItemRecord.getId().getValue()
|
|
1107
|
+
const name = catalogItemRecord.get('name')?.asString()?.getValue()
|
|
1108
|
+
|
|
1109
|
+
if (sysId && typeof sysId === 'string') {
|
|
1110
|
+
overrideValues.set('template_catalog_item', sysId)
|
|
1111
|
+
if (name) {
|
|
1112
|
+
displayValues.set('template_catalog_item', name)
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
// Convert catalog_variables to slushbucket format
|
|
1117
|
+
const catalogVariablesShape = instanceInputs.get('catalog_variables')
|
|
1118
|
+
|
|
1119
|
+
// Handle string format: "html,email,ipAddress"
|
|
1120
|
+
if (catalogVariablesShape?.isString()) {
|
|
1121
|
+
const variableNames = catalogVariablesShape.asString().getValue()
|
|
1122
|
+
if (variableNames) {
|
|
1123
|
+
const slushBucketString = convertVariableNamesToSlushBucket(variableNames, catalogItemRecord, logger)
|
|
1124
|
+
if (slushBucketString) {
|
|
1125
|
+
overrideValues.set('catalog_variables', slushBucketString)
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
// Handle array format: [catalogItem.variables.html, catalogItem.variables.email, ...]
|
|
1130
|
+
else if (catalogVariablesShape?.isArray()) {
|
|
1131
|
+
const arrayShape = catalogVariablesShape.asArray()
|
|
1132
|
+
const elements = arrayShape.getElements(false) // Get unresolved elements
|
|
1133
|
+
const variableNames: string[] = []
|
|
1134
|
+
|
|
1135
|
+
// Extract variable names from PropertyAccessShapes
|
|
1136
|
+
for (const element of elements) {
|
|
1137
|
+
if (element instanceof PropertyAccessShape) {
|
|
1138
|
+
const propElements = element.getElements()
|
|
1139
|
+
const lastElement = propElements[propElements.length - 1]
|
|
1140
|
+
|
|
1141
|
+
if (lastElement instanceof IdentifierShape) {
|
|
1142
|
+
const varName = lastElement.getName()
|
|
1143
|
+
variableNames.push(varName)
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
// Look up sys_ids from catalog item's item_option_new descendants
|
|
1149
|
+
if (variableNames.length > 0) {
|
|
1150
|
+
const variableNamesString = variableNames.join(',')
|
|
1151
|
+
const slushBucketString = convertVariableNamesToSlushBucket(variableNamesString, catalogItemRecord, logger)
|
|
1152
|
+
if (slushBucketString) {
|
|
1153
|
+
overrideValues.set('catalog_variables', slushBucketString)
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
return { overrideValues, displayValues }
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
async function prepareActionInstanceValueJson(
|
|
1162
|
+
instanceInputs: ObjectShape | undefined,
|
|
1163
|
+
actionDef: Record | StringShape,
|
|
1164
|
+
transform: Transform,
|
|
1165
|
+
logger: Logger
|
|
1166
|
+
) {
|
|
1167
|
+
const actionDefRecord = actionDef.isRecord() ? actionDef.as(Record) : undefined
|
|
1168
|
+
if (!instanceInputs) {
|
|
1169
|
+
return []
|
|
1170
|
+
}
|
|
1171
|
+
const isActionDefString = actionDef instanceof StringShape
|
|
1172
|
+
|
|
1173
|
+
// Special handling for getCatalogVariables action
|
|
1174
|
+
let overrideValues = new Map<string, string>()
|
|
1175
|
+
let displayValues = new Map<string, string>()
|
|
1176
|
+
|
|
1177
|
+
if (actionDefRecord) {
|
|
1178
|
+
const actionSysId = actionDefRecord.getId().getValue()
|
|
1179
|
+
const actionName = typeof actionSysId === 'string' ? CORE_ACTIONS_SYS_ID_NAME_MAP[actionSysId] : undefined
|
|
1180
|
+
|
|
1181
|
+
// Check if this is the getCatalogVariables action or createCatalogTask action
|
|
1182
|
+
if (actionName === 'getCatalogVariables' || actionName === 'createCatalogTask') {
|
|
1183
|
+
try {
|
|
1184
|
+
const result = processGetCatalogVariablesInputs(instanceInputs, logger)
|
|
1185
|
+
overrideValues = result.overrideValues
|
|
1186
|
+
displayValues = result.displayValues
|
|
1187
|
+
} catch (error) {
|
|
1188
|
+
logger.error('[getCatalogVariables] Error:', error)
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
// Check for datapills and resolve them (skip keys already in overrideValues)
|
|
1194
|
+
const dataPillResults = await checkAndResolveDataPills(instanceInputs, transform, overrideValues)
|
|
1195
|
+
|
|
1196
|
+
// Check for inline script tags and resolve them (only returns scripts)
|
|
1197
|
+
const inlineScriptResults = await checkAndResolveInlineScripts(instanceInputs, transform)
|
|
1198
|
+
const inlineScriptMap = new Map(inlineScriptResults)
|
|
1199
|
+
|
|
1200
|
+
// Merge: use inline scripts where they exist, otherwise use datapill results
|
|
1201
|
+
// Note: Inline script can be applied to only top level properties; No need to handle nested objects
|
|
1202
|
+
// Merge results: prioritize overrideValues > inline scripts > datapill results
|
|
1203
|
+
const mergedResults = dataPillResults.map(([key, value]) => {
|
|
1204
|
+
// Use override value if available (catalog item sys_id or slushbucket string)
|
|
1205
|
+
if (overrideValues.has(key)) {
|
|
1206
|
+
return [key, overrideValues.get(key)]
|
|
1207
|
+
}
|
|
1208
|
+
// Otherwise use inline script if available
|
|
1209
|
+
return inlineScriptMap.has(key) ? [key, inlineScriptMap.get(key)] : [key, value]
|
|
1210
|
+
})
|
|
1211
|
+
|
|
1212
|
+
const objShape = new ObjectShape({
|
|
1213
|
+
source: instanceInputs.getSource(),
|
|
1214
|
+
properties: Object.fromEntries(mergedResults),
|
|
1215
|
+
})
|
|
1216
|
+
|
|
1217
|
+
const result: unknown[] = []
|
|
1218
|
+
|
|
1219
|
+
// When isActionDefString is true, there's no action definition in fluent
|
|
1220
|
+
// We expect arbitrary inputs and should process all provided inputs directly
|
|
1221
|
+
if (actionDefRecord) {
|
|
1222
|
+
// When action definition record is present, process only definition inputs
|
|
1223
|
+
const definitionInputs = actionDefRecord.flat().filter((v) => v.getTable() === 'sys_hub_action_input')
|
|
1224
|
+
const providedInputNames = new Set(objShape.keys())
|
|
1225
|
+
|
|
1226
|
+
for (const inputDef of definitionInputs) {
|
|
1227
|
+
const inputName = inputDef.get('element')?.asString()?.getValue()
|
|
1228
|
+
if (!inputName) {
|
|
1229
|
+
continue
|
|
1230
|
+
}
|
|
1231
|
+
// If input is provided in objShape(ie provided by user), process it
|
|
1232
|
+
if (providedInputNames.has(inputName)) {
|
|
1233
|
+
const processedValue = processInputValue(
|
|
1234
|
+
inputName,
|
|
1235
|
+
objShape,
|
|
1236
|
+
{
|
|
1237
|
+
actionDefRecord,
|
|
1238
|
+
inputTableName: 'sys_hub_action_input',
|
|
1239
|
+
logger,
|
|
1240
|
+
},
|
|
1241
|
+
displayValues
|
|
1242
|
+
)
|
|
1243
|
+
result.push(processedValue)
|
|
1244
|
+
} else {
|
|
1245
|
+
// Process default or hidden input
|
|
1246
|
+
const processedValue = processDefaultOrHiddenInput(inputDef, inputName)
|
|
1247
|
+
if (processedValue) {
|
|
1248
|
+
result.push(processedValue)
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
} else if (isActionDefString) {
|
|
1253
|
+
for (const inputName of objShape.keys()) {
|
|
1254
|
+
const processedValue = processInputValue(inputName, objShape, { type: 'string' }, displayValues)
|
|
1255
|
+
result.push(processedValue)
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
return result
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1262
|
+
async function prepareSubflowInstanceValueJson(
|
|
1263
|
+
instanceInputs: ObjectShape,
|
|
1264
|
+
subflowDef: Record | StringShape,
|
|
1265
|
+
transform: Transform
|
|
1266
|
+
) {
|
|
1267
|
+
// Check for datapills and resolve them
|
|
1268
|
+
const dataPillResults = await checkAndResolveDataPills(instanceInputs, transform)
|
|
1269
|
+
|
|
1270
|
+
// Check for inline script tags and resolve them (only returns scripts)
|
|
1271
|
+
const inlineScriptResults = await checkAndResolveInlineScripts(instanceInputs, transform)
|
|
1272
|
+
const inlineScriptMap = new Map(inlineScriptResults)
|
|
1273
|
+
|
|
1274
|
+
// Merge: use inline scripts where they exist, otherwise use datapill results
|
|
1275
|
+
const mergedResults = dataPillResults.map(([key, value]) => {
|
|
1276
|
+
return inlineScriptMap.has(key) ? [key, inlineScriptMap.get(key)] : [key, value]
|
|
1277
|
+
})
|
|
1278
|
+
|
|
1279
|
+
const objShape = new ObjectShape({
|
|
1280
|
+
source: instanceInputs.getSource(),
|
|
1281
|
+
properties: Object.fromEntries(mergedResults),
|
|
1282
|
+
})
|
|
1283
|
+
|
|
1284
|
+
return objShape
|
|
1285
|
+
.keys()
|
|
1286
|
+
.filter((key) => key !== 'waitForCompletion')
|
|
1287
|
+
.map((key) => {
|
|
1288
|
+
const value = objShape.get(key)
|
|
1289
|
+
const primitiveValue = value.getValue()
|
|
1290
|
+
|
|
1291
|
+
// If checkAndResolveInlineScripts already returned a script object, return it as-is
|
|
1292
|
+
if (isInlineScriptValue(primitiveValue)) {
|
|
1293
|
+
return primitiveValue
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1296
|
+
let resolvedValue: { value: unknown; internalType: unknown; children?: unknown[] } = {
|
|
1297
|
+
value: primitiveValue,
|
|
1298
|
+
internalType: undefined,
|
|
1299
|
+
}
|
|
1300
|
+
if (subflowDef.isRecord()) {
|
|
1301
|
+
resolvedValue = resolveComplexInput(key, primitiveValue, subflowDef.as(Record), 'sys_hub_flow_input')
|
|
1302
|
+
}
|
|
1303
|
+
|
|
1304
|
+
const result: globalThis.Record<string, unknown> = {
|
|
1305
|
+
name: key,
|
|
1306
|
+
value: resolvedValue.value,
|
|
1307
|
+
displayValue: resolvedValue.value,
|
|
1308
|
+
parameter: {
|
|
1309
|
+
type: resolvedValue.internalType,
|
|
1310
|
+
}, // populate later if needed
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
// Add children array if present (for FlowObject with datapills)
|
|
1314
|
+
if (resolvedValue.children && resolvedValue.children.length > 0) {
|
|
1315
|
+
result['children'] = resolvedValue.children
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1318
|
+
return result
|
|
1319
|
+
})
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
/**
|
|
1323
|
+
* Type guard to check if a shape is a data pill shape that needs resolution.
|
|
1324
|
+
* Data pill shapes include PropertyAccessShape, TemplateExpressionShape, and IdentifierShape.
|
|
1325
|
+
* @param shape - The shape to check
|
|
1326
|
+
* @returns true if the shape is a data pill shape, false otherwise
|
|
1327
|
+
*/
|
|
1328
|
+
function isDataPillShape(shape: Shape): shape is PropertyAccessShape | TemplateExpressionShape | IdentifierShape {
|
|
1329
|
+
return (
|
|
1330
|
+
shape instanceof PropertyAccessShape ||
|
|
1331
|
+
shape instanceof TemplateExpressionShape ||
|
|
1332
|
+
shape instanceof IdentifierShape
|
|
1333
|
+
)
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1336
|
+
/**
|
|
1337
|
+
* Recursively resolves data pills in nested object structures.
|
|
1338
|
+
* Handles objects with nested data pills and constructs the resolved object back.
|
|
1339
|
+
* Special shapes like TemplateValueShape and ApprovalRulesShape are also processed recursively
|
|
1340
|
+
* since they can contain data pills in their nested structures.
|
|
1341
|
+
* @param shape - The ObjectShape to process
|
|
1342
|
+
* @param transform - The transform instance
|
|
1343
|
+
* @returns Resolved object with all nested data pills resolved
|
|
1344
|
+
*/
|
|
1345
|
+
async function resolveObjectShapeRecursively(shape: ObjectShape, transform: Transform): Promise<unknown> {
|
|
1346
|
+
const entries = shape.entries({ resolve: false })
|
|
1347
|
+
const resolvedObject: { [key: string]: unknown } = {}
|
|
1348
|
+
|
|
1349
|
+
for (const [key, valueShape] of entries) {
|
|
1350
|
+
if (isDataPillShape(valueShape)) {
|
|
1351
|
+
// Resolve data pill shapes
|
|
1352
|
+
resolvedObject[key] = await resolveDataPillShape(valueShape, transform)
|
|
1353
|
+
} else if (valueShape.isObject()) {
|
|
1354
|
+
// Recursively resolve all ObjectShapes including special types
|
|
1355
|
+
// TemplateValueShape and ApprovalRulesShape can contain data pills in their nested structures
|
|
1356
|
+
// DurationShape only contains primitive numbers, but handling it recursively is harmless
|
|
1357
|
+
resolvedObject[key] = await resolveObjectShapeRecursively(valueShape.asObject(), transform)
|
|
1358
|
+
} else if (valueShape.isArray()) {
|
|
1359
|
+
// Handle array: recursively resolve each element
|
|
1360
|
+
const arrayShape = valueShape.asArray()
|
|
1361
|
+
const elements = arrayShape.getElements(false)
|
|
1362
|
+
const resolvedArray: unknown[] = []
|
|
1363
|
+
|
|
1364
|
+
for (const element of elements) {
|
|
1365
|
+
if (isDataPillShape(element)) {
|
|
1366
|
+
resolvedArray.push(await resolveDataPillShape(element, transform))
|
|
1367
|
+
} else if (element.isObject()) {
|
|
1368
|
+
resolvedArray.push(await resolveObjectShapeRecursively(element.asObject(), transform))
|
|
1369
|
+
} else if (element.isArray()) {
|
|
1370
|
+
// Recursively handle nested arrays by creating a temporary ObjectShape wrapper
|
|
1371
|
+
const tempShape = new ObjectShape({
|
|
1372
|
+
source: element.getSource(),
|
|
1373
|
+
properties: { temp: element },
|
|
1374
|
+
})
|
|
1375
|
+
const resolved = await resolveObjectShapeRecursively(tempShape, transform)
|
|
1376
|
+
resolvedArray.push((resolved as { temp: unknown }).temp)
|
|
1377
|
+
} else {
|
|
1378
|
+
resolvedArray.push(element.getValue())
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
|
|
1382
|
+
resolvedObject[key] = resolvedArray
|
|
1383
|
+
} else {
|
|
1384
|
+
// For all other shapes (primitives), get the value directly
|
|
1385
|
+
resolvedObject[key] = valueShape.getValue()
|
|
1386
|
+
}
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1389
|
+
return resolvedObject
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
/**
|
|
1393
|
+
* Wraps special shape types (ApprovalRulesShape, TemplateValueShape, DurationShape) with their string representations.
|
|
1394
|
+
* @param shape - The original shape
|
|
1395
|
+
* @param resolvedValue - The resolved value
|
|
1396
|
+
* @param source - The source for creating new shapes
|
|
1397
|
+
* @returns The appropriately wrapped value or the original resolved value
|
|
1398
|
+
*/
|
|
1399
|
+
function wrapSpecialShape(shape: Shape, resolvedValue: unknown, source: Source): unknown {
|
|
1400
|
+
if (shape.is(ApprovalRulesShape)) {
|
|
1401
|
+
return new ApprovalRulesShape({
|
|
1402
|
+
source,
|
|
1403
|
+
value: resolvedValue as ApprovalRulesType,
|
|
1404
|
+
}).toString()
|
|
1405
|
+
} else if (shape.is(TemplateValueShape)) {
|
|
1406
|
+
return new TemplateValueShape({
|
|
1407
|
+
source,
|
|
1408
|
+
value: resolvedValue as globalThis.Record<string, unknown>,
|
|
1409
|
+
}).toString()
|
|
1410
|
+
} else if (shape.is(DurationShape)) {
|
|
1411
|
+
return new DurationShape({
|
|
1412
|
+
source,
|
|
1413
|
+
value: resolvedValue as Duration,
|
|
1414
|
+
}).toString()
|
|
1415
|
+
} else if (shape.is(ApprovalDueDateShape)) {
|
|
1416
|
+
return new ApprovalDueDateShape({
|
|
1417
|
+
source,
|
|
1418
|
+
value: resolvedValue as ApprovalDueDateType,
|
|
1419
|
+
}).toString()
|
|
1420
|
+
}
|
|
1421
|
+
return resolvedValue
|
|
1422
|
+
}
|
|
1423
|
+
|
|
1424
|
+
/**
|
|
1425
|
+
* Checks for datapills and resolves them in instance inputs.
|
|
1426
|
+
* Similar to resolveObjectShapeRecursively but returns key-value pairs and handles special shapes.
|
|
1427
|
+
* @param instanceInputs - The instance inputs object shape
|
|
1428
|
+
* @param transform - The transform instance
|
|
1429
|
+
* @returns Array of [key, value] pairs with resolved datapills
|
|
1430
|
+
*/
|
|
1431
|
+
async function checkAndResolveDataPills(
|
|
1432
|
+
instanceInputs: ObjectShape,
|
|
1433
|
+
transform: Transform,
|
|
1434
|
+
skipKeys?: Map<string, string>
|
|
1435
|
+
) {
|
|
1436
|
+
const entries = instanceInputs.entries({ resolve: false })
|
|
1437
|
+
const results: [string, unknown][] = []
|
|
1438
|
+
|
|
1439
|
+
for (const [key, shape] of entries) {
|
|
1440
|
+
// Skip datapill resolution for keys that have already been processed (e.g., catalog_variables in array format)
|
|
1441
|
+
// But still add the override value so the key exists in results
|
|
1442
|
+
if (skipKeys?.has(key)) {
|
|
1443
|
+
results.push([key, skipKeys.get(key)])
|
|
1444
|
+
continue
|
|
1445
|
+
}
|
|
1446
|
+
if (shape && isDataPillShape(shape)) {
|
|
1447
|
+
const resolvedValue = await resolveDataPillShape(shape, transform)
|
|
1448
|
+
results.push([key, resolvedValue])
|
|
1449
|
+
} else if (shape.is(DurationShape)) {
|
|
1450
|
+
// Handle DurationShape specially - convert to string representation
|
|
1451
|
+
// DurationShape.getValue() returns a symbol, so we need to get the duration value differently
|
|
1452
|
+
const durationShape = shape.as(DurationShape)
|
|
1453
|
+
const durationValue = durationShape.getDuration()
|
|
1454
|
+
const wrappedValue = wrapSpecialShape(shape, durationValue, instanceInputs.getSource())
|
|
1455
|
+
results.push([key, wrappedValue])
|
|
1456
|
+
} else if (shape.isObject() || shape.is(TemplateValueShape)) {
|
|
1457
|
+
const objShape = shape.is(TemplateValueShape) ? shape.getTemplateValue() : shape.asObject()
|
|
1458
|
+
// Recursively resolve object shapes
|
|
1459
|
+
const resolvedValue = await resolveObjectShapeRecursively(objShape, transform)
|
|
1460
|
+
// Preserve special shapes like TemplateValue by passing the original shape
|
|
1461
|
+
const wrappedValue = wrapSpecialShape(shape, resolvedValue, instanceInputs.getSource())
|
|
1462
|
+
results.push([key, wrappedValue])
|
|
1463
|
+
} else if (shape.isArray()) {
|
|
1464
|
+
// Resolve arrays using the shared recursive logic
|
|
1465
|
+
const resolvedArray = await resolveArrayElements(shape.asArray(), transform)
|
|
1466
|
+
results.push([key, resolvedArray])
|
|
1467
|
+
} else {
|
|
1468
|
+
results.push([key, shape.getValue()])
|
|
1469
|
+
}
|
|
1470
|
+
}
|
|
1471
|
+
return results
|
|
1472
|
+
}
|
|
1473
|
+
|
|
1474
|
+
/**
|
|
1475
|
+
* Resolves all elements in an array shape, handling datapills, objects, and nested arrays.
|
|
1476
|
+
* Shared logic extracted from both resolveObjectShapeRecursively and checkAndResolveDataPills.
|
|
1477
|
+
* @param arrayShape - The array shape to resolve
|
|
1478
|
+
* @param transform - The transform instance
|
|
1479
|
+
* @returns Resolved array with all datapills resolved
|
|
1480
|
+
*/
|
|
1481
|
+
async function resolveArrayElements(arrayShape: Shape, transform: Transform): Promise<unknown[]> {
|
|
1482
|
+
const elements = arrayShape.asArray().getElements(false)
|
|
1483
|
+
const resolvedArray: unknown[] = []
|
|
1484
|
+
|
|
1485
|
+
for (const element of elements) {
|
|
1486
|
+
if (isDataPillShape(element)) {
|
|
1487
|
+
resolvedArray.push(await resolveDataPillShape(element, transform))
|
|
1488
|
+
} else if (element.isObject()) {
|
|
1489
|
+
resolvedArray.push(await resolveObjectShapeRecursively(element.asObject(), transform))
|
|
1490
|
+
} else if (element.isArray()) {
|
|
1491
|
+
// Recursively handle nested arrays
|
|
1492
|
+
resolvedArray.push(await resolveArrayElements(element, transform))
|
|
1493
|
+
} else {
|
|
1494
|
+
resolvedArray.push(element.getValue())
|
|
1495
|
+
}
|
|
1496
|
+
}
|
|
1497
|
+
|
|
1498
|
+
return resolvedArray
|
|
1499
|
+
}
|