@servicenow/sdk-build-plugins 4.0.1 → 4.1.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 (111) hide show
  1. package/dist/acl-plugin.js +23 -16
  2. package/dist/acl-plugin.js.map +1 -1
  3. package/dist/application-menu-plugin.js +15 -14
  4. package/dist/application-menu-plugin.js.map +1 -1
  5. package/dist/atf/test-plugin.js +37 -34
  6. package/dist/atf/test-plugin.js.map +1 -1
  7. package/dist/basic-syntax-plugin.js +50 -1
  8. package/dist/basic-syntax-plugin.js.map +1 -1
  9. package/dist/business-rule-plugin.js +12 -10
  10. package/dist/business-rule-plugin.js.map +1 -1
  11. package/dist/claims-plugin.d.ts +3 -0
  12. package/dist/claims-plugin.js +95 -0
  13. package/dist/claims-plugin.js.map +1 -0
  14. package/dist/client-script-plugin.js +1 -1
  15. package/dist/client-script-plugin.js.map +1 -1
  16. package/dist/column/column-to-record.d.ts +3 -3
  17. package/dist/column/column-to-record.js +17 -16
  18. package/dist/column/column-to-record.js.map +1 -1
  19. package/dist/column-plugin.js +86 -8
  20. package/dist/column-plugin.js.map +1 -1
  21. package/dist/cross-scope-privilege-plugin.js +17 -3
  22. package/dist/cross-scope-privilege-plugin.js.map +1 -1
  23. package/dist/html-import-plugin.js +8 -1
  24. package/dist/html-import-plugin.js.map +1 -1
  25. package/dist/index.d.ts +2 -1
  26. package/dist/index.js +3 -1
  27. package/dist/index.js.map +1 -1
  28. package/dist/json-plugin.d.ts +7 -2
  29. package/dist/json-plugin.js +28 -12
  30. package/dist/json-plugin.js.map +1 -1
  31. package/dist/list-plugin.js +29 -17
  32. package/dist/list-plugin.js.map +1 -1
  33. package/dist/now-config-plugin.js +14 -5
  34. package/dist/now-config-plugin.js.map +1 -1
  35. package/dist/now-include-plugin.d.ts +6 -7
  36. package/dist/now-include-plugin.js +59 -26
  37. package/dist/now-include-plugin.js.map +1 -1
  38. package/dist/now-ref-plugin.js +1 -1
  39. package/dist/now-ref-plugin.js.map +1 -1
  40. package/dist/package-json-plugin.js +5 -7
  41. package/dist/package-json-plugin.js.map +1 -1
  42. package/dist/property-plugin.js +1 -1
  43. package/dist/property-plugin.js.map +1 -1
  44. package/dist/record-plugin.js +23 -9
  45. package/dist/record-plugin.js.map +1 -1
  46. package/dist/repack/index.d.ts +2 -0
  47. package/dist/repack/index.js +8 -0
  48. package/dist/repack/index.js.map +1 -1
  49. package/dist/rest-api-plugin.js +12 -12
  50. package/dist/rest-api-plugin.js.map +1 -1
  51. package/dist/role-plugin.js +18 -16
  52. package/dist/role-plugin.js.map +1 -1
  53. package/dist/script-action-plugin.js +1 -1
  54. package/dist/script-action-plugin.js.map +1 -1
  55. package/dist/script-include-plugin.js +6 -4
  56. package/dist/script-include-plugin.js.map +1 -1
  57. package/dist/server-module-plugin/index.d.ts +3 -1
  58. package/dist/server-module-plugin/index.js +110 -28
  59. package/dist/server-module-plugin/index.js.map +1 -1
  60. package/dist/service-portal/angular-provider-plugin.js +3 -3
  61. package/dist/service-portal/angular-provider-plugin.js.map +1 -1
  62. package/dist/service-portal/dependency-plugin.js +9 -12
  63. package/dist/service-portal/dependency-plugin.js.map +1 -1
  64. package/dist/service-portal/widget-plugin.js +8 -8
  65. package/dist/service-portal/widget-plugin.js.map +1 -1
  66. package/dist/static-content-plugin.d.ts +2 -0
  67. package/dist/static-content-plugin.js +16 -13
  68. package/dist/static-content-plugin.js.map +1 -1
  69. package/dist/table-plugin.js +55 -33
  70. package/dist/table-plugin.js.map +1 -1
  71. package/dist/ui-action-plugin.js +29 -19
  72. package/dist/ui-action-plugin.js.map +1 -1
  73. package/dist/ui-page-plugin.js +6 -3
  74. package/dist/ui-page-plugin.js.map +1 -1
  75. package/dist/user-preference-plugin.js +2 -2
  76. package/dist/user-preference-plugin.js.map +1 -1
  77. package/package.json +5 -5
  78. package/src/acl-plugin.ts +31 -27
  79. package/src/application-menu-plugin.ts +39 -39
  80. package/src/atf/test-plugin.ts +82 -81
  81. package/src/basic-syntax-plugin.ts +54 -1
  82. package/src/business-rule-plugin.ts +74 -73
  83. package/src/claims-plugin.ts +116 -0
  84. package/src/client-script-plugin.ts +1 -1
  85. package/src/column/column-to-record.ts +59 -53
  86. package/src/column-plugin.ts +93 -8
  87. package/src/cross-scope-privilege-plugin.ts +18 -3
  88. package/src/html-import-plugin.ts +12 -2
  89. package/src/index.ts +2 -1
  90. package/src/json-plugin.ts +35 -15
  91. package/src/list-plugin.ts +39 -30
  92. package/src/now-config-plugin.ts +19 -8
  93. package/src/now-include-plugin.ts +64 -30
  94. package/src/now-ref-plugin.ts +1 -1
  95. package/src/package-json-plugin.ts +7 -6
  96. package/src/property-plugin.ts +1 -1
  97. package/src/record-plugin.ts +25 -9
  98. package/src/repack/index.ts +14 -0
  99. package/src/rest-api-plugin.ts +15 -15
  100. package/src/role-plugin.ts +15 -15
  101. package/src/script-action-plugin.ts +1 -1
  102. package/src/script-include-plugin.ts +7 -4
  103. package/src/server-module-plugin/index.ts +158 -43
  104. package/src/service-portal/angular-provider-plugin.ts +12 -10
  105. package/src/service-portal/dependency-plugin.ts +12 -13
  106. package/src/service-portal/widget-plugin.ts +36 -30
  107. package/src/static-content-plugin.ts +12 -10
  108. package/src/table-plugin.ts +71 -56
  109. package/src/ui-action-plugin.ts +49 -33
  110. package/src/ui-page-plugin.ts +6 -3
  111. package/src/user-preference-plugin.ts +2 -2
