@servicenow/sdk-build-plugins 4.4.1 → 4.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (337) hide show
  1. package/dist/acl-plugin.js +54 -4
  2. package/dist/acl-plugin.js.map +1 -1
  3. package/dist/applicability-plugin.js +2 -0
  4. package/dist/applicability-plugin.js.map +1 -1
  5. package/dist/application-menu-plugin.js +2 -0
  6. package/dist/application-menu-plugin.js.map +1 -1
  7. package/dist/arrow-function-plugin.d.ts +6 -1
  8. package/dist/arrow-function-plugin.js +105 -12
  9. package/dist/arrow-function-plugin.js.map +1 -1
  10. package/dist/atf/test-plugin.js +2 -0
  11. package/dist/atf/test-plugin.js.map +1 -1
  12. package/dist/basic-syntax-plugin.js +20 -0
  13. package/dist/basic-syntax-plugin.js.map +1 -1
  14. package/dist/call-expression-plugin.js +1 -0
  15. package/dist/call-expression-plugin.js.map +1 -1
  16. package/dist/claims-plugin.js +1 -0
  17. package/dist/claims-plugin.js.map +1 -1
  18. package/dist/client-script-plugin.js +1 -0
  19. package/dist/client-script-plugin.js.map +1 -1
  20. package/dist/column-plugin.js +4 -7
  21. package/dist/column-plugin.js.map +1 -1
  22. package/dist/cross-scope-privilege-plugin.js +1 -0
  23. package/dist/cross-scope-privilege-plugin.js.map +1 -1
  24. package/dist/dashboard/dashboard-plugin.js +2 -0
  25. package/dist/dashboard/dashboard-plugin.js.map +1 -1
  26. package/dist/data-plugin.js +1 -0
  27. package/dist/data-plugin.js.map +1 -1
  28. package/dist/email-notification-plugin.js +9 -13
  29. package/dist/email-notification-plugin.js.map +1 -1
  30. package/dist/flow/constants/flow-plugin-constants.d.ts +1 -1
  31. package/dist/flow/constants/flow-plugin-constants.js +1 -1
  32. package/dist/flow/constants/flow-plugin-constants.js.map +1 -1
  33. package/dist/flow/flow-logic/flow-logic-diagnostics.js +5 -5
  34. package/dist/flow/flow-logic/flow-logic-diagnostics.js.map +1 -1
  35. package/dist/flow/flow-logic/flow-logic-plugin-helpers.d.ts +82 -2
  36. package/dist/flow/flow-logic/flow-logic-plugin-helpers.js +48 -40
  37. package/dist/flow/flow-logic/flow-logic-plugin-helpers.js.map +1 -1
  38. package/dist/flow/flow-logic/flow-logic-plugin.js +1 -0
  39. package/dist/flow/flow-logic/flow-logic-plugin.js.map +1 -1
  40. package/dist/flow/plugins/approval-rules-plugin.js +1 -0
  41. package/dist/flow/plugins/approval-rules-plugin.js.map +1 -1
  42. package/dist/flow/plugins/flow-action-definition-plugin.js +1232 -55
  43. package/dist/flow/plugins/flow-action-definition-plugin.js.map +1 -1
  44. package/dist/flow/plugins/flow-data-pill-plugin.js +6 -2
  45. package/dist/flow/plugins/flow-data-pill-plugin.js.map +1 -1
  46. package/dist/flow/plugins/flow-definition-plugin.js +23 -44
  47. package/dist/flow/plugins/flow-definition-plugin.js.map +1 -1
  48. package/dist/flow/plugins/flow-diagnostics-plugin.d.ts +2 -2
  49. package/dist/flow/plugins/flow-diagnostics-plugin.js +3 -2
  50. package/dist/flow/plugins/flow-diagnostics-plugin.js.map +1 -1
  51. package/dist/flow/plugins/flow-instance-plugin.js +136 -34
  52. package/dist/flow/plugins/flow-instance-plugin.js.map +1 -1
  53. package/dist/flow/plugins/flow-trigger-instance-plugin.js +1 -0
  54. package/dist/flow/plugins/flow-trigger-instance-plugin.js.map +1 -1
  55. package/dist/flow/plugins/inline-script-plugin.js +1 -0
  56. package/dist/flow/plugins/inline-script-plugin.js.map +1 -1
  57. package/dist/flow/plugins/step-definition-plugin.js +4 -2
  58. package/dist/flow/plugins/step-definition-plugin.js.map +1 -1
  59. package/dist/flow/plugins/step-instance-plugin.d.ts +9 -1
  60. package/dist/flow/plugins/step-instance-plugin.js +649 -135
  61. package/dist/flow/plugins/step-instance-plugin.js.map +1 -1
  62. package/dist/flow/plugins/trigger-plugin.js +2 -0
  63. package/dist/flow/plugins/trigger-plugin.js.map +1 -1
  64. package/dist/flow/plugins/wfa-datapill-plugin.js +21 -5
  65. package/dist/flow/plugins/wfa-datapill-plugin.js.map +1 -1
  66. package/dist/flow/post-install.d.ts +2 -0
  67. package/dist/flow/post-install.js +59 -0
  68. package/dist/flow/post-install.js.map +1 -0
  69. package/dist/flow/utils/complex-object-resolver.js +4 -1
  70. package/dist/flow/utils/complex-object-resolver.js.map +1 -1
  71. package/dist/flow/utils/complex-objects.js +5 -3
  72. package/dist/flow/utils/complex-objects.js.map +1 -1
  73. package/dist/flow/utils/flow-constants.d.ts +90 -2
  74. package/dist/flow/utils/flow-constants.js +430 -7
  75. package/dist/flow/utils/flow-constants.js.map +1 -1
  76. package/dist/flow/utils/flow-io-to-record.d.ts +1 -1
  77. package/dist/flow/utils/flow-io-to-record.js +37 -16
  78. package/dist/flow/utils/flow-io-to-record.js.map +1 -1
  79. package/dist/flow/utils/flow-shapes.js +4 -0
  80. package/dist/flow/utils/flow-shapes.js.map +1 -1
  81. package/dist/flow/utils/flow-to-xml.d.ts +3 -2
  82. package/dist/flow/utils/flow-to-xml.js +3 -4
  83. package/dist/flow/utils/flow-to-xml.js.map +1 -1
  84. package/dist/flow/utils/label-cache-parser.d.ts +9 -2
  85. package/dist/flow/utils/label-cache-parser.js +32 -4
  86. package/dist/flow/utils/label-cache-parser.js.map +1 -1
  87. package/dist/flow/utils/label-cache-processor.d.ts +5 -0
  88. package/dist/flow/utils/label-cache-processor.js +14 -2
  89. package/dist/flow/utils/label-cache-processor.js.map +1 -1
  90. package/dist/flow/utils/pill-shape-helpers.d.ts +15 -0
  91. package/dist/flow/utils/pill-shape-helpers.js +35 -0
  92. package/dist/flow/utils/pill-shape-helpers.js.map +1 -0
  93. package/dist/flow/utils/pill-string-parser.js +1 -0
  94. package/dist/flow/utils/pill-string-parser.js.map +1 -1
  95. package/dist/flow/utils/schema-to-flow-object.d.ts +6 -1
  96. package/dist/flow/utils/schema-to-flow-object.js +131 -15
  97. package/dist/flow/utils/schema-to-flow-object.js.map +1 -1
  98. package/dist/flow/utils/service-catalog.js +5 -1
  99. package/dist/flow/utils/service-catalog.js.map +1 -1
  100. package/dist/flow/utils/utils.d.ts +1 -0
  101. package/dist/flow/utils/utils.js +6 -1
  102. package/dist/flow/utils/utils.js.map +1 -1
  103. package/dist/form-plugin.d.ts +2 -0
  104. package/dist/form-plugin.js +1132 -0
  105. package/dist/form-plugin.js.map +1 -0
  106. package/dist/html-import-plugin.js +1 -0
  107. package/dist/html-import-plugin.js.map +1 -1
  108. package/dist/import-sets-plugin.js +2 -0
  109. package/dist/import-sets-plugin.js.map +1 -1
  110. package/dist/inbound-email-action-plugin.d.ts +10 -0
  111. package/dist/inbound-email-action-plugin.js +128 -0
  112. package/dist/inbound-email-action-plugin.js.map +1 -0
  113. package/dist/index.d.ts +13 -0
  114. package/dist/index.js +17 -1
  115. package/dist/index.js.map +1 -1
  116. package/dist/instance-scan-plugin.d.ts +2 -0
  117. package/dist/instance-scan-plugin.js +293 -0
  118. package/dist/instance-scan-plugin.js.map +1 -0
  119. package/dist/json-plugin.js +1 -0
  120. package/dist/json-plugin.js.map +1 -1
  121. package/dist/list-plugin.js +1 -0
  122. package/dist/list-plugin.js.map +1 -1
  123. package/dist/now-attach-plugin.js +1 -0
  124. package/dist/now-attach-plugin.js.map +1 -1
  125. package/dist/now-config-plugin.js +659 -51
  126. package/dist/now-config-plugin.js.map +1 -1
  127. package/dist/now-id-plugin.js +1 -0
  128. package/dist/now-id-plugin.js.map +1 -1
  129. package/dist/now-include-plugin.js +1 -0
  130. package/dist/now-include-plugin.js.map +1 -1
  131. package/dist/now-ref-plugin.js +1 -0
  132. package/dist/now-ref-plugin.js.map +1 -1
  133. package/dist/now-unresolved-plugin.js +1 -0
  134. package/dist/now-unresolved-plugin.js.map +1 -1
  135. package/dist/package-json-plugin.js +1 -0
  136. package/dist/package-json-plugin.js.map +1 -1
  137. package/dist/property-plugin.js +3 -1
  138. package/dist/property-plugin.js.map +1 -1
  139. package/dist/record-plugin.d.ts +37 -0
  140. package/dist/record-plugin.js +47 -3
  141. package/dist/record-plugin.js.map +1 -1
  142. package/dist/repack/lint/Rules.d.ts +11 -2
  143. package/dist/repack/lint/Rules.js +160 -16
  144. package/dist/repack/lint/Rules.js.map +1 -1
  145. package/dist/repack/lint/index.d.ts +10 -5
  146. package/dist/repack/lint/index.js +76 -50
  147. package/dist/repack/lint/index.js.map +1 -1
  148. package/dist/rest-api-plugin.js +22 -1
  149. package/dist/rest-api-plugin.js.map +1 -1
  150. package/dist/role-plugin.js +1 -0
  151. package/dist/role-plugin.js.map +1 -1
  152. package/dist/schedule-script/index.d.ts +1 -0
  153. package/dist/schedule-script/index.js +18 -0
  154. package/dist/schedule-script/index.js.map +1 -0
  155. package/dist/schedule-script/scheduled-script-plugin.d.ts +2 -0
  156. package/dist/schedule-script/scheduled-script-plugin.js +556 -0
  157. package/dist/schedule-script/scheduled-script-plugin.js.map +1 -0
  158. package/dist/schedule-script/timeZoneConverter.d.ts +61 -0
  159. package/dist/schedule-script/timeZoneConverter.js +170 -0
  160. package/dist/schedule-script/timeZoneConverter.js.map +1 -0
  161. package/dist/script-action-plugin.js +2 -0
  162. package/dist/script-action-plugin.js.map +1 -1
  163. package/dist/script-include-plugin.js +2 -0
  164. package/dist/script-include-plugin.js.map +1 -1
  165. package/dist/server-module-plugin/index.js +13 -2
  166. package/dist/server-module-plugin/index.js.map +1 -1
  167. package/dist/service-catalog/catalog-clientscript-plugin.js +2 -0
  168. package/dist/service-catalog/catalog-clientscript-plugin.js.map +1 -1
  169. package/dist/service-catalog/catalog-item-plugin.js +2 -0
  170. package/dist/service-catalog/catalog-item-plugin.js.map +1 -1
  171. package/dist/service-catalog/catalog-ui-policy-plugin.js +2 -0
  172. package/dist/service-catalog/catalog-ui-policy-plugin.js.map +1 -1
  173. package/dist/service-catalog/sc-record-producer-plugin.js +2 -0
  174. package/dist/service-catalog/sc-record-producer-plugin.js.map +1 -1
  175. package/dist/service-catalog/service-catalog-base.d.ts +18 -18
  176. package/dist/service-catalog/service-catalog-base.js +22 -22
  177. package/dist/service-catalog/service-catalog-base.js.map +1 -1
  178. package/dist/service-catalog/service-catalog-diagnostics.d.ts +6 -0
  179. package/dist/service-catalog/service-catalog-diagnostics.js +20 -0
  180. package/dist/service-catalog/service-catalog-diagnostics.js.map +1 -1
  181. package/dist/service-catalog/shape-to-record.js +7 -2
  182. package/dist/service-catalog/shape-to-record.js.map +1 -1
  183. package/dist/service-catalog/variable-set-plugin.js +2 -0
  184. package/dist/service-catalog/variable-set-plugin.js.map +1 -1
  185. package/dist/service-portal/angular-provider-plugin.js +2 -0
  186. package/dist/service-portal/angular-provider-plugin.js.map +1 -1
  187. package/dist/service-portal/dependency-plugin.js +5 -31
  188. package/dist/service-portal/dependency-plugin.js.map +1 -1
  189. package/dist/service-portal/header-footer-plugin.d.ts +2 -0
  190. package/dist/service-portal/header-footer-plugin.js +50 -0
  191. package/dist/service-portal/header-footer-plugin.js.map +1 -0
  192. package/dist/service-portal/menu-plugin.d.ts +2 -0
  193. package/dist/service-portal/menu-plugin.js +334 -0
  194. package/dist/service-portal/menu-plugin.js.map +1 -0
  195. package/dist/service-portal/page-plugin.d.ts +2 -0
  196. package/dist/service-portal/page-plugin.js +681 -0
  197. package/dist/service-portal/page-plugin.js.map +1 -0
  198. package/dist/service-portal/page-route-map-plugin.d.ts +2 -0
  199. package/dist/service-portal/page-route-map-plugin.js +114 -0
  200. package/dist/service-portal/page-route-map-plugin.js.map +1 -0
  201. package/dist/service-portal/portal-plugin.d.ts +2 -0
  202. package/dist/service-portal/portal-plugin.js +309 -0
  203. package/dist/service-portal/portal-plugin.js.map +1 -0
  204. package/dist/service-portal/theme-plugin.d.ts +2 -0
  205. package/dist/service-portal/theme-plugin.js +112 -0
  206. package/dist/service-portal/theme-plugin.js.map +1 -0
  207. package/dist/service-portal/utils.d.ts +46 -0
  208. package/dist/service-portal/utils.js +331 -0
  209. package/dist/service-portal/utils.js.map +1 -0
  210. package/dist/service-portal/widget-plugin.js +10 -182
  211. package/dist/service-portal/widget-plugin.js.map +1 -1
  212. package/dist/sla-plugin.js +2 -0
  213. package/dist/sla-plugin.js.map +1 -1
  214. package/dist/static-content-plugin.js +5 -0
  215. package/dist/static-content-plugin.js.map +1 -1
  216. package/dist/table-plugin.js +191 -26
  217. package/dist/table-plugin.js.map +1 -1
  218. package/dist/ui-action-plugin.js +3 -4
  219. package/dist/ui-action-plugin.js.map +1 -1
  220. package/dist/ui-page-plugin.js +101 -21
  221. package/dist/ui-page-plugin.js.map +1 -1
  222. package/dist/ui-policy-plugin.js +1 -0
  223. package/dist/ui-policy-plugin.js.map +1 -1
  224. package/dist/user-preference-plugin.js +2 -0
  225. package/dist/user-preference-plugin.js.map +1 -1
  226. package/dist/utils.d.ts +20 -2
  227. package/dist/utils.js +34 -3
  228. package/dist/utils.js.map +1 -1
  229. package/dist/ux-list-menu-config-plugin.js +2 -0
  230. package/dist/ux-list-menu-config-plugin.js.map +1 -1
  231. package/dist/view-plugin.js +9 -3
  232. package/dist/view-plugin.js.map +1 -1
  233. package/dist/workspace-plugin.js +41 -36
  234. package/dist/workspace-plugin.js.map +1 -1
  235. package/package.json +11 -11
  236. package/src/_types/eslint-community-eslint-utils.d.ts +15 -0
  237. package/src/acl-plugin.ts +97 -8
  238. package/src/applicability-plugin.ts +2 -0
  239. package/src/application-menu-plugin.ts +2 -0
  240. package/src/arrow-function-plugin.ts +128 -13
  241. package/src/atf/test-plugin.ts +2 -0
  242. package/src/basic-syntax-plugin.ts +21 -0
  243. package/src/call-expression-plugin.ts +1 -0
  244. package/src/claims-plugin.ts +1 -0
  245. package/src/client-script-plugin.ts +2 -1
  246. package/src/column-plugin.ts +4 -8
  247. package/src/cross-scope-privilege-plugin.ts +2 -1
  248. package/src/dashboard/dashboard-plugin.ts +2 -0
  249. package/src/data-plugin.ts +1 -0
  250. package/src/email-notification-plugin.ts +3 -23
  251. package/src/flow/constants/flow-plugin-constants.ts +1 -1
  252. package/src/flow/flow-logic/flow-logic-diagnostics.ts +5 -6
  253. package/src/flow/flow-logic/flow-logic-plugin-helpers.ts +47 -45
  254. package/src/flow/flow-logic/flow-logic-plugin.ts +1 -0
  255. package/src/flow/plugins/approval-rules-plugin.ts +1 -0
  256. package/src/flow/plugins/flow-action-definition-plugin.ts +1584 -62
  257. package/src/flow/plugins/flow-data-pill-plugin.ts +6 -2
  258. package/src/flow/plugins/flow-definition-plugin.ts +22 -51
  259. package/src/flow/plugins/flow-diagnostics-plugin.ts +3 -2
  260. package/src/flow/plugins/flow-instance-plugin.ts +201 -36
  261. package/src/flow/plugins/flow-trigger-instance-plugin.ts +1 -0
  262. package/src/flow/plugins/inline-script-plugin.ts +1 -0
  263. package/src/flow/plugins/step-definition-plugin.ts +4 -2
  264. package/src/flow/plugins/step-instance-plugin.ts +772 -155
  265. package/src/flow/plugins/trigger-plugin.ts +2 -0
  266. package/src/flow/plugins/wfa-datapill-plugin.ts +26 -5
  267. package/src/flow/post-install.ts +93 -0
  268. package/src/flow/utils/complex-object-resolver.ts +4 -1
  269. package/src/flow/utils/complex-objects.ts +11 -3
  270. package/src/flow/utils/flow-constants.ts +451 -6
  271. package/src/flow/utils/flow-io-to-record.ts +43 -17
  272. package/src/flow/utils/flow-shapes.ts +4 -0
  273. package/src/flow/utils/flow-to-xml.ts +4 -4
  274. package/src/flow/utils/label-cache-parser.ts +33 -4
  275. package/src/flow/utils/label-cache-processor.ts +14 -2
  276. package/src/flow/utils/pill-shape-helpers.ts +42 -0
  277. package/src/flow/utils/pill-string-parser.ts +1 -0
  278. package/src/flow/utils/schema-to-flow-object.ts +183 -15
  279. package/src/flow/utils/service-catalog.ts +5 -2
  280. package/src/flow/utils/utils.ts +12 -1
  281. package/src/form-plugin.ts +1409 -0
  282. package/src/html-import-plugin.ts +1 -0
  283. package/src/import-sets-plugin.ts +2 -0
  284. package/src/inbound-email-action-plugin.ts +145 -0
  285. package/src/index.ts +13 -0
  286. package/src/instance-scan-plugin.ts +313 -0
  287. package/src/json-plugin.ts +1 -0
  288. package/src/list-plugin.ts +2 -1
  289. package/src/now-attach-plugin.ts +1 -0
  290. package/src/now-config-plugin.ts +833 -53
  291. package/src/now-id-plugin.ts +1 -0
  292. package/src/now-include-plugin.ts +1 -0
  293. package/src/now-ref-plugin.ts +1 -0
  294. package/src/now-unresolved-plugin.ts +1 -0
  295. package/src/package-json-plugin.ts +1 -0
  296. package/src/property-plugin.ts +6 -1
  297. package/src/record-plugin.ts +56 -6
  298. package/src/repack/lint/Rules.ts +171 -22
  299. package/src/repack/lint/index.ts +80 -56
  300. package/src/rest-api-plugin.ts +28 -2
  301. package/src/role-plugin.ts +2 -1
  302. package/src/schedule-script/index.ts +1 -0
  303. package/src/schedule-script/scheduled-script-plugin.ts +690 -0
  304. package/src/schedule-script/timeZoneConverter.ts +188 -0
  305. package/src/script-action-plugin.ts +2 -0
  306. package/src/script-include-plugin.ts +2 -0
  307. package/src/server-module-plugin/index.ts +14 -2
  308. package/src/service-catalog/catalog-clientscript-plugin.ts +2 -0
  309. package/src/service-catalog/catalog-item-plugin.ts +2 -0
  310. package/src/service-catalog/catalog-ui-policy-plugin.ts +2 -0
  311. package/src/service-catalog/sc-record-producer-plugin.ts +2 -0
  312. package/src/service-catalog/service-catalog-base.ts +22 -22
  313. package/src/service-catalog/service-catalog-diagnostics.ts +30 -0
  314. package/src/service-catalog/shape-to-record.ts +8 -2
  315. package/src/service-catalog/variable-set-plugin.ts +2 -0
  316. package/src/service-portal/angular-provider-plugin.ts +2 -0
  317. package/src/service-portal/dependency-plugin.ts +6 -53
  318. package/src/service-portal/header-footer-plugin.ts +57 -0
  319. package/src/service-portal/menu-plugin.ts +413 -0
  320. package/src/service-portal/page-plugin.ts +805 -0
  321. package/src/service-portal/page-route-map-plugin.ts +124 -0
  322. package/src/service-portal/portal-plugin.ts +342 -0
  323. package/src/service-portal/theme-plugin.ts +135 -0
  324. package/src/service-portal/utils.ts +470 -0
  325. package/src/service-portal/widget-plugin.ts +18 -224
  326. package/src/sla-plugin.ts +2 -0
  327. package/src/static-content-plugin.ts +4 -0
  328. package/src/table-plugin.ts +228 -37
  329. package/src/ui-action-plugin.ts +3 -8
  330. package/src/ui-page-plugin.ts +110 -21
  331. package/src/ui-policy-plugin.ts +2 -1
  332. package/src/user-preference-plugin.ts +2 -0
  333. package/src/utils.ts +42 -2
  334. package/src/ux-list-menu-config-plugin.ts +2 -0
  335. package/src/view-plugin.ts +11 -4
  336. package/src/workspace-plugin.ts +45 -43
  337. package/src/_types/eslint-plugin-es-x.d.ts +0 -17
