@servicenow/sdk-build-plugins 4.6.1 → 4.7.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.
Files changed (279) hide show
  1. package/dist/acl-plugin.js +0 -3
  2. package/dist/acl-plugin.js.map +1 -1
  3. package/dist/applicability-plugin.js +0 -2
  4. package/dist/applicability-plugin.js.map +1 -1
  5. package/dist/application-menu-plugin.js +0 -2
  6. package/dist/application-menu-plugin.js.map +1 -1
  7. package/dist/arrow-function-plugin.js +0 -1
  8. package/dist/arrow-function-plugin.js.map +1 -1
  9. package/dist/atf/test-plugin.js +0 -2
  10. package/dist/atf/test-plugin.js.map +1 -1
  11. package/dist/basic-syntax-plugin.js +0 -1
  12. package/dist/basic-syntax-plugin.js.map +1 -1
  13. package/dist/business-rule-plugin.js +0 -1
  14. package/dist/business-rule-plugin.js.map +1 -1
  15. package/dist/call-expression-plugin.js +0 -1
  16. package/dist/call-expression-plugin.js.map +1 -1
  17. package/dist/claims-plugin.js +0 -1
  18. package/dist/claims-plugin.js.map +1 -1
  19. package/dist/client-script-plugin.js +0 -1
  20. package/dist/client-script-plugin.js.map +1 -1
  21. package/dist/column-plugin.js +24 -7
  22. package/dist/column-plugin.js.map +1 -1
  23. package/dist/cross-scope-privilege-plugin.js +0 -1
  24. package/dist/cross-scope-privilege-plugin.js.map +1 -1
  25. package/dist/dashboard/dashboard-plugin.js +0 -2
  26. package/dist/dashboard/dashboard-plugin.js.map +1 -1
  27. package/dist/data-plugin.js +0 -1
  28. package/dist/data-plugin.js.map +1 -1
  29. package/dist/data-policy-plugin.d.ts +2 -0
  30. package/dist/data-policy-plugin.js +276 -0
  31. package/dist/data-policy-plugin.js.map +1 -0
  32. package/dist/email-notification-plugin.js +2 -3
  33. package/dist/email-notification-plugin.js.map +1 -1
  34. package/dist/flow/flow-logic/flow-logic-constants.d.ts +2 -0
  35. package/dist/flow/flow-logic/flow-logic-constants.js +6 -1
  36. package/dist/flow/flow-logic/flow-logic-constants.js.map +1 -1
  37. package/dist/flow/flow-logic/flow-logic-diagnostics.js +192 -56
  38. package/dist/flow/flow-logic/flow-logic-diagnostics.js.map +1 -1
  39. package/dist/flow/flow-logic/flow-logic-plugin-helpers.d.ts +2 -1
  40. package/dist/flow/flow-logic/flow-logic-plugin-helpers.js +44 -5
  41. package/dist/flow/flow-logic/flow-logic-plugin-helpers.js.map +1 -1
  42. package/dist/flow/flow-logic/flow-logic-plugin.js +279 -29
  43. package/dist/flow/flow-logic/flow-logic-plugin.js.map +1 -1
  44. package/dist/flow/flow-logic/flow-logic-shapes.d.ts +15 -0
  45. package/dist/flow/flow-logic/flow-logic-shapes.js +25 -1
  46. package/dist/flow/flow-logic/flow-logic-shapes.js.map +1 -1
  47. package/dist/flow/plugins/approval-rules-plugin.js +0 -1
  48. package/dist/flow/plugins/approval-rules-plugin.js.map +1 -1
  49. package/dist/flow/plugins/flow-action-definition-plugin.js +804 -205
  50. package/dist/flow/plugins/flow-action-definition-plugin.js.map +1 -1
  51. package/dist/flow/plugins/flow-data-pill-plugin.js +3 -5
  52. package/dist/flow/plugins/flow-data-pill-plugin.js.map +1 -1
  53. package/dist/flow/plugins/flow-definition-plugin.js +84 -17
  54. package/dist/flow/plugins/flow-definition-plugin.js.map +1 -1
  55. package/dist/flow/plugins/flow-diagnostics-plugin.js +65 -3
  56. package/dist/flow/plugins/flow-diagnostics-plugin.js.map +1 -1
  57. package/dist/flow/plugins/flow-instance-plugin.js +13 -5
  58. package/dist/flow/plugins/flow-instance-plugin.js.map +1 -1
  59. package/dist/flow/plugins/flow-trigger-instance-plugin.js +0 -1
  60. package/dist/flow/plugins/flow-trigger-instance-plugin.js.map +1 -1
  61. package/dist/flow/plugins/inline-script-plugin.js +0 -1
  62. package/dist/flow/plugins/inline-script-plugin.js.map +1 -1
  63. package/dist/flow/plugins/step-definition-plugin.js +0 -2
  64. package/dist/flow/plugins/step-definition-plugin.js.map +1 -1
  65. package/dist/flow/plugins/step-instance-plugin.js +216 -77
  66. package/dist/flow/plugins/step-instance-plugin.js.map +1 -1
  67. package/dist/flow/plugins/trigger-plugin.js +0 -2
  68. package/dist/flow/plugins/trigger-plugin.js.map +1 -1
  69. package/dist/flow/plugins/wfa-datapill-plugin.js +0 -1
  70. package/dist/flow/plugins/wfa-datapill-plugin.js.map +1 -1
  71. package/dist/flow/utils/datapill-transformer.js +9 -5
  72. package/dist/flow/utils/datapill-transformer.js.map +1 -1
  73. package/dist/flow/utils/flow-constants.d.ts +12 -0
  74. package/dist/flow/utils/flow-constants.js +17 -3
  75. package/dist/flow/utils/flow-constants.js.map +1 -1
  76. package/dist/flow/utils/flow-io-to-record.d.ts +1 -1
  77. package/dist/flow/utils/flow-io-to-record.js +21 -13
  78. package/dist/flow/utils/flow-io-to-record.js.map +1 -1
  79. package/dist/flow/utils/flow-pill-utils.d.ts +26 -0
  80. package/dist/flow/utils/flow-pill-utils.js +50 -0
  81. package/dist/flow/utils/flow-pill-utils.js.map +1 -0
  82. package/dist/flow/utils/flow-stage-processor.d.ts +138 -0
  83. package/dist/flow/utils/flow-stage-processor.js +665 -0
  84. package/dist/flow/utils/flow-stage-processor.js.map +1 -0
  85. package/dist/flow/utils/pill-string-parser.js +28 -43
  86. package/dist/flow/utils/pill-string-parser.js.map +1 -1
  87. package/dist/flow/utils/utils.d.ts +11 -6
  88. package/dist/flow/utils/utils.js +37 -28
  89. package/dist/flow/utils/utils.js.map +1 -1
  90. package/dist/form-plugin.js +4 -14
  91. package/dist/form-plugin.js.map +1 -1
  92. package/dist/html-import-plugin.js +0 -1
  93. package/dist/html-import-plugin.js.map +1 -1
  94. package/dist/import-sets-plugin.js +0 -2
  95. package/dist/import-sets-plugin.js.map +1 -1
  96. package/dist/inbound-email-action-plugin.js +0 -1
  97. package/dist/inbound-email-action-plugin.js.map +1 -1
  98. package/dist/index.d.ts +2 -1
  99. package/dist/index.js +5 -1
  100. package/dist/index.js.map +1 -1
  101. package/dist/instance-scan-plugin.js +0 -7
  102. package/dist/instance-scan-plugin.js.map +1 -1
  103. package/dist/json-plugin.js +0 -1
  104. package/dist/json-plugin.js.map +1 -1
  105. package/dist/list-plugin.js +4 -1
  106. package/dist/list-plugin.js.map +1 -1
  107. package/dist/now-attach-plugin.js +0 -1
  108. package/dist/now-attach-plugin.js.map +1 -1
  109. package/dist/now-config-plugin.js +0 -1
  110. package/dist/now-config-plugin.js.map +1 -1
  111. package/dist/now-id-plugin.js +0 -1
  112. package/dist/now-id-plugin.js.map +1 -1
  113. package/dist/now-include-plugin.js +0 -1
  114. package/dist/now-include-plugin.js.map +1 -1
  115. package/dist/now-ref-plugin.js +0 -1
  116. package/dist/now-ref-plugin.js.map +1 -1
  117. package/dist/now-unresolved-plugin.js +0 -1
  118. package/dist/now-unresolved-plugin.js.map +1 -1
  119. package/dist/package-json-plugin.js +3 -2
  120. package/dist/package-json-plugin.js.map +1 -1
  121. package/dist/property-plugin.js +0 -2
  122. package/dist/property-plugin.js.map +1 -1
  123. package/dist/record-plugin.d.ts +2 -0
  124. package/dist/record-plugin.js +2 -2
  125. package/dist/record-plugin.js.map +1 -1
  126. package/dist/repack/lint/Rules.d.ts +1 -2
  127. package/dist/rest-api-plugin.js +6 -5
  128. package/dist/rest-api-plugin.js.map +1 -1
  129. package/dist/role-plugin.js +0 -1
  130. package/dist/role-plugin.js.map +1 -1
  131. package/dist/schedule-script/scheduled-script-plugin.js +5 -4
  132. package/dist/schedule-script/scheduled-script-plugin.js.map +1 -1
  133. package/dist/script-action-plugin.js +0 -2
  134. package/dist/script-action-plugin.js.map +1 -1
  135. package/dist/script-include-plugin.js +0 -4
  136. package/dist/script-include-plugin.js.map +1 -1
  137. package/dist/server-module-plugin/index.js +2 -3
  138. package/dist/server-module-plugin/index.js.map +1 -1
  139. package/dist/service-catalog/catalog-clientscript-plugin.js +0 -2
  140. package/dist/service-catalog/catalog-clientscript-plugin.js.map +1 -1
  141. package/dist/service-catalog/catalog-item-plugin.js +0 -2
  142. package/dist/service-catalog/catalog-item-plugin.js.map +1 -1
  143. package/dist/service-catalog/catalog-ui-policy-plugin.js +0 -2
  144. package/dist/service-catalog/catalog-ui-policy-plugin.js.map +1 -1
  145. package/dist/service-catalog/sc-record-producer-plugin.js +0 -2
  146. package/dist/service-catalog/sc-record-producer-plugin.js.map +1 -1
  147. package/dist/service-catalog/variable-set-plugin.js +0 -2
  148. package/dist/service-catalog/variable-set-plugin.js.map +1 -1
  149. package/dist/service-portal/angular-provider-plugin.js +0 -2
  150. package/dist/service-portal/angular-provider-plugin.js.map +1 -1
  151. package/dist/service-portal/dependency-plugin.js +3 -5
  152. package/dist/service-portal/dependency-plugin.js.map +1 -1
  153. package/dist/service-portal/header-footer-plugin.js +3 -5
  154. package/dist/service-portal/header-footer-plugin.js.map +1 -1
  155. package/dist/service-portal/menu-plugin.js +0 -1
  156. package/dist/service-portal/menu-plugin.js.map +1 -1
  157. package/dist/service-portal/page-plugin.js +0 -1
  158. package/dist/service-portal/page-plugin.js.map +1 -1
  159. package/dist/service-portal/page-route-map-plugin.js +0 -1
  160. package/dist/service-portal/page-route-map-plugin.js.map +1 -1
  161. package/dist/service-portal/portal-plugin.js +0 -2
  162. package/dist/service-portal/portal-plugin.js.map +1 -1
  163. package/dist/service-portal/theme-plugin.js +0 -2
  164. package/dist/service-portal/theme-plugin.js.map +1 -1
  165. package/dist/service-portal/widget-plugin.js +3 -5
  166. package/dist/service-portal/widget-plugin.js.map +1 -1
  167. package/dist/sla-plugin.js +0 -2
  168. package/dist/sla-plugin.js.map +1 -1
  169. package/dist/static-content-plugin.js +32 -3
  170. package/dist/static-content-plugin.js.map +1 -1
  171. package/dist/table-plugin.js +102 -11
  172. package/dist/table-plugin.js.map +1 -1
  173. package/dist/ui-action-plugin.js +26 -17
  174. package/dist/ui-action-plugin.js.map +1 -1
  175. package/dist/ui-page-plugin.js +159 -17
  176. package/dist/ui-page-plugin.js.map +1 -1
  177. package/dist/ui-policy-plugin.js +0 -1
  178. package/dist/ui-policy-plugin.js.map +1 -1
  179. package/dist/user-preference-plugin.js +0 -2
  180. package/dist/user-preference-plugin.js.map +1 -1
  181. package/dist/utils.d.ts +1 -9
  182. package/dist/utils.js +0 -14
  183. package/dist/utils.js.map +1 -1
  184. package/dist/ux-list-menu-config-plugin.js +0 -2
  185. package/dist/ux-list-menu-config-plugin.js.map +1 -1
  186. package/dist/view-plugin.js +0 -1
  187. package/dist/view-plugin.js.map +1 -1
  188. package/dist/workspace-plugin.js +0 -2
  189. package/dist/workspace-plugin.js.map +1 -1
  190. package/package.json +6 -6
  191. package/src/acl-plugin.ts +1 -4
  192. package/src/applicability-plugin.ts +0 -2
  193. package/src/application-menu-plugin.ts +0 -2
  194. package/src/arrow-function-plugin.ts +0 -1
  195. package/src/atf/test-plugin.ts +0 -2
  196. package/src/basic-syntax-plugin.ts +0 -1
  197. package/src/business-rule-plugin.ts +1 -2
  198. package/src/call-expression-plugin.ts +0 -1
  199. package/src/claims-plugin.ts +0 -1
  200. package/src/client-script-plugin.ts +1 -2
  201. package/src/column-plugin.ts +29 -9
  202. package/src/cross-scope-privilege-plugin.ts +1 -2
  203. package/src/dashboard/dashboard-plugin.ts +0 -2
  204. package/src/data-plugin.ts +0 -1
  205. package/src/data-policy-plugin.ts +333 -0
  206. package/src/email-notification-plugin.ts +8 -4
  207. package/src/flow/flow-logic/flow-logic-constants.ts +6 -0
  208. package/src/flow/flow-logic/flow-logic-diagnostics.ts +236 -58
  209. package/src/flow/flow-logic/flow-logic-plugin-helpers.ts +59 -6
  210. package/src/flow/flow-logic/flow-logic-plugin.ts +368 -38
  211. package/src/flow/flow-logic/flow-logic-shapes.ts +25 -0
  212. package/src/flow/plugins/approval-rules-plugin.ts +0 -1
  213. package/src/flow/plugins/flow-action-definition-plugin.ts +940 -208
  214. package/src/flow/plugins/flow-data-pill-plugin.ts +3 -5
  215. package/src/flow/plugins/flow-definition-plugin.ts +159 -26
  216. package/src/flow/plugins/flow-diagnostics-plugin.ts +89 -3
  217. package/src/flow/plugins/flow-instance-plugin.ts +26 -12
  218. package/src/flow/plugins/flow-trigger-instance-plugin.ts +0 -1
  219. package/src/flow/plugins/inline-script-plugin.ts +0 -1
  220. package/src/flow/plugins/step-definition-plugin.ts +0 -2
  221. package/src/flow/plugins/step-instance-plugin.ts +259 -65
  222. package/src/flow/plugins/trigger-plugin.ts +0 -2
  223. package/src/flow/plugins/wfa-datapill-plugin.ts +0 -1
  224. package/src/flow/utils/datapill-transformer.ts +13 -5
  225. package/src/flow/utils/flow-constants.ts +19 -1
  226. package/src/flow/utils/flow-io-to-record.ts +29 -19
  227. package/src/flow/utils/flow-pill-utils.ts +48 -0
  228. package/src/flow/utils/flow-stage-processor.ts +831 -0
  229. package/src/flow/utils/pill-string-parser.ts +29 -47
  230. package/src/flow/utils/utils.ts +39 -35
  231. package/src/form-plugin.ts +5 -15
  232. package/src/html-import-plugin.ts +0 -1
  233. package/src/import-sets-plugin.ts +0 -2
  234. package/src/inbound-email-action-plugin.ts +1 -2
  235. package/src/index.ts +7 -1
  236. package/src/instance-scan-plugin.ts +0 -7
  237. package/src/json-plugin.ts +0 -1
  238. package/src/list-plugin.ts +6 -2
  239. package/src/now-attach-plugin.ts +0 -1
  240. package/src/now-config-plugin.ts +0 -1
  241. package/src/now-id-plugin.ts +0 -1
  242. package/src/now-include-plugin.ts +0 -1
  243. package/src/now-ref-plugin.ts +0 -1
  244. package/src/now-unresolved-plugin.ts +0 -1
  245. package/src/package-json-plugin.ts +8 -3
  246. package/src/property-plugin.ts +0 -2
  247. package/src/record-plugin.ts +3 -3
  248. package/src/repack/lint/Rules.ts +1 -1
  249. package/src/rest-api-plugin.ts +7 -6
  250. package/src/role-plugin.ts +1 -2
  251. package/src/schedule-script/scheduled-script-plugin.ts +11 -5
  252. package/src/script-action-plugin.ts +0 -2
  253. package/src/script-include-plugin.ts +0 -4
  254. package/src/server-module-plugin/index.ts +2 -3
  255. package/src/service-catalog/catalog-clientscript-plugin.ts +0 -2
  256. package/src/service-catalog/catalog-item-plugin.ts +0 -2
  257. package/src/service-catalog/catalog-ui-policy-plugin.ts +0 -2
  258. package/src/service-catalog/sc-record-producer-plugin.ts +0 -2
  259. package/src/service-catalog/variable-set-plugin.ts +0 -2
  260. package/src/service-portal/angular-provider-plugin.ts +0 -2
  261. package/src/service-portal/dependency-plugin.ts +0 -2
  262. package/src/service-portal/header-footer-plugin.ts +0 -2
  263. package/src/service-portal/menu-plugin.ts +1 -2
  264. package/src/service-portal/page-plugin.ts +1 -2
  265. package/src/service-portal/page-route-map-plugin.ts +1 -2
  266. package/src/service-portal/portal-plugin.ts +0 -2
  267. package/src/service-portal/theme-plugin.ts +0 -2
  268. package/src/service-portal/widget-plugin.ts +0 -2
  269. package/src/sla-plugin.ts +0 -2
  270. package/src/static-content-plugin.ts +37 -4
  271. package/src/table-plugin.ts +118 -16
  272. package/src/ui-action-plugin.ts +30 -17
  273. package/src/ui-page-plugin.ts +188 -20
  274. package/src/ui-policy-plugin.ts +1 -2
  275. package/src/user-preference-plugin.ts +0 -2
  276. package/src/utils.ts +0 -15
  277. package/src/ux-list-menu-config-plugin.ts +0 -2
  278. package/src/view-plugin.ts +0 -1
  279. package/src/workspace-plugin.ts +0 -2
