@servicenow/sdk-build-plugins 4.4.0 → 4.5.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 (287) 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 +1 -0
  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-plugin-helpers.d.ts +82 -2
  34. package/dist/flow/flow-logic/flow-logic-plugin-helpers.js +48 -40
  35. package/dist/flow/flow-logic/flow-logic-plugin-helpers.js.map +1 -1
  36. package/dist/flow/flow-logic/flow-logic-plugin.js +1 -0
  37. package/dist/flow/flow-logic/flow-logic-plugin.js.map +1 -1
  38. package/dist/flow/plugins/approval-rules-plugin.js +1 -0
  39. package/dist/flow/plugins/approval-rules-plugin.js.map +1 -1
  40. package/dist/flow/plugins/flow-action-definition-plugin.js +4 -2
  41. package/dist/flow/plugins/flow-action-definition-plugin.js.map +1 -1
  42. package/dist/flow/plugins/flow-data-pill-plugin.js +1 -0
  43. package/dist/flow/plugins/flow-data-pill-plugin.js.map +1 -1
  44. package/dist/flow/plugins/flow-definition-plugin.js +8 -3
  45. package/dist/flow/plugins/flow-definition-plugin.js.map +1 -1
  46. package/dist/flow/plugins/flow-diagnostics-plugin.js +1 -0
  47. package/dist/flow/plugins/flow-diagnostics-plugin.js.map +1 -1
  48. package/dist/flow/plugins/flow-instance-plugin.js +68 -12
  49. package/dist/flow/plugins/flow-instance-plugin.js.map +1 -1
  50. package/dist/flow/plugins/flow-trigger-instance-plugin.js +1 -0
  51. package/dist/flow/plugins/flow-trigger-instance-plugin.js.map +1 -1
  52. package/dist/flow/plugins/inline-script-plugin.js +1 -0
  53. package/dist/flow/plugins/inline-script-plugin.js.map +1 -1
  54. package/dist/flow/plugins/step-definition-plugin.js +3 -2
  55. package/dist/flow/plugins/step-definition-plugin.js.map +1 -1
  56. package/dist/flow/plugins/step-instance-plugin.js +1 -0
  57. package/dist/flow/plugins/step-instance-plugin.js.map +1 -1
  58. package/dist/flow/plugins/trigger-plugin.js +2 -0
  59. package/dist/flow/plugins/trigger-plugin.js.map +1 -1
  60. package/dist/flow/plugins/wfa-datapill-plugin.js +1 -0
  61. package/dist/flow/plugins/wfa-datapill-plugin.js.map +1 -1
  62. package/dist/flow/post-install.d.ts +2 -0
  63. package/dist/flow/post-install.js +58 -0
  64. package/dist/flow/post-install.js.map +1 -0
  65. package/dist/flow/utils/complex-objects.js +4 -2
  66. package/dist/flow/utils/complex-objects.js.map +1 -1
  67. package/dist/flow/utils/flow-constants.d.ts +24 -0
  68. package/dist/flow/utils/flow-constants.js +29 -2
  69. package/dist/flow/utils/flow-constants.js.map +1 -1
  70. package/dist/flow/utils/flow-to-xml.d.ts +3 -2
  71. package/dist/flow/utils/flow-to-xml.js +3 -4
  72. package/dist/flow/utils/flow-to-xml.js.map +1 -1
  73. package/dist/flow/utils/label-cache-processor.d.ts +5 -0
  74. package/dist/flow/utils/label-cache-processor.js +14 -2
  75. package/dist/flow/utils/label-cache-processor.js.map +1 -1
  76. package/dist/flow/utils/service-catalog.js +5 -1
  77. package/dist/flow/utils/service-catalog.js.map +1 -1
  78. package/dist/form-plugin.d.ts +2 -0
  79. package/dist/form-plugin.js +1134 -0
  80. package/dist/form-plugin.js.map +1 -0
  81. package/dist/html-import-plugin.js +1 -0
  82. package/dist/html-import-plugin.js.map +1 -1
  83. package/dist/import-sets-plugin.js +2 -0
  84. package/dist/import-sets-plugin.js.map +1 -1
  85. package/dist/index.d.ts +9 -0
  86. package/dist/index.js +13 -1
  87. package/dist/index.js.map +1 -1
  88. package/dist/instance-scan-plugin.d.ts +2 -0
  89. package/dist/instance-scan-plugin.js +298 -0
  90. package/dist/instance-scan-plugin.js.map +1 -0
  91. package/dist/json-plugin.js +1 -0
  92. package/dist/json-plugin.js.map +1 -1
  93. package/dist/list-plugin.js +1 -0
  94. package/dist/list-plugin.js.map +1 -1
  95. package/dist/now-attach-plugin.js +1 -0
  96. package/dist/now-attach-plugin.js.map +1 -1
  97. package/dist/now-config-plugin.js +659 -51
  98. package/dist/now-config-plugin.js.map +1 -1
  99. package/dist/now-id-plugin.js +1 -0
  100. package/dist/now-id-plugin.js.map +1 -1
  101. package/dist/now-include-plugin.js +1 -0
  102. package/dist/now-include-plugin.js.map +1 -1
  103. package/dist/now-ref-plugin.js +1 -0
  104. package/dist/now-ref-plugin.js.map +1 -1
  105. package/dist/now-unresolved-plugin.js +1 -0
  106. package/dist/now-unresolved-plugin.js.map +1 -1
  107. package/dist/package-json-plugin.js +1 -0
  108. package/dist/package-json-plugin.js.map +1 -1
  109. package/dist/property-plugin.js +3 -1
  110. package/dist/property-plugin.js.map +1 -1
  111. package/dist/record-plugin.d.ts +30 -0
  112. package/dist/record-plugin.js +37 -1
  113. package/dist/record-plugin.js.map +1 -1
  114. package/dist/repack/lint/Rules.d.ts +11 -2
  115. package/dist/repack/lint/Rules.js +160 -16
  116. package/dist/repack/lint/Rules.js.map +1 -1
  117. package/dist/repack/lint/index.d.ts +10 -5
  118. package/dist/repack/lint/index.js +76 -50
  119. package/dist/repack/lint/index.js.map +1 -1
  120. package/dist/rest-api-plugin.js +14 -0
  121. package/dist/rest-api-plugin.js.map +1 -1
  122. package/dist/role-plugin.js +1 -0
  123. package/dist/role-plugin.js.map +1 -1
  124. package/dist/schedule-script/index.d.ts +1 -0
  125. package/dist/schedule-script/index.js +18 -0
  126. package/dist/schedule-script/index.js.map +1 -0
  127. package/dist/schedule-script/scheduled-script-plugin.d.ts +2 -0
  128. package/dist/schedule-script/scheduled-script-plugin.js +551 -0
  129. package/dist/schedule-script/scheduled-script-plugin.js.map +1 -0
  130. package/dist/schedule-script/timeZoneConverter.d.ts +61 -0
  131. package/dist/schedule-script/timeZoneConverter.js +170 -0
  132. package/dist/schedule-script/timeZoneConverter.js.map +1 -0
  133. package/dist/script-action-plugin.js +2 -0
  134. package/dist/script-action-plugin.js.map +1 -1
  135. package/dist/script-include-plugin.js +2 -0
  136. package/dist/script-include-plugin.js.map +1 -1
  137. package/dist/server-module-plugin/index.js +13 -2
  138. package/dist/server-module-plugin/index.js.map +1 -1
  139. package/dist/service-catalog/catalog-clientscript-plugin.js +2 -0
  140. package/dist/service-catalog/catalog-clientscript-plugin.js.map +1 -1
  141. package/dist/service-catalog/catalog-item-plugin.js +2 -0
  142. package/dist/service-catalog/catalog-item-plugin.js.map +1 -1
  143. package/dist/service-catalog/catalog-ui-policy-plugin.js +2 -0
  144. package/dist/service-catalog/catalog-ui-policy-plugin.js.map +1 -1
  145. package/dist/service-catalog/sc-record-producer-plugin.js +2 -0
  146. package/dist/service-catalog/sc-record-producer-plugin.js.map +1 -1
  147. package/dist/service-catalog/service-catalog-diagnostics.d.ts +6 -0
  148. package/dist/service-catalog/service-catalog-diagnostics.js +20 -0
  149. package/dist/service-catalog/service-catalog-diagnostics.js.map +1 -1
  150. package/dist/service-catalog/shape-to-record.js +7 -2
  151. package/dist/service-catalog/shape-to-record.js.map +1 -1
  152. package/dist/service-catalog/variable-set-plugin.js +2 -0
  153. package/dist/service-catalog/variable-set-plugin.js.map +1 -1
  154. package/dist/service-portal/angular-provider-plugin.js +2 -0
  155. package/dist/service-portal/angular-provider-plugin.js.map +1 -1
  156. package/dist/service-portal/dependency-plugin.js +5 -31
  157. package/dist/service-portal/dependency-plugin.js.map +1 -1
  158. package/dist/service-portal/menu-plugin.d.ts +2 -0
  159. package/dist/service-portal/menu-plugin.js +353 -0
  160. package/dist/service-portal/menu-plugin.js.map +1 -0
  161. package/dist/service-portal/page-plugin.d.ts +2 -0
  162. package/dist/service-portal/page-plugin.js +702 -0
  163. package/dist/service-portal/page-plugin.js.map +1 -0
  164. package/dist/service-portal/portal-plugin.d.ts +2 -0
  165. package/dist/service-portal/portal-plugin.js +296 -0
  166. package/dist/service-portal/portal-plugin.js.map +1 -0
  167. package/dist/service-portal/theme-plugin.d.ts +2 -0
  168. package/dist/service-portal/theme-plugin.js +112 -0
  169. package/dist/service-portal/theme-plugin.js.map +1 -0
  170. package/dist/service-portal/utils.d.ts +8 -0
  171. package/dist/service-portal/utils.js +50 -0
  172. package/dist/service-portal/utils.js.map +1 -0
  173. package/dist/service-portal/widget-plugin.js +45 -8
  174. package/dist/service-portal/widget-plugin.js.map +1 -1
  175. package/dist/sla-plugin.js +2 -0
  176. package/dist/sla-plugin.js.map +1 -1
  177. package/dist/static-content-plugin.js +1 -0
  178. package/dist/static-content-plugin.js.map +1 -1
  179. package/dist/table-plugin.js +1 -0
  180. package/dist/table-plugin.js.map +1 -1
  181. package/dist/ui-action-plugin.js +2 -0
  182. package/dist/ui-action-plugin.js.map +1 -1
  183. package/dist/ui-page-plugin.js +33 -8
  184. package/dist/ui-page-plugin.js.map +1 -1
  185. package/dist/ui-policy-plugin.js +1 -0
  186. package/dist/ui-policy-plugin.js.map +1 -1
  187. package/dist/user-preference-plugin.js +2 -0
  188. package/dist/user-preference-plugin.js.map +1 -1
  189. package/dist/utils.d.ts +20 -2
  190. package/dist/utils.js +34 -3
  191. package/dist/utils.js.map +1 -1
  192. package/dist/ux-list-menu-config-plugin.js +2 -0
  193. package/dist/ux-list-menu-config-plugin.js.map +1 -1
  194. package/dist/view-plugin.js +1 -0
  195. package/dist/view-plugin.js.map +1 -1
  196. package/dist/workspace-plugin.js +2 -0
  197. package/dist/workspace-plugin.js.map +1 -1
  198. package/package.json +10 -11
  199. package/src/_types/eslint-community-eslint-utils.d.ts +15 -0
  200. package/src/acl-plugin.ts +97 -8
  201. package/src/applicability-plugin.ts +2 -0
  202. package/src/application-menu-plugin.ts +2 -0
  203. package/src/arrow-function-plugin.ts +128 -13
  204. package/src/atf/test-plugin.ts +2 -0
  205. package/src/basic-syntax-plugin.ts +21 -0
  206. package/src/call-expression-plugin.ts +1 -0
  207. package/src/claims-plugin.ts +1 -0
  208. package/src/client-script-plugin.ts +2 -1
  209. package/src/column-plugin.ts +1 -0
  210. package/src/cross-scope-privilege-plugin.ts +2 -1
  211. package/src/dashboard/dashboard-plugin.ts +2 -0
  212. package/src/data-plugin.ts +1 -0
  213. package/src/email-notification-plugin.ts +3 -23
  214. package/src/flow/constants/flow-plugin-constants.ts +1 -1
  215. package/src/flow/flow-logic/flow-logic-plugin-helpers.ts +47 -45
  216. package/src/flow/flow-logic/flow-logic-plugin.ts +1 -0
  217. package/src/flow/plugins/approval-rules-plugin.ts +1 -0
  218. package/src/flow/plugins/flow-action-definition-plugin.ts +4 -2
  219. package/src/flow/plugins/flow-data-pill-plugin.ts +1 -0
  220. package/src/flow/plugins/flow-definition-plugin.ts +10 -4
  221. package/src/flow/plugins/flow-diagnostics-plugin.ts +1 -0
  222. package/src/flow/plugins/flow-instance-plugin.ts +103 -14
  223. package/src/flow/plugins/flow-trigger-instance-plugin.ts +1 -0
  224. package/src/flow/plugins/inline-script-plugin.ts +1 -0
  225. package/src/flow/plugins/step-definition-plugin.ts +3 -2
  226. package/src/flow/plugins/step-instance-plugin.ts +1 -0
  227. package/src/flow/plugins/trigger-plugin.ts +2 -0
  228. package/src/flow/plugins/wfa-datapill-plugin.ts +1 -0
  229. package/src/flow/post-install.ts +92 -0
  230. package/src/flow/utils/complex-objects.ts +10 -2
  231. package/src/flow/utils/flow-constants.ts +30 -1
  232. package/src/flow/utils/flow-to-xml.ts +4 -4
  233. package/src/flow/utils/label-cache-processor.ts +14 -2
  234. package/src/flow/utils/service-catalog.ts +5 -2
  235. package/src/form-plugin.ts +1411 -0
  236. package/src/html-import-plugin.ts +1 -0
  237. package/src/import-sets-plugin.ts +2 -0
  238. package/src/index.ts +9 -0
  239. package/src/instance-scan-plugin.ts +318 -0
  240. package/src/json-plugin.ts +1 -0
  241. package/src/list-plugin.ts +2 -1
  242. package/src/now-attach-plugin.ts +1 -0
  243. package/src/now-config-plugin.ts +833 -53
  244. package/src/now-id-plugin.ts +1 -0
  245. package/src/now-include-plugin.ts +1 -0
  246. package/src/now-ref-plugin.ts +1 -0
  247. package/src/now-unresolved-plugin.ts +1 -0
  248. package/src/package-json-plugin.ts +1 -0
  249. package/src/property-plugin.ts +3 -1
  250. package/src/record-plugin.ts +42 -2
  251. package/src/repack/lint/Rules.ts +171 -22
  252. package/src/repack/lint/index.ts +80 -56
  253. package/src/rest-api-plugin.ts +21 -1
  254. package/src/role-plugin.ts +2 -1
  255. package/src/schedule-script/index.ts +1 -0
  256. package/src/schedule-script/scheduled-script-plugin.ts +679 -0
  257. package/src/schedule-script/timeZoneConverter.ts +188 -0
  258. package/src/script-action-plugin.ts +2 -0
  259. package/src/script-include-plugin.ts +2 -0
  260. package/src/server-module-plugin/index.ts +14 -2
  261. package/src/service-catalog/catalog-clientscript-plugin.ts +2 -0
  262. package/src/service-catalog/catalog-item-plugin.ts +2 -0
  263. package/src/service-catalog/catalog-ui-policy-plugin.ts +2 -0
  264. package/src/service-catalog/sc-record-producer-plugin.ts +2 -0
  265. package/src/service-catalog/service-catalog-diagnostics.ts +30 -0
  266. package/src/service-catalog/shape-to-record.ts +8 -2
  267. package/src/service-catalog/variable-set-plugin.ts +2 -0
  268. package/src/service-portal/angular-provider-plugin.ts +2 -0
  269. package/src/service-portal/dependency-plugin.ts +6 -53
  270. package/src/service-portal/menu-plugin.ts +435 -0
  271. package/src/service-portal/page-plugin.ts +830 -0
  272. package/src/service-portal/portal-plugin.ts +319 -0
  273. package/src/service-portal/theme-plugin.ts +135 -0
  274. package/src/service-portal/utils.ts +69 -0
  275. package/src/service-portal/widget-plugin.ts +79 -9
  276. package/src/sla-plugin.ts +2 -0
  277. package/src/static-content-plugin.ts +1 -0
  278. package/src/table-plugin.ts +2 -1
  279. package/src/ui-action-plugin.ts +2 -0
  280. package/src/ui-page-plugin.ts +34 -8
  281. package/src/ui-policy-plugin.ts +2 -1
  282. package/src/user-preference-plugin.ts +2 -0
  283. package/src/utils.ts +42 -2
  284. package/src/ux-list-menu-config-plugin.ts +2 -0
  285. package/src/view-plugin.ts +1 -0
  286. package/src/workspace-plugin.ts +2 -0
  287. package/src/_types/eslint-plugin-es-x.d.ts +0 -17