@@ -37,6 +37,7 @@ export const ListPlugin = Plugin.create({
37
37
  name: 'ListPlugin',
38
38
  records: {
39
39
  sys_ui_list: {
40
+ composite: true,
40
41
  coalesce: ['name', 'view', 'sys_domain', 'element', 'relationship', 'parent'],
41
42
  relationships: {
42
43
  sys_ui_list_element: {
@@ -126,12 +127,17 @@ export const ListPlugin = Plugin.create({
126
127
  }
127
128
  })
128
129
 
129
- const child = root.ele('sys_ui_list', { action: 'INSERT_OR_UPDATE' })
130
+ const child = root.ele('sys_ui_list', { action: list.getAction() })
130
131
  child.ele('sys_id').txt(list.getId().getValue())
131
132
  child.ele('sys_scope', { display_value: config.scope }).txt(config.scopeId)
132
133
 
133
- const view = list.get('view').toRecordId()
134
- child.ele('view', view.resolveKeys()).txt(view.getValue())
134
+ const view = list.get('view')
135
+ if (view.isRecordId() || view.isRecord()) {
136
+ const viewId = view.isRecordId() ? view : view.getId()
137
+ child.ele('view', viewId.resolveKeys()).txt(viewId.getValue())
138
+ } else {
139
+ child.ele('view').txt(view.asString().getValue())
140
+ }
135
141
 
136
142
  const name = list.get('name')
137
143
  if (name.isDefined()) {
@@ -153,6 +159,7 @@ export const ListPlugin = Plugin.create({
153
159
  return {
154
160
  success: true,
155
161
  value: {
162
+ source: list,
156
163
  name: `sys_ui_list_${list.getId().getValue()}.xml`,
157
164
  category: list.getInstallCategory(),
158
165
  content: xml.end({ prettyPrint: true }),
@@ -175,46 +182,48 @@ export const ListPlugin = Plugin.create({
175
182
 
176
183
  const arg = callExpression.getArgument(0).asObject()
177
184
  const columns = arg.get('columns').ifArray()?.getElements() ?? []
178
- const list = factory.createRecord({
185
+ const view = arg.get('view')
186
+ const viewReference = view.isString()
187
+ ? await factory.createReference({
188
+ source: view,
189
+ table: 'sys_ui_view',
190
+ keys: { name: view },
191
+ })
192
+ : view
193
+
194
+ const list = await factory.createRecord({
179
195
  source: callExpression,
180
196
  table: 'sys_ui_list',
181
197
  explicitId: arg.get('$id'),
182
198
  properties: arg.transform(({ $ }) => ({
183
199
  name: $.from('table'),
184
- view: $.map((v) =>
185
- v.ifString()
186
- ? factory.createReference({
187
- source: v,
188
- table: 'sys_ui_view',
189
- keys: {
190
- name: v,
191
- },
192
- })
193
- : v
194
- ),
200
+ view: $.val(viewReference),
195
201
  parent: $,
196
202
  relationship: $.map((v) => v.if([Record, StringShape])),
197
203
  sys_domain: $.val('global'), // TODO: Domain support?
198
204
  })),
199
205
  })
200
206
 
207
+ const columnRecords: Record[] = []
208
+ for (const [index, column] of columns.entries()) {
209
+ columnRecords.push(
210
+ await factory.createRecord({
211
+ source: callExpression,
212
+ table: 'sys_ui_list_element',
213
+ properties: {
214
+ list_id: list,
215
+ position: index,
216
+ ...(column.isString()
217
+ ? { element: column }
218
+ : generateListColumnProps(column.asObject(), index, diagnostics)),
219
+ },
220
+ })
221
+ )
222
+ }
223
+
201
224
  return {
202
225
  success: true,
203
- value: list.with(
204
- ...columns.map((column, index) =>
205
- factory.createRecord({
206
- source: callExpression,
207
- table: 'sys_ui_list_element',
208
- properties: {
209
- list_id: list,
210
- position: index,
211
- ...(column.isString()
212
- ? { element: column }
213
- : generateListColumnProps(column.asObject(), index, diagnostics)),
214
- },
215
- })
216
- )
217
- ),
226
+ value: list.with(...columnRecords),
218
227
  }
219
228
  },
220
229
  },
@@ -1,4 +1,4 @@
1
- import { NowConfig, ObjectShape, Plugin, Shape } from '@servicenow/sdk-build-core'
1
+ import { NowConfig, ObjectShape, MODULE_RESOLUTION, Plugin, Shape } from '@servicenow/sdk-build-core'
2
2
 
3
3
  import { JsonFileShape } from './json-plugin'
4
4
 
@@ -14,9 +14,8 @@ export const NowConfigPlugin = Plugin.create({
14
14
  ],
15
15
  records: {
16
16
  sys_app: {
17
- toShape(record, { packageJson }) {
17
+ toShape(record, { packageJson, config }) {
18
18
  const { name: packageName } = packageJson
19
-
20
19
  return {
21
20
  success: true,
22
21
  value: new NowConfigShape({
@@ -114,6 +113,9 @@ export const NowConfigPlugin = Plugin.create({
114
113
  logo: $.toString().def(''),
115
114
  guidedSetupGuid: $.from('guided_setup_guid').toString().def(''),
116
115
  installedAsDependency: $.from('installed_as_dependency').toBoolean().def(false),
116
+ packageResolverVersion: $.from('package_resolver_version').def(
117
+ config.scope === 'global' ? MODULE_RESOLUTION.V2 : MODULE_RESOLUTION.V1
118
+ ),
117
119
  })),
118
120
  }),
119
121
  }
@@ -123,7 +125,7 @@ export const NowConfigPlugin = Plugin.create({
123
125
  shapes: [
124
126
  {
125
127
  shape: JsonFileShape,
126
- toRecord(file, { factory, config: rawConfig, packageJson }) {
128
+ async toRecord(file, { factory, config: rawConfig, packageJson, diagnostics }) {
127
129
  if (file.getBaseName() !== NowConfig.FILE_NAME) {
128
130
  return { success: false }
129
131
  }
@@ -134,12 +136,19 @@ export const NowConfigPlugin = Plugin.create({
134
136
  const { name: packageName, version } = packageJson
135
137
  const name = config.get('name').isDefined() ? config.get('name').asString().getValue() : packageName
136
138
 
139
+ let packageJsonPath: string
140
+ try {
141
+ packageJsonPath = NowConfig.moduleResolutionPath(rawConfig, packageJson, false, 'package.json')
142
+ } catch (e: any) {
143
+ diagnostics.error(file, e.message)
144
+ }
145
+
137
146
  const accessControls = config.get('accessControls').ifDefined()?.asObject()
138
147
  const licensing = config.get('licensing').ifDefined()?.asObject()
139
148
 
140
149
  return {
141
150
  success: true,
142
- value: factory.createRecord({
151
+ value: await factory.createRecord({
143
152
  source: config,
144
153
  table: 'sys_app',
145
154
  properties: config.transform(({ $ }) => ({
@@ -176,15 +185,17 @@ export const NowConfigPlugin = Plugin.create({
176
185
  trackable: $.val(accessControls?.get('trackable')).toBoolean().def(true),
177
186
  uninstall_blocked: $.val(accessControls?.get('uninstallBlocked')).toBoolean().def(false),
178
187
  hide_on_ui: $.val(accessControls?.get('hideOnUI')).toBoolean().def(false),
179
- installed_as_dependency: $.toBoolean().def(false),
188
+ installed_as_dependency: $.from('installedAsDependency').toBoolean().def(false),
180
189
  license_category: $.val(licensing?.get('licenseCategory')).toString().def('none'),
181
-
182
190
  scope: $.val(scope),
183
- package_json: $.val(`${scope}/${packageName}/${version}/package.json`),
191
+ package_json: $.val(packageJsonPath),
184
192
  name: $.val(name),
185
193
  source: $.val(scope),
186
194
  sys_id: $.from('scopeId'),
187
195
  version: $.val(version),
196
+ package_resolver_version: $.from('packageResolverVersion').def(
197
+ scope === 'global' ? MODULE_RESOLUTION.V2 : MODULE_RESOLUTION.V1
198
+ ),
188
199
  })),
189
200
  }),
190
201
  }
@@ -1,45 +1,53 @@
1
1
  import {
2
- type ts,
3
2
  path as pathModule,
4
3
  CallExpressionShape,
5
4
  Plugin,
6
5
  type ProjectFile,
6
+ type Record,
7
7
  type Source,
8
8
  StringShape,
9
9
  Shape,
10
+ FileSystem,
11
+ type Transform,
10
12
  } from '@servicenow/sdk-build-core'
11
13
  import { CallExpressionPlugin } from './call-expression-plugin'
12
14
 
13
15
  export class NowIncludeShape extends CallExpressionShape {
14
- private readonly includedFile: ProjectFile
16
+ private readonly includedText: string
15
17
 
16
- constructor({ source, path, includedFile }: { source: Source; path: string; includedFile: ProjectFile }) {
18
+ constructor({ source, path, includedText }: { source: Source; path: string; includedText: string }) {
17
19
  super({ source, callee: 'Now.include', args: [path] })
18
- this.includedFile = includedFile
20
+ this.includedText = includedText
19
21
  }
20
22
 
21
23
  getPath(): string {
22
24
  return this.getArgument(0).asString().getValue()
23
25
  }
24
26
 
25
- getAbsolutePath(): string {
26
- return this.getIncludedFile().getPath()
27
+ override getValue(): string {
28
+ return this.includedText
27
29
  }
28
30
 
29
- getRelativePathFrom(node: ts.Node): string {
30
- return pathModule.relative(pathModule.dirname(node.getSourceFile().getFilePath()), this.getAbsolutePath())
31
+ override toString(): StringShape {
32
+ return Shape.from(this, this.getValue()).asString().withContentType('cdata')
31
33
  }
32
34
 
33
- getIncludedFile(): ProjectFile {
34
- return this.includedFile
35
+ override equals(other: unknown): boolean {
36
+ if (typeof other === 'string') {
37
+ return this.includedText === other
38
+ } else if (other instanceof Shape) {
39
+ return other.equals(this.includedText)
40
+ } else {
41
+ return super.equals(other)
42
+ }
35
43
  }
36
44
 
37
- override getValue(): string {
38
- return this.getIncludedFile().getContent()
39
- }
40
-
41
- override toString(): StringShape {
42
- return Shape.from(this, this.getValue()).asString().withContentType('cdata')
45
+ static async fromRecord(record: Record, text: string | Shape, transform: Transform): Promise<NowIncludeShape> {
46
+ return new NowIncludeShape({
47
+ source: record,
48
+ path: `./${await transform.getUpdateName(record)}.js`,
49
+ includedText: text instanceof Shape ? text.toString().getValue() : text,
50
+ })
43
51
  }
44
52
  }
45
53
 
@@ -61,7 +69,6 @@ export const NowIncludePlugin = Plugin.create({
61
69
  }
62
70
 
63
71
  const path = arg.getValue()
64
-
65
72
  if (!/^\.\.?\/.*$/.test(path.trim()) && path.includes('/')) {
66
73
  diagnostics.error(arg, 'Now.include() argument must be a relative path')
67
74
  return { success: false }
@@ -86,38 +93,64 @@ export const NowIncludePlugin = Plugin.create({
86
93
 
87
94
  return {
88
95
  success: true,
89
- value: new NowIncludeShape({ source: callExpression, path, includedFile }),
96
+ value: new NowIncludeShape({
97
+ source: callExpression,
98
+ path,
99
+ includedText: includedFile.getContent(),
100
+ }),
90
101
  }
91
102
  },
92
103
  },
93
104
  {
94
105
  shape: NowIncludeShape,
95
- async commit(shape, target, { transform, commit }) {
106
+ async commit(shape, target, { transform, commit, project, fs }) {
96
107
  const targetResult = await transform.toShape(target)
97
108
  if (!targetResult.success) {
98
109
  return { success: false }
99
110
  }
100
111
 
112
+ const targetDirPath = target.getSourceFile().getDirectoryPath()
113
+ const targetPath = project.resolvePath(targetDirPath, shape.getPath())
114
+
101
115
  const { value: targetShape } = targetResult
116
+ if (targetShape.equals(shape.getValue())) {
117
+ return { success: true }
118
+ }
119
+
102
120
  if (targetShape.is(NowIncludeShape)) {
103
- if (targetShape.getAbsolutePath() === shape.getAbsolutePath()) {
104
- // It's already a Now.include() call pointing to the same file, so nothing to do
105
- return { success: true }
121
+ // Never update the path of an existing Now.include() - just update the file content
122
+ project
123
+ .getFile(project.resolvePath(targetDirPath, targetShape.getPath()))
124
+ .setContent(shape.getValue())
125
+ } else if (targetShape.is(CallExpressionShape) && targetShape.getCallee() === 'Now.include') {
126
+ // TODO: This is hacky AF. When Now.include() is generated for the first time, it's
127
+ // just written to the file using getCode() which doesn't generate any file at the
128
+ // included path. Therefore, the shape is not parsed into a NowIncludeShape because
129
+ // we check if the file exists and return success: false if it doesn't. So it just
130
+ // comes back as a generic CallExpressionShape.
131
+ await commit(shape, target, CallExpressionPlugin)
132
+ if (FileSystem.existsSync(fs, targetPath)) {
133
+ project
134
+ .addFile(targetPath, { resolveDependencies: false, excludeFromCompiler: true })
135
+ .setContent(shape.getValue())
136
+ } else {
137
+ project.addFile(
138
+ { path: targetPath, content: shape.getValue() },
139
+ { resolveDependencies: false, excludeFromCompiler: true }
140
+ )
106
141
  }
107
142
  } else {
108
- if (targetShape.equals(shape.getIncludedFile().getContent())) {
109
- // It's not a Now.include() call, but it's equivalent to the content, so leave it (probably an inline string literal)
110
- return { success: true }
111
- }
143
+ // If we reach this point it's likely an inline string literal or some other value that
144
+ // just needs to be replaced.
145
+ target.replaceWithText(shape.toString().getCode())
112
146
  }
113
147
 
114
- await commit(shape, target, CallExpressionPlugin)
115
148
  return { success: true }
116
149
  },
117
150
  },
118
151
  {
119
152
  shape: StringShape,
120
- async commit(shape, target, { transform }) {
153
+ async commit(shape, target, { transform, project }) {
121
154
  const targetResult = await transform.toShape(target)
122
155
  if (!targetResult.success) {
123
156
  return { success: false }
@@ -128,8 +161,9 @@ export const NowIncludePlugin = Plugin.create({
128
161
  return { success: false }
129
162
  }
130
163
 
131
- const file = targetShape.getIncludedFile()
132
- if (!shape.equals(file.getContent())) {
164
+ if (!shape.equals(targetShape.getValue())) {
165
+ const targetDirPath = target.getSourceFile().getDirectoryPath()
166
+ const file = project.getFile(project.resolvePath(targetDirPath, targetShape.getPath()))
133
167
  file.setContent(shape.getValue())
134
168
  }
135
169
 
@@ -40,7 +40,7 @@ export const NowRefPlugin = Plugin.create({
40
40
 
41
41
  return {
42
42
  success: true,
43
- value: factory.createReference({ source: node, table, guid, keys }),
43
+ value: await factory.createReference({ source: node, table, guid, keys }),
44
44
  }
45
45
  },
46
46
  },
@@ -5,6 +5,7 @@ import {
5
5
  Plugin,
6
6
  type ObjectShape,
7
7
  Shape,
8
+ NowConfig,
8
9
  } from '@servicenow/sdk-build-core'
9
10
  import { RepackService } from './repack'
10
11
  import { JsonFileShape } from './json-plugin'
@@ -20,22 +21,22 @@ export const PackageJsonPlugin = Plugin.create({
20
21
  }
21
22
 
22
23
  const relativePath = pathModule.relative(project.getRootDir(), file.getPath())
23
- const sysModulePath = pathModule.join(config.scope, packageJson.name, packageJson.version, relativePath)
24
+ const sysModulePath = NowConfig.moduleResolutionPath(config, packageJson, false, relativePath)
24
25
 
25
- const sbomRecord = factory.createRecord({
26
+ const sbomRecord = await factory.createRecord({
26
27
  source: file,
27
28
  table: 'sys_module',
28
29
  explicitId: 'bom_json',
29
30
  properties: {
30
- path: pathModule.join(config.scope, packageJson.name, packageJson.version, 'bom.json'),
31
+ path: NowConfig.moduleResolutionPath(config, packageJson, false, 'bom.json'),
31
32
  external_source: false,
32
33
  },
33
34
  })
34
35
 
35
36
  return {
36
37
  success: true,
37
- value: factory
38
- .createRecord({
38
+ value: (
39
+ await factory.createRecord({
39
40
  source: file,
40
41
  table: 'sys_module',
41
42
  explicitId: relativePath.replaceAll(/[./\\]/g, '_'),
@@ -56,7 +57,7 @@ export const PackageJsonPlugin = Plugin.create({
56
57
  sys_name: sysModulePath,
57
58
  },
58
59
  })
59
- .with(sbomRecord),
60
+ ).with(sbomRecord),
60
61
  }
61
62
  },
62
63
  },
@@ -73,7 +73,7 @@ export const PropertyPlugin = Plugin.create({
73
73
 
74
74
  return {
75
75
  success: true,
76
- value: factory.createRecord({
76
+ value: await factory.createRecord({
77
77
  source: callExpression,
78
78
  table: 'sys_properties',
79
79
  explicitId: prop.get('$id'),
@@ -29,6 +29,9 @@ export const RecordPlugin = Plugin.create({
29
29
  name: 'RecordPlugin',
30
30
  records: {
31
31
  '*': {
32
+ getUpdateName(record) {
33
+ return { success: true, value: `${record.getTable()}_${record.getId().getValue()}` }
34
+ },
32
35
  toShape(record) {
33
36
  return {
34
37
  success: true,
@@ -52,21 +55,34 @@ export const RecordPlugin = Plugin.create({
52
55
  }),
53
56
  }
54
57
  },
55
- toFile(record, { config }) {
58
+ async toFile(record, { config, database, transform }) {
56
59
  const recordBuilder = unloadBuilder(config)
57
- const table = record.getTable()
58
- const guid = record.getId().getValue()
59
- const builder = recordBuilder.record(record)
60
+ const updateName = await transform.getUpdateName(record)
61
+ const builder = recordBuilder.record(record, updateName)
60
62
 
61
63
  record
62
64
  .entries()
63
65
  .sort(([a], [b]) => a.localeCompare(b)) // Sort keys to make outputs more deterministic
64
66
  .forEach(([prop, shape]) => builder.field(prop, shape))
65
67
 
68
+ const claims = database
69
+ .query('sys_claim')
70
+ .filter((claim) => claim.get('metadata_update_name').equals(updateName))
71
+
72
+ for (const claim of claims) {
73
+ const claimUpdateName = await transform.getUpdateName(claim)
74
+ const claimBuilder = recordBuilder.record(claim, claimUpdateName)
75
+ claim
76
+ .entries()
77
+ .sort(([a], [b]) => a.localeCompare(b)) // Sort keys to make outputs more deterministic
78
+ .forEach(([prop, shape]) => claimBuilder.field(prop, shape))
79
+ }
80
+
66
81
  return {
67
82
  success: true,
68
83
  value: {
69
- name: `${table}_${guid}.xml`,
84
+ source: record,
85
+ name: `${updateName}.xml`,
70
86
  category: record.getInstallCategory(),
71
87
  content: recordBuilder.end(),
72
88
  },
@@ -78,7 +94,7 @@ export const RecordPlugin = Plugin.create({
78
94
  {
79
95
  shape: CallExpressionShape,
80
96
  fileTypes: ['fluent'],
81
- toRecord(callExpression, { factory, diagnostics }) {
97
+ async toRecord(callExpression, { factory, diagnostics }) {
82
98
  if (callExpression.getCallee() !== 'Record') {
83
99
  return { success: false }
84
100
  }
@@ -94,7 +110,7 @@ export const RecordPlugin = Plugin.create({
94
110
  }
95
111
  return {
96
112
  success: true,
97
- value: factory.createRecord({
113
+ value: await factory.createRecord({
98
114
  source: callExpression,
99
115
  table,
100
116
  explicitId: record.get('$id'),
@@ -107,9 +123,9 @@ export const RecordPlugin = Plugin.create({
107
123
  files: [
108
124
  {
109
125
  matcher: /\.xml$/,
110
- toRecord(file, { parser, logger }) {
126
+ async toRecord(file, { parser, logger }) {
111
127
  try {
112
- const [first, ...rest] = parser.parsePayload(file)
128
+ const [first, ...rest] = await parser.parsePayload(file)
113
129
 
114
130
  if (!first) {
115
131
  return { success: false }
@@ -1,6 +1,16 @@
1
1
  import { path } from '@servicenow/sdk-build-core'
2
2
  import type { DependencyNode, RepackOptions } from '@servicenow/sdk-repack'
3
3
 
4
+ export async function checkModuleExists(
5
+ module: string,
6
+ logger: RepackOptions['logger'],
7
+ fs: RepackOptions['fs'],
8
+ workingDir: RepackOptions['workingDir']
9
+ ) {
10
+ const repackService = await RepackService.create(logger, fs, workingDir)
11
+ return repackService.checkModuleExists(module)
12
+ }
13
+
4
14
  export const REPACK_OUTPUT_DIR = path.join('.now', '.output')
5
15
 
6
16
  export class RepackService {
@@ -38,4 +48,8 @@ export class RepackService {
38
48
  logger: this.logger!,
39
49
  })
40
50
  }
51
+
52
+ async checkModuleExists(module: string) {
53
+ return this.repack.checkModuleExists(module, this.fs, this.workingDir, this.logger!)
54
+ }
41
55
  }
@@ -94,7 +94,7 @@ function getVersionId(
94
94
  return versionToVersionRecordMap.get(`v${version}`)!.getId()
95
95
  }
96
96
 
97
- function generateVersionRecords(
97
+ async function generateVersionRecords(
98
98
  versions: Shape[],
99
99
  restApi: ObjectShape,
100
100
  restRecord: Record,
@@ -102,12 +102,12 @@ function generateVersionRecords(
102
102
  factory: Factory,
103
103
  diagnostics: Diagnostics,
104
104
  callExpression: CallExpressionShape
105
- ): Map<string, Record> {
105
+ ): Promise<Map<string, Record>> {
106
106
  const versionMap = new Map<string, Record>()
107
107
  for (const v of versions) {
108
108
  const version = v.asObject().get('version').getValue()
109
109
  const versionId = `v${version}`
110
- const versionRecord = factory.createRecord({
110
+ const versionRecord = await factory.createRecord({
111
111
  source: callExpression,
112
112
  table: 'sys_ws_version',
113
113
  explicitId: v.asObject().get('$id'),
@@ -155,7 +155,7 @@ function checkForDuplicateRecords(
155
155
  }
156
156
  }
157
157
 
158
- function generateRouteAttributeRecords(
158
+ async function generateRouteAttributeRecords(
159
159
  attributes: Shape[],
160
160
  restDef: Record,
161
161
  routeDef: Record,
@@ -164,10 +164,10 @@ function generateRouteAttributeRecords(
164
164
  factory: Factory,
165
165
  diagnostics: Diagnostics,
166
166
  callExpression: CallExpressionShape
167
- ): Record[] {
167
+ ): Promise<Record[]> {
168
168
  const records: Record[] = []
169
169
  for (const attr of attributes) {
170
- const attrRecord = factory.createRecord({
170
+ const attrRecord = await factory.createRecord({
171
171
  source: callExpression,
172
172
  table: `sys_ws_${attrType}`,
173
173
  explicitId: attr.asObject().get('$id'),
@@ -182,7 +182,7 @@ function generateRouteAttributeRecords(
182
182
 
183
183
  checkForDuplicateRecords(attrMap, attrRecord, attr.asObject(), diagnostics)
184
184
 
185
- const attributeMappingRecord = factory.createRecord({
185
+ const attributeMappingRecord = await factory.createRecord({
186
186
  source: callExpression,
187
187
  table: `sys_ws_${attrType}_map`,
188
188
  properties: attr.asObject().transform(({ $ }) => ({
@@ -197,7 +197,7 @@ function generateRouteAttributeRecords(
197
197
  return records
198
198
  }
199
199
 
200
- function generateRouteAndRouteAttrRecords(
200
+ async function generateRouteAndRouteAttrRecords(
201
201
  routes: Shape[],
202
202
  restDef: Record,
203
203
  factory: Factory,
@@ -205,7 +205,7 @@ function generateRouteAndRouteAttrRecords(
205
205
  diagnostics: Diagnostics,
206
206
  versionToVersionRecordMap: Map<string, Record>,
207
207
  callExpression: CallExpressionShape
208
- ): Record[] {
208
+ ): Promise<Record[]> {
209
209
  const routeRecords: Record[] = []
210
210
  const headersMap = new Map<string, Record>()
211
211
  const parametersMap = new Map<string, Record>()
@@ -246,7 +246,7 @@ function generateRouteAndRouteAttrRecords(
246
246
  )
247
247
  }
248
248
 
249
- const routeRecord = factory.createRecord({
249
+ const routeRecord = await factory.createRecord({
250
250
  source: callExpression,
251
251
  table: 'sys_ws_operation',
252
252
  explicitId: route.get('$id'),
@@ -285,7 +285,7 @@ function generateRouteAndRouteAttrRecords(
285
285
  h.asObject().withAliasedKeys(attributeAliases)
286
286
  generateDeprecatedDiagnostics(h.asObject(), diagnostics)
287
287
  })
288
- const headerRecords = generateRouteAttributeRecords(
288
+ const headerRecords = await generateRouteAttributeRecords(
289
289
  routeHeaders,
290
290
  restDef,
291
291
  routeRecord,
@@ -301,7 +301,7 @@ function generateRouteAndRouteAttrRecords(
301
301
  p.asObject().withAliasedKeys(attributeAliases)
302
302
  generateDeprecatedDiagnostics(p.asObject(), diagnostics)
303
303
  })
304
- const parameterRecords = generateRouteAttributeRecords(
304
+ const parameterRecords = await generateRouteAttributeRecords(
305
305
  routeParameters,
306
306
  restDef,
307
307
  routeRecord,
@@ -594,7 +594,7 @@ export const RestApiPlugin = Plugin.create({
594
594
  }
595
595
 
596
596
  const enforceAcls = restApi.get('enforceAcl')
597
- const restRecord = factory.createRecord({
597
+ const restRecord = await factory.createRecord({
598
598
  source: callExpression,
599
599
  table: 'sys_ws_definition',
600
600
  explicitId: restApi.get('$id'),
@@ -622,7 +622,7 @@ export const RestApiPlugin = Plugin.create({
622
622
  enforce_acl: $.val(mergeAcls(enforceAcls)),
623
623
  })),
624
624
  })
625
- const versionToVersionRecordMap = generateVersionRecords(
625
+ const versionToVersionRecordMap = await generateVersionRecords(
626
626
  versions,
627
627
  restApi,
628
628
  restRecord,
@@ -638,7 +638,7 @@ export const RestApiPlugin = Plugin.create({
638
638
  generateDeprecatedDiagnostics(r.asObject(), diagnostics)
639
639
  })
640
640
 
641
- const routeAndRouteAttrRecords = generateRouteAndRouteAttrRecords(
641
+ const routeAndRouteAttrRecords = await generateRouteAndRouteAttrRecords(
642
642
  routes,
643
643
  restRecord,
644
644
  factory,