@@ -0,0 +1,690 @@
1
+ import {
2
+ CallExpressionShape,
3
+ Plugin,
4
+ DurationShape,
5
+ TimeShape,
6
+ timeFieldToXML,
7
+ formatDateToPlatformFormat,
8
+ type Shape,
9
+ } from '@servicenow/sdk-build-core'
10
+ import { NowIdShape } from '../now-id-plugin'
11
+ import { NowIncludeShape } from '../now-include-plugin'
12
+ import { ModuleFunctionShape } from '../server-module-plugin'
13
+ import { createSdkDocEntry, toReference } from '../utils'
14
+ import { dateTimeFieldToXML, convertXMLToDateTime, formatTimeDataToDateTime, formatToUTC } from './timeZoneConverter'
15
+
16
+ const DEFAULT_DATE_TIME = '1970-01-01 00:00:00'
17
+
18
+ /**
19
+ * Calculate the default entered_run_time for 00:00:00 based on timezone
20
+ * @param timeZone - The IANA timezone identifier
21
+ * @returns Formatted datetime string representing 00:00:00 in the specified timezone
22
+ */
23
+ function getDefaultRunTime(timeZone: string): string {
24
+ try {
25
+ // Floating timezone → return raw epoch
26
+ if (timeZone === 'floating') {
27
+ return DEFAULT_DATE_TIME
28
+ }
29
+
30
+ // Valid timezone → treat reference as LOCAL in that timezone → convert to UTC
31
+ const utcDate = timeFieldToXML({ hours: 0, minutes: 0, seconds: 0 }, timeZone)
32
+ return formatDateToPlatformFormat(utcDate)
33
+ } catch (error) {
34
+ return DEFAULT_DATE_TIME
35
+ }
36
+ }
37
+
38
+ /**
39
+ * Map day of week numeric values to day names
40
+ */
41
+ const dayOfWeekMap = new Map([
42
+ ['1', 'monday'],
43
+ ['2', 'tuesday'],
44
+ ['3', 'wednesday'],
45
+ ['4', 'thursday'],
46
+ ['5', 'friday'],
47
+ ['6', 'saturday'],
48
+ ['7', 'sunday'],
49
+ ])
50
+
51
+ const offsetTypeMap = new Map([
52
+ ['1', 'past'],
53
+ ['2', 'future'],
54
+ ])
55
+
56
+ /**
57
+ * Reverse map: offset type names to numeric values (generated from offsetTypeMap)
58
+ */
59
+ const reverseOffsetTypeMap = new Map(Array.from(offsetTypeMap.entries()).map(([num, type]) => [type, num]))
60
+
61
+ /**
62
+ * Reverse map: day names to numeric values (generated from dayOfWeekMap)
63
+ */
64
+ const reverseDayOfWeekMap = new Map(Array.from(dayOfWeekMap.entries()).map(([num, day]) => [day, num]))
65
+
66
+ /**
67
+ * Negate a duration object (multiply all values by -1)
68
+ * @param duration - Duration object with days, hours, minutes, seconds
69
+ * @returns Negated duration object
70
+ */
71
+ function negateDuration(duration: { days?: number; hours?: number; minutes?: number; seconds?: number }) {
72
+ return {
73
+ days: duration.days ? -duration.days : 0,
74
+ hours: duration.hours ? -duration.hours : 0,
75
+ minutes: duration.minutes ? -duration.minutes : 0,
76
+ seconds: duration.seconds ? -duration.seconds : 0,
77
+ }
78
+ }
79
+
80
+ /**
81
+ * Add duration to a Date object in place
82
+ * @param date - Date object to modify
83
+ * @param duration - Duration to add (days, hours, minutes, seconds)
84
+ */
85
+ function addDuration(date: Date, duration: { days?: number; hours?: number; minutes?: number; seconds?: number }) {
86
+ if (duration.days) {
87
+ date.setDate(date.getDate() + duration.days)
88
+ }
89
+ if (duration.hours) {
90
+ date.setHours(date.getHours() + duration.hours)
91
+ }
92
+ if (duration.minutes) {
93
+ date.setMinutes(date.getMinutes() + duration.minutes)
94
+ }
95
+ if (duration.seconds) {
96
+ date.setSeconds(date.getSeconds() + duration.seconds)
97
+ }
98
+ }
99
+
100
+ /**
101
+ * Add duration to a datetime string without timezone conversion
102
+ * @param dateTimeStr - Datetime string in format 'YYYY-MM-DD HH:MM:SS'
103
+ * @param duration - Duration to add (days, hours, minutes, seconds)
104
+ * @returns New datetime string with duration added
105
+ */
106
+ function addDurationToString(
107
+ dateTimeStr: string,
108
+ duration: { days?: number; hours?: number; minutes?: number; seconds?: number }
109
+ ): string {
110
+ const parts = dateTimeStr.split(' ')
111
+ if (parts.length !== 2 || !parts[0] || !parts[1]) {
112
+ return dateTimeStr
113
+ }
114
+
115
+ const dateParts = parts[0].split('-').map(Number)
116
+ const timeParts = parts[1].split(':').map(Number)
117
+
118
+ if (dateParts.length !== 3 || timeParts.length !== 3) {
119
+ return dateTimeStr
120
+ }
121
+ if (dateParts.some(isNaN) || timeParts.some(isNaN)) {
122
+ return dateTimeStr
123
+ }
124
+
125
+ const date = new Date(
126
+ dateParts[0] ?? 0,
127
+ (dateParts[1] ?? 1) - 1,
128
+ dateParts[2] ?? 1,
129
+ timeParts[0] ?? 0,
130
+ timeParts[1] ?? 0,
131
+ timeParts[2] ?? 0
132
+ )
133
+ addDuration(date, duration)
134
+
135
+ const newYear = date.getFullYear()
136
+ const newMonth = String(date.getMonth() + 1).padStart(2, '0')
137
+ const newDay = String(date.getDate()).padStart(2, '0')
138
+ const newHours = String(date.getHours()).padStart(2, '0')
139
+ const newMinutes = String(date.getMinutes()).padStart(2, '0')
140
+ const newSeconds = String(date.getSeconds()).padStart(2, '0')
141
+ return `${newYear}-${newMonth}-${newDay} ${newHours}:${newMinutes}:${newSeconds}`
142
+ }
143
+
144
+ /**
145
+ * Calculate the recurring interval in days for different run types
146
+ * @param frequency - The type of recurring schedule
147
+ * @returns Number of days in the interval, or undefined if not a fixed-interval type
148
+ */
149
+ function calculateRecurringInterval(frequency: string): number | undefined {
150
+ const recurrenceIntervals: Record<string, number> = {
151
+ daily: 1,
152
+ weekly: 7,
153
+ day_and_month_in_year: 365,
154
+ day_week_month_year: 365,
155
+ }
156
+ return recurrenceIntervals[frequency]
157
+ }
158
+
159
+ /**
160
+ * Calculate minimum end date for monthly recurring jobs
161
+ * @param executionStart - Start datetime string
162
+ * @param maxDrift - Optional max drift duration
163
+ * @returns Object with minEndStr and intervalDescription
164
+ */
165
+ function calculateMonthlyMinEndDate(
166
+ executionStart: string,
167
+ maxDrift?: { days?: number; hours?: number; minutes?: number; seconds?: number }
168
+ ): { minEndStr: string | undefined; intervalDescription: string | undefined } {
169
+ const parts = executionStart.split(' ')
170
+ if (parts.length !== 2 || !parts[0] || !parts[1]) {
171
+ return { minEndStr: undefined, intervalDescription: undefined }
172
+ }
173
+
174
+ const [datePart] = parts
175
+ const dateParts = datePart.split('-').map(Number)
176
+ if (dateParts.length !== 3) {
177
+ return { minEndStr: undefined, intervalDescription: undefined }
178
+ }
179
+
180
+ const [year, month, day] = dateParts
181
+ const nextDate = new Date(year!, month!, day!)
182
+ const nextYear = nextDate.getFullYear()
183
+ const nextMonth = String(nextDate.getMonth() + 1).padStart(2, '0')
184
+ const nextDay = String(nextDate.getDate()).padStart(2, '0')
185
+ let minEndStr = `${nextYear}-${nextMonth}-${nextDay} ${parts[1]}`
186
+
187
+ if (maxDrift) {
188
+ minEndStr = addDurationToString(minEndStr, negateDuration(maxDrift))
189
+ }
190
+
191
+ const intervalDescription = `1 month${maxDrift ? ' - maxDrift' : ''}`
192
+ return { minEndStr, intervalDescription }
193
+ }
194
+
195
+ /**
196
+ * Calculate minimum end date for periodically recurring jobs
197
+ * @param executionStart - Start datetime string
198
+ * @param executionInterval - Duration for the period
199
+ * @param maxDrift - Optional max drift duration
200
+ * @returns Object with minEndStr and intervalDescription
201
+ */
202
+ function calculatePeriodicallyMinEndDate(
203
+ executionStart: string,
204
+ executionInterval: { days?: number; hours?: number; minutes?: number; seconds?: number },
205
+ maxDrift?: { days?: number; hours?: number; minutes?: number; seconds?: number }
206
+ ): { minEndStr: string; intervalDescription: string } {
207
+ let minEndStr = addDurationToString(executionStart, executionInterval)
208
+
209
+ if (maxDrift) {
210
+ minEndStr = addDurationToString(minEndStr, negateDuration(maxDrift))
211
+ }
212
+
213
+ const intervalDescription = `executionInterval${maxDrift ? ' - maxDrift' : ''}`
214
+ return { minEndStr, intervalDescription }
215
+ }
216
+
217
+ /**
218
+ * Calculate minimum end date for fixed-interval recurring jobs (daily, weekly, yearly)
219
+ * @param executionStart - Start datetime string
220
+ * @param intervalDays - Number of days in the interval
221
+ * @param maxDrift - Optional max drift duration
222
+ * @returns Object with minEndStr and intervalDescription
223
+ */
224
+ function calculateFixedIntervalMinEndDate(
225
+ executionStart: string,
226
+ intervalDays: number,
227
+ maxDrift?: { days?: number; hours?: number; minutes?: number; seconds?: number }
228
+ ): { minEndStr: string; intervalDescription: string } {
229
+ let minEndStr = addDurationToString(executionStart, { days: intervalDays })
230
+
231
+ if (maxDrift) {
232
+ minEndStr = addDurationToString(minEndStr, negateDuration(maxDrift))
233
+ }
234
+
235
+ const intervalDescription = `${intervalDays} day${intervalDays > 1 ? 's' : ''}${maxDrift ? ' - maxDrift' : ''}`
236
+ return { minEndStr, intervalDescription }
237
+ }
238
+
239
+ /**
240
+ * Validate that executionEnd allows at least one execution for recurring jobs
241
+ * Based on ServiceNow's "Ensure Valid Schedule" business rules
242
+ * @param executionStart - Start datetime string
243
+ * @param executionEnd - End datetime string
244
+ * @param frequency - Type of recurring schedule
245
+ * @param executionIntervalShape - Shape containing executionInterval duration (for periodically jobs)
246
+ * @param maxDriftShape - Shape containing maxDrift duration
247
+ * @returns Object with minEndStr and intervalDescription if validation is needed, undefined otherwise
248
+ */
249
+ function validateRecurringJobSchedule(
250
+ executionStart: string,
251
+ executionEnd: string,
252
+ frequency: string,
253
+ executionIntervalShape: Shape,
254
+ maxDriftShape: Shape
255
+ ): { minEndStr: string | undefined; intervalDescription: string | undefined } | undefined {
256
+ if (frequency === 'once' || frequency === 'on_demand') {
257
+ return
258
+ }
259
+
260
+ const maxDrift = maxDriftShape.is(DurationShape) ? maxDriftShape.as(DurationShape).getDuration() : undefined
261
+
262
+ let minEndStr: string | undefined
263
+ let intervalDescription: string | undefined
264
+
265
+ if (frequency === 'periodically' && executionIntervalShape.is(DurationShape)) {
266
+ const duration = executionIntervalShape.as(DurationShape).getDuration()
267
+ const result = calculatePeriodicallyMinEndDate(executionStart, duration, maxDrift)
268
+ minEndStr = result.minEndStr
269
+ intervalDescription = result.intervalDescription
270
+ } else if (frequency === 'monthly' || frequency === 'week_in_month') {
271
+ const result = calculateMonthlyMinEndDate(executionStart, maxDrift)
272
+ minEndStr = result.minEndStr
273
+ intervalDescription = result.intervalDescription
274
+ } else {
275
+ const intervalDays = calculateRecurringInterval(frequency)
276
+ if (intervalDays) {
277
+ const result = calculateFixedIntervalMinEndDate(executionStart, intervalDays, maxDrift)
278
+ minEndStr = result.minEndStr
279
+ intervalDescription = result.intervalDescription
280
+ }
281
+ }
282
+
283
+ if (minEndStr && executionEnd < minEndStr) {
284
+ return { minEndStr, intervalDescription }
285
+ }
286
+
287
+ return undefined
288
+ }
289
+
290
+ export const ScheduledScriptPlugin = Plugin.create({
291
+ name: 'ScheduledScriptPlugin',
292
+ docs: [createSdkDocEntry('ScheduledScript', ['sysauto_script'])],
293
+ records: {
294
+ sysauto_script: {
295
+ async toShape(record, { transform }) {
296
+ const scriptValue = record.get('script').ifString()?.ifNotEmpty()
297
+ const script = scriptValue
298
+ ? await NowIncludeShape.fromRecord(record, record.get('script'), transform)
299
+ : undefined
300
+ const timeZone = record.get('time_zone').ifString()?.ifNotEmpty()?.getValue()
301
+
302
+ return {
303
+ success: true,
304
+ value: new CallExpressionShape({
305
+ source: record,
306
+ callee: 'ScheduledScript',
307
+ args: [
308
+ record.transform(({ $ }) => ({
309
+ $id: $.val(NowIdShape.from(record)),
310
+ name: $,
311
+ active: $.from('active').toBoolean().def(true),
312
+ conditional: $.toBoolean().def(false),
313
+ condition: $.def(''),
314
+
315
+ // Offset configuration
316
+ offset: $.map((v) => {
317
+ const stringShape = v.ifString()?.ifNotEmpty()
318
+ if (!stringShape) {
319
+ return undefined
320
+ }
321
+ return DurationShape.from(record, stringShape)
322
+ }),
323
+ offsetType: $.from('offset_type').map((v) => {
324
+ const value = v.ifString()?.getValue()
325
+ // Map: 1='past', 2='future', 0=undefined (no offset)
326
+ if (!value || value === '0') {
327
+ return undefined
328
+ }
329
+ return offsetTypeMap.get(value)
330
+ }),
331
+
332
+ // Run as configuration
333
+ runAs: $.from('run_as').def(''),
334
+ userTimeZone: $.from('run_as_tz').def(''),
335
+
336
+ // Schedule type and timing
337
+ frequency: $.from('run_type'),
338
+ dayOfWeek: $.from('run_dayofweek').map((v) => {
339
+ const val = v.ifString()?.getValue()
340
+ return val ? dayOfWeekMap.get(val) : undefined
341
+ }),
342
+ daysOfWeek: $.from('run_daysofweek').map((v) => {
343
+ const val = v.ifString()?.getValue()
344
+ if (!val) {
345
+ return undefined
346
+ }
347
+ // Convert numeric string like '1234' to array of day names
348
+ const days = val
349
+ .split('')
350
+ .map((num) => dayOfWeekMap.get(num))
351
+ .filter(Boolean)
352
+ return days.length > 0 ? days : undefined
353
+ }),
354
+ dayOfMonth: $.from('run_dayofmonth').map((v) => {
355
+ const val = v.ifString()?.ifNotEmpty()
356
+ return val ? val.toNumber() : undefined
357
+ }),
358
+ weekInMonth: $.from('run_weekinmonth').map((v) => {
359
+ const val = v.ifString()?.ifNotEmpty()
360
+ return val ? val.toNumber() : undefined
361
+ }),
362
+ month: $.from('run_month').map((v) => {
363
+ const val = v.ifString()?.ifNotEmpty()
364
+ return val ? val.toNumber() : undefined
365
+ }),
366
+
367
+ // Time and duration configuration
368
+ executionTime: $.from('run_time').map((v) => {
369
+ const stringShape = v.ifString()?.ifNotEmpty()
370
+ if (!stringShape) {
371
+ return undefined
372
+ }
373
+ // Get timezone from time_zone field
374
+
375
+ // If timezone is 'floating', treat it as UTC for TimeShape conversion
376
+ const tz = timeZone === 'floating' ? 'UTC' : timeZone
377
+ // Convert to TimeShape with timezone
378
+ const timeShape = TimeShape.from(record, stringShape, tz)
379
+ const timeData = timeShape.getTimeData()
380
+ // Return undefined if Time object would be empty (no hours, minutes, or seconds)
381
+ if (!timeData.hours && !timeData.minutes && !timeData.seconds) {
382
+ return undefined
383
+ }
384
+ return timeShape
385
+ }),
386
+ executionInterval: $.from('run_period').map((v) => {
387
+ const stringShape = v.ifString()?.ifNotEmpty()
388
+ if (!stringShape) {
389
+ return undefined
390
+ }
391
+ return DurationShape.from(record, stringShape)
392
+ }),
393
+ executionStart: $.from('run_start').map((v) => {
394
+ const stringShape = v.ifString()?.ifNotEmpty()
395
+ if (stringShape) {
396
+ return convertXMLToDateTime(stringShape.getValue(), timeZone)
397
+ }
398
+ return undefined
399
+ }),
400
+ executionEnd: $.from('run_end').map((v) => {
401
+ const stringShape = v.ifString()?.ifNotEmpty()
402
+ if (stringShape) {
403
+ return convertXMLToDateTime(stringShape.getValue(), timeZone)
404
+ }
405
+ return undefined
406
+ }),
407
+
408
+ maxDrift: $.from('max_drift').map((v) => {
409
+ const stringShape = v.ifString()?.ifNotEmpty()
410
+ if (!stringShape) {
411
+ return undefined
412
+ }
413
+ return DurationShape.from(record, stringShape)
414
+ }),
415
+
416
+ // Additional scheduling options
417
+ repeatEvery: $.from('repeat_every').map((v) =>
418
+ v.ifString()?.isEmpty() || v.isUndefined() ? undefined : v.toNumber().getValue()
419
+ ),
420
+ upgradeSafe: $.from('upgrade_safe').toBoolean().def(false),
421
+ timeZone: $.from('time_zone').map((v) => {
422
+ const val = v.ifString()?.getValue()
423
+ return val || undefined
424
+ }),
425
+ businessCalendar: $.from('business_calendar').def(''),
426
+ advanced: $.toBoolean().def(false),
427
+
428
+ // Protection policy
429
+ protectionPolicy: $.from('sys_policy').map((v) => {
430
+ const val = v.ifString()?.ifNotEmpty()?.getValue()
431
+ // Only return valid values: 'read' or 'protected'
432
+ return val === 'read' || val === 'protected' ? val : undefined
433
+ }),
434
+
435
+ // Script
436
+ script: $.val(script),
437
+ })),
438
+ ],
439
+ }),
440
+ }
441
+ },
442
+ },
443
+ },
444
+ shapes: [
445
+ {
446
+ shape: CallExpressionShape,
447
+ fileTypes: ['fluent'],
448
+ async toRecord(callExpression, { factory, diagnostics, config }) {
449
+ if (callExpression.getCallee() !== 'ScheduledScript') {
450
+ return { success: false }
451
+ }
452
+
453
+ const args = callExpression.getArgument(0).asObject()
454
+
455
+ // Check if script is unresolved module
456
+ if (args.get('script').isUnresolved()) {
457
+ diagnostics.error(
458
+ args.get('script').getOriginalNode(),
459
+ `Unable to resolve the script reference, ensure the imported module is within the ${config.serverModulesDir} directory.`
460
+ )
461
+ }
462
+
463
+ // Validate executionInterval is defined when frequency is 'periodically'
464
+ const frequency = args.get('frequency').ifString()?.getValue()
465
+ if (frequency === 'periodically' && args.get('executionInterval').isUndefined()) {
466
+ diagnostics.error(
467
+ args.get('frequency'),
468
+ `executionInterval must be defined when frequency is 'periodically'`
469
+ )
470
+ }
471
+
472
+ // Validate daysOfWeek is defined when frequency is 'weekly'
473
+ if (frequency === 'weekly' && args.get('daysOfWeek').isUndefined()) {
474
+ diagnostics.error(args.get('frequency'), `daysOfWeek must be defined when frequency is 'weekly'`)
475
+ }
476
+
477
+ // Validate businessCalendar is not empty when frequency is business calendar related
478
+ const businessCalendarArg = args.get('businessCalendar')
479
+ const businessCalendar = toReference(businessCalendarArg)
480
+
481
+ if (
482
+ (frequency === 'business_calendar_start' || frequency === 'business_calendar_end') &&
483
+ !businessCalendar
484
+ ) {
485
+ diagnostics.error(
486
+ businessCalendarArg,
487
+ `businessCalendar cannot be empty when frequency is '${frequency}'. Provide a valid business calendar reference.`
488
+ )
489
+ }
490
+
491
+ // Validate executionStart datetime format
492
+ const startDate = args.get('executionStart').ifString()?.getValue()
493
+
494
+ if (startDate && !/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/.test(startDate)) {
495
+ diagnostics.error(
496
+ args.get('executionStart'),
497
+ `Invalid datetime format for executionStart: '${startDate}'. Expected format: 'YYYY-MM-DD HH:MM:SS' (e.g., '2024-01-01 00:00:00')`
498
+ )
499
+ }
500
+
501
+ // Validate executionEnd datetime format
502
+ const endDate = args.get('executionEnd').ifString()?.getValue()
503
+
504
+ if (endDate) {
505
+ if (!/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/.test(endDate)) {
506
+ diagnostics.error(
507
+ args.get('executionEnd'),
508
+ `Invalid datetime format for executionEnd: '${endDate}'. Expected format: 'YYYY-MM-DD HH:MM:SS' (e.g., '2024-12-31 23:59:59')`
509
+ )
510
+ }
511
+ // Validate executionStart and executionEnd relationship
512
+ else if (startDate) {
513
+ const start = new Date(startDate)
514
+ const end = new Date(endDate)
515
+
516
+ if (end <= start) {
517
+ diagnostics.error(
518
+ args.get('executionEnd'),
519
+ `executionEnd ('${endDate}') must be after executionStart ('${startDate}')`
520
+ )
521
+ }
522
+
523
+ // Validate recurring job schedule allows at least one execution
524
+ else {
525
+ const validationResult = validateRecurringJobSchedule(
526
+ startDate,
527
+ endDate,
528
+ frequency ?? 'daily',
529
+ args.get('executionInterval'),
530
+ args.get('maxDrift')
531
+ )
532
+
533
+ if (validationResult) {
534
+ diagnostics.error(
535
+ args.get('executionEnd'),
536
+ `executionEnd ('${endDate}') may not allow any executions for recurring job type '${frequency}'. ` +
537
+ `Minimum executionEnd should be at least '${validationResult.minEndStr}' (executionStart + ${validationResult.intervalDescription})`
538
+ )
539
+ }
540
+ }
541
+ }
542
+ }
543
+
544
+ // Check timezone before transformation
545
+ const timeZone = args.get('timeZone').ifString()?.getValue()
546
+
547
+ // Validate executionTime has timezone if ScheduledScript has timeZone
548
+ const executionTimeArg = args.get('executionTime')
549
+ if (timeZone && timeZone !== 'floating' && executionTimeArg.is(TimeShape)) {
550
+ const timeShape = executionTimeArg.as(TimeShape)
551
+ const timeShapeTimeZone = timeShape.getTimeZone()
552
+ if (!timeShapeTimeZone) {
553
+ diagnostics.error(
554
+ executionTimeArg,
555
+ `executionTime must include timezone when ScheduledScript timeZone is '${timeZone}'. ` +
556
+ `Use Time({ hours: ..., minutes: ..., }, '${timeZone}' }) instead of Time({ hours: ..., minutes: ... }).`
557
+ )
558
+ } else if (timeShapeTimeZone !== timeZone) {
559
+ diagnostics.error(
560
+ executionTimeArg,
561
+ `executionTime timezone '${timeShapeTimeZone}' does not match ScheduledScript timeZone '${timeZone}'. ` +
562
+ `They should be the same.`
563
+ )
564
+ }
565
+ }
566
+
567
+ // Calculate default entered_run_time based on timezone
568
+ const defaultRunTime = getDefaultRunTime(timeZone ?? '')
569
+
570
+ const record = await factory.createRecord({
571
+ source: callExpression,
572
+ table: 'sysauto_script',
573
+ explicitId: args.get('$id'),
574
+ properties: args.transform(({ $ }) => ({
575
+ name: $,
576
+ active: $.from('active').def(true),
577
+ conditional: $.def(false),
578
+ condition: $.toCdata(),
579
+
580
+ // Offset configuration
581
+ offset: $.map((v) => v.toString()),
582
+ offset_type: $.from('offsetType').map((v) => {
583
+ const val = v.ifString()?.getValue()
584
+ return val ? reverseOffsetTypeMap.get(val) : '0'
585
+ }),
586
+
587
+ // Run as configuration
588
+ run_as: $.from('runAs').map(toReference),
589
+ run_as_tz: $.from('userTimeZone'),
590
+
591
+ // Schedule type and timing
592
+ run_type: $.from('frequency').def('daily'),
593
+ run_dayofweek: $.from('dayOfWeek').map((v) => {
594
+ const val = v.ifString()?.getValue()
595
+ return val ? reverseDayOfWeekMap.get(val) : '1'
596
+ }),
597
+ run_daysofweek: $.from('daysOfWeek').map((v) => {
598
+ // Convert array of day names to numeric string like '1234'
599
+ if (v.isArray()) {
600
+ const nums = v
601
+ .asArray()
602
+ .map((item) => {
603
+ const dayName = item.ifString()?.getValue()
604
+ return dayName ? reverseDayOfWeekMap.get(dayName) : null
605
+ })
606
+ .filter(Boolean)
607
+ return nums.length > 0 ? nums.join('') : undefined
608
+ }
609
+ return undefined
610
+ }),
611
+ run_dayofmonth: $.from('dayOfMonth').def('1'),
612
+ run_weekinmonth: $.from('weekInMonth').def('1'),
613
+ run_month: $.from('month').def('1'),
614
+
615
+ // Time and duration configuration
616
+ run_time: $.from('executionTime').map((v) => {
617
+ if (v.isUndefined()) {
618
+ return defaultRunTime
619
+ }
620
+ // If timezone is floating, return the actual time without UTC conversion
621
+ if (timeZone === 'floating' && v.is(TimeShape)) {
622
+ const timeData = v.as(TimeShape).getTimeData()
623
+ return formatTimeDataToDateTime(timeData)
624
+ }
625
+ return v.toString()
626
+ }),
627
+ entered_time: $.from('executionTime')
628
+ .map((v) => {
629
+ if (v.is(TimeShape)) {
630
+ const timeData = v.as(TimeShape).getTimeData()
631
+ return formatTimeDataToDateTime(timeData)
632
+ }
633
+ return undefined
634
+ })
635
+ .def('1970-01-01 00:00:00'),
636
+ run_period: $.from('executionInterval').map((v) => v.toString()),
637
+ run_start: $.from('executionStart')
638
+ .map((v) => {
639
+ const dateTimeStr = v.ifString()?.getValue()
640
+ if (dateTimeStr) {
641
+ return dateTimeFieldToXML(dateTimeStr, timeZone)
642
+ }
643
+ return undefined
644
+ })
645
+ .def(formatToUTC()),
646
+ run_end: $.from('executionEnd').map((v) => {
647
+ const dateTimeStr = v.ifString()?.getValue()
648
+ if (!dateTimeStr) {
649
+ return undefined
650
+ }
651
+ return dateTimeFieldToXML(dateTimeStr, timeZone)
652
+ }),
653
+ entered_run_start: $.from('executionStart').map((v) => {
654
+ const dateTimeStr = v.ifString()?.getValue()
655
+ if (dateTimeStr && timeZone) {
656
+ return dateTimeStr
657
+ }
658
+ return undefined
659
+ }),
660
+ entered_run_end: $.from('executionEnd').map((v) => {
661
+ const dateTimeStr = v.ifString()?.getValue()
662
+ if (dateTimeStr && timeZone) {
663
+ return dateTimeStr
664
+ }
665
+ return undefined
666
+ }),
667
+ max_drift: $.from('maxDrift').map((v) => v.toString()),
668
+
669
+ // Additional scheduling options
670
+ repeat_every: $.from('repeatEvery'),
671
+ upgrade_safe: $.from('upgradeSafe').def(false),
672
+ time_zone: $.from('timeZone'),
673
+ business_calendar: $.val(businessCalendar),
674
+ advanced: $.def(false),
675
+
676
+ // Protection policy
677
+ sys_policy: $.from('protectionPolicy'),
678
+
679
+ // Script - handle both module functions and strings
680
+ script: $.map(
681
+ (v) => v.if(ModuleFunctionShape)?.toString((n) => `${n}({{PARAMS}})`, []) ?? v
682
+ ).toCdata(),
683
+ })),
684
+ })
685
+
686
+ return { success: true, value: record }
687
+ },
688
+ },
689
+ ],
690
+ })