@@ -0,0 +1,188 @@
1
+ /**
2
+ * Formats a Date object to ServiceNow UTC datetime format (YYYY-MM-DD HH:MM:SS)
3
+ * @param date - The Date object to format (defaults to current time)
4
+ * @returns Formatted UTC datetime string
5
+ *
6
+ * @example
7
+ * const formatted = formatToUTC(new Date());
8
+ * // Returns: '1970-01-01 09:45:00'
9
+ *
10
+ * @example
11
+ * const formatted = formatToUTC();
12
+ * // Returns current time in UTC: '2026-02-27 07:43:00'
13
+ */
14
+ export function formatToUTC(date: Date = new Date()): string {
15
+ const year = date.getUTCFullYear()
16
+ const month = String(date.getUTCMonth() + 1).padStart(2, '0')
17
+ const day = String(date.getUTCDate()).padStart(2, '0')
18
+ const hour = String(date.getUTCHours()).padStart(2, '0')
19
+ const minute = String(date.getUTCMinutes()).padStart(2, '0')
20
+ const second = String(date.getUTCSeconds()).padStart(2, '0')
21
+
22
+ return `${year}-${month}-${day} ${hour}:${minute}:${second}`
23
+ }
24
+
25
+ /**
26
+ * Converts a datetime string from a specified timezone to UTC.
27
+ * Similar to timeFieldToXML but handles full date and time, not just time of day.
28
+ *
29
+ * @param dateTimeStr - DateTime string in format 'YYYY-MM-DD HH:MM:SS'
30
+ * @param timeZone - Optional IANA timezone string (e.g., 'America/New_York', 'Asia/Kolkata'). Defaults to system timezone.
31
+ * @returns Formatted UTC datetime string in 'YYYY-MM-DD HH:MM:SS' format
32
+ *
33
+ * @example
34
+ * // Convert '2026-03-02 14:30:00' from IST to UTC
35
+ * const utcDate = dateTimeFieldToXML('2026-03-02 14:30:00', 'Asia/Kolkata')
36
+ * // Returns '2026-03-02 09:00:00'
37
+ */
38
+ export function dateTimeFieldToXML(dateTimeStr: string, timeZone?: string): string {
39
+ // Parse the datetime string
40
+ const match = dateTimeStr.match(/^(\d{4})-(\d{2})-(\d{2})\s+(\d{2}):(\d{2}):(\d{2})$/)
41
+ if (!match) {
42
+ throw new Error(`Invalid datetime format: ${dateTimeStr}. Expected format: YYYY-MM-DD HH:MM:SS`)
43
+ }
44
+ // If timezone is 'floating' or not provided, use system timezone
45
+ const targetTimeZone =
46
+ timeZone === 'floating' || !timeZone ? Intl.DateTimeFormat().resolvedOptions().timeZone : timeZone
47
+
48
+ if (targetTimeZone === 'GMT' || targetTimeZone === 'UTC') {
49
+ return dateTimeStr
50
+ }
51
+
52
+ const year = parseInt(match[1]!, 10)
53
+ const month = parseInt(match[2]!, 10)
54
+ const day = parseInt(match[3]!, 10)
55
+ const hours = parseInt(match[4]!, 10)
56
+ const minutes = parseInt(match[5]!, 10)
57
+ const seconds = parseInt(match[6]!, 10)
58
+
59
+ const padZero = (n: number) => String(n).padStart(2, '0')
60
+
61
+ // Convert from specified timezone to UTC
62
+ // Create a reference date to calculate the timezone offset
63
+ const localDateStr = `${year}-${padZero(month)}-${padZero(day)}T${padZero(hours)}:${padZero(minutes)}:${padZero(seconds)}`
64
+
65
+ // Create a Date treating the input as UTC first
66
+ const utcDate = new Date(`${localDateStr}Z`)
67
+
68
+ // Get what this UTC time looks like in the target timezone
69
+ const formatter = new Intl.DateTimeFormat('en-US', {
70
+ timeZone: targetTimeZone,
71
+ year: 'numeric',
72
+ month: '2-digit',
73
+ day: '2-digit',
74
+ hour: '2-digit',
75
+ minute: '2-digit',
76
+ second: '2-digit',
77
+ hour12: false,
78
+ })
79
+
80
+ const parts = formatter.formatToParts(utcDate)
81
+ const dateParts: Record<string, string> = {}
82
+
83
+ parts.forEach((part) => {
84
+ if (part.type !== 'literal') {
85
+ dateParts[part.type] = part.value
86
+ }
87
+ })
88
+
89
+ // Calculate the difference between what we want and what we got
90
+ const targetYear = parseInt(dateParts['year']!, 10)
91
+ const targetMonth = parseInt(dateParts['month']!, 10)
92
+ const targetDay = parseInt(dateParts['day']!, 10)
93
+ const targetHour = parseInt(dateParts['hour']!, 10)
94
+ const targetMinute = parseInt(dateParts['minute']!, 10)
95
+ const targetSecond = parseInt(dateParts['second']!, 10)
96
+
97
+ // Calculate the offset in milliseconds
98
+ const wantedTime = new Date(year, month - 1, day, hours, minutes, seconds).getTime()
99
+ const gotTime = new Date(targetYear, targetMonth - 1, targetDay, targetHour, targetMinute, targetSecond).getTime()
100
+ const offset = gotTime - wantedTime
101
+
102
+ // Apply the offset to get the correct UTC time
103
+ const resultDate = new Date(utcDate.getTime() - offset)
104
+ return formatToUTC(resultDate)
105
+ }
106
+
107
+ /**
108
+ * Converts an XML datetime string (in UTC) to a datetime string in a specified timezone
109
+ * @param utcDateTimeStr - UTC datetime string in format 'YYYY-MM-DD HH:MM:SS'
110
+ * @param timeZone - Optional IANA timezone string (e.g., 'America/New_York', 'Asia/Kolkata'). If not provided, returns the UTC string as-is.
111
+ * @returns Datetime string in the specified timezone in 'YYYY-MM-DD HH:MM:SS' format
112
+ *
113
+ * @example
114
+ * // Convert '2026-03-02 09:00:00' UTC to IST
115
+ * const localDateTime = convertXMLToDateTime('2026-03-02 09:00:00', 'Asia/Kolkata')
116
+ * // Returns '2026-03-02 14:30:00'
117
+ *
118
+ * @example
119
+ * // Without timezone, returns the UTC string as-is
120
+ * const utcDateTime = convertXMLToDateTime('2026-03-02 09:00:00')
121
+ * // Returns '2026-03-02 09:00:00'
122
+ */
123
+ export function convertXMLToDateTime(utcDateTimeStr: string, timeZone?: string): string {
124
+ // Parse the UTC datetime string
125
+ const match = utcDateTimeStr.match(/^(\d{4})-(\d{2})-(\d{2})\s+(\d{2}):(\d{2}):(\d{2})$/)
126
+ if (!match) {
127
+ throw new Error(`Invalid datetime format: ${utcDateTimeStr}. Expected format: YYYY-MM-DD HH:MM:SS`)
128
+ }
129
+
130
+ // If timezone is 'floating' or not provided, use system timezone
131
+ const targetTimeZone =
132
+ timeZone === 'floating' || !timeZone ? Intl.DateTimeFormat().resolvedOptions().timeZone : timeZone
133
+
134
+ if (targetTimeZone === 'GMT' || targetTimeZone === 'UTC') {
135
+ return utcDateTimeStr
136
+ }
137
+
138
+ const year = parseInt(match[1]!, 10)
139
+ const month = parseInt(match[2]!, 10)
140
+ const day = parseInt(match[3]!, 10)
141
+ const hours = parseInt(match[4]!, 10)
142
+ const minutes = parseInt(match[5]!, 10)
143
+ const seconds = parseInt(match[6]!, 10)
144
+
145
+ // Create a Date object from the UTC datetime
146
+ const utcDate = new Date(Date.UTC(year, month - 1, day, hours, minutes, seconds))
147
+
148
+ // Format the date in the target timezone
149
+ const formatter = new Intl.DateTimeFormat('en-US', {
150
+ timeZone: targetTimeZone,
151
+ year: 'numeric',
152
+ month: '2-digit',
153
+ day: '2-digit',
154
+ hour: '2-digit',
155
+ minute: '2-digit',
156
+ second: '2-digit',
157
+ hour12: false,
158
+ })
159
+
160
+ const parts = formatter.formatToParts(utcDate)
161
+ const dateParts: Record<string, string> = {}
162
+
163
+ parts.forEach((part) => {
164
+ if (part.type !== 'literal') {
165
+ dateParts[part.type] = part.value
166
+ }
167
+ })
168
+
169
+ return `${dateParts['year']}-${dateParts['month']}-${dateParts['day']} ${dateParts['hour']}:${dateParts['minute']}:${dateParts['second']}`
170
+ }
171
+
172
+ /**
173
+ * Formats time data (hours, minutes, seconds) as a datetime string without timezone conversion.
174
+ * Used for storing the original user-entered time value in the 'entered_time' field.
175
+ *
176
+ * @param timeData - Object containing hours, minutes, and seconds
177
+ * @returns Formatted datetime string in 'YYYY-MM-DD HH:MM:SS' format with epoch date (1970-01-01)
178
+ *
179
+ * @example
180
+ * formatTimeDataToDateTime({ hours: 14, minutes: 30, seconds: 0 })
181
+ * // Returns '1970-01-01 14:30:00'
182
+ */
183
+ export function formatTimeDataToDateTime(timeData: { hours?: number; minutes?: number; seconds?: number }): string {
184
+ const hours = String(timeData.hours || 0).padStart(2, '0')
185
+ const minutes = String(timeData.minutes || 0).padStart(2, '0')
186
+ const seconds = String(timeData.seconds || 0).padStart(2, '0')
187
+ return `1970-01-01 ${hours}:${minutes}:${seconds}`
188
+ }
@@ -1,9 +1,11 @@
1
1
  import { CallExpressionShape, Plugin } from '@servicenow/sdk-build-core'
