@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.
Files changed (349) hide show
  1. package/dist/acl-plugin.js +11 -0
  2. package/dist/acl-plugin.js.map +1 -1
  3. package/dist/applicability-plugin.d.ts +2 -0
  4. package/dist/applicability-plugin.js +72 -0
  5. package/dist/applicability-plugin.js.map +1 -0
  6. package/dist/atf/test-plugin.js +5 -2
  7. package/dist/atf/test-plugin.js.map +1 -1
  8. package/dist/basic-syntax-plugin.js +7 -1
  9. package/dist/basic-syntax-plugin.js.map +1 -1
  10. package/dist/business-rule-plugin.js +1 -0
  11. package/dist/business-rule-plugin.js.map +1 -1
  12. package/dist/call-expression-plugin.js +1 -107
  13. package/dist/call-expression-plugin.js.map +1 -1
  14. package/dist/column/column-to-record.d.ts +10 -3
  15. package/dist/column/column-to-record.js +44 -7
  16. package/dist/column/column-to-record.js.map +1 -1
  17. package/dist/column-plugin.d.ts +3 -1
  18. package/dist/column-plugin.js +12 -12
  19. package/dist/column-plugin.js.map +1 -1
  20. package/dist/dashboard/dashboard-component-property-defaults.d.ts +152 -0
  21. package/dist/dashboard/dashboard-component-property-defaults.js +264 -0
  22. package/dist/dashboard/dashboard-component-property-defaults.js.map +1 -0
  23. package/dist/dashboard/dashboard-component-resolver.d.ts +13 -0
  24. package/dist/dashboard/dashboard-component-resolver.js +69 -0
  25. package/dist/dashboard/dashboard-component-resolver.js.map +1 -0
  26. package/dist/dashboard/dashboard-plugin.d.ts +12 -0
  27. package/dist/dashboard/dashboard-plugin.js +397 -0
  28. package/dist/dashboard/dashboard-plugin.js.map +1 -0
  29. package/dist/data-plugin.d.ts +3 -0
  30. package/dist/data-plugin.js +61 -113
  31. package/dist/data-plugin.js.map +1 -1
  32. package/dist/email-notification-plugin.d.ts +2 -0
  33. package/dist/email-notification-plugin.js +541 -0
  34. package/dist/email-notification-plugin.js.map +1 -0
  35. package/dist/flow/constants/flow-plugin-constants.d.ts +58 -0
  36. package/dist/flow/constants/flow-plugin-constants.js +70 -0
  37. package/dist/flow/constants/flow-plugin-constants.js.map +1 -0
  38. package/dist/flow/flow-logic/flow-logic-constants.d.ts +38 -0
  39. package/dist/flow/flow-logic/flow-logic-constants.js +118 -0
  40. package/dist/flow/flow-logic/flow-logic-constants.js.map +1 -0
  41. package/dist/flow/flow-logic/flow-logic-diagnostics.d.ts +19 -0
  42. package/dist/flow/flow-logic/flow-logic-diagnostics.js +503 -0
  43. package/dist/flow/flow-logic/flow-logic-diagnostics.js.map +1 -0
  44. package/dist/flow/flow-logic/flow-logic-plugin-helpers.d.ts +62 -0
  45. package/dist/flow/flow-logic/flow-logic-plugin-helpers.js +2092 -0
  46. package/dist/flow/flow-logic/flow-logic-plugin-helpers.js.map +1 -0
  47. package/dist/flow/flow-logic/flow-logic-plugin.d.ts +52 -0
  48. package/dist/flow/flow-logic/flow-logic-plugin.js +283 -0
  49. package/dist/flow/flow-logic/flow-logic-plugin.js.map +1 -0
  50. package/dist/flow/flow-logic/flow-logic-shapes.d.ts +104 -0
  51. package/dist/flow/flow-logic/flow-logic-shapes.js +201 -0
  52. package/dist/flow/flow-logic/flow-logic-shapes.js.map +1 -0
  53. package/dist/flow/plugins/approval-rules-plugin.d.ts +2 -0
  54. package/dist/flow/plugins/approval-rules-plugin.js +49 -0
  55. package/dist/flow/plugins/approval-rules-plugin.js.map +1 -0
  56. package/dist/flow/plugins/flow-action-definition-plugin.d.ts +2 -0
  57. package/dist/flow/plugins/flow-action-definition-plugin.js +286 -0
  58. package/dist/flow/plugins/flow-action-definition-plugin.js.map +1 -0
  59. package/dist/flow/plugins/flow-data-pill-plugin.d.ts +9 -0
  60. package/dist/flow/plugins/flow-data-pill-plugin.js +212 -0
  61. package/dist/flow/plugins/flow-data-pill-plugin.js.map +1 -0
  62. package/dist/flow/plugins/flow-definition-plugin.d.ts +2 -0
  63. package/dist/flow/plugins/flow-definition-plugin.js +1668 -0
  64. package/dist/flow/plugins/flow-definition-plugin.js.map +1 -0
  65. package/dist/flow/plugins/flow-diagnostics-plugin.d.ts +26 -0
  66. package/dist/flow/plugins/flow-diagnostics-plugin.js +217 -0
  67. package/dist/flow/plugins/flow-diagnostics-plugin.js.map +1 -0
  68. package/dist/flow/plugins/flow-instance-plugin.d.ts +12 -0
  69. package/dist/flow/plugins/flow-instance-plugin.js +1205 -0
  70. package/dist/flow/plugins/flow-instance-plugin.js.map +1 -0
  71. package/dist/flow/plugins/flow-trigger-instance-plugin.d.ts +2 -0
  72. package/dist/flow/plugins/flow-trigger-instance-plugin.js +338 -0
  73. package/dist/flow/plugins/flow-trigger-instance-plugin.js.map +1 -0
  74. package/dist/flow/plugins/inline-script-plugin.d.ts +39 -0
  75. package/dist/flow/plugins/inline-script-plugin.js +80 -0
  76. package/dist/flow/plugins/inline-script-plugin.js.map +1 -0
  77. package/dist/flow/plugins/step-definition-plugin.d.ts +5 -0
  78. package/dist/flow/plugins/step-definition-plugin.js +71 -0
  79. package/dist/flow/plugins/step-definition-plugin.js.map +1 -0
  80. package/dist/flow/plugins/step-instance-plugin.d.ts +31 -0
  81. package/dist/flow/plugins/step-instance-plugin.js +339 -0
  82. package/dist/flow/plugins/step-instance-plugin.js.map +1 -0
  83. package/dist/flow/plugins/trigger-plugin.d.ts +2 -0
  84. package/dist/flow/plugins/trigger-plugin.js +96 -0
  85. package/dist/flow/plugins/trigger-plugin.js.map +1 -0
  86. package/dist/flow/plugins/wfa-datapill-plugin.d.ts +15 -0
  87. package/dist/flow/plugins/wfa-datapill-plugin.js +178 -0
  88. package/dist/flow/plugins/wfa-datapill-plugin.js.map +1 -0
  89. package/dist/flow/utils/approval-rules-processor.d.ts +13 -0
  90. package/dist/flow/utils/approval-rules-processor.js +267 -0
  91. package/dist/flow/utils/approval-rules-processor.js.map +1 -0
  92. package/dist/flow/utils/built-in-complex-objects.d.ts +19 -0
  93. package/dist/flow/utils/built-in-complex-objects.js +62 -0
  94. package/dist/flow/utils/built-in-complex-objects.js.map +1 -0
  95. package/dist/flow/utils/complex-object-resolver.d.ts +8 -0
  96. package/dist/flow/utils/complex-object-resolver.js +614 -0
  97. package/dist/flow/utils/complex-object-resolver.js.map +1 -0
  98. package/dist/flow/utils/complex-objects.d.ts +36 -0
  99. package/dist/flow/utils/complex-objects.js +481 -0
  100. package/dist/flow/utils/complex-objects.js.map +1 -0
  101. package/dist/flow/utils/data-pill-shapes.d.ts +58 -0
  102. package/dist/flow/utils/data-pill-shapes.js +135 -0
  103. package/dist/flow/utils/data-pill-shapes.js.map +1 -0
  104. package/dist/flow/utils/datapill-transformer.d.ts +110 -0
  105. package/dist/flow/utils/datapill-transformer.js +503 -0
  106. package/dist/flow/utils/datapill-transformer.js.map +1 -0
  107. package/dist/flow/utils/flow-constants.d.ts +72 -0
  108. package/dist/flow/utils/flow-constants.js +230 -0
  109. package/dist/flow/utils/flow-constants.js.map +1 -0
  110. package/dist/flow/utils/flow-io-to-record.d.ts +44 -0
  111. package/dist/flow/utils/flow-io-to-record.js +409 -0
  112. package/dist/flow/utils/flow-io-to-record.js.map +1 -0
  113. package/dist/flow/utils/flow-shapes.d.ts +161 -0
  114. package/dist/flow/utils/flow-shapes.js +255 -0
  115. package/dist/flow/utils/flow-shapes.js.map +1 -0
  116. package/dist/flow/utils/flow-to-xml.d.ts +16 -0
  117. package/dist/flow/utils/flow-to-xml.js +237 -0
  118. package/dist/flow/utils/flow-to-xml.js.map +1 -0
  119. package/dist/flow/utils/flow-variable-processor.d.ts +51 -0
  120. package/dist/flow/utils/flow-variable-processor.js +69 -0
  121. package/dist/flow/utils/flow-variable-processor.js.map +1 -0
  122. package/dist/flow/utils/label-cache-parser.d.ts +7 -0
  123. package/dist/flow/utils/label-cache-parser.js +24 -0
  124. package/dist/flow/utils/label-cache-parser.js.map +1 -0
  125. package/dist/flow/utils/label-cache-processor.d.ts +119 -0
  126. package/dist/flow/utils/label-cache-processor.js +719 -0
  127. package/dist/flow/utils/label-cache-processor.js.map +1 -0
  128. package/dist/flow/utils/pill-string-parser.d.ts +88 -0
  129. package/dist/flow/utils/pill-string-parser.js +306 -0
  130. package/dist/flow/utils/pill-string-parser.js.map +1 -0
  131. package/dist/flow/utils/schema-to-flow-object.d.ts +22 -0
  132. package/dist/flow/utils/schema-to-flow-object.js +318 -0
  133. package/dist/flow/utils/schema-to-flow-object.js.map +1 -0
  134. package/dist/flow/utils/service-catalog.d.ts +47 -0
  135. package/dist/flow/utils/service-catalog.js +137 -0
  136. package/dist/flow/utils/service-catalog.js.map +1 -0
  137. package/dist/flow/utils/utils.d.ts +117 -0
  138. package/dist/flow/utils/utils.js +345 -0
  139. package/dist/flow/utils/utils.js.map +1 -0
  140. package/dist/index.d.ts +20 -1
  141. package/dist/index.js +21 -1
  142. package/dist/index.js.map +1 -1
  143. package/dist/list-plugin.js +1 -1
  144. package/dist/list-plugin.js.map +1 -1
  145. package/dist/now-attach-plugin.d.ts +1 -0
  146. package/dist/now-attach-plugin.js +10 -10
  147. package/dist/now-attach-plugin.js.map +1 -1
  148. package/dist/now-ref-plugin.js +1 -1
  149. package/dist/now-ref-plugin.js.map +1 -1
  150. package/dist/record-plugin.d.ts +29 -0
  151. package/dist/record-plugin.js +66 -7
  152. package/dist/record-plugin.js.map +1 -1
  153. package/dist/repack/index.d.ts +2 -0
  154. package/dist/repack/index.js +8 -0
  155. package/dist/repack/index.js.map +1 -1
  156. package/dist/rest-api-plugin.js +54 -44
  157. package/dist/rest-api-plugin.js.map +1 -1
  158. package/dist/server-module-plugin/index.d.ts +10 -0
  159. package/dist/server-module-plugin/index.js +83 -59
  160. package/dist/server-module-plugin/index.js.map +1 -1
  161. package/dist/service-catalog/catalog-clientscript-plugin.d.ts +2 -0
  162. package/dist/service-catalog/catalog-clientscript-plugin.js +117 -0
  163. package/dist/service-catalog/catalog-clientscript-plugin.js.map +1 -0
  164. package/dist/service-catalog/catalog-item-plugin.d.ts +2 -0
  165. package/dist/service-catalog/catalog-item-plugin.js +115 -0
  166. package/dist/service-catalog/catalog-item-plugin.js.map +1 -0
  167. package/dist/service-catalog/catalog-ui-policy-plugin.d.ts +2 -0
  168. package/dist/service-catalog/catalog-ui-policy-plugin.js +266 -0
  169. package/dist/service-catalog/catalog-ui-policy-plugin.js.map +1 -0
  170. package/dist/service-catalog/index.d.ts +5 -0
  171. package/dist/service-catalog/index.js +22 -0
  172. package/dist/service-catalog/index.js.map +1 -0
  173. package/dist/service-catalog/record-to-shape.d.ts +6 -0
  174. package/dist/service-catalog/record-to-shape.js +93 -0
  175. package/dist/service-catalog/record-to-shape.js.map +1 -0
  176. package/dist/service-catalog/sc-record-producer-plugin.d.ts +2 -0
  177. package/dist/service-catalog/sc-record-producer-plugin.js +140 -0
  178. package/dist/service-catalog/sc-record-producer-plugin.js.map +1 -0
  179. package/dist/service-catalog/service-catalog-base.d.ts +311 -0
  180. package/dist/service-catalog/service-catalog-base.js +542 -0
  181. package/dist/service-catalog/service-catalog-base.js.map +1 -0
  182. package/dist/service-catalog/service-catalog-diagnostics.d.ts +45 -0
  183. package/dist/service-catalog/service-catalog-diagnostics.js +172 -0
  184. package/dist/service-catalog/service-catalog-diagnostics.js.map +1 -0
  185. package/dist/service-catalog/shape-to-record.d.ts +8 -0
  186. package/dist/service-catalog/shape-to-record.js +235 -0
  187. package/dist/service-catalog/shape-to-record.js.map +1 -0
  188. package/dist/service-catalog/utils.d.ts +323 -0
  189. package/dist/service-catalog/utils.js +1216 -0
  190. package/dist/service-catalog/utils.js.map +1 -0
  191. package/dist/service-catalog/variable-helper.d.ts +43 -0
  192. package/dist/service-catalog/variable-helper.js +92 -0
  193. package/dist/service-catalog/variable-helper.js.map +1 -0
  194. package/dist/service-catalog/variable-set-plugin.d.ts +2 -0
  195. package/dist/service-catalog/variable-set-plugin.js +175 -0
  196. package/dist/service-catalog/variable-set-plugin.js.map +1 -0
  197. package/dist/service-catalog/variables-transform.d.ts +139 -0
  198. package/dist/service-catalog/variables-transform.js +403 -0
  199. package/dist/service-catalog/variables-transform.js.map +1 -0
  200. package/dist/sla/sla-validators.d.ts +61 -0
  201. package/dist/sla/sla-validators.js +224 -0
  202. package/dist/sla/sla-validators.js.map +1 -0
  203. package/dist/sla-plugin.d.ts +5 -0
  204. package/dist/sla-plugin.js +280 -0
  205. package/dist/sla-plugin.js.map +1 -0
  206. package/dist/static-content-plugin.js +25 -2
  207. package/dist/static-content-plugin.js.map +1 -1
  208. package/dist/table-plugin.js +32 -15
  209. package/dist/table-plugin.js.map +1 -1
  210. package/dist/ui-page-plugin.js +832 -19
  211. package/dist/ui-page-plugin.js.map +1 -1
  212. package/dist/ui-policy-plugin.js +5 -7
  213. package/dist/ui-policy-plugin.js.map +1 -1
  214. package/dist/utils.d.ts +10 -1
  215. package/dist/utils.js +16 -0
  216. package/dist/utils.js.map +1 -1
  217. package/dist/ux-list-menu-config-plugin.d.ts +2 -0
  218. package/dist/ux-list-menu-config-plugin.js +292 -0
  219. package/dist/ux-list-menu-config-plugin.js.map +1 -0
  220. package/dist/workspace-plugin/chrome-tab.d.ts +2 -0
  221. package/dist/workspace-plugin/chrome-tab.js +46 -0
  222. package/dist/workspace-plugin/chrome-tab.js.map +1 -0
  223. package/dist/workspace-plugin/constants.d.ts +52 -0
  224. package/dist/workspace-plugin/constants.js +56 -0
  225. package/dist/workspace-plugin/constants.js.map +1 -0
  226. package/dist/workspace-plugin/fluent-utils.d.ts +9 -0
  227. package/dist/workspace-plugin/fluent-utils.js +60 -0
  228. package/dist/workspace-plugin/fluent-utils.js.map +1 -0
  229. package/dist/workspace-plugin/page.d.ts +8 -0
  230. package/dist/workspace-plugin/page.js +108 -0
  231. package/dist/workspace-plugin/page.js.map +1 -0
  232. package/dist/workspace-plugin/screen.d.ts +1 -0
  233. package/dist/workspace-plugin/screen.js +38 -0
  234. package/dist/workspace-plugin/screen.js.map +1 -0
  235. package/dist/workspace-plugin/templates/index.d.ts +10 -0
  236. package/dist/workspace-plugin/templates/index.js +20 -0
  237. package/dist/workspace-plugin/templates/index.js.map +1 -0
  238. package/dist/workspace-plugin/templates/record-page-composition.d.ts +1 -0
  239. package/dist/workspace-plugin/templates/record-page-composition.js +4043 -0
  240. package/dist/workspace-plugin/templates/record-page-composition.js.map +1 -0
  241. package/dist/workspace-plugin/templates/record-page-data.d.ts +1 -0
  242. package/dist/workspace-plugin/templates/record-page-data.js +527 -0
  243. package/dist/workspace-plugin/templates/record-page-data.js.map +1 -0
  244. package/dist/workspace-plugin/templates/record-page-interalEventMappings.d.ts +1 -0
  245. package/dist/workspace-plugin/templates/record-page-interalEventMappings.js +39 -0
  246. package/dist/workspace-plugin/templates/record-page-interalEventMappings.js.map +1 -0
  247. package/dist/workspace-plugin/templates/record-page-layoutModel.d.ts +1 -0
  248. package/dist/workspace-plugin/templates/record-page-layoutModel.js +55 -0
  249. package/dist/workspace-plugin/templates/record-page-layoutModel.js.map +1 -0
  250. package/dist/workspace-plugin/templates/record-page-properties.d.ts +1 -0
  251. package/dist/workspace-plugin/templates/record-page-properties.js +135 -0
  252. package/dist/workspace-plugin/templates/record-page-properties.js.map +1 -0
  253. package/dist/workspace-plugin/templates/record-page.d.ts +3 -0
  254. package/dist/workspace-plugin/templates/record-page.js +8 -0
  255. package/dist/workspace-plugin/templates/record-page.js.map +1 -0
  256. package/dist/workspace-plugin.d.ts +2 -0
  257. package/dist/workspace-plugin.js +453 -0
  258. package/dist/workspace-plugin.js.map +1 -0
  259. package/package.json +10 -12
  260. package/src/acl-plugin.ts +16 -1
  261. package/src/applicability-plugin.ts +82 -0
  262. package/src/atf/test-plugin.ts +6 -3
  263. package/src/basic-syntax-plugin.ts +10 -1
  264. package/src/business-rule-plugin.ts +2 -1
  265. package/src/call-expression-plugin.ts +2 -130
  266. package/src/column/column-to-record.ts +54 -8
  267. package/src/column-plugin.ts +29 -13
  268. package/src/dashboard/dashboard-component-property-defaults.ts +277 -0
  269. package/src/dashboard/dashboard-component-resolver.ts +69 -0
  270. package/src/dashboard/dashboard-plugin.ts +450 -0
  271. package/src/data-plugin.ts +67 -139
  272. package/src/email-notification-plugin.ts +850 -0
  273. package/src/flow/constants/flow-plugin-constants.ts +79 -0
  274. package/src/flow/flow-logic/flow-logic-constants.ts +120 -0
  275. package/src/flow/flow-logic/flow-logic-diagnostics.ts +591 -0
  276. package/src/flow/flow-logic/flow-logic-plugin-helpers.ts +2550 -0
  277. package/src/flow/flow-logic/flow-logic-plugin.ts +337 -0
  278. package/src/flow/flow-logic/flow-logic-shapes.ts +215 -0
  279. package/src/flow/plugins/approval-rules-plugin.ts +48 -0
  280. package/src/flow/plugins/flow-action-definition-plugin.ts +295 -0
  281. package/src/flow/plugins/flow-data-pill-plugin.ts +258 -0
  282. package/src/flow/plugins/flow-definition-plugin.ts +2173 -0
  283. package/src/flow/plugins/flow-diagnostics-plugin.ts +280 -0
  284. package/src/flow/plugins/flow-instance-plugin.ts +1499 -0
  285. package/src/flow/plugins/flow-trigger-instance-plugin.ts +444 -0
  286. package/src/flow/plugins/inline-script-plugin.ts +83 -0
  287. package/src/flow/plugins/step-definition-plugin.ts +67 -0
  288. package/src/flow/plugins/step-instance-plugin.ts +431 -0
  289. package/src/flow/plugins/trigger-plugin.ts +95 -0
  290. package/src/flow/plugins/wfa-datapill-plugin.ts +213 -0
  291. package/src/flow/utils/approval-rules-processor.ts +298 -0
  292. package/src/flow/utils/built-in-complex-objects.ts +81 -0
  293. package/src/flow/utils/complex-object-resolver.ts +875 -0
  294. package/src/flow/utils/complex-objects.ts +656 -0
  295. package/src/flow/utils/data-pill-shapes.ts +165 -0
  296. package/src/flow/utils/datapill-transformer.ts +632 -0
  297. package/src/flow/utils/flow-constants.ts +285 -0
  298. package/src/flow/utils/flow-io-to-record.ts +533 -0
  299. package/src/flow/utils/flow-shapes.ts +296 -0
  300. package/src/flow/utils/flow-to-xml.ts +318 -0
  301. package/src/flow/utils/flow-variable-processor.ts +100 -0
  302. package/src/flow/utils/label-cache-parser.ts +37 -0
  303. package/src/flow/utils/label-cache-processor.ts +870 -0
  304. package/src/flow/utils/pill-string-parser.ts +375 -0
  305. package/src/flow/utils/schema-to-flow-object.ts +385 -0
  306. package/src/flow/utils/service-catalog.ts +174 -0
  307. package/src/flow/utils/utils.ts +395 -0
  308. package/src/index.ts +20 -1
  309. package/src/list-plugin.ts +1 -1
  310. package/src/now-attach-plugin.ts +14 -11
  311. package/src/now-ref-plugin.ts +1 -1
  312. package/src/record-plugin.ts +76 -11
  313. package/src/repack/index.ts +14 -0
  314. package/src/rest-api-plugin.ts +62 -50
  315. package/src/server-module-plugin/index.ts +112 -86
  316. package/src/service-catalog/catalog-clientscript-plugin.ts +140 -0
  317. package/src/service-catalog/catalog-item-plugin.ts +162 -0
  318. package/src/service-catalog/catalog-ui-policy-plugin.ts +324 -0
  319. package/src/service-catalog/index.ts +5 -0
  320. package/src/service-catalog/record-to-shape.ts +109 -0
  321. package/src/service-catalog/sc-record-producer-plugin.ts +201 -0
  322. package/src/service-catalog/service-catalog-base.ts +600 -0
  323. package/src/service-catalog/service-catalog-diagnostics.ts +254 -0
  324. package/src/service-catalog/shape-to-record.ts +279 -0
  325. package/src/service-catalog/utils.ts +1455 -0
  326. package/src/service-catalog/variable-helper.ts +135 -0
  327. package/src/service-catalog/variable-set-plugin.ts +197 -0
  328. package/src/service-catalog/variables-transform.ts +438 -0
  329. package/src/sla/sla-validators.ts +331 -0
  330. package/src/sla-plugin.ts +358 -0
  331. package/src/static-content-plugin.ts +25 -2
  332. package/src/table-plugin.ts +49 -16
  333. package/src/ui-page-plugin.ts +1063 -20
  334. package/src/ui-policy-plugin.ts +5 -9
  335. package/src/utils.ts +24 -1
  336. package/src/ux-list-menu-config-plugin.ts +312 -0
  337. package/src/workspace-plugin/chrome-tab.ts +44 -0
  338. package/src/workspace-plugin/constants.ts +53 -0
  339. package/src/workspace-plugin/fluent-utils.ts +60 -0
  340. package/src/workspace-plugin/page.ts +139 -0
  341. package/src/workspace-plugin/screen.ts +34 -0
  342. package/src/workspace-plugin/templates/index.ts +17 -0
  343. package/src/workspace-plugin/templates/record-page-composition.ts +4051 -0
  344. package/src/workspace-plugin/templates/record-page-data.ts +523 -0
  345. package/src/workspace-plugin/templates/record-page-interalEventMappings.ts +35 -0
  346. package/src/workspace-plugin/templates/record-page-layoutModel.ts +51 -0
  347. package/src/workspace-plugin/templates/record-page-properties.ts +131 -0
  348. package/src/workspace-plugin/templates/record-page.ts +6 -0
  349. 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
+ }