@servicenow/sdk-build-plugins 4.6.0 → 4.6.1
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 +3 -1
- package/dist/acl-plugin.js.map +1 -1
- package/dist/atf/test-plugin.js +6 -8
- package/dist/atf/test-plugin.js.map +1 -1
- package/dist/basic-syntax-plugin.js +10 -3
- package/dist/basic-syntax-plugin.js.map +1 -1
- package/dist/column-plugin.js +96 -42
- package/dist/column-plugin.js.map +1 -1
- package/dist/now-config-plugin.js +1 -0
- package/dist/now-config-plugin.js.map +1 -1
- package/dist/record-plugin.js +3 -2
- package/dist/record-plugin.js.map +1 -1
- package/dist/script-include-plugin.js +4 -0
- package/dist/script-include-plugin.js.map +1 -1
- package/dist/service-catalog/catalog-clientscript-plugin.js +2 -2
- package/dist/service-catalog/catalog-clientscript-plugin.js.map +1 -1
- package/dist/service-catalog/catalog-ui-policy-plugin.js +2 -2
- package/dist/service-catalog/catalog-ui-policy-plugin.js.map +1 -1
- package/dist/service-catalog/service-catalog-base.d.ts +2 -2
- package/dist/service-catalog/service-catalog-base.js +2 -2
- package/dist/service-catalog/service-catalog-base.js.map +1 -1
- package/dist/service-catalog/utils.js +1 -1
- package/dist/service-catalog/utils.js.map +1 -1
- package/dist/table-plugin.js +201 -55
- package/dist/table-plugin.js.map +1 -1
- package/dist/ui-policy-plugin.js +28 -96
- package/dist/ui-policy-plugin.js.map +1 -1
- package/dist/utils.d.ts +5 -1
- package/dist/utils.js +41 -0
- package/dist/utils.js.map +1 -1
- package/package.json +4 -4
- package/src/acl-plugin.ts +3 -1
- package/src/atf/test-plugin.ts +6 -9
- package/src/basic-syntax-plugin.ts +11 -3
- package/src/column-plugin.ts +134 -67
- package/src/now-config-plugin.ts +1 -0
- package/src/record-plugin.ts +11 -3
- package/src/script-include-plugin.ts +8 -0
- package/src/service-catalog/catalog-clientscript-plugin.ts +2 -2
- package/src/service-catalog/catalog-ui-policy-plugin.ts +2 -2
- package/src/service-catalog/service-catalog-base.ts +2 -2
- package/src/service-catalog/utils.ts +1 -1
- package/src/table-plugin.ts +254 -77
- package/src/ui-policy-plugin.ts +32 -128
- package/src/utils.ts +52 -0
package/src/ui-policy-plugin.ts
CHANGED
|
@@ -108,128 +108,35 @@ export const UiPolicyPlugin = Plugin.create({
|
|
|
108
108
|
},
|
|
109
109
|
},
|
|
110
110
|
toShape(record, { descendants }) {
|
|
111
|
-
const actions = descendants
|
|
112
|
-
.
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
fieldMessage?: string
|
|
128
|
-
fieldMessageType?: string
|
|
129
|
-
valueAction?: string
|
|
130
|
-
} = {
|
|
131
|
-
field: fieldValue,
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// Convert ServiceNow string format to boolean | 'ignore'
|
|
135
|
-
const visible = stringToBoolean(action.get('visible')?.ifString()?.getValue())
|
|
136
|
-
const disabled = stringToBoolean(action.get('disabled')?.ifString()?.getValue())
|
|
137
|
-
const mandatory = stringToBoolean(action.get('mandatory')?.ifString()?.getValue())
|
|
138
|
-
|
|
139
|
-
// Only include visible if it's not 'ignore'
|
|
140
|
-
if (visible !== undefined && visible !== 'ignore') {
|
|
141
|
-
actionObj.visible = visible
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// Convert 'disabled' to 'readOnly'
|
|
145
|
-
// Only include 'readOnly' if it's not 'ignore'
|
|
146
|
-
if (disabled !== undefined && disabled !== 'ignore') {
|
|
147
|
-
actionObj.readOnly = disabled
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
// Only include mandatory if it's not 'ignore'
|
|
151
|
-
if (mandatory !== undefined && mandatory !== 'ignore') {
|
|
152
|
-
actionObj.mandatory = mandatory
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
const cleared = action.get('cleared')?.ifBoolean()?.getValue()
|
|
156
|
-
if (cleared) {
|
|
157
|
-
actionObj.cleared = cleared
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// Add new optional fields - only if they have meaningful values
|
|
161
|
-
const table = action.get('table')?.ifString()?.getValue()
|
|
162
|
-
const parentTable = record.get('table')?.ifString()?.getValue()
|
|
163
|
-
// Only include table if it's different from the parent policy's table
|
|
164
|
-
if (table && table !== parentTable) {
|
|
165
|
-
actionObj.table = table
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
const value = action.get('value')?.ifString()?.getValue()
|
|
169
|
-
if (value) {
|
|
170
|
-
actionObj.value = value
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
const fieldMessage = action.get('field_message')?.ifString()?.getValue()
|
|
174
|
-
if (fieldMessage) {
|
|
175
|
-
actionObj.fieldMessage = fieldMessage
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
const fieldMessageType = action.get('field_message_type')?.ifString()?.getValue()
|
|
179
|
-
// Only include if it's not the default value 'none'
|
|
180
|
-
if (fieldMessageType && fieldMessageType !== 'none') {
|
|
181
|
-
actionObj.fieldMessageType = fieldMessageType
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
const valueAction = action.get('value_action')?.ifString()?.getValue()
|
|
185
|
-
// Only include if it's not the default value 'ignore'
|
|
186
|
-
if (valueAction && valueAction !== 'ignore') {
|
|
187
|
-
actionObj.valueAction = valueAction
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// Skip actions that have no meaningful properties (all are 'ignore')
|
|
191
|
-
if (Object.keys(actionObj).length === 1) {
|
|
192
|
-
return null // Only 'field' property exists, skip this action
|
|
193
|
-
}
|
|
111
|
+
const actions = descendants.query(SYS_UI_POLICY_ACTION).map((action) => {
|
|
112
|
+
return action.transform(({ $ }) => ({
|
|
113
|
+
field: $,
|
|
114
|
+
visible: $.map((v) => stringToBoolean(v?.asString()?.getValue())).def('ignore'),
|
|
115
|
+
readOnly: $.from('disabled')
|
|
116
|
+
.map((v) => stringToBoolean(v?.asString()?.getValue()))
|
|
117
|
+
.def('ignore'),
|
|
118
|
+
mandatory: $.map((v) => stringToBoolean(v?.asString()?.getValue())).def('ignore'),
|
|
119
|
+
cleared: $.toBoolean().def(false),
|
|
120
|
+
table: $.def(''),
|
|
121
|
+
value: $.def(''),
|
|
122
|
+
fieldMessage: $.from('field_message').def(''),
|
|
123
|
+
fieldMessageType: $.from('field_message_type').def('none'),
|
|
124
|
+
valueAction: $.from('value_action').def('ignore'),
|
|
125
|
+
}))
|
|
126
|
+
})
|
|
194
127
|
|
|
195
|
-
|
|
196
|
-
})
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
.query(SYS_UI_POLICY_RL_ACTION)
|
|
202
|
-
.map((rlAction) => {
|
|
203
|
-
const rlActionObj: {
|
|
204
|
-
list?: string
|
|
205
|
-
visible?: boolean | 'ignore'
|
|
206
|
-
} = {}
|
|
207
|
-
|
|
208
|
-
const listValue = rlAction.get('list')?.ifString()?.getValue()
|
|
209
|
-
if (listValue) {
|
|
210
|
-
// Strip REL: prefix if present (transform ServiceNow → Fluent)
|
|
211
|
-
// Users write plain GUIDs or table.field format in Fluent code
|
|
212
|
-
if (listValue.startsWith('REL:')) {
|
|
213
|
-
rlActionObj.list = listValue.substring(4) // Remove 'REL:' prefix
|
|
214
|
-
} else {
|
|
215
|
-
rlActionObj.list = listValue
|
|
128
|
+
const relatedListActions = descendants.query(SYS_UI_POLICY_RL_ACTION).map((rlAction) =>
|
|
129
|
+
rlAction.transform(({ $ }) => ({
|
|
130
|
+
list: $.map((v) => {
|
|
131
|
+
if (v?.ifString()?.ifDefined()) {
|
|
132
|
+
const listVal = v.asString().getValue()
|
|
133
|
+
return listVal.startsWith('REL:') ? listVal.substring(4) : listVal
|
|
216
134
|
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
rlActionObj.visible = visible
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
// Skip if no meaningful properties (only $id exists)
|
|
226
|
-
if (Object.keys(rlActionObj).length === 0) {
|
|
227
|
-
return null
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
return rlActionObj
|
|
231
|
-
})
|
|
232
|
-
.filter((rlAction) => rlAction !== null) // Remove null actions
|
|
135
|
+
return ''
|
|
136
|
+
}).def(''),
|
|
137
|
+
visible: $.map((v) => stringToBoolean(v?.asString()?.getValue())).def('ignore'),
|
|
138
|
+
}))
|
|
139
|
+
)
|
|
233
140
|
|
|
234
141
|
return {
|
|
235
142
|
success: true,
|
|
@@ -278,7 +185,7 @@ export const UiPolicyPlugin = Plugin.create({
|
|
|
278
185
|
order: $.from('order').toNumber().def(100),
|
|
279
186
|
setValues: $.from('set_values').def(''),
|
|
280
187
|
view: $.from('view').def(''),
|
|
281
|
-
actions: $.val(actions.
|
|
188
|
+
actions: $.val(actions).def([]),
|
|
282
189
|
relatedListActions: $.val(
|
|
283
190
|
relatedListActions.length > 0 ? relatedListActions : undefined
|
|
284
191
|
),
|
|
@@ -401,11 +308,10 @@ export const UiPolicyPlugin = Plugin.create({
|
|
|
401
308
|
const hasClearedProp = action.get('cleared')?.isBoolean() || false
|
|
402
309
|
|
|
403
310
|
if (!hasVisibleProp && !hasReadOnlyProp && !hasMandatoryProp && !hasClearedProp) {
|
|
404
|
-
diagnostics.
|
|
311
|
+
diagnostics.hint(
|
|
405
312
|
action,
|
|
406
|
-
`Action at index ${i}
|
|
313
|
+
`Action at index ${i} has no effect — consider specifying at least one of: visible, readOnly, mandatory, or cleared`
|
|
407
314
|
)
|
|
408
|
-
continue
|
|
409
315
|
}
|
|
410
316
|
|
|
411
317
|
const actionRecord = await factory.createRecord({
|
|
@@ -475,14 +381,12 @@ export const UiPolicyPlugin = Plugin.create({
|
|
|
475
381
|
}
|
|
476
382
|
}
|
|
477
383
|
|
|
478
|
-
// At least one property must be specified (visible or list)
|
|
479
384
|
const hasVisibleProp = isValidActionValue(rlAction.get('visible'))
|
|
480
385
|
if (!hasVisibleProp && !listValue) {
|
|
481
|
-
diagnostics.
|
|
386
|
+
diagnostics.hint(
|
|
482
387
|
rlAction,
|
|
483
|
-
`Related list action at index ${i}
|
|
388
|
+
`Related list action at index ${i} has no effect — consider specifying at least one of: list or visible`
|
|
484
389
|
)
|
|
485
|
-
continue
|
|
486
390
|
}
|
|
487
391
|
|
|
488
392
|
const rlActionRecord = await factory.createRecord({
|
package/src/utils.ts
CHANGED
|
@@ -6,7 +6,10 @@ import {
|
|
|
6
6
|
type Compiler,
|
|
7
7
|
type PluginApiDoc,
|
|
8
8
|
type Record as FluentRecord,
|
|
9
|
+
type OutputFile,
|
|
10
|
+
type Transform,
|
|
9
11
|
} from '@servicenow/sdk-build-core'
|
|
12
|
+
import { create } from 'xmlbuilder2'
|
|
10
13
|
|
|
11
14
|
export function toReference(shape: Shape) {
|
|
12
15
|
return shape.ifRecord()?.getId() ?? shape.ifString()?.getValue() ?? ''
|
|
@@ -130,6 +133,55 @@ export const showGuidFieldDiagnostic = (
|
|
|
130
133
|
}
|
|
131
134
|
}
|
|
132
135
|
|
|
136
|
+
export async function generateChoiceSetFile(
|
|
137
|
+
choiceSet: FluentRecord,
|
|
138
|
+
choices: FluentRecord[],
|
|
139
|
+
config: { scope: string; scopeId: string },
|
|
140
|
+
transform: Transform
|
|
141
|
+
): Promise<OutputFile> {
|
|
142
|
+
const tableName = choiceSet.get('name').asString().getValue()
|
|
143
|
+
const elementName = choiceSet.get('element').asString().getValue()
|
|
144
|
+
const xml = create().ele('record_update')
|
|
145
|
+
const root = xml.ele('sys_choice_set', { table: tableName, field: elementName })
|
|
146
|
+
|
|
147
|
+
choices.forEach((choice) => {
|
|
148
|
+
const child = root.ele('sys_choice', { action: choice.getAction() })
|
|
149
|
+
child.ele('sys_id').txt(choice.getId().getValue())
|
|
150
|
+
child.ele('name').txt(tableName)
|
|
151
|
+
child.ele('element').txt(elementName)
|
|
152
|
+
|
|
153
|
+
for (const prop of [
|
|
154
|
+
'label',
|
|
155
|
+
'value',
|
|
156
|
+
'sequence',
|
|
157
|
+
'dependent_value',
|
|
158
|
+
'hint',
|
|
159
|
+
'inactive',
|
|
160
|
+
'inactive_on_update',
|
|
161
|
+
'language',
|
|
162
|
+
]) {
|
|
163
|
+
choice
|
|
164
|
+
.get(prop)
|
|
165
|
+
.ifDefined()
|
|
166
|
+
?.toString()
|
|
167
|
+
.pipe((p) => child.ele(prop).txt(p.getValue()))
|
|
168
|
+
}
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
const child = root.ele('sys_choice_set', { action: choiceSet.getAction() })
|
|
172
|
+
child.ele('sys_id').txt(choiceSet.getId().getValue())
|
|
173
|
+
child.ele('sys_scope', { display_value: config.scope }).txt(config.scopeId)
|
|
174
|
+
child.ele('name').txt(tableName)
|
|
175
|
+
child.ele('element').txt(elementName)
|
|
176
|
+
|
|
177
|
+
return {
|
|
178
|
+
source: choiceSet,
|
|
179
|
+
name: `${await transform.getUpdateName(choiceSet)}.xml`,
|
|
180
|
+
category: choiceSet.getInstallCategory(),
|
|
181
|
+
content: xml.end({ prettyPrint: true }),
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
133
185
|
/**
|
|
134
186
|
* Creates a documentation entry for first-party SDK plugins.
|
|
135
187
|
*
|