@servicenow/sdk-build-core 4.1.0 → 4.2.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 (58) hide show
  1. package/dist/compression.d.ts +2 -1
  2. package/dist/compression.js +12 -1
  3. package/dist/compression.js.map +1 -1
  4. package/dist/index.d.ts +1 -0
  5. package/dist/index.js +1 -0
  6. package/dist/index.js.map +1 -1
  7. package/dist/now-config-dependencies.d.ts +49 -0
  8. package/dist/now-config-dependencies.js +46 -0
  9. package/dist/now-config-dependencies.js.map +1 -0
  10. package/dist/now-config.d.ts +105 -29
  11. package/dist/now-config.js +7 -10
  12. package/dist/now-config.js.map +1 -1
  13. package/dist/plugins/data-shape.d.ts +118 -0
  14. package/dist/plugins/data-shape.js +252 -0
  15. package/dist/plugins/data-shape.js.map +1 -0
  16. package/dist/plugins/database.d.ts +2 -0
  17. package/dist/plugins/database.js +21 -0
  18. package/dist/plugins/database.js.map +1 -1
  19. package/dist/plugins/file.d.ts +1 -1
  20. package/dist/plugins/index.d.ts +1 -0
  21. package/dist/plugins/index.js +1 -0
  22. package/dist/plugins/index.js.map +1 -1
  23. package/dist/plugins/plugin.d.ts +38 -0
  24. package/dist/plugins/plugin.js +51 -2
  25. package/dist/plugins/plugin.js.map +1 -1
  26. package/dist/plugins/project.d.ts +1 -0
  27. package/dist/plugins/shape.d.ts +19 -1
  28. package/dist/plugins/shape.js +22 -3
  29. package/dist/plugins/shape.js.map +1 -1
  30. package/dist/plugins/time.d.ts +34 -4
  31. package/dist/plugins/time.js +121 -5
  32. package/dist/plugins/time.js.map +1 -1
  33. package/dist/taxonomy.d.ts +34 -0
  34. package/dist/taxonomy.js +333 -0
  35. package/dist/taxonomy.js.map +1 -0
  36. package/dist/typescript.d.ts +4 -0
  37. package/dist/typescript.js +4 -0
  38. package/dist/typescript.js.map +1 -1
  39. package/dist/xml.d.ts +3 -6
  40. package/dist/xml.js +14 -8
  41. package/dist/xml.js.map +1 -1
  42. package/now.config.schema.json +195 -30
  43. package/package.json +2 -2
  44. package/src/compression.ts +13 -2
  45. package/src/index.ts +1 -0
  46. package/src/now-config-dependencies.ts +47 -0
  47. package/src/now-config.ts +10 -13
  48. package/src/plugins/data-shape.ts +288 -0
  49. package/src/plugins/database.ts +26 -0
  50. package/src/plugins/file.ts +1 -0
  51. package/src/plugins/index.ts +1 -0
  52. package/src/plugins/plugin.ts +99 -2
  53. package/src/plugins/project.ts +2 -0
  54. package/src/plugins/shape.ts +40 -3
  55. package/src/plugins/time.ts +153 -10
  56. package/src/taxonomy.ts +343 -0
  57. package/src/typescript.ts +4 -0
  58. package/src/xml.ts +18 -9
@@ -1,17 +1,26 @@
1
- import type { TimeDuration } from '@servicenow/sdk/core'
1
+ import type { Duration, TimeOfDay } from '@servicenow/sdk/core'
2
2
 
3
- function prefixZeroIfNeeded(n: number) {
4
- return n < 10 ? `0${n}` : `${n}`
5
- }
3
+ const padZero = (n: number) => String(n).padStart(2, '0')
6
4
 
7
5
  export function formatDateToPlatformFormat(date: Date | undefined): string {
8
6
  if (date === undefined) {
9
7
  return '1970-01-01 00:00:00'
10
8
  }
11
- return `${date.getUTCFullYear()}-${prefixZeroIfNeeded(date.getUTCMonth() + 1)}-${prefixZeroIfNeeded(date.getUTCDate())} ${prefixZeroIfNeeded(date.getUTCHours())}:${prefixZeroIfNeeded(date.getUTCMinutes())}:${prefixZeroIfNeeded(date.getUTCSeconds())}`
9
+ return `${date.getUTCFullYear()}-${padZero(date.getUTCMonth() + 1)}-${padZero(date.getUTCDate())} ${padZero(date.getUTCHours())}:${padZero(date.getUTCMinutes())}:${padZero(date.getUTCSeconds())}`
10
+ }
11
+
12
+ /**
13
+ * Format a Date object to ServiceNow platform datetime format using local time (not UTC).
14
+ * This is used for glide_time fields which are timezone-aware.
15
+ */
16
+ export function formatDateToPlatformFormatLocal(date: Date | undefined): string {
17
+ if (date === undefined) {
18
+ return '1970-01-01 00:00:00'
19
+ }
20
+ return `${date.getFullYear()}-${padZero(date.getMonth() + 1)}-${padZero(date.getDate())} ${padZero(date.getHours())}:${padZero(date.getMinutes())}:${padZero(date.getSeconds())}`
12
21
  }
13
22
 