2
2
  import { NowIdShape } from './now-id-plugin'
3
3
  import { ModuleFunctionShape } from './server-module-plugin'
4
+ import { createSdkDocEntry } from './utils'
4
5
 
5
6
  export const ScriptActionPlugin = Plugin.create({
6
7
  name: 'ScriptActionPlugin',
8
+ docs: [createSdkDocEntry('ScriptAction', ['sysevent_script_action'])],
7
9
  records: {
8
10
  sysevent_script_action: {
9
11
  toShape(record) {
@@ -1,11 +1,13 @@
1
1
  import { CallExpressionShape, isSNScope, Plugin } from '@servicenow/sdk-build-core'
2
2
  import { NowIdShape } from './now-id-plugin'
3
3
  import { NowIncludeShape } from './now-include-plugin'
4
+ import { createSdkDocEntry } from './utils'
4
5
 
5
6
  const nameRegex = /^[a-zA-Z_$][0-9a-zA-Z_$]+$/
6
7
 
7
8
  export const ScriptIncludePlugin = Plugin.create({
8
9
  name: `ScriptIncludePlugin`,
10
+ docs: [createSdkDocEntry('ScriptInclude', ['sys_script_include'])],
9
11
  records: {
10
12
  sys_script_include: {
11
13
  async toShape(record, { transform }) {
@@ -351,6 +351,7 @@ function getModuleDependencyPath(
351
351
 
352
352
  export const ServerModulePlugin = Plugin.create({
353
353
  name: 'ServerModulePlugin',
354
+ docs: [],
354
355
  files: [
355
356
  {
356
357
  entryPoint: true,
@@ -432,6 +433,16 @@ export const ServerModulePlugin = Plugin.create({
432
433
  return { success: false }
433
434
  }
434
435
 
436
+ // Lint local module for Rhino compatibility (no Glide restrictions)
437
+ if (/\.(js|cjs|mjs|ts)$/.test(pathModule.extname(resolvedPath))) {
438
+ const { LocalModuleLint } = await import('../repack/lint/index.js')
439
+ const lint = new LocalModuleLint()
440
+ const lintResult = lint.check(content)
441
+ if (lintResult) {
442
+ diagnostics.error(file, `Unsupported APIs detected in module:\n${lintResult}`)
443
+ }
444
+ }
445
+
435
446
  const relativePath = pathModule.relative(project.getRootDir(), resolvedPath)
436
447
  const sysModulePath = NowConfig.moduleResolutionPath(config, packageJson, false, relativePath)
437
448
 
@@ -487,6 +498,7 @@ export const ServerModulePlugin = Plugin.create({
487
498
 
488
499
  const modules: { id: string; path: string; content: string }[] = []
489
500
  const { Lint } = await import('../repack/lint/index.js')
501
+ const lint = new Lint()
490
502
  for (const node of dependencyNodes) {
491
503
  const { packagePath, files, updatedManifest, originalPath } = node
492
504
  const { name, version } = updatedManifest
@@ -499,8 +511,8 @@ export const ServerModulePlugin = Plugin.create({
499
511
  )
500
512
  for (const file of files) {
501
513
  const fileContent = fs.readFileSync(pathModule.join(packagePath, file)).toString('utf-8')
502
- if (/(.js|.cjs|.mjs)$/.test(pathModule.extname(file))) {
503
- const result = await new Lint().check(fileContent)
514
+ if (/\.(js|cjs|mjs)$/.test(pathModule.extname(file))) {
515
+ const result = lint.check(fileContent)
504
516
  if (result) {
505
517
  logger.warn(`Use of unsupported APIs detected in npm dependency ${name}`)
506
518
  logger.warn(result)
@@ -11,9 +11,11 @@ import {
11
11
  resolveAndValidateVariableId,
12
12
  } from './utils'
13
13
  import { validateCatalogItemVariableSetExclusivity } from './service-catalog-diagnostics'
14
+ import { createSdkDocEntry } from '../utils'
14
15
 
15
16
  export const CatalogClientScriptPlugin = Plugin.create({
16
17
  name: 'CatalogClientScriptPlugin',
18
+ docs: [createSdkDocEntry('CatalogClientScript', ['catalog_script_client'])],
17
19
  records: {
18
20
  catalog_script_client: {
19
21
  async toShape(record, { database, transform }) {
@@ -14,6 +14,7 @@ import {
14
14
  createScript,
15
15
  } from './utils'
16
16
  import { validateFulfillmentProcessExclusivity, validateCategoriesRequireCatalogs } from './service-catalog-diagnostics'
17
+ import { createSdkDocEntry } from '../utils'
17
18
  import {
18
19
  buildVariablesSchema,
19
20
  CatalogItemBaseRelationships,
@@ -27,6 +28,7 @@ import {
27
28
 
28
29
  export const CatalogItemPlugin = Plugin.create({
29
30
  name: 'CatalogItemPlugin',
31
+ docs: [createSdkDocEntry('CatalogItem', ['sc_cat_item'])],
30
32
  records: {
31
33
  sc_cat_item: {
32
34
  relationships: CatalogItemBaseRelationships,
@@ -25,6 +25,7 @@ import {
25
25
  getValueActionToDb,
26
26
  } from './utils'
27
27
  import { validateCatalogItemVariableSetExclusivity, validateUiPolicyActionMessage } from './service-catalog-diagnostics'
28
+ import { createSdkDocEntry } from '../utils'
28
29
 
29
30
  // Define table names as constants since they're not exported from the core tables
30
31
  const CATALOG_UI_POLICY = 'catalog_ui_policy'
@@ -50,6 +51,7 @@ const stripIOPrefix = (value: string): string => {
50
51
 
51
52
  export const CatalogUiPolicyPlugin = Plugin.create({
52
53
  name: 'CatalogUiPolicyPlugin',
54
+ docs: [createSdkDocEntry('CatalogUiPolicy', ['catalog_ui_policy'])],
53
55
  records: {
54
56
  [CATALOG_UI_POLICY]: {
55
57
  relationships: {
@@ -28,9 +28,11 @@ import {
28
28
  } from './service-catalog-base'
29
29
  import { validateFulfillmentProcessExclusivity, validateCategoriesRequireCatalogs } from './service-catalog-diagnostics'
30
30
  import { ModuleFunctionShape } from '../server-module-plugin'
31
+ import { createSdkDocEntry } from '../utils'
31
32
 
32
33
  export const CatalogItemRecordProducerPlugin = Plugin.create({
33
34
  name: 'CatalogItemRecordProducerPlugin',
35
+ docs: [createSdkDocEntry('CatalogItemRecordProducer', ['sc_cat_item_producer'])],
34
36
  records: {
35
37
  sc_cat_item_producer: {
36
38
  relationships: CatalogItemBaseRelationships,
@@ -156,6 +156,36 @@ export function validateMandatoryReadOnlyHidden(config: ObjectShape, diagnostics
156
156
  return true
157
157
  }
158
158
 
159
+ /**
160
+ * Validates that selectionRequired is not true when hidden or readOnly is true, and vice versa.
161
+ * This is specific to Checkbox variables which use selectionRequired instead of mandatory.
162
+ * Returns true if valid, false if a diagnostic was emitted.
163
+ */
164
+ export function validateSelectionRequiredReadOnlyHidden(config: ObjectShape, diagnostics: Diagnostics): boolean {
165
+ const isSelectionRequired =
166
+ config.get('selectionRequired').isDefined() && config.get('selectionRequired').ifBoolean()?.getValue() === true
167
+ const isReadOnly = config.get('readOnly').isDefined() && config.get('readOnly').ifBoolean()?.getValue() === true
168
+ const isHidden = config.get('hidden').isDefined() && config.get('hidden').ifBoolean()?.getValue() === true
169
+
170
+ if (isSelectionRequired && isReadOnly) {
171
+ diagnostics.error(
172
+ config.get('selectionRequired'),
173
+ `'selectionRequired' cannot be true when 'readOnly' is true. A checkbox cannot be both required and read-only.`
174
+ )
175
+ return false
176
+ }
177
+
178
+ if (isSelectionRequired && isHidden) {
179
+ diagnostics.error(
180
+ config.get('selectionRequired'),
181
+ `'selectionRequired' cannot be true when 'hidden' is true. A checkbox cannot be both required and hidden.`
182
+ )
183
+ return false
184
+ }
185
+
186
+ return true
187
+ }
188
+
159
189
  /**
160
190
  * Validates lookup variable configuration: table-based and choice-based properties are mutually exclusive,
161
191
  * and price fields are not allowed when uniqueValuesOnly is true.
@@ -11,6 +11,7 @@ import { convertRolesToString, getVisibilityId, validateFieldNameBelongsToTable
11
11
  import {
12
12
  validateMapToFieldRequiresField,
13
13
  validateMandatoryReadOnlyHidden,
14
+ validateSelectionRequiredReadOnlyHidden,
14
15
  validateLookupSourceExclusivity,
15
16
  validateReferenceQualifierExclusivity,
16
17
  } from './service-catalog-diagnostics'
@@ -59,7 +60,9 @@ export async function buildVariableRecords(options: {
59
60
  }
60
61
 
61
62
  // Validate mandatory/readOnly/hidden consistency (applies to interactive variables)
62
- if (
63
+ if (calleeName === VariableTypeName.CHECKBOX) {
64
+ validateSelectionRequiredReadOnlyHidden(config, diagnostics)
65
+ } else if (
63
66
  calleeName !== VariableTypeName.BREAK &&
64
67
  calleeName !== VariableTypeName.CONTAINER_END &&
65
68
  calleeName !== VariableTypeName.CONTAINER_SPLIT &&
@@ -112,7 +115,10 @@ export async function buildVariableRecords(options: {
112
115
  question_text: $.from('question').def(''),
113
116
  order: $.def(0),
114
117
  active: $.from('active').toBoolean().def(true),
115
- mandatory: $.from('mandatory').toBoolean().def(false),
118
+ mandatory:
119
+ calleeName === VariableTypeName.CHECKBOX
120
+ ? $.from('selectionRequired').toBoolean().def(false)
121
+ : $.from('mandatory').toBoolean().def(false),
116
122
  read_only: $.from('readOnly').toBoolean().def(false),
117
123
  hidden: $.from('hidden').toBoolean().def(false),
118
124
  disable_initial_slot_fill: $.from('disableInitialSlotFill').toBoolean().def(false),
@@ -20,9 +20,11 @@ import {
20
20
  getVariableSetTypeFromDb,
21
21
  getVariableSetTypeToDb,
22
22
  } from './utils'
23
+ import { createSdkDocEntry } from '../utils'
23
24
 
24
25
  export const VariableSetPlugin = Plugin.create({
25
26
  name: 'VariableSetPlugin',
27
+ docs: [createSdkDocEntry('VariableSet', ['item_option_new_set'])],
26
28
  records: {
27
29
  item_option_new_set: {
28
30
  relationships: {
@@ -1,8 +1,10 @@
1
1
  import { CallExpressionShape, Plugin } from '@servicenow/sdk-build-core'
2
2
  import { NowIdShape } from '../now-id-plugin'
3
+ import { createSdkDocEntry } from '../utils'
3
4
 
4
5
  export const SPAngularProviderPlugin = Plugin.create({
5
6
  name: 'SPAngularProviderPlugin',
7
+ docs: [createSdkDocEntry('SPAngularProvider', ['sp_angular_provider'])],
6
8
  records: {
7
9
  sp_angular_provider: {
8
10
  relationships: {
@@ -1,17 +1,12 @@
1
- import {
2
- CallExpressionShape,
3
- type Diagnostics,
4
- type Factory,
5
- Plugin,
6
- type Record,
7
- type Shape,
8
- type RecordId,
9
- } from '@servicenow/sdk-build-core'
1
+ import { CallExpressionShape, Plugin } from '@servicenow/sdk-build-core'
10
2
  import { toReference } from '../utils'
11
3
  import { NowIdShape } from '../now-id-plugin'
4
+ import { createSdkDocEntry } from '../utils'
5
+ import { getIncludeRecords } from './utils'
12
6
 
13
7
  export const SPWidgetDependencyPlugin = Plugin.create({
14
8
  name: 'SPWidgetDependencyPlugin',
9
+ docs: [createSdkDocEntry('SPWidgetDependency', ['sp_dependency'])],
15
10
  records: {
16
11
  sp_dependency: {
17
12
  relationships: {
@@ -217,6 +212,7 @@ export const SPWidgetDependencyPlugin = Plugin.create({
217
212
  factory,
218
213
  'm2m_sp_dependency_css_include',
219
214
  'sp_css_include',
215
+ 'sp_dependency',
220
216
  diagnostics
221
217
  )
222
218
 
@@ -226,6 +222,7 @@ export const SPWidgetDependencyPlugin = Plugin.create({
226
222
  factory,
227
223
  'm2m_sp_dependency_js_include',
228
224
  'sp_js_include',
225
+ 'sp_dependency',
229
226
  diagnostics
230
227
  )
231
228
 
@@ -237,47 +234,3 @@ export const SPWidgetDependencyPlugin = Plugin.create({
237
234
  },
238
235
  ],
239
236
  })
240
-
241
- async function getIncludeRecords(
242
- shape: Shape,
243
- dependencyId: Shape,
244
- factory: Factory,
245
- m2mTable: string,
246
- includeTable: string,
247
- diagnostics: Diagnostics
248
- ) {
249
- return (
250
- await Promise.all(
251
- shape?.ifArray()?.map(async (include) => {
252
- const includeProps = include.ifObject()?.get('include')
253
-
254
- let includeId: string | RecordId
255
- if (includeProps?.isString()) {
256
- includeId = includeProps.toString().getValue()
257
- } else if (includeProps?.isRecord()) {
258
- includeId = includeProps.getId()
259
- } else {
260
- const necessaryPlugin = includeTable === 'sp_js_include' ? 'JsInclude' : 'CssInclude'
261
- diagnostics.error(
262
- includeProps!,
263
- `include must contain a valid ${necessaryPlugin}, Record<'${includeTable}'> or sys_id'`
264
- )
265
- return undefined
266
- }
267
-
268
- const m2mProps = {
269
- [includeTable]: includeId,
270
- sp_dependency: dependencyId,
271
- }
272
- return await factory.createRecord({
273
- source: shape,
274
- table: m2mTable,
275
- properties: {
276
- order: include.ifObject()?.get('order').asNumber().getValue() || 100,
277
- ...m2mProps,
278
- },
279
- })
280
- }) ?? []
281
- )
282
- ).filter((rec) => rec) as Record[]
283
- }