@@ -8,6 +8,7 @@ import {
8
8
  isSNScope,
9
9
  zipSync,
10
10
  unzipSync,
11
+ ts,
11
12
  type Logger,
12
13
  type Diagnostics,
13
14
  type Project,
@@ -21,9 +22,10 @@ import { parseDocument, DomUtils } from 'htmlparser2'
21
22
  import { XMLParser, XMLBuilder, type X2jOptions, type XmlBuilderOptions } from 'fast-xml-parser'
22
23
  import { create } from 'xmlbuilder2'
23
24
  import { NowIdShape } from './now-id-plugin'
25
+ import { NowIncludeShape } from './now-include-plugin'
24
26
  import { CHUNK_SIZE, chunkData, generateId } from './static-content-plugin'
25
27
  import { sha256 } from './now-attach-plugin'
26
- import { createSdkDocEntry } from './utils'
28
+ import { TRANSLATIONS_SUFFIX } from '@servicenow/isomorphic-rollup'
27
29
 
28
30
  const parserOptions: X2jOptions = {
29
31
  ignoreAttributes: false,
@@ -157,6 +159,50 @@ const SOURCE_ARTIFACT_RELATIONSHIPS = {
157
159
 
158
160
  const parser = new XMLParser(parserOptions)
159
161
 
162
+ const escapeHtml = (s: string): string => s.replace(/&/g, '&')
163
+
164
+ const escapeSingle = (s: string): string => escapeHtml(s).replace(/\\/g, '\\\\').replace(/'/g, "\\'")
165
+
166
+ const escapeDouble = (s: string): string => escapeHtml(s).replace(/\\/g, '\\\\').replace(/"/g, '\\"')
167
+
168
+ const getTranslationMessages = (
169
+ fs: FileSystem,
170
+ config: NowConfig,
171
+ rootDir: string,
172
+ htmlRelPathFromClientDir: string
173
+ ): string[] => {
174
+ // The rollup plugin emits `<stem>.translations.json` next to each bundled html, preserving
175
+ // the html's subdirectory structure under clientDir. So a source html at
176
+ // `<clientDir>/admin/page.html` produces `<staticContentDir>/admin/page.translations.json`.
177
+ if (htmlRelPathFromClientDir.startsWith('..')) {
178
+ return []
179
+ }
180
+ const translationsRelPath = htmlRelPathFromClientDir.replace(/\.html$/, TRANSLATIONS_SUFFIX)
181
+ const translationsPath = path.join(rootDir, config.staticContentDir, translationsRelPath)
182
+ try {
183
+ fs.accessSync(translationsPath)
184
+ } catch {
185
+ return []
186
+ }
187
+ try {
188
+ const content = fs.readFileSync(translationsPath, { encoding: 'utf-8' })
189
+ const parsed = JSON.parse(content) as { messages: Array<string | { [key: string]: string }> }
190
+ return parsed.messages.map((entry) => (typeof entry === 'string' ? entry : (entry['code'] ?? '')))
191
+ } catch {
192
+ return []
193
+ }
194
+ }
195
+
196
+ const translationsJellyScript = (scope: string, messages: string[]): string => `
197
+ <script type="text/javascript">
198
+ 'use strict';
199
+
200
+ window.__TRANSLATIONS__ = {
201
+ ${messages.map((message) => `'${escapeSingle(message)}': '\${NS,JS:sn_i18n.Message.getMessage("${escapeDouble(scope)}", "${escapeDouble(message)}")}'`).join(',\n ')}
202
+ };
203
+ </script>
204
+ `
205
+
160
206
  // TODO: Remove this shim tag once we've shipped Glide support for this feature.
161
207
  const nowUxGlobals = (themeId: string = POLARIS_APPSHELL_THEME_ID) => {
162
208
  return parser.parse(`<!-- @sdk:now-ux-globals -->
@@ -216,7 +262,6 @@ const nodeTransformer = (nodes: any[]) => {
216
262
 
217
263
  export const UiPagePlugin = Plugin.create({
218
264
  name: 'UiPagePlugin',
219
- docs: [createSdkDocEntry('UiPage', ['sys_ui_page'])],
220
265
  records: {
221
266
  sys_ui_page: {
222
267
  composite: true,
@@ -271,7 +316,7 @@ export const UiPagePlugin = Plugin.create({
271
316
  }
272
317
  },
273
318
 
274
- async toFile(uiPage, { config, descendants, transform }) {
319
+ async toFile(uiPage, { config, database, descendants, transform }) {
275
320
  if (!uiPage.has('endpoint') && !uiPage.has('name')) {
276
321
  return { success: false }
277
322
  }
@@ -296,6 +341,7 @@ export const UiPagePlugin = Plugin.create({
296
341
 
297
342
  const result = await serializeWithArtifact(uiPage, uiPagePropsToSerialize, {
298
343
  config,
344
+ database,
299
345
  descendants,
300
346
  transform,
301
347
  })
@@ -410,9 +456,29 @@ export const UiPagePlugin = Plugin.create({
410
456
  diagnostics.error(endpoint.getOriginalNode(), 'endpoint must include a page name before .do')
411
457
  return { success: false }
412
458
  }
413
- let html = arg.get('html').toString().getValue()
459
+ const htmlShape = arg.get('html')
460
+ let html = htmlShape.toString().getValue()
414
461
  let sourceFilePaths: string[] = []
415
462
  let assetNames: string[] = []
463
+ let vendorAssetNames: string[] = []
464
+ let htmlRelPathFromClientDir: string | undefined
465
+
466
+ const clientAbsDir = path.join(project.getRootDir(), config.clientDir)
467
+ const computeRelFromClientDir = (htmlIncludePath: string): string => {
468
+ const sourceFileDir = path.dirname(callExpression.getOriginalNode().getSourceFile().getFilePath())
469
+ const absoluteHtmlPath = path.resolve(sourceFileDir, htmlIncludePath)
470
+ return path.relative(clientAbsDir, absoluteHtmlPath).replace(/\\/g, '/')
471
+ }
472
+
473
+ // `html: Now.include('../ui/hello.html')` resolves to a NowIncludeShape whose path
474
+ // we can read directly. The included content has no HTML_IMPORT_PREFIX, so detect
475
+ // this case before the prefix check below.
476
+ if (htmlShape.is(NowIncludeShape)) {
477
+ const includePath = htmlShape.as(NowIncludeShape).getPath()
478
+ if (includePath.endsWith('.html')) {
479
+ htmlRelPathFromClientDir = computeRelFromClientDir(includePath)
480
+ }
481
+ }
416
482
 
417
483
  // HtmlImportPlugin (which runs before toRecord) resolves `html: _html` identifiers
418
484
  // to the file content and prepends an HTML_IMPORT_PREFIX warning comment.
@@ -421,16 +487,23 @@ export const UiPagePlugin = Plugin.create({
421
487
  // An inline string (e.g. `html: '<h1>...</h1>'`) never gets the prefix, so an
422
488
  // unrelated `.html` import in the same file does NOT trigger artifact creation.
423
489
  if (html.trimStart().startsWith(HTML_IMPORT_PREFIX)) {
424
- const originalNode = callExpression.getOriginalNode()
425
- const sourceFile = originalNode.getSourceFile()
426
- // biome-ignore lint/suspicious/noExplicitAny: ts-morph ImportDeclaration type not exported
427
- const htmlImport = (sourceFile.getImportDeclarations() as any[]).find((imp) =>
428
- imp.getModuleSpecifierValue().endsWith('.html')
429
- )
430
- if (htmlImport) {
431
- const relativeHtmlPath = htmlImport.getModuleSpecifierValue()
432
- const sourceFileDir = path.dirname(sourceFile.getFilePath())
433
- const absoluteHtmlPath = path.resolve(sourceFileDir, relativeHtmlPath)
490
+ // Resolve the import declaration from the specific identifier passed as the
491
+ // `html` argument — NOT the first .html import in the file. A single .now.ts
492
+ // may declare several UiPages with different html imports, and each one must
493
+ // pick up only the manifest/translations for the file it actually imports.
494
+ const htmlNode = htmlShape.getOriginalNode()
495
+ const moduleSpecifier = ts.Node.isIdentifier(htmlNode)
496
+ ? htmlNode
497
+ .getSymbol()
498
+ ?.getDeclarations()[0]
499
+ ?.getParent()
500
+ ?.asKind(ts.SyntaxKind.ImportDeclaration)
501
+ ?.getModuleSpecifierValue()
502
+ : undefined
503
+ if (moduleSpecifier?.endsWith('.html')) {
504
+ htmlRelPathFromClientDir = computeRelFromClientDir(moduleSpecifier)
505
+ const sourceFileDir = path.dirname(htmlNode.getSourceFile().getFilePath())
506
+ const absoluteHtmlPath = path.resolve(sourceFileDir, moduleSpecifier)
434
507
  const manifest = getUIPageSourceFilePaths(
435
508
  absoluteHtmlPath,
436
509
  fs,
@@ -440,6 +513,7 @@ export const UiPagePlugin = Plugin.create({
440
513
  )
441
514
  sourceFilePaths = manifest.files
442
515
  assetNames = manifest.assetNames
516
+ vendorAssetNames = manifest.vendorAssetNames
443
517
  }
444
518
  }
445
519
 
@@ -458,6 +532,17 @@ export const UiPagePlugin = Plugin.create({
458
532
  }
459
533
  return { success: false }
460
534
  }
535
+ if (htmlRelPathFromClientDir) {
536
+ const messages = getTranslationMessages(
537
+ fs,
538
+ config,
539
+ project.getRootDir(),
540
+ htmlRelPathFromClientDir
541
+ )
542
+ if (messages.length > 0) {
543
+ html += translationsJellyScript(config.scope, messages)
544
+ }
545
+ }
461
546
  }
462
547
 
463
548
  const record = await factory.createRecord({
@@ -503,6 +588,28 @@ export const UiPagePlugin = Plugin.create({
503
588
  assetNames
504
589
  )
505
590
 
591
+ // Link this page's source artifact to each vendor chunk it depends on.
592
+ // Emitted for both configuration and package builds: configuration
593
+ // deploys need the M2Ms so the platform knows which vendor chunks belong
594
+ // to this page; package builds need them so vendor refs are tracked in
595
+ // keys.ts and not flagged as deletes on the next sync.
596
+ if (vendorAssetNames.length > 0) {
597
+ const artifactRecord = sourceArtifactRecords.find(
598
+ (r) => r.getTable() === 'sn_glider_source_artifact'
599
+ )
600
+ if (artifactRecord) {
601
+ const vendorM2ms = await Promise.all(
602
+ vendorAssetNames.map((name) =>
603
+ createAssetArtifactM2mRecord(artifactRecord, name, record, {
604
+ factory,
605
+ config,
606
+ })
607
+ )
608
+ )
609
+ sourceArtifactRecords.push(...vendorM2ms)
610
+ }
611
+ }
612
+
506
613
  if (sourceArtifactRecords.length > 0) {
507
614
  record.with(...sourceArtifactRecords)
508
615
  } else {
@@ -523,17 +630,18 @@ export const UiPagePlugin = Plugin.create({
523
630
  })
524
631
 
525
632
  /**
526
- * Reads source file paths from the UI source manifest file.
633
+ * Reads source file paths and vendor asset names from the UI source manifest file.
527
634
  *
528
635
  * The manifest is generated by isomorphic-rollup's sourceManifest plugin during build.
529
- * It's a JSON file with the structure: { html, entry, files: string[] }
636
+ * It's a JSON file with the structure:
637
+ * { html, entry, files: string[], vendors: [fileName, contentHash][] }
530
638
  *
531
639
  * @param htmlFilePath - Path to the HTML file
532
640
  * @param fs - File system interface
533
641
  * @param logger - Logger for diagnostics
534
642
  * @param config - NowConfig with staticContentDir
535
643
  * @param rootDir - Project root directory
536
- * @returns Array of source file paths (empty array if manifest not found)
644
+ * @returns Source file paths, entry asset names, and vendor asset names
537
645
  */
538
646
  const getUIPageSourceFilePaths = (
539
647
  htmlFilePath: string,
@@ -541,8 +649,8 @@ const getUIPageSourceFilePaths = (
541
649
  logger: Logger,
542
650
  config: NowConfig,
543
651
  rootDir: string
544
- ): { files: string[]; assetNames: string[] } => {
545
- const empty = { files: [], assetNames: [] }
652
+ ): { files: string[]; assetNames: string[]; vendorAssetNames: string[] } => {
653
+ const empty = { files: [], assetNames: [], vendorAssetNames: [] }
546
654
  try {
547
655
  // Derive manifest path from HTML path by mirroring the directory structure
548
656
  // from clientDir into staticContentDir and swapping the extension.
@@ -596,7 +704,30 @@ const getUIPageSourceFilePaths = (
596
704
  // no source map in this build output — skip
597
705
  }
598
706
 
599
- return { files: manifest.files, assetNames }
707
+ // Derive vendor asset names from the manifest's vendors field.
708
+ // Each vendor entry is [fileName, contentHash], e.g.
709
+ // ["vendor-react-dom--d217b640.jsdbx", "d217b640"]
710
+ // The asset name mirrors static-content-plugin's formula:
711
+ // path.join(scope, fileNameWithoutExt)
712
+ const vendorAssetNames: string[] = []
713
+ const vendors: [string, string][] = manifest.vendors ?? []
714
+ for (const [fileName] of vendors) {
715
+ const ext = path.extname(fileName)
716
+ const nameWithoutExt = fileName.substring(0, fileName.length - ext.length)
717
+ const vendorAssetName = path.join(config.scope, nameWithoutExt).replace(/\\/g, '/')
718
+ vendorAssetNames.push(vendorAssetName)
719
+
720
+ // Check for vendor sourcemap
721
+ const vendorMapPath = path.join(staticContentAbsDir, `${nameWithoutExt}.jsdbx.map`)
722
+ try {
723
+ fs.accessSync(vendorMapPath)
724
+ vendorAssetNames.push(path.join(config.scope, `${nameWithoutExt}.js.map`).replace(/\\/g, '/'))
725
+ } catch {
726
+ // no sourcemap for this vendor chunk
727
+ }
728
+ }
729
+
730
+ return { files: manifest.files, assetNames, vendorAssetNames }
600
731
  } catch (error) {
601
732
  logger.warn(`Failed to read source manifest: ${error}`)
602
733
  return empty
@@ -1114,6 +1245,7 @@ async function serializeWithArtifact(
1114
1245
  metadataRecord: Record,
1115
1246
  metadataProps: string[],
1116
1247
  context: {
1248
+ database: Database
1117
1249
  descendants: { query: (table: string) => Record[] }
1118
1250
  config: { scope: string; scopeId: string }
1119
1251
  transform: Transform
@@ -1293,6 +1425,42 @@ async function serializeWithArtifact(
1293
1425
  ? `sys_attachment.table_sys_id=${artifactId}^sys_idNOT IN${currentDocIds.join(',')}`
1294
1426
  : `sys_attachment.table_sys_id=${artifactId}`
1295
1427
  recordUpdate.ele('sys_attachment_doc', { action: 'delete_multiple', query: docQuery })
1428
+
1429
+ // Clean up stale source-artifact M2Ms for this artifact (e.g. when a vendor
1430
+ // chunk hash changes, the M2M to the prior vendor asset must be removed).
1431
+ //
1432
+ // Query the full database, not page descendants: asset M2Ms are descendants
1433
+ // of their sys_ux_lib_asset records, not of the page, so the page's
1434
+ // descendants only have the page M2M. The NOT IN list must include every
1435
+ // current-build M2M for this artifact, otherwise the sweep would also
1436
+ // delete live entry/vendor M2Ms inserted by the asset XMLs.
1437
+ //
1438
+ // Skip DELETE-action rows: on a same-project package rebuild,
1439
+ // generateRecordsFromDeletedKeys inserts DELETE rows for keys no longer
1440
+ // registered (e.g. the prior vendor M2M). Adding their sys_ids to NOT IN
1441
+ // would protect the stale rows on the platform — defeating the sweep.
1442
+ const currentM2mIds = context.database
1443
+ .query('sn_glider_source_artifact_m2m')
1444
+ .filter((m2m) => {
1445
+ if (m2m.isDeleted()) {
1446
+ return false
1447
+ }
1448
+ const srcArtifact = m2m.get('source_artifact')
1449
+ const srcId = srcArtifact.isRecord()
1450
+ ? srcArtifact.asRecord().getId().getValue()
1451
+ : srcArtifact.toString().getValue()
1452
+ return srcId === artifactId
1453
+ })
1454
+ .map((m2m) => m2m.getId().getValue())
1455
+
1456
+ const m2mQuery =
1457
+ currentM2mIds.length > 0
1458
+ ? `source_artifact=${artifactId}^sys_idNOT IN${currentM2mIds.join(',')}`
1459
+ : `source_artifact=${artifactId}`
1460
+ recordUpdate.ele('sn_glider_source_artifact_m2m', {
1461
+ action: 'delete_multiple',
1462
+ query: m2mQuery,
1463
+ })
1296
1464
  })
1297
1465
 
1298
1466
  return {
@@ -8,7 +8,7 @@ import {
8
8
  type Record,
9
9
  type Shape,
10
10
  } from '@servicenow/sdk-build-core'
11
- import { createSdkDocEntry, validateClientSideScript } from './utils'
11
+ import { validateClientSideScript } from './utils'
12
12
  import { NowIdShape } from './now-id-plugin'
13
13
 
14
14
  // Define table names as constants since they're not exported from the core tables
@@ -93,7 +93,6 @@ const validateScriptProperty = (
93
93
 
94
94
  export const UiPolicyPlugin = Plugin.create({
95
95
  name: 'UiPolicyPlugin',
96
- docs: [createSdkDocEntry('UiPolicy', ['sys_ui_policy'])],
97
96
  records: {
98
97
  [SYS_UI_POLICY]: {
99
98
  coalesce: ['table', 'short_description'],
@@ -1,6 +1,5 @@
1
1
  import { CallExpressionShape, Plugin } from '@servicenow/sdk-build-core'
2
2
  import { NowIdShape } from './now-id-plugin'
3
- import { createSdkDocEntry } from './utils'
4
3
 
5
4
  /**
6
5
  * Creates a User Preference (sys_user_preference).
@@ -17,7 +16,6 @@ import { createSdkDocEntry } from './utils'
17
16
  */
18
17
  export const UserPreferencePlugin = Plugin.create({
19
18
  name: 'UserPreferencePlugin',
20
- docs: [createSdkDocEntry('UserPreference', ['sys_user_preference'])],
21
19
  records: {
22
20
  sys_user_preference: {
23
21
  toShape(record) {
package/src/utils.ts CHANGED
@@ -4,7 +4,6 @@ import {
4
4
  type ObjectShape,
5
5
  type Diagnostics,
6
6
  type Compiler,
7
- type PluginApiDoc,
8
7
  type Record as FluentRecord,
9
8
  type OutputFile,
10
9
  type Transform,
@@ -182,20 +181,6 @@ export async function generateChoiceSetFile(
182
181
  }
183
182
  }
184
183
 
185
- /**
186
- * Creates a documentation entry for first-party SDK plugins.
187
- *
188
- * @param apiName - The API name (e.g., 'BusinessRule', 'Acl')
189
- * @param tags - Keywords for categorization (typically includes the ServiceNow table name)
190
- * @returns A complete PluginApiDoc entry
191
- */
192
- export function createSdkDocEntry(apiName: string, tags: string[]): PluginApiDoc {
193
- return {
194
- apiName,
195
- tags,
196
- }
197
- }
198
-
199
184
  /**
200
185
  * Parses a number from a shape record field with fallback to default value.
201
186
  * Returns undefined if the field doesn't exist and no default is provided.
@@ -1,11 +1,9 @@
1
1
  import { Plugin, CallExpressionShape, type Record } from '@servicenow/sdk-build-core'
2
2
 
3
3
  import { NowIdShape } from './now-id-plugin'
4
- import { createSdkDocEntry } from './utils'
5
4
 
6
5
  export const UxListMenuConfigPlugin = Plugin.create({
7
6
  name: 'UxListMenuConfigPlugin',
8
- docs: [createSdkDocEntry('UxListMenuConfig', ['sys_ux_list_menu_config'])],
9
7
  records: {
10
8
  sys_ux_list_menu_config: {
11
9
  relationships: {
@@ -2,7 +2,6 @@ import { Plugin, Record, RecordId, Shape, ts } from '@servicenow/sdk-build-core'
2
2
 
3
3
  export const ViewPlugin = Plugin.create({
4
4
  name: 'ViewPlugin',
5
- docs: [],
6
5
  records: {
7
6
  sys_ui_view: {
8
7
  coalesce: ['name'],
@@ -8,7 +8,6 @@ import {
8
8
  Database,
9
9
  } from '@servicenow/sdk-build-core'
10
10
  import { NowIdShape } from './now-id-plugin'
11
- import { createSdkDocEntry } from './utils'
12
11
  import { parsePagePropChromeTabJson, createChromeTabJsonStringForPageProp } from './workspace-plugin/chrome-tab'
13
12
  import { createPage } from './workspace-plugin/page'
14
13
  import {
@@ -43,7 +42,6 @@ type InnerTransformFromObjectShape = Parameters<Parameters<ObjectShape['transfor
43
42
 
44
43
  export const WorkspacePlugin = Plugin.create({
45
44
  name: 'WorkspacePlugin',
46
- docs: [createSdkDocEntry('Workspace', ['sys_ux_page_registry'])],
47
45
  records: {
48
46
  sys_ux_page_registry: {
49
47
  relationships: {