14
- export function parseGlideDuration(dateTimeStr: string | undefined): TimeDuration | undefined {
23
+ export function parseGlideDuration(dateTimeStr: string | undefined): Duration | undefined {
15
24
  if (!dateTimeStr) {
16
25
  return undefined
17
26
  }
@@ -34,7 +43,7 @@ export function parseGlideDuration(dateTimeStr: string | undefined): TimeDuratio
34
43
 
35
44
  let diffMs = inputDate.getTime() - epochDate.getTime()
36
45
 
37
- const duration: TimeDuration = {}
46
+ const duration: Duration = {}
38
47
 
39
48
  // Calculate days
40
49
  const days = Math.floor(diffMs / (1000 * 60 * 60 * 24))
@@ -66,7 +75,85 @@ export function parseGlideDuration(dateTimeStr: string | undefined): TimeDuratio
66
75
  return duration
67
76
  }
68
77
 
69
- export function parseDateTime(dateTimeStr: string | undefined) {
78
+ /**
79
+ * Parse a datetime string to a TimeOfDay object.
80
+ * Respects user's timezone by reversing the timeFieldToXML conversion.
81
+ * The datetime string is in UTC format, but represents a local time that was converted.
82
+ * @param dateTimeStr - ServiceNow datetime format string (e.g., '1970-01-01 14:30:00')
83
+ * @param timeZone - Optional IANA timezone string (e.g., 'America/New_York'). Defaults to system timezone.
84
+ * @returns TimeOfDay object with hours, minutes, and seconds, or undefined if parsing fails
85
+ */
86
+ export function parseGlideTime(dateTimeStr: string | undefined, timeZone?: string): TimeOfDay | undefined {
87
+ if (!dateTimeStr) {
88
+ return undefined
89
+ }
90
+
91
+ const components = parseDateTime(dateTimeStr)
92
+ if (!components) {
93
+ return undefined
94
+ }
95
+
96
+ // Create a UTC Date from the parsed components
97
+ const utcDate = new Date(
98
+ Date.UTC(
99
+ components.year,
100
+ components.month - 1,
101
+ components.day,
102
+ components.hours,
103
+ components.minutes,
104
+ components.seconds
105
+ )
106
+ )
107
+
108
+ let localHours: number
109
+ let localMinutes: number
110
+ let localSeconds: number
111
+
112
+ if (timeZone) {
113
+ // Use Intl.DateTimeFormat to convert UTC to specified timezone
114
+ const { hour, minute, second } = new Intl.DateTimeFormat('en-US', {
115
+ timeZone,
116
+ hour: 'numeric',
117
+ minute: 'numeric',
118
+ second: 'numeric',
119
+ hourCycle: 'h23', // Use 0-23 hour format (midnight = 0, not 24)
120
+ })
121
+ .formatToParts(utcDate)
122
+ .reduce(
123
+ (acc, p) => {
124
+ if (p.type === 'hour' || p.type === 'minute' || p.type === 'second') {
125
+ acc[p.type] = Number(p.value)
126
+ }
127
+ return acc
128
+ },
129
+ { hour: 0, minute: 0, second: 0 }
130
+ )
131
+
132
+ localHours = hour
133
+ localMinutes = minute
134
+ localSeconds = second
135
+ } else {
136
+ // Use system timezone (JavaScript's default behavior)
137
+ localHours = utcDate.getHours()
138
+ localMinutes = utcDate.getMinutes()
139
+ localSeconds = utcDate.getSeconds()
140
+ }
141
+
142
+ const timeOfDay: TimeOfDay = {}
143
+ if (localHours > 0) {
144
+ timeOfDay.hours = localHours
145
+ }
146
+ if (localMinutes > 0) {
147
+ timeOfDay.minutes = localMinutes
148
+ }
149
+ if (localSeconds > 0) {
150
+ timeOfDay.seconds = localSeconds
151
+ }
152
+
153
+ return timeOfDay
154
+ }
155
+
156
+ export function parseDateTime(dateTimeStr: string) {
70
157
  if (!dateTimeStr) {
71
158
  return undefined
72
159
  }
@@ -88,14 +175,70 @@ export function parseDateTime(dateTimeStr: string | undefined) {
88
175
  return undefined
89
176
  }
90
177
 
91
- export function durationFieldToXML(duration: TimeDuration): Date {
178
+ /**
179
+ * Convert a Duration object to a Date for glide_duration fields.
180
+ * Duration fields are timezone-agnostic (they represent a span of time),
181
+ * so we create the Date in UTC.
182
+ */
183
+ export function durationFieldToXML(duration: Duration): Date {
92
184
  const durationInMs = toMilliseconds(
93
185
  duration['days'] !== undefined ? duration['days'] : 0,
94
186
  duration['hours'] !== undefined ? duration['hours'] : 0,
95
187
  duration['minutes'] !== undefined ? duration['minutes'] : 0,
96
188
  duration['seconds'] !== undefined ? duration['seconds'] : 0
97
189
  )
98
- return new Date(durationInMs)
190
+ // Create Date in UTC to avoid timezone conversion issues
191
+ // Date.UTC() returns milliseconds since epoch in UTC
192
+ return new Date(Date.UTC(1970, 0, 1) + durationInMs)
193
+ }
194
+
195
+ /**
196
+ * Convert a time object to a Date for glide_time fields.
197
+ * Time fields represent a time-of-day and are timezone-aware.
198
+ * We create the Date in local time (or specified timezone), then format it as UTC.
199
+ * This means the UTC time will include the timezone offset,
200
+ * and ServiceNow will display it correctly in the user's timezone.
201
+ *
202
+ * @param time - TimeOfDay object with hours, minutes, seconds
203
+ * @param timeZone - Optional IANA timezone string (e.g., 'America/New_York'). Defaults to system timezone.
204
+ */
205
+ export function timeFieldToXML(time: TimeOfDay, timeZone?: string): Date {
206
+ const hours = time.hours ?? 0
207
+ const minutes = time.minutes ?? 0
208
+ const seconds = time.seconds ?? 0
209
+
210
+ if (timeZone) {
211
+ // Convert from specified timezone to UTC
212
+ // Calculate offset by comparing UTC time with timezone time
213
+ const refUtc = Date.UTC(1970, 0, 1, 12, 0, 0)
214
+ const refDate = new Date(refUtc)
215
+ const tzString = refDate.toLocaleString('en-US', {
216
+ timeZone,
217
+ hour: '2-digit',
218
+ minute: '2-digit',
219
+ hour12: false,
220
+ })
221
+ const parts = tzString.split(':').map(Number)
222
+ const tzHour = parts[0] ?? 12
223
+ const tzMin = parts[1] ?? 0
224
+ const offsetMinutes = (tzHour - 12) * 60 + tzMin // Offset from UTC in minutes
225
+
226
+ // Apply the offset: local time in timezone -> UTC
227
+ // If timezone is UTC+5:30, then 14:00 local = 08:30 UTC (subtract offset)
228
+ const totalMinutes = hours * 60 + minutes - offsetMinutes
229
+ return new Date(Date.UTC(1970, 0, 1, Math.floor(totalMinutes / 60), totalMinutes % 60, seconds))
230
+ }
231
+
232
+ // Default: use system timezone
233
+ // Create a Date in local time - this will have the timezone offset built in
234
+ return new Date(
235
+ 1970,
236
+ 0, // January
237
+ 1,
238
+ hours,
239
+ minutes,
240
+ seconds
241
+ )
99
242
  }
100
243
 
101
244
  function toMilliseconds(days: number, hours: number, minutes: number, seconds: number): number {
@@ -0,0 +1,343 @@
1
+ import * as z from 'zod'
2
+ import kebabCase from 'lodash/kebabCase'
3
+
4
+ const TableNames = {
5
+ // Automation tables
6
+ SYS_ALIAS: 'sys_alias',
7
+ SYS_HUB_ACTION_TYPE_DEFINITION: 'sys_hub_action_type_definition',
8
+ SYS_HUB_TRIGGER_DEFINITION: 'sys_hub_trigger_definition',
9
+ SYS_HUB_FLOW: 'sys_hub_flow',
10
+ SYS_PD_ACTIVITY_DEFINITION: 'sys_pd_activity_definition',
11
+ SYS_DECISION: 'sys_decision',
12
+ SYSEVENT_EMAIL_TEMPLATE: 'sysevent_email_template',
13
+ SYSEVENT_EMAIL_ACTION: 'sysevent_email_action',
14
+ SYS_PD_PROCESS_DEFINITION: 'sys_pd_process_definition',
15
+ SYS_HUB_TRIGGER_TEMPLATE: 'sys_hub_trigger_template',
16
+
17
+ // Client Development tables
18
+ DL_U_ASSIGNMENT: 'dl_u_assignment',
19
+ SYS_SCRIPT_CLIENT: 'sys_script_client',
20
+ SYS_UI_SCRIPT: 'sys_ui_script',
21
+ DL_DEFINITION: 'dl_definition',
22
+ DL_U_PRIORITY: 'dl_u_priority',
23
+ SYS_CLIENT_EXTENSION_INSTANCE: 'sys_client_extension_instance',
24
+ SYS_CLIENT_EXTENSION_POINT: 'sys_client_extension_point',
25
+ SYS_UI_EXTENSION_INSTANCE: 'sys_ui_extension_instance',
26
+ SYS_UI_EXTENSION_POINT: 'sys_ui_extension_point',
27
+
28
+ // Content tables
29
+ CONTENT_BLOCK_PROGRAMMATIC: 'content_block_programmatic',
30
+ CONTENT_BLOCK_STATIC: 'content_block_static',
31
+ CONTENT_BLOCK_DETAIL: 'content_block_detail',
32
+ CONTENT_BLOCK_IFRAME: 'content_block_iframe',
33
+
34
+ // Data tables
35
+ DB_AUDIO: 'db_audio',
36
+ DB_IMAGE: 'db_image',
37
+ SYS_DB_OBJECT: 'sys_db_object',
38
+ SYS_DICTIONARY: 'sys_dictionary',
39
+ SYS_UI_FORM: 'sys_ui_form',
40
+ SYS_M2M: 'sys_m2m',
41
+ SYS_RELATIONSHIP: 'sys_relationship',
42
+
43
+ // Integrations Inbound tables
44
+ SYS_REST_MESSAGE: 'sys_rest_message',
45
+ SYS_WEB_SERVICE: 'sys_web_service',
46
+ SYS_DATA_SOURCE: 'sys_data_source',
47
+ SN_IHUB_INTEGRATION_INSTANCE: 'sn_ihub_integration_instance',
48
+ SCHEDULED_IMPORT_SET: 'scheduled_import_set',
49
+ SCHEDULED_DATA_IMPORT: 'scheduled_data_import',
50
+ SYS_WS_DEFINITION: 'sys_ws_definition',
51
+
52
+ // Integrations Outbound tables
53
+ SYS_EXPORT_DEFINITION: 'sys_export_definition',
54
+ SYS_EXPORT_TARGET: 'sys_export_target',
55
+ SYS_EXPORT_SET: 'sys_export_set',
56
+ SCHEDULED_DATA_EXPORT: 'scheduled_data_export',
57
+ SYS_SOAP_MESSAGE: 'sys_soap_message',
58
+
59
+ // Mid Server tables
60
+ ECC_AGENT_APPLICATION: 'ecc_agent_application',
61
+ ECC_AGENT_SCRIPT_INCLUDE: 'ecc_agent_script_include',
62
+ ECC_AGENT_IP_RANGE: 'ecc_agent_ip_range',
63
+ ECC_AGENT_PROPERTY: 'ecc_agent_property',
64
+ ECC_AGENT_SCRIPT_FILE: 'ecc_agent_script_file',
65
+ ECC_AGENT_CAPABILITY_VALUE_TEST: 'ecc_agent_capability_value_test',
66
+
67
+ // Mobile tables
68
+ SYS_SG_BROWSER_SCREEN: 'sys_sg_browser_screen',
69
+ SYS_SG_CHART: 'sys_sg_chart',
70
+ SYS_SG_FORM_SCREEN: 'sys_sg_form_screen',
71
+ SYS_SG_LIST_SCREEN: 'sys_sg_list_screen',
72
+ SYS_SG_NATIVE_CLIENT: 'sys_sg_native_client',
73
+ SYS_SG_CUSTOM_MAP_SCREEN: 'sys_sg_custom_map_screen',
74
+ SYS_SG_MAP_SCREEN: 'sys_sg_map_screen',
75
+ SYS_SG_CHART_SCREEN: 'sys_sg_chart_screen',
76
+ SYS_SG_CALENDAR_SCREEN: 'sys_sg_calendar_screen',
77
+ SYS_SG_BUTTON: 'sys_sg_button',
78
+ SYS_SG_PARAMETER_SCREEN: 'sys_sg_parameter_screen',
79
+ SYS_SG_APPLET_LAUNCHER: 'sys_sg_applet_launcher',
80
+
81
+ // Natural Language Understanding tables
82
+ SYS_NLU_MODEL: 'sys_nlu_model',
83
+
84
+ // Properties tables
85
+ SYS_PROPERTIES: 'sys_properties',
86
+ SYS_PROPERTIES_CATEGORY: 'sys_properties_category',
87
+ SYS_UI_MESSAGE: 'sys_ui_message',
88
+
89
+ // Reporting tables
90
+ METRIC_DEFINITION: 'metric_definition',
91
+ SYS_REPORT: 'sys_report',
92
+ SYS_REPORT_RANGE: 'sys_report_range',
93
+ SYS_REPORT_CHART_COLOR: 'sys_report_chart_color',
94
+ SYS_REPORT_COLOR: 'sys_report_color',
95
+ SYSAUTO_REPORT: 'sysauto_report',
96
+ PA_DASHBOARDS: 'pa_dashboards',
97
+
98
+ // Schedules tables
99
+ CMN_SCHEDULE: 'cmn_schedule',
100
+ CMN_SCHEDULE_PAGE: 'cmn_schedule_page',
101
+ SYSAUTO_PA: 'sysauto_pa',
102
+ SYSAUTO_SCRIPT: 'sysauto_script',
103
+ CMN_SCHEDULE_BLACKOUT: 'cmn_schedule_blackout',
104
+ CMN_SCHEDULE_MAINTENANCE: 'cmn_schedule_maintenance',
105
+ CMN_RELATIVE_DURATION: 'cmn_relative_duration',
106
+ RISK_CONDITIONS: 'risk_conditions',
107
+
108
+ // Security-related tables
109
+ SYS_PUBLIC: 'sys_public',
110
+ SYS_SECURITY_ACL: 'sys_security_acl',
111
+ SYS_USER_ROLE: 'sys_user_role',
112
+ SYS_USER_ROLE_CONTAINS: 'sys_user_role_contains',
113
+
114
+ // Server Development tables
115
+ SYS_SCRIPT: 'sys_script',
116
+ SYS_SCRIPT_FIX: 'sys_script_fix',
117
+ SYS_SCRIPT_INCLUDE: 'sys_script_include',
118
+ SYS_TRANSFORM_MAP: 'sys_transform_map',
119
+ SYS_UI_ACTION: 'sys_ui_action',
120
+ SYSEVENT_REGISTER: 'sysevent_register',
121
+ SYS_DATA_POLICY2: 'sys_data_policy2',
122
+ SYS_EXTENSION_INSTANCE: 'sys_extension_instance',
123
+ SYS_EXTENSION_POINT: 'sys_extension_point',
124
+ SYSEVENT_SCRIPT_ACTION: 'sysevent_script_action',
125
+
126
+ // Service Portal tables
127
+ SP_PORTAL: 'sp_portal',
128
+
129
+ // User Interface tables
130
+ ASMT_METRIC: 'asmt_metric',
131
+ SYS_APP_APPLICATION: 'sys_app_application',
132
+ SYS_APP_MODULE: 'sys_app_module',
133
+ SYS_UI_POLICY: 'sys_ui_policy',
134
+ SYS_UI_SECTION: 'sys_ui_section',
135
+ SYS_EMBEDDED_HELP_QUALIFIER: 'sys_embedded_help_qualifier',
136
+ SC_CATALOG: 'sc_catalog',
137
+ SC_CAT_ITEM: 'sc_cat_item',
138
+ SC_CAT_ITEM_PRODUCER: 'sc_cat_item_producer',
139
+ SYS_UI_CONTEXT_MENU: 'sys_ui_context_menu',
140
+ SYS_UI_LIST: 'sys_ui_list',
141
+ SYS_UI_LIST_CONTROL: 'sys_ui_list_control',
142
+ SYS_UI_RELATED_LIST: 'sys_ui_related_list',
143
+ SYS_UI_STYLE: 'sys_ui_style',
144
+ SYS_UI_THEME: 'sys_ui_theme',
145
+ SYS_UI_VIEW: 'sys_ui_view',
146
+ SYS_EMBEDDED_HELP_CONTENT: 'sys_embedded_help_content',
147
+ SYS_EMBEDDED_TOUR_GUIDE: 'sys_embedded_tour_guide',
148
+ CMN_MAP_PAGE: 'cmn_map_page',
149
+ CMN_TIMELINE_PAGE: 'cmn_timeline_page',
150
+ SYS_UX_EXTENSION_POINT: 'sys_ux_extension_point',
151
+ SYS_UX_APP_CONFIG: 'sys_ux_app_config',
152
+ SYS_UX_PAGE_REGISTRY: 'sys_ux_page_registry',
153
+ SYS_TEMPLATE: 'sys_template',
154
+ SYSRULE_VIEW: 'sysrule_view',
155
+ }
156
+
157
+ // String format: one or more path segments separated by '/' (e.g., 'server-development/business-rule' or 'integration/outbound/rest-api')
158
+ const taxonomyItem = z.string().regex(/^[a-z0-9_-]+(\/[a-z0-9_-]+)*$/)
159
+
160
+ const taxonomyMapping = z
161
+ .object({
162
+ // Automation tables
163
+ [TableNames.SYS_HUB_ACTION_TYPE_DEFINITION]: taxonomyItem.default('automation/action'),
164
+ [TableNames.SYS_HUB_TRIGGER_DEFINITION]: taxonomyItem.default('automation/trigger'),
165
+ [TableNames.SYS_PD_ACTIVITY_DEFINITION]: taxonomyItem.default('automation/activity-definition'),
166
+ [TableNames.SYS_ALIAS]: taxonomyItem.default('automation/workflow-activity'),
167
+ [TableNames.SYS_HUB_FLOW]: taxonomyItem.default('automation/flow'),
168
+ [TableNames.SYS_DECISION]: taxonomyItem.default('automation/decision-table'),
169
+ [TableNames.SYSEVENT_EMAIL_TEMPLATE]: taxonomyItem.default('automation/email-template'),
170
+ [TableNames.SYSEVENT_EMAIL_ACTION]: taxonomyItem.default('automation/notification'),
171
+ [TableNames.SYS_PD_PROCESS_DEFINITION]: taxonomyItem.default('automation/playbook'),
172
+ [TableNames.SYS_HUB_TRIGGER_TEMPLATE]: taxonomyItem.default('automation/trigger'),
173
+
174
+ // Client Development tables
175
+ [TableNames.DL_U_ASSIGNMENT]: taxonomyItem.default('client-development/assignment-data-lookup'),
176
+ [TableNames.SYS_SCRIPT_CLIENT]: taxonomyItem.default('client-development/client-script'),
177
+ [TableNames.SYS_UI_SCRIPT]: taxonomyItem.default('client-development/ui-script'),
178
+ [TableNames.DL_DEFINITION]: taxonomyItem.default('client-development/data-lookup-definitions'),
179
+ [TableNames.DL_U_PRIORITY]: taxonomyItem.default('client-development/priority-data-lookup'),
180
+ [TableNames.SYS_CLIENT_EXTENSION_INSTANCE]: taxonomyItem.default(
181
+ 'client-development/client-extension-instance'
182
+ ),
183
+ [TableNames.SYS_CLIENT_EXTENSION_POINT]: taxonomyItem.default('client-development/client-extension-point'),
184
+ [TableNames.SYS_UI_EXTENSION_INSTANCE]: taxonomyItem.default('client-development/ui-extension-instance'),
185
+ [TableNames.SYS_UI_EXTENSION_POINT]: taxonomyItem.default('client-development/ui-extension-point'),
186
+
187
+ // Content tables
188
+ [TableNames.CONTENT_BLOCK_PROGRAMMATIC]: taxonomyItem.default('content/dynamic-content'),
189
+ [TableNames.CONTENT_BLOCK_STATIC]: taxonomyItem.default('content/static-content'),
190
+ [TableNames.CONTENT_BLOCK_DETAIL]: taxonomyItem.default('content/detailed-content'),
191
+ [TableNames.CONTENT_BLOCK_IFRAME]: taxonomyItem.default('content/i-frames'),
192
+
193
+ // Data tables
194
+ [TableNames.DB_AUDIO]: taxonomyItem.default('content/audio'),
195
+ [TableNames.DB_IMAGE]: taxonomyItem.default('content/images'),
196
+ [TableNames.SYS_DB_OBJECT]: taxonomyItem.default('data/table'),
197
+ [TableNames.SYS_DICTIONARY]: taxonomyItem.default('data/table-column'),
198
+ [TableNames.SYS_UI_FORM]: taxonomyItem.default('data/form'),
199
+ [TableNames.SYS_M2M]: taxonomyItem.default('data/many-to-many-definition'),
200
+ [TableNames.SYS_RELATIONSHIP]: taxonomyItem.default('data/relationship'),
201
+
202
+ // Integrations Inbound tables
203
+ [TableNames.SYS_WEB_SERVICE]: taxonomyItem.default('integrations-inbound/scripted-web-service'),
204
+ [TableNames.SYS_DATA_SOURCE]: taxonomyItem.default('integrations-inbound/data-source'),
205
+ [TableNames.SYS_TRANSFORM_MAP]: taxonomyItem.default('integrations-inbound/table-transform-map'),
206
+ [TableNames.SN_IHUB_INTEGRATION_INSTANCE]: taxonomyItem.default('integrations-inbound/data-import'),
207
+ [TableNames.SCHEDULED_IMPORT_SET]: taxonomyItem.default('integrations-inbound/scheduled-data-import'),
208
+ [TableNames.SCHEDULED_DATA_IMPORT]: taxonomyItem.default('integrations-inbound/scheduled-data-import'),
209
+ [TableNames.SYS_WS_DEFINITION]: taxonomyItem.default('integrations-inbound/scripted-rest-api'),
210
+
211
+ // Integrations Outbound tables
212
+ [TableNames.SYS_EXPORT_DEFINITION]: taxonomyItem.default('integrations-outbound/export-definition'),
213
+ [TableNames.SYS_EXPORT_TARGET]: taxonomyItem.default('integrations-outbound/export-target'),
214
+ [TableNames.SYS_EXPORT_SET]: taxonomyItem.default('integrations-outbound/export-set'),
215
+ [TableNames.SYS_REST_MESSAGE]: taxonomyItem.default('integrations-outbound/rest-message'),
216
+ [TableNames.SCHEDULED_DATA_EXPORT]: taxonomyItem.default('integrations-outbound/scheduled-data-export'),
217
+ [TableNames.SYS_SOAP_MESSAGE]: taxonomyItem.default('integrations-outbound/soap-message'),
218
+
219
+ // Mid Server tables
220
+ [TableNames.ECC_AGENT_APPLICATION]: taxonomyItem.default('mid-server/mid-server-application'),
221
+ [TableNames.ECC_AGENT_SCRIPT_INCLUDE]: taxonomyItem.default('mid-server/mid-server-script-include'),
222
+ [TableNames.ECC_AGENT_IP_RANGE]: taxonomyItem.default('mid-server/mid-server-ip-range'),
223
+ [TableNames.ECC_AGENT_PROPERTY]: taxonomyItem.default('mid-server/mid-server-property'),
224
+ [TableNames.ECC_AGENT_SCRIPT_FILE]: taxonomyItem.default('mid-server/mid-server-script-file'),
225
+ [TableNames.ECC_AGENT_CAPABILITY_VALUE_TEST]: taxonomyItem.default(
226
+ 'mid-server/mid-server-capability-value-test'
227
+ ),
228
+
229
+ // Mobile tables
230
+ [TableNames.SYS_SG_CHART]: taxonomyItem.default('mobile/analytics-preview'),
231
+ [TableNames.SYS_SG_BROWSER_SCREEN]: taxonomyItem.default('mobile/mobile-web-screen'),
232
+ [TableNames.SYS_SG_FORM_SCREEN]: taxonomyItem.default('mobile/record-screen'),
233
+ [TableNames.SYS_SG_LIST_SCREEN]: taxonomyItem.default('mobile/list-screen'),
234
+ [TableNames.SYS_SG_NATIVE_CLIENT]: taxonomyItem.default('mobile/mobile-app-config'),
235
+ [TableNames.SYS_SG_CUSTOM_MAP_SCREEN]: taxonomyItem.default('mobile/custom-map-screen'),
236
+ [TableNames.SYS_SG_MAP_SCREEN]: taxonomyItem.default('mobile/map-screen'),
237
+ [TableNames.SYS_SG_CHART_SCREEN]: taxonomyItem.default('mobile/chart-screen'),
238
+ [TableNames.SYS_SG_CALENDAR_SCREEN]: taxonomyItem.default('mobile/calendar-screen'),
239
+ [TableNames.SYS_SG_BUTTON]: taxonomyItem.default('mobile/function'),
240
+ [TableNames.SYS_SG_PARAMETER_SCREEN]: taxonomyItem.default('mobile/input-form-screen'),
241
+ [TableNames.SYS_SG_APPLET_LAUNCHER]: taxonomyItem.default('mobile/launcher-screen'),
242
+
243
+ // Natural Language Understanding tables
244
+ [TableNames.SYS_NLU_MODEL]: taxonomyItem.default('natural-language-understanding/nlu-model'),
245
+
246
+ // Properties tables
247
+ [TableNames.SYS_PROPERTIES]: taxonomyItem.default('properties/system-property'),
248
+ [TableNames.SYS_PROPERTIES_CATEGORY]: taxonomyItem.default('properties/system-property-category'),
249
+ [TableNames.SYS_UI_MESSAGE]: taxonomyItem.default('properties/message'),
250
+
251
+ // Reporting tables
252
+ [TableNames.METRIC_DEFINITION]: taxonomyItem.default('reporting/metric-definition'),
253
+ [TableNames.SYS_REPORT]: taxonomyItem.default('reporting/report'),
254
+ [TableNames.SYS_REPORT_RANGE]: taxonomyItem.default('reporting/range'),
255
+ [TableNames.SYS_REPORT_CHART_COLOR]: taxonomyItem.default('reporting/chart-colors'),
256
+ [TableNames.SYS_REPORT_COLOR]: taxonomyItem.default('reporting/color-definition'),
257
+ [TableNames.SYSAUTO_REPORT]: taxonomyItem.default('reporting/scheduled-email-of-report'),
258
+ [TableNames.PA_DASHBOARDS]: taxonomyItem.default('reporting/dashboard'),
259
+
260
+ // Schedules tables
261
+ [TableNames.CMN_SCHEDULE]: taxonomyItem.default('schedules/schedule'),
262
+ [TableNames.CMN_SCHEDULE_PAGE]: taxonomyItem.default('schedules/schedule-page'),
263
+ [TableNames.SYSAUTO_PA]: taxonomyItem.default('schedules/performance-analytics-job'),
264
+ [TableNames.SYSAUTO_SCRIPT]: taxonomyItem.default('schedules/scheduled-script-execution'),
265
+ [TableNames.CMN_SCHEDULE_BLACKOUT]: taxonomyItem.default('schedules/blackout-schedule'),
266
+ [TableNames.CMN_SCHEDULE_MAINTENANCE]: taxonomyItem.default('schedules/maintenance-schedule'),
267
+ [TableNames.CMN_RELATIVE_DURATION]: taxonomyItem.default('schedules/relative-duration'),
268
+ [TableNames.RISK_CONDITIONS]: taxonomyItem.default('schedules/risk-conditions'),
269
+
270
+ // Security-related tables
271
+ [TableNames.SYS_SECURITY_ACL]: taxonomyItem.default('security/access-control'),
272
+ [TableNames.SYS_PUBLIC]: taxonomyItem.default('security/public-pages'),
273
+ [TableNames.SYS_USER_ROLE]: taxonomyItem.default('security/role'),
274
+ [TableNames.SYS_USER_ROLE_CONTAINS]: taxonomyItem.default('security/role'),
275
+
276
+ // Server Development tables
277
+ [TableNames.SYS_SCRIPT]: taxonomyItem.default('server-development/business-rule'),
278
+ [TableNames.SYS_SCRIPT_FIX]: taxonomyItem.default('server-development/fix-script'),
279
+ [TableNames.SYS_SCRIPT_INCLUDE]: taxonomyItem.default('server-development/script-include'),
280
+ [TableNames.SYS_UI_ACTION]: taxonomyItem.default('server-development/ui-action'),
281
+ [TableNames.SYSEVENT_REGISTER]: taxonomyItem.default('server-development/event-registration'),
282
+ [TableNames.SYS_DATA_POLICY2]: taxonomyItem.default('server-development/data-policy'),
283
+ [TableNames.SYS_EXTENSION_INSTANCE]: taxonomyItem.default('server-development/extension-instance'),
284
+ [TableNames.SYS_EXTENSION_POINT]: taxonomyItem.default('server-development/extension-point'),
285
+ [TableNames.SYSEVENT_SCRIPT_ACTION]: taxonomyItem.default('server-development/script-action'),
286
+
287
+ // Service Portal tables
288
+ [TableNames.SP_PORTAL]: taxonomyItem.default('service-portal/service-portal'),
289
+
290
+ // User Interface tables
291
+ [TableNames.SYS_APP_APPLICATION]: taxonomyItem.default('user-interface/application-menu'),
292
+ [TableNames.ASMT_METRIC]: taxonomyItem.default('user-interface/assessment-metric'),
293
+ [TableNames.SYS_APP_MODULE]: taxonomyItem.default('user-interface/module'),
294
+ [TableNames.SYS_UI_POLICY]: taxonomyItem.default('client-development/ui-policy'),
295
+ [TableNames.SYS_UI_SECTION]: taxonomyItem.default('data/form-section'),
296
+ [TableNames.SYS_EMBEDDED_HELP_QUALIFIER]: taxonomyItem.default('user-interface/embedded-help-qualifier'),
297
+ [TableNames.SC_CATALOG]: taxonomyItem.default('user-interface/catalog'),
298
+ [TableNames.SC_CAT_ITEM]: taxonomyItem.default('user-interface/catalog-item'),
299
+ [TableNames.SC_CAT_ITEM_PRODUCER]: taxonomyItem.default('user-interface/record-producer'),
300
+ [TableNames.SYS_UI_CONTEXT_MENU]: taxonomyItem.default('user-interface/context-menu'),
301
+ [TableNames.SYS_UI_LIST]: taxonomyItem.default('user-interface/list'),
302
+ [TableNames.SYS_UI_VIEW]: taxonomyItem.default('user-interface/view'),
303
+ [TableNames.SYS_UI_LIST_CONTROL]: taxonomyItem.default('user-interface/list-control'),
304
+ [TableNames.SYS_UI_RELATED_LIST]: taxonomyItem.default('user-interface/related-list'),
305
+ [TableNames.SYS_UI_STYLE]: taxonomyItem.default('user-interface/style'),
306
+ [TableNames.SYS_UI_THEME]: taxonomyItem.default('user-interface/theme'),
307
+ [TableNames.SYS_EMBEDDED_HELP_CONTENT]: taxonomyItem.default('user-interface/embedded-help'),
308
+ [TableNames.SYS_EMBEDDED_TOUR_GUIDE]: taxonomyItem.default('user-interface/guided-tour'),
309
+ [TableNames.CMN_MAP_PAGE]: taxonomyItem.default('user-interface/map-page'),
310
+ [TableNames.CMN_TIMELINE_PAGE]: taxonomyItem.default('user-interface/timeline-page'),
311
+ [TableNames.SYS_UX_EXTENSION_POINT]: taxonomyItem.default('user-interface/page-collection'),
312
+ [TableNames.SYS_UX_APP_CONFIG]: taxonomyItem.default('user-interface/ux-app-configuration'),
313
+ [TableNames.SYS_UX_PAGE_REGISTRY]: taxonomyItem.default('user-interface/workspace'),
314
+ [TableNames.SYS_TEMPLATE]: taxonomyItem.default('user-interface/template'),
315
+ [TableNames.SYSRULE_VIEW]: taxonomyItem.default('user-interface/view-rule'),
316
+ })
317
+ .catchall(taxonomyItem)
318
+ .default({})
319
+
320
+ export const taxonomySchemaDefault = taxonomyMapping.parse({})
321
+
322
+ export const taxonomy = z
323
+ .object({
324
+ mapping: taxonomyMapping.default({}),
325
+ fallbackFolderName: z.string().default('other'),
326
+ })
327
+ .transform((data) => {
328
+ const mappingWithDefaults = new Proxy(data.mapping || {}, {
329
+ get(target, prop) {
330
+ if (typeof prop === 'string' && !(prop in target)) {
331
+ // Return fallback path for unmapped tables
332
+ return `${data.fallbackFolderName}/${kebabCase(prop)}`
333
+ }
334
+ return Reflect.get(target, prop)
335
+ },
336
+ }) as Record<string, string>
337
+
338
+ return {
339
+ mapping: mappingWithDefaults,
340
+ fallbackFolderName: data.fallbackFolderName,
341
+ }
342
+ })
343
+ .default({})
package/src/typescript.ts CHANGED
@@ -122,6 +122,10 @@ export const SupportedKinds = {
122
122
  name: 'TypeLiteral',
123
123
  node: {} as ts.TypeLiteralNode,
124
124
  },
125
+ [ts.SyntaxKind.LiteralType]: {
126
+ name: 'LiteralType',
127
+ node: {} as ts.LiteralTypeNode,
128
+ },
125
129
  [ts.SyntaxKind.PropertySignature]: {
126
130
  name: 'PropertySignature',
127
131
  node: {} as ts.PropertySignature,
package/src/xml.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { type Action, Record, RecordId, ResolvableShape, Shape } from './plugins'
1
+ import { Record, RecordId, ResolvableShape, Shape } from './plugins'
2
2
  import { js2xml, type Element } from 'xml-js'
3
3
 
4
- export function unloadBuilder({ scope, scopeId }: { scope: string; scopeId: string }) {
4
+ export function unloadBuilder({ scope, scopeId, table }: { scope: string; scopeId: string; table?: string }) {
5
5
  const recordUpdateElements = []
6
6
  const xmlJsObj = {
7
7
  declaration: {
@@ -13,6 +13,9 @@ export function unloadBuilder({ scope, scopeId }: { scope: string; scopeId: stri
13
13
  {
14
14
  type: 'element',
15
15
  name: 'record_update',
16
+ attributes: {
17
+ table,
18
+ },
16
19
  elements: recordUpdateElements,
17
20
  },
18
21
  ],
@@ -24,18 +27,24 @@ export function unloadBuilder({ scope, scopeId }: { scope: string; scopeId: stri
24
27
  recordUpdateElements,
25
28
  end,
26
29
  record: (record: Record, updateName: string) => {
27
- const rec = recordXml(recordUpdateElements, record.getTable(), record.getId().getValue(), {
28
- attr: { action: record.getAction() },
30
+ const table = record.getTable()
31
+
32
+ // TODO: Let the plugins define this kind of thing?
33
+ const extraAttributes =
34
+ table === 'sys_dictionary'
35
+ ? {
36
+ element: record.get('element').ifString()?.getValue() ?? '',
37
+ table: record.get('name').ifString()?.getValue() ?? '',
38
+ }
39
+ : {}
40
+
41
+ const rec = recordXml(recordUpdateElements, table, record.getId().getValue(), {
42
+ attr: { action: record.getAction(), ...extraAttributes },
29
43
  })
30
44
  rec.field('sys_scope', scopeId, { display_value: scope })
31
45
  rec.field('sys_update_name', updateName)
32
46
  return rec
33
47
  },
34
- createXML: (tableName: string, id: string | number, action: Action = 'INSERT_OR_UPDATE') => {
35
- const rec = recordXml(recordUpdateElements, tableName, id, { attr: { action } })
36
- rec.addSysScope(scope, scopeId)
37
- return rec
38
- },
39
48
  }
40
49
  }
41
50