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