@servicenow/sdk-build-plugins 3.0.3 → 4.0.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 (359) hide show
  1. package/dist/acl-plugin.d.ts +19 -0
  2. package/dist/acl-plugin.js +210 -0
  3. package/dist/acl-plugin.js.map +1 -0
  4. package/dist/application-menu-plugin.d.ts +18 -0
  5. package/dist/application-menu-plugin.js +104 -0
  6. package/dist/application-menu-plugin.js.map +1 -0
  7. package/dist/arrow-function-plugin.d.ts +16 -0
  8. package/dist/arrow-function-plugin.js +107 -0
  9. package/dist/arrow-function-plugin.js.map +1 -0
  10. package/dist/atf/step-configs.d.ts +39 -0
  11. package/dist/atf/step-configs.js +2334 -0
  12. package/dist/atf/step-configs.js.map +1 -0
  13. package/dist/atf/test-plugin.d.ts +4 -0
  14. package/dist/atf/test-plugin.js +600 -0
  15. package/dist/atf/test-plugin.js.map +1 -0
  16. package/dist/basic-syntax-plugin.d.ts +2 -0
  17. package/dist/basic-syntax-plugin.js +636 -0
  18. package/dist/basic-syntax-plugin.js.map +1 -0
  19. package/dist/business-rule-plugin.d.ts +3 -0
  20. package/dist/business-rule-plugin.js +205 -0
  21. package/dist/business-rule-plugin.js.map +1 -0
  22. package/dist/call-expression-plugin.d.ts +2 -0
  23. package/dist/call-expression-plugin.js +175 -0
  24. package/dist/call-expression-plugin.js.map +1 -0
  25. package/dist/client-script-plugin.d.ts +29 -0
  26. package/dist/client-script-plugin.js +164 -0
  27. package/dist/client-script-plugin.js.map +1 -0
  28. package/dist/column/column-helper.d.ts +12 -0
  29. package/dist/column/column-helper.js +84 -0
  30. package/dist/column/column-helper.js.map +1 -0
  31. package/dist/column/column-to-record.d.ts +3 -0
  32. package/dist/column/column-to-record.js +105 -0
  33. package/dist/column/column-to-record.js.map +1 -0
  34. package/dist/column-plugin.d.ts +8 -0
  35. package/dist/column-plugin.js +453 -0
  36. package/dist/column-plugin.js.map +1 -0
  37. package/dist/cross-scope-privilege-plugin.d.ts +15 -0
  38. package/dist/cross-scope-privilege-plugin.js +82 -0
  39. package/dist/cross-scope-privilege-plugin.js.map +1 -0
  40. package/dist/html-import-plugin.d.ts +2 -0
  41. package/dist/html-import-plugin.js +72 -0
  42. package/dist/html-import-plugin.js.map +1 -0
  43. package/dist/index.d.ts +37 -21
  44. package/dist/index.js +40 -45
  45. package/dist/index.js.map +1 -1
  46. package/dist/json-plugin.d.ts +15 -0
  47. package/dist/json-plugin.js +104 -0
  48. package/dist/json-plugin.js.map +1 -0
  49. package/dist/list-plugin.d.ts +2 -0
  50. package/dist/list-plugin.js +191 -0
  51. package/dist/list-plugin.js.map +1 -0
  52. package/dist/now-config-plugin.d.ts +4 -0
  53. package/dist/now-config-plugin.js +154 -0
  54. package/dist/now-config-plugin.js.map +1 -0
  55. package/dist/now-id-plugin.d.ts +11 -0
  56. package/dist/now-id-plugin.js +71 -0
  57. package/dist/now-id-plugin.js.map +1 -0
  58. package/dist/now-include-plugin.d.ts +16 -0
  59. package/dist/now-include-plugin.js +118 -0
  60. package/dist/now-include-plugin.js.map +1 -0
  61. package/dist/now-ref-plugin.d.ts +2 -0
  62. package/dist/now-ref-plugin.js +43 -0
  63. package/dist/now-ref-plugin.js.map +1 -0
  64. package/dist/now-unresolved-plugin.d.ts +2 -0
  65. package/dist/now-unresolved-plugin.js +32 -0
  66. package/dist/now-unresolved-plugin.js.map +1 -0
  67. package/dist/package-json-plugin.d.ts +2 -0
  68. package/dist/package-json-plugin.js +70 -0
  69. package/dist/package-json-plugin.js.map +1 -0
  70. package/dist/property-plugin.d.ts +2 -0
  71. package/dist/property-plugin.js +105 -0
  72. package/dist/property-plugin.js.map +1 -0
  73. package/dist/record-plugin.d.ts +43 -0
  74. package/dist/record-plugin.js +147 -0
  75. package/dist/record-plugin.js.map +1 -0
  76. package/dist/repack/index.d.ts +1 -0
  77. package/dist/repack/index.js +10 -2
  78. package/dist/repack/index.js.map +1 -1
  79. package/dist/repack/lint/Rules.d.ts +1 -1
  80. package/dist/repack/lint/Rules.js +7 -3
  81. package/dist/repack/lint/Rules.js.map +1 -1
  82. package/dist/repack/lint/index.js +1 -1
  83. package/dist/rest-api-plugin.d.ts +2 -0
  84. package/dist/rest-api-plugin.js +469 -0
  85. package/dist/rest-api-plugin.js.map +1 -0
  86. package/dist/role-plugin.d.ts +2 -0
  87. package/dist/role-plugin.js +117 -0
  88. package/dist/role-plugin.js.map +1 -0
  89. package/dist/script-action-plugin.d.ts +2 -0
  90. package/dist/script-action-plugin.js +62 -0
  91. package/dist/script-action-plugin.js.map +1 -0
  92. package/dist/script-include-plugin.d.ts +2 -0
  93. package/dist/script-include-plugin.js +102 -0
  94. package/dist/script-include-plugin.js.map +1 -0
  95. package/dist/server-module-plugin/index.d.ts +14 -0
  96. package/dist/server-module-plugin/index.js +378 -0
  97. package/dist/server-module-plugin/index.js.map +1 -0
  98. package/dist/server-module-plugin/sbom-builder.d.ts +45 -0
  99. package/dist/server-module-plugin/sbom-builder.js +179 -0
  100. package/dist/server-module-plugin/sbom-builder.js.map +1 -0
  101. package/dist/service-portal/angular-provider-plugin.d.ts +2 -0
  102. package/dist/service-portal/angular-provider-plugin.js +78 -0
  103. package/dist/service-portal/angular-provider-plugin.js.map +1 -0
  104. package/dist/service-portal/dependency-plugin.d.ts +2 -0
  105. package/dist/service-portal/dependency-plugin.js +235 -0
  106. package/dist/service-portal/dependency-plugin.js.map +1 -0
  107. package/dist/service-portal/widget-plugin.d.ts +6 -0
  108. package/dist/service-portal/widget-plugin.js +230 -0
  109. package/dist/service-portal/widget-plugin.js.map +1 -0
  110. package/dist/static-content-plugin.d.ts +2 -0
  111. package/dist/static-content-plugin.js +272 -0
  112. package/dist/static-content-plugin.js.map +1 -0
  113. package/dist/table-plugin.d.ts +3 -0
  114. package/dist/table-plugin.js +1324 -0
  115. package/dist/table-plugin.js.map +1 -0
  116. package/dist/ui-action-plugin.d.ts +2 -0
  117. package/dist/ui-action-plugin.js +291 -0
  118. package/dist/ui-action-plugin.js.map +1 -0
  119. package/dist/ui-page-plugin.d.ts +2 -0
  120. package/dist/ui-page-plugin.js +165 -0
  121. package/dist/ui-page-plugin.js.map +1 -0
  122. package/dist/user-preference-plugin.d.ts +15 -0
  123. package/dist/user-preference-plugin.js +63 -0
  124. package/dist/user-preference-plugin.js.map +1 -0
  125. package/dist/utils.d.ts +17 -0
  126. package/dist/utils.js +72 -0
  127. package/dist/utils.js.map +1 -0
  128. package/dist/view-plugin.d.ts +2 -0
  129. package/dist/view-plugin.js +45 -0
  130. package/dist/view-plugin.js.map +1 -0
  131. package/package.json +17 -13
  132. package/src/acl-plugin.ts +256 -0
  133. package/src/application-menu-plugin.ts +109 -0
  134. package/src/arrow-function-plugin.ts +127 -0
  135. package/src/atf/step-configs.ts +2384 -0
  136. package/src/atf/test-plugin.ts +739 -0
  137. package/src/basic-syntax-plugin.ts +729 -0
  138. package/src/business-rule-plugin.ts +266 -0
  139. package/src/call-expression-plugin.ts +202 -0
  140. package/src/client-script-plugin.ts +179 -0
  141. package/src/column/column-helper.ts +119 -0
  142. package/src/column/column-to-record.ts +131 -0
  143. package/src/column-plugin.ts +506 -0
  144. package/src/cross-scope-privilege-plugin.ts +82 -0
  145. package/src/html-import-plugin.ts +79 -0
  146. package/src/index.ts +39 -21
  147. package/src/json-plugin.ts +128 -0
  148. package/src/list-plugin.ts +222 -0
  149. package/src/now-config-plugin.ts +194 -0
  150. package/src/now-id-plugin.ts +78 -0
  151. package/src/now-include-plugin.ts +140 -0
  152. package/src/now-ref-plugin.ts +48 -0
  153. package/src/now-unresolved-plugin.ts +30 -0
  154. package/src/package-json-plugin.ts +87 -0
  155. package/src/property-plugin.ts +118 -0
  156. package/src/record-plugin.ts +171 -0
  157. package/src/repack/index.ts +10 -1
  158. package/src/repack/lint/Rules.ts +5 -4
  159. package/src/repack/lint/index.ts +1 -1
  160. package/src/rest-api-plugin.ts +658 -0
  161. package/src/role-plugin.ts +128 -0
  162. package/src/script-action-plugin.ts +63 -0
  163. package/src/script-include-plugin.ts +110 -0
  164. package/src/server-module-plugin/index.ts +470 -0
  165. package/src/server-module-plugin/sbom-builder.ts +183 -0
  166. package/src/service-portal/angular-provider-plugin.ts +83 -0
  167. package/src/service-portal/dependency-plugin.ts +284 -0
  168. package/src/service-portal/widget-plugin.ts +263 -0
  169. package/src/static-content-plugin.ts +254 -0
  170. package/src/table-plugin.ts +1698 -0
  171. package/src/ui-action-plugin.ts +324 -0
  172. package/src/ui-page-plugin.ts +168 -0
  173. package/src/user-preference-plugin.ts +62 -0
  174. package/src/utils.ts +69 -0
  175. package/src/view-plugin.ts +46 -0
  176. package/dist/AttachmentPlugin.d.ts +0 -254
  177. package/dist/AttachmentPlugin.js +0 -220
  178. package/dist/AttachmentPlugin.js.map +0 -1
  179. package/dist/BusinessRulePlugin.d.ts +0 -30
  180. package/dist/BusinessRulePlugin.js +0 -149
  181. package/dist/BusinessRulePlugin.js.map +0 -1
  182. package/dist/CrossScopePrivilegePlugin.d.ts +0 -35
  183. package/dist/CrossScopePrivilegePlugin.js +0 -80
  184. package/dist/CrossScopePrivilegePlugin.js.map +0 -1
  185. package/dist/DefaultPlugin.d.ts +0 -86
  186. package/dist/DefaultPlugin.js +0 -226
  187. package/dist/DefaultPlugin.js.map +0 -1
  188. package/dist/HtmlTemplatePlugin.d.ts +0 -21
  189. package/dist/HtmlTemplatePlugin.js +0 -29
  190. package/dist/HtmlTemplatePlugin.js.map +0 -1
  191. package/dist/IdPlugin.d.ts +0 -28
  192. package/dist/IdPlugin.js +0 -68
  193. package/dist/IdPlugin.js.map +0 -1
  194. package/dist/IncludePlugin.d.ts +0 -34
  195. package/dist/IncludePlugin.js +0 -155
  196. package/dist/IncludePlugin.js.map +0 -1
  197. package/dist/JsonPlugin.d.ts +0 -28
  198. package/dist/JsonPlugin.js +0 -69
  199. package/dist/JsonPlugin.js.map +0 -1
  200. package/dist/ListPlugin.d.ts +0 -93
  201. package/dist/ListPlugin.js +0 -456
  202. package/dist/ListPlugin.js.map +0 -1
  203. package/dist/NowConfigPlugin.d.ts +0 -45
  204. package/dist/NowConfigPlugin.js +0 -64
  205. package/dist/NowConfigPlugin.js.map +0 -1
  206. package/dist/PackageJsonPlugin.d.ts +0 -34
  207. package/dist/PackageJsonPlugin.js +0 -63
  208. package/dist/PackageJsonPlugin.js.map +0 -1
  209. package/dist/PropertyPlugin.d.ts +0 -51
  210. package/dist/PropertyPlugin.js +0 -181
  211. package/dist/PropertyPlugin.js.map +0 -1
  212. package/dist/ScriptTemplatePlugin.d.ts +0 -13
  213. package/dist/ScriptTemplatePlugin.js +0 -55
  214. package/dist/ScriptTemplatePlugin.js.map +0 -1
  215. package/dist/ServerModulePlugin.d.ts +0 -75
  216. package/dist/ServerModulePlugin.js +0 -368
  217. package/dist/ServerModulePlugin.js.map +0 -1
  218. package/dist/UserPreferencePlugin.d.ts +0 -19
  219. package/dist/UserPreferencePlugin.js +0 -32
  220. package/dist/UserPreferencePlugin.js.map +0 -1
  221. package/dist/aclAndRole/AclPlugin.d.ts +0 -82
  222. package/dist/aclAndRole/AclPlugin.js +0 -262
  223. package/dist/aclAndRole/AclPlugin.js.map +0 -1
  224. package/dist/aclAndRole/RolePlugin.d.ts +0 -66
  225. package/dist/aclAndRole/RolePlugin.js +0 -179
  226. package/dist/aclAndRole/RolePlugin.js.map +0 -1
  227. package/dist/aclAndRole/Util.d.ts +0 -3
  228. package/dist/aclAndRole/Util.js +0 -90
  229. package/dist/aclAndRole/Util.js.map +0 -1
  230. package/dist/app/ApplicationMenuPlugin.d.ts +0 -34
  231. package/dist/app/ApplicationMenuPlugin.js +0 -112
  232. package/dist/app/ApplicationMenuPlugin.js.map +0 -1
  233. package/dist/db/ColumnPlugins.d.ts +0 -750
  234. package/dist/db/ColumnPlugins.js +0 -114
  235. package/dist/db/ColumnPlugins.js.map +0 -1
  236. package/dist/db/DBUtils.d.ts +0 -2
  237. package/dist/db/DBUtils.js +0 -27
  238. package/dist/db/DBUtils.js.map +0 -1
  239. package/dist/db/DocumentationPlugin.d.ts +0 -67
  240. package/dist/db/DocumentationPlugin.js +0 -258
  241. package/dist/db/DocumentationPlugin.js.map +0 -1
  242. package/dist/db/LicensingPlugin.d.ts +0 -60
  243. package/dist/db/LicensingPlugin.js +0 -117
  244. package/dist/db/LicensingPlugin.js.map +0 -1
  245. package/dist/db/RecordPlugin.d.ts +0 -133
  246. package/dist/db/RecordPlugin.js +0 -337
  247. package/dist/db/RecordPlugin.js.map +0 -1
  248. package/dist/db/TablePlugin.d.ts +0 -231
  249. package/dist/db/TablePlugin.js +0 -1630
  250. package/dist/db/TablePlugin.js.map +0 -1
  251. package/dist/db/index.d.ts +0 -6
  252. package/dist/db/index.js +0 -32
  253. package/dist/db/index.js.map +0 -1
  254. package/dist/scriptedRESTAPI/RESTDeserializationUtils.d.ts +0 -10
  255. package/dist/scriptedRESTAPI/RESTDeserializationUtils.js +0 -373
  256. package/dist/scriptedRESTAPI/RESTDeserializationUtils.js.map +0 -1
  257. package/dist/scriptedRESTAPI/RESTSerializationUtils.d.ts +0 -13
  258. package/dist/scriptedRESTAPI/RESTSerializationUtils.js +0 -177
  259. package/dist/scriptedRESTAPI/RESTSerializationUtils.js.map +0 -1
  260. package/dist/scriptedRESTAPI/RestApiPlugin.d.ts +0 -81
  261. package/dist/scriptedRESTAPI/RestApiPlugin.js +0 -345
  262. package/dist/scriptedRESTAPI/RestApiPlugin.js.map +0 -1
  263. package/dist/scriptedRESTAPI/RestSchemaUtils.d.ts +0 -190
  264. package/dist/scriptedRESTAPI/RestSchemaUtils.js +0 -53
  265. package/dist/scriptedRESTAPI/RestSchemaUtils.js.map +0 -1
  266. package/dist/scriptedRESTAPI/RestUtils.d.ts +0 -69
  267. package/dist/scriptedRESTAPI/RestUtils.js +0 -497
  268. package/dist/scriptedRESTAPI/RestUtils.js.map +0 -1
  269. package/dist/scripts/ClientScriptPlugin.d.ts +0 -64
  270. package/dist/scripts/ClientScriptPlugin.js +0 -170
  271. package/dist/scripts/ClientScriptPlugin.js.map +0 -1
  272. package/dist/scripts/scriptUtils.d.ts +0 -1
  273. package/dist/scripts/scriptUtils.js +0 -9
  274. package/dist/scripts/scriptUtils.js.map +0 -1
  275. package/dist/uxf/ExperiencePlugin.d.ts +0 -45
  276. package/dist/uxf/ExperiencePlugin.js +0 -61
  277. package/dist/uxf/ExperiencePlugin.js.map +0 -1
  278. package/dist/uxf/RoutesPlugin.d.ts +0 -29
  279. package/dist/uxf/RoutesPlugin.js +0 -181
  280. package/dist/uxf/RoutesPlugin.js.map +0 -1
  281. package/dist/uxf/UxfFormulaParser/cleanUxValue.d.ts +0 -4
  282. package/dist/uxf/UxfFormulaParser/cleanUxValue.js +0 -65
  283. package/dist/uxf/UxfFormulaParser/cleanUxValue.js.map +0 -1
  284. package/dist/uxf/UxfFormulaParser/grammerParser/api.d.ts +0 -189
  285. package/dist/uxf/UxfFormulaParser/grammerParser/api.js +0 -158
  286. package/dist/uxf/UxfFormulaParser/grammerParser/api.js.map +0 -1
  287. package/dist/uxf/UxfFormulaParser/grammerParser/clientTransformMap.d.ts +0 -13
  288. package/dist/uxf/UxfFormulaParser/grammerParser/clientTransformMap.js +0 -604
  289. package/dist/uxf/UxfFormulaParser/grammerParser/clientTransformMap.js.map +0 -1
  290. package/dist/uxf/UxfFormulaParser/grammerParser/grammarParser.d.ts +0 -12
  291. package/dist/uxf/UxfFormulaParser/grammerParser/grammarParser.js +0 -551
  292. package/dist/uxf/UxfFormulaParser/grammerParser/grammarParser.js.map +0 -1
  293. package/dist/uxf/UxfFormulaParser/grammerParser/spanHelpers.d.ts +0 -31
  294. package/dist/uxf/UxfFormulaParser/grammerParser/spanHelpers.js +0 -64
  295. package/dist/uxf/UxfFormulaParser/grammerParser/spanHelpers.js.map +0 -1
  296. package/dist/uxf/UxfFormulaParser/index.d.ts +0 -3
  297. package/dist/uxf/UxfFormulaParser/index.js +0 -11
  298. package/dist/uxf/UxfFormulaParser/index.js.map +0 -1
  299. package/dist/uxf/UxfFormulaParser/parser.d.ts +0 -8
  300. package/dist/uxf/UxfFormulaParser/parser.js +0 -87
  301. package/dist/uxf/UxfFormulaParser/parser.js.map +0 -1
  302. package/dist/uxf/UxfFormulaParser/utils/getErrorMsg.d.ts +0 -8
  303. package/dist/uxf/UxfFormulaParser/utils/getErrorMsg.js +0 -17
  304. package/dist/uxf/UxfFormulaParser/utils/getErrorMsg.js.map +0 -1
  305. package/dist/uxf/constants.d.ts +0 -2
  306. package/dist/uxf/constants.js +0 -8
  307. package/dist/uxf/constants.js.map +0 -1
  308. package/dist/uxf/index.d.ts +0 -2
  309. package/dist/uxf/index.js +0 -11
  310. package/dist/uxf/index.js.map +0 -1
  311. package/dist/uxf/tectonicIdGenerator.d.ts +0 -12
  312. package/dist/uxf/tectonicIdGenerator.js +0 -79
  313. package/dist/uxf/tectonicIdGenerator.js.map +0 -1
  314. package/src/AttachmentPlugin.ts +0 -268
  315. package/src/BusinessRulePlugin.ts +0 -238
  316. package/src/CrossScopePrivilegePlugin.ts +0 -115
  317. package/src/DefaultPlugin.ts +0 -288
  318. package/src/HtmlTemplatePlugin.ts +0 -31
  319. package/src/IdPlugin.ts +0 -74
  320. package/src/IncludePlugin.ts +0 -206
  321. package/src/JsonPlugin.ts +0 -76
  322. package/src/ListPlugin.ts +0 -570
  323. package/src/NowConfigPlugin.ts +0 -69
  324. package/src/PackageJsonPlugin.ts +0 -68
  325. package/src/PropertyPlugin.ts +0 -237
  326. package/src/ScriptTemplatePlugin.ts +0 -53
  327. package/src/ServerModulePlugin.ts +0 -480
  328. package/src/UserPreferencePlugin.ts +0 -45
  329. package/src/aclAndRole/AclPlugin.ts +0 -420
  330. package/src/aclAndRole/RolePlugin.ts +0 -254
  331. package/src/aclAndRole/Util.ts +0 -113
  332. package/src/app/ApplicationMenuPlugin.ts +0 -165
  333. package/src/db/ColumnPlugins.ts +0 -114
  334. package/src/db/DBUtils.ts +0 -36
  335. package/src/db/DocumentationPlugin.ts +0 -316
  336. package/src/db/LicensingPlugin.ts +0 -138
  337. package/src/db/RecordPlugin.ts +0 -459
  338. package/src/db/TablePlugin.ts +0 -2072
  339. package/src/db/index.ts +0 -6
  340. package/src/scriptedRESTAPI/RESTDeserializationUtils.ts +0 -419
  341. package/src/scriptedRESTAPI/RESTSerializationUtils.ts +0 -228
  342. package/src/scriptedRESTAPI/RestApiPlugin.ts +0 -469
  343. package/src/scriptedRESTAPI/RestSchemaUtils.ts +0 -72
  344. package/src/scriptedRESTAPI/RestUtils.ts +0 -569
  345. package/src/scripts/ClientScriptPlugin.ts +0 -257
  346. package/src/scripts/scriptUtils.ts +0 -5
  347. package/src/uxf/ExperiencePlugin.ts +0 -67
  348. package/src/uxf/RoutesPlugin.ts +0 -211
  349. package/src/uxf/UxfFormulaParser/cleanUxValue.ts +0 -73
  350. package/src/uxf/UxfFormulaParser/grammerParser/api.js +0 -166
  351. package/src/uxf/UxfFormulaParser/grammerParser/clientTransformMap.js +0 -606
  352. package/src/uxf/UxfFormulaParser/grammerParser/grammarParser.js +0 -551
  353. package/src/uxf/UxfFormulaParser/grammerParser/spanHelpers.js +0 -65
  354. package/src/uxf/UxfFormulaParser/index.ts +0 -4
  355. package/src/uxf/UxfFormulaParser/parser.ts +0 -64
  356. package/src/uxf/UxfFormulaParser/utils/getErrorMsg.ts +0 -13
  357. package/src/uxf/constants.ts +0 -4
  358. package/src/uxf/index.ts +0 -2
  359. package/src/uxf/tectonicIdGenerator.ts +0 -78
@@ -0,0 +1,739 @@
1
+ import {
2
+ CallExpressionShape,
3
+ type Diagnostics,
4
+ IdentifierShape,
5
+ ObjectShape,
6
+ Plugin,
7
+ PropertyAccessShape,
8
+ type Record as RecordShape,
9
+ type Shape,
10
+ type Source,
11
+ type StringShape,
12
+ TemplateExpressionShape,
13
+ TemplateSpanShape,
14
+ type TemplateSubstitutions,
15
+ ts,
16
+ UndefinedShape,
17
+ VariableStatementShape,
18
+ } from '@servicenow/sdk-build-core'
19
+ import { NowIdShape } from '../now-id-plugin'
20
+ import { ArrowFunctionShape } from '../arrow-function-plugin'
21
+ import { create } from 'xmlbuilder2'
22
+ import { Test } from '@servicenow/sdk-core/runtime/app'
23
+ import { type ATFVariableInfo, type Category, ToShapeStepConfigs, ToRecordStepConfigs } from './step-configs'
24
+ import { durationFieldToXML, formatDateToPlatformFormat, parseGlideDuration } from '@servicenow/sdk-build-core'
25
+ import type { TimeDuration } from '@servicenow/sdk/core'
26
+
27
+ export const TestPlugin = Plugin.create({
28
+ name: 'TestPlugin',
29
+ records: {
30
+ sys_atf_test: {
31
+ relationships: {
32
+ sys_atf_step: {
33
+ via: 'test',
34
+ descendant: true,
35
+ relationships: {
36
+ sys_variable_value: {
37
+ descendant: true,
38
+ via: 'document_key',
39
+ },
40
+ sys_element_mapping: {
41
+ descendant: true,
42
+ via: 'id',
43
+ },
44
+ },
45
+ },
46
+ },
47
+ toShape(record, { descendants }) {
48
+ const arrowParameter = getArrowFunctionParameter(record)
49
+
50
+ const elementMappingRecords = descendants.query('sys_element_mapping')
51
+ const stepsWhichShouldDeclareAVariable =
52
+ getStepIdsThatAreBeingReferencedByOtherSteps(elementMappingRecords)
53
+ const elementMappingValueMap = getFieldValuesFromElementMappingRecords(elementMappingRecords)
54
+
55
+ const stepRecords = descendants
56
+ .query('sys_atf_step')
57
+ .sort((a, b) => a.get('order').toNumber().getValue() - b.get('order').toNumber().getValue())
58
+
59
+ if (anyStepsAreUnknown(stepRecords, record.get('name').toString().getValue())) {
60
+ return { success: false }
61
+ }
62
+
63
+ const stepVarNames = getVariableNamesForSteps(stepRecords)
64
+
65
+ const statements = stepRecords.map((step) => {
66
+ const stepConfigId = step.get('step_config').toString().getValue()
67
+ const stepId = step.getId().getValue()
68
+ const stepConfig = ToShapeStepConfigs[stepConfigId]!
69
+ const gemIdentifier = stepsWhichShouldDeclareAVariable.has(stepId)
70
+ ? stepVarNames.get(stepId)
71
+ : undefined
72
+
73
+ const variables = descendants
74
+ .query('sys_variable_value', { document: 'sys_atf_step', document_key: stepId })
75
+ .map((svvRecord) => {
76
+ const variableShape = svvRecord.get('variable')
77
+ const variableInfo = stepConfig.variables[variableShape.getValue() as string]
78
+ if (!variableInfo) {
79
+ throw new Error(
80
+ `sys_variable_value variable ${variableShape.getValue()} does not correspond to any known ATF input variables for step type '${stepConfig.name}'`
81
+ )
82
+ }
83
+
84
+ const rawValue =
85
+ elementMappingValueMap.get(`${stepId}:${variableInfo.field}`) ?? svvRecord.get('value')
86
+
87
+ const deserializedValue = serializeValueToShape(
88
+ rawValue?.ifDefined()?.toString().getValue(),
89
+ variableInfo.type,
90
+ variableInfo.mandatory
91
+ )
92
+ if (deserializedValue === undefined) {
93
+ return undefined
94
+ }
95
+
96
+ const value = getElementMappingValues(svvRecord, deserializedValue, stepVarNames)
97
+ if (variableInfo.default !== undefined && value === variableInfo.default) {
98
+ // no need to set the value if its already default
99
+ return undefined
100
+ }
101
+
102
+ const name = variableInfo.name
103
+ return {
104
+ name,
105
+ value,
106
+ }
107
+ })
108
+ .filter((v) => v !== undefined)
109
+ .map((v) => ({ [v.name]: v.value }))
110
+ .reduce((acc, v) => ({ ...acc, ...v }), {})
111
+
112
+ const rawTimeoutValue = step.get('timeout').ifString()?.getValue()
113
+ const timeout = parseGlideDuration(rawTimeoutValue)
114
+
115
+ const callExpression = new CallExpressionShape({
116
+ source: step,
117
+ callee: `${arrowParameter}.${stepConfig?.callName}`,
118
+ args: [
119
+ new ObjectShape({
120
+ source: step,
121
+ properties: step.transform(({ $, merge }) => ({
122
+ $id: $.val(NowIdShape.from(step)),
123
+ active: $.toBoolean().def(true),
124
+ description: $.def(''),
125
+ notes: $.def(''),
126
+ warning: $.from('warning_message').def(''),
127
+ timeout: $.val(timeout),
128
+ [merge]: $.val(variables),
129
+ })),
130
+ }),
131
+ ],
132
+ })
133
+
134
+ return gemIdentifier
135
+ ? new VariableStatementShape({
136
+ source: step,
137
+ variableName: gemIdentifier,
138
+ initializer: callExpression,
139
+ })
140
+ : callExpression
141
+ })
142
+ const arrowFunction =
143
+ statements.length > 0
144
+ ? new ArrowFunctionShape({
145
+ source: record,
146
+ parameters: [arrowParameter],
147
+ statements,
148
+ })
149
+ : undefined
150
+
151
+ return {
152
+ success: true,
153
+ value: new CallExpressionShape({
154
+ source: record,
155
+ callee: Test.name,
156
+ args: [
157
+ record.transform(({ $ }) => ({
158
+ $id: $.val(NowIdShape.from(record)),
159
+ name: $,
160
+ description: $.def(''),
161
+ active: $.toBoolean().def(true),
162
+ failOnServerError: $.from('fail_on_server_error').toBoolean().def(false),
163
+ })),
164
+ arrowFunction,
165
+ ].filter((arg) => arg),
166
+ }),
167
+ }
168
+ },
169
+ },
170
+ sys_variable_value: {
171
+ coalesce: ['document', 'document_key', 'variable'],
172
+ },
173
+ sys_atf_step: {
174
+ toFile(step, { database }) {
175
+ const recordUpdate = create().ele('record_update', { table: 'sys_atf_step' })
176
+ const stepElement = recordUpdate.ele('sys_atf_step', { action: 'INSERT_OR_UPDATE' })
177
+ const stepId = step.getId().getValue()
178
+ if (!stepId) {
179
+ throw new Error('Invalid step id')
180
+ }
181
+
182
+ stepElement.ele('sys_id').txt(stepId)
183
+
184
+ Object.entries(step.properties()).forEach(([key, value]) => {
185
+ stepElement.ele(key).txt(value.ifDefined()?.toString()?.getValue() ?? '')
186
+ })
187
+
188
+ const variableValues = database.query('sys_variable_value', {
189
+ document: 'sys_atf_step',
190
+ document_key: step.getId(),
191
+ })
192
+
193
+ recordUpdate.ele('sys_variable_value', {
194
+ action: 'delete_multiple',
195
+ query: `document_key=${stepId}`,
196
+ })
197
+
198
+ variableValues.forEach((varRecord) => {
199
+ const variableElement = recordUpdate.ele('sys_variable_value', { action: 'INSERT_OR_UPDATE' })
200
+ variableElement.ele('sys_id').txt(varRecord.getId().getValue())
201
+ Object.entries(varRecord.properties()).forEach(([key, value]) => {
202
+ variableElement.ele(key).txt(value instanceof UndefinedShape ? '' : value.toString().getValue())
203
+ })
204
+ })
205
+
206
+ const elementMappingRecords = database.query('sys_element_mapping', { id: stepId })
207
+ if (elementMappingRecords.length > 0) {
208
+ recordUpdate.ele('sys_element_mapping', {
209
+ action: 'delete_multiple',
210
+ query: `id=${stepId}`,
211
+ })
212
+ }
213
+
214
+ elementMappingRecords.forEach((record) => {
215
+ const elementMappingElement = recordUpdate.ele('sys_element_mapping', {
216
+ action: 'INSERT_OR_UPDATE',
217
+ })
218
+ elementMappingElement.ele('sys_id').txt(record.getId().getValue())
219
+ Object.entries(record.properties()).forEach(([key, value]) => {
220
+ elementMappingElement.ele(key).txt(value.toString().getValue())
221
+ })
222
+ })
223
+
224
+ return {
225
+ success: true,
226
+ value: {
227
+ name: `sys_atf_step_${step.getId().getValue()}.xml`,
228
+ category: step.getInstallCategory(),
229
+ content: recordUpdate.end({ prettyPrint: true }),
230
+ },
231
+ }
232
+ },
233
+ },
234
+ sys_element_mapping: {
235
+ coalesce: ['field', 'id'],
236
+ },
237
+ },
238
+ shapes: [
239
+ {
240
+ shape: CallExpressionShape,
241
+ fileTypes: ['fluent'],
242
+ async toRecord(callExpression, { factory, diagnostics }) {
243
+ if (callExpression.getCallee() !== Test.name) {
244
+ return { success: false }
245
+ }
246
+
247
+ const prop = callExpression.getArgument(0).asObject()
248
+ const arrowFunc = callExpression.getArgument(1).if(ArrowFunctionShape)
249
+ const testId = prop.get('$id')
250
+
251
+ const steps = arrowFunc ? getStepInfoFromArrowFunction(arrowFunc, diagnostics) : []
252
+ if (steps.some((step) => !step)) {
253
+ return { success: false }
254
+ }
255
+
256
+ const testRecord = factory.createRecord({
257
+ source: callExpression,
258
+ table: 'sys_atf_test',
259
+ explicitId: testId,
260
+ properties: prop.transform(({ $ }) => ({
261
+ name: $,
262
+ active: $.def(true),
263
+ description: $.def(''),
264
+ fail_on_server_error: $.from('failOnServerError').def(false),
265
+ })),
266
+ })
267
+
268
+ const stepRecords = steps.map((step, index) => {
269
+ const rawTimeout = step.values.get('timeout')
270
+ const timeout = rawTimeout.isUndefined()
271
+ ? step.defaultTimeout
272
+ : convertTimeoutToSystemFormat(rawTimeout)
273
+
274
+ return factory.createRecord({
275
+ table: 'sys_atf_step',
276
+ source: step.source,
277
+ explicitId: step.values.get('$id'),
278
+ properties: step.values.transform(({ $ }) => ({
279
+ active: $.toBoolean().def(true),
280
+ description: $,
281
+ display_name: $.val(step.displayName),
282
+ notes: $,
283
+ order: $.val(index + 1),
284
+ step_config: $.val(step.stepConfigId),
285
+ table: $.val(step.table),
286
+ test: $.val(testRecord.getId()),
287
+ timeout: $.val(timeout),
288
+ warning_message: $.from('warning'),
289
+ })),
290
+ })
291
+ })
292
+
293
+ const stepAndVariableValueRecords = steps.flatMap((step, index) => {
294
+ const variableRecords: RecordShape[] = Object.entries(step.variables).flatMap(
295
+ ([varName, atfVariableInfo]) => {
296
+ const valueShape = step.values.get(varName, false)
297
+
298
+ let elementMappingRecord: RecordShape | undefined
299
+
300
+ const value = createGemExpressionsFromShape(valueShape, stepRecords, diagnostics)
301
+ if (value !== undefined) {
302
+ elementMappingRecord = factory.createRecord({
303
+ table: 'sys_element_mapping',
304
+ source: step.source,
305
+ properties: {
306
+ field: atfVariableInfo.field,
307
+ id: stepRecords[index]?.getId(),
308
+ table: `var__m_atf_input_variable_${step.stepConfigId}`,
309
+ value: serializeValueToRecord(
310
+ value,
311
+ atfVariableInfo.type,
312
+ atfVariableInfo.default
313
+ ),
314
+ },
315
+ })
316
+ }
317
+
318
+ return [
319
+ factory.createRecord({
320
+ table: 'sys_variable_value',
321
+ source: step.source,
322
+ properties: {
323
+ document: 'sys_atf_step',
324
+ document_key: stepRecords[index]?.getId(),
325
+ value: serializeValueToRecord(
326
+ value ??
327
+ valueShape
328
+ .ifArray()
329
+ ?.getElements()
330
+ .map((v) => v.ifRecord()?.getId().getValue() ?? v.getValue()) ??
331
+ valueShape.ifResolvable()?.resolve().ifRecord()?.getId().getValue() ??
332
+ valueShape.getValue(),
333
+ atfVariableInfo.type,
334
+ atfVariableInfo.default
335
+ ),
336
+ variable: atfVariableInfo.inputVariableId,
337
+ order: atfVariableInfo.order,
338
+ },
339
+ }),
340
+ ...(elementMappingRecord ? [elementMappingRecord] : []),
341
+ ]
342
+ }
343
+ )
344
+
345
+ return variableRecords
346
+ })
347
+
348
+ return {
349
+ success: true,
350
+ value: testRecord.with(...stepRecords, ...stepAndVariableValueRecords),
351
+ }
352
+ },
353
+ },
354
+ ],
355
+ })
356
+
357
+ const UNSUPPORTED_STEP_CONFIGS = {
358
+ '38907e937322130007d738682bf6a742': 'Component State Validation (Custom UI)',
359
+ '475e0de3d732130089fca2285e610361': 'Assert Text on Page (Custom UI)',
360
+ b4758c7453370300c792ddeeff7b128d: 'Component Value Validation (Custom UI)',
361
+ def25c4b73730300c79260bdfaf6a700: 'Click Component (Custom UI)',
362
+ e5dd168473330300c79260bdfaf6a794: 'Set Component Values (Custom UI)',
363
+ fc7e65d577332300e46abe41a9106106: 'Open Service Portal Page',
364
+ '012105620fe2330091d0f00c97767ec4': 'Validate List UI Action Visibility',
365
+ '0200ac2fe72003005c85cd19d2f6a942': 'Open a Record in List',
366
+ '7bdce31387400300709861fb97cb0b5a': 'Validate Record Present in List',
367
+ '8b84e5e837b1030064a52f3c8e41f170': 'Validate Related List Visibility',
368
+ a69843f2531332007e7829cac2dc34d7: 'Apply Filter to List',
369
+ c5f44934532332007e7829cac2dc342e: 'Click a List UI Action',
370
+ }
371
+
372
+ function getFieldValuesFromElementMappingRecords(elementMappingRecords: RecordShape[]) {
373
+ return elementMappingRecords
374
+ .filter((em) => em.get('value').getValue())
375
+ .reduce((map, em) => {
376
+ const field = em.get('field').getValue()
377
+ const stepId = em.get('id').getValue()
378
+ return map.set(`${stepId}:${field}`, em.get('value'))
379
+ }, new Map<string, Shape>())
380
+ }
381
+
382
+ function convertTimeoutToSystemFormat(timeoutShape: Shape) {
383
+ const timeoutDuration = timeoutShape.ifObject()?.getValue() as TimeDuration | undefined
384
+ const timeoutDate = timeoutDuration && durationFieldToXML(timeoutDuration)
385
+ return timeoutDate && formatDateToPlatformFormat(timeoutDate)
386
+ }
387
+
388
+ function anyStepsAreUnknown(stepRecords: RecordShape[], testName: string) {
389
+ return stepRecords.some((stepRecord) => {
390
+ const stepConfigId = stepRecord.get('step_config').toString().getValue()
391
+ if (!ToShapeStepConfigs[stepConfigId]) {
392
+ const stepConfigName = UNSUPPORTED_STEP_CONFIGS[stepConfigId] ?? stepConfigId
393
+ console.error(
394
+ `Unable to transform ATF test '${testName}' because of unsupported step_config: '${stepConfigName}'`
395
+ )
396
+ return true
397
+ }
398
+ return false
399
+ })
400
+ }
401
+
402
+ function getArrowFunctionParameter(record: RecordShape) {
403
+ const source = record.getOriginalSource()
404
+
405
+ return (
406
+ (ts.Node.isNode(source) &&
407
+ source.isKind(ts.SyntaxKind.CallExpression) &&
408
+ source.getArguments()[1]?.asKind(ts.SyntaxKind.ArrowFunction)?.getParameters()[0]?.getName()) ||
409
+ 'atf'
410
+ )
411
+ }
412
+
413
+ function propertyAccessToGemExpression(
414
+ propertyAccess: PropertyAccessShape,
415
+ stepRecords: RecordShape[],
416
+ diagnostics: Diagnostics
417
+ ) {
418
+ const split = propertyAccess.getCode().split('.')
419
+ if (!split[0]) {
420
+ diagnostics.error(propertyAccess, `Invalid expression`)
421
+ return undefined
422
+ }
423
+
424
+ const sourceStep = stepRecords.find(
425
+ (rec) => rec.getSource() === propertyAccess.getFirstElement().resolve().if(CallExpressionShape)
426
+ )
427
+ if (!sourceStep) {
428
+ diagnostics.error(propertyAccess, `Invalid expression, expecting a reference to an ATF step`)
429
+ }
430
+
431
+ const stepId = sourceStep?.getId().getValue()
432
+ const elementPath = split.slice(1).join('.')
433
+ const suffix = elementPath ? `.${elementPath}` : ''
434
+
435
+ return `{{step['${stepId}']${suffix}}}`
436
+ }
437
+
438
+ function createGemExpressionsFromShape(shape: Shape, stepRecords: RecordShape[], diagnostics: Diagnostics) {
439
+ if (shape instanceof PropertyAccessShape) {
440
+ return propertyAccessToGemExpression(shape, stepRecords, diagnostics)
441
+ }
442
+ if (shape instanceof TemplateExpressionShape) {
443
+ const gemExpressions = shape
444
+ .getSpans()
445
+ .map((span) =>
446
+ propertyAccessToGemExpression(span.getExpression().as(PropertyAccessShape), stepRecords, diagnostics)
447
+ )
448
+ .reduce((acc, gemExpression, index) => ({ ...acc, [index]: gemExpression }), {}) as TemplateSubstitutions
449
+
450
+ return shape.getValue(gemExpressions)
451
+ }
452
+
453
+ if (shape instanceof ObjectShape) {
454
+ const obj = {}
455
+ let gemExpressionFound = false
456
+ for (const key in shape.properties()) {
457
+ const value = createGemExpressionsFromShape(shape.get(key, false), stepRecords, diagnostics)
458
+ gemExpressionFound = gemExpressionFound || value !== undefined
459
+ obj[key] = value || shape.get(key).getValue()
460
+ }
461
+ return gemExpressionFound ? obj : undefined
462
+ }
463
+
464
+ return undefined
465
+ }
466
+
467
+ function getStepInfoFromArrowFunction(arrowFunc: ArrowFunctionShape, diagnostics: Diagnostics) {
468
+ return arrowFunc
469
+ .getStatements()
470
+ .filter((statement) => statement instanceof CallExpressionShape || statement instanceof VariableStatementShape)
471
+ .map((statement) => getStepInfoFromAtfCallExpression(statement, diagnostics))
472
+ .filter((step) => step) as StepInfo[]
473
+ }
474
+
475
+ type StepInfo = {
476
+ displayName: string
477
+ source: Source
478
+ stepConfigId: string
479
+ table: StringShape | undefined
480
+ variables: Record<string, ATFVariableInfo>
481
+ values: ObjectShape
482
+ identifier: string | undefined
483
+ defaultTimeout?: string
484
+ }
485
+
486
+ function getStepInfoFromAtfCallExpression(
487
+ statement: CallExpressionShape | VariableStatementShape,
488
+ diagnostics: Diagnostics
489
+ ): StepInfo | undefined {
490
+ let callExpression: CallExpressionShape
491
+ let identifier: string | undefined
492
+ if (statement instanceof VariableStatementShape) {
493
+ callExpression = statement.getInitializer() as CallExpressionShape
494
+ identifier = statement.getVariableName().getName()
495
+ } else if (statement instanceof CallExpressionShape) {
496
+ callExpression = statement
497
+ } else {
498
+ return undefined
499
+ }
500
+
501
+ const [, category, funcName] = callExpression.getCallee().split('.')
502
+ if (!category || !funcName) {
503
+ diagnostics.info(callExpression, 'Invalid ATF step')
504
+ return undefined
505
+ }
506
+
507
+ if (!ToRecordStepConfigs[category]) {
508
+ diagnostics.warn(callExpression, `Unknown category: ${category}`)
509
+ return undefined
510
+ }
511
+
512
+ if (!ToRecordStepConfigs[category][funcName]) {
513
+ diagnostics.warn(callExpression, `Unknown step: ${funcName}`)
514
+ return undefined
515
+ }
516
+
517
+ const stepConfig = ToRecordStepConfigs[category as Category][funcName]!
518
+ const values = callExpression.getArgument(0).asObject()
519
+ return {
520
+ displayName: stepConfig.name,
521
+ stepConfigId: stepConfig.stepConfigId,
522
+ variables: stepConfig.variables,
523
+ table: values.get('table')?.ifString(),
524
+ source: callExpression,
525
+ identifier,
526
+ defaultTimeout: stepConfig.defaultTimeout,
527
+ values,
528
+ }
529
+ }
530
+
531
+ function getVariableNamesForSteps(stepRecords: RecordShape[]) {
532
+ return stepRecords.reduce((map, step, index) => {
533
+ const source = step.getOriginalSource()
534
+ const name =
535
+ (ts.Node.isNode(source) && source.getParentIfKind(ts.SyntaxKind.VariableDeclaration)?.getName()) ||
536
+ `step${index + 1}`
537
+
538
+ return map.set(step.getId().getValue(), name)
539
+ }, new Map<string, string>())
540
+ }
541
+
542
+ const GemRegex = /{{step\[(?:'|.{6})(?<stepId>[0-9a-f]{32})(?:'|.{6})\]\.(?<elementPath>.*?)}}/gm
543
+
544
+ function getStepIdsThatAreBeingReferencedByOtherSteps(elementMappingRecord: RecordShape[]) {
545
+ return elementMappingRecord
546
+ .flatMap((rec) => {
547
+ const str = rec.get('value').toString().getValue()
548
+ const matches = str.matchAll(GemRegex)
549
+
550
+ return Array.from(matches).map((m) => {
551
+ const [, stepId] = m
552
+ return stepId
553
+ })
554
+ })
555
+ .filter((stepId) => stepId !== undefined)
556
+ .reduce((acc, stepId) => acc.add(stepId), new Set<string>())
557
+ }
558
+
559
+ function variableElementPathToPropertyAccess(source: Source, propertyAccessPath: string) {
560
+ const elements = propertyAccessPath.split('.').map((e) => new IdentifierShape({ source, name: e }))
561
+
562
+ return new PropertyAccessShape({
563
+ source,
564
+ elements: [elements[0], elements[1], ...elements.slice(2)],
565
+ })
566
+ }
567
+
568
+ function getElementMappingValues(source: Source, value: any, stepIdToVarName: Map<string, string>) {
569
+ if (typeof value === 'object' && value !== null) {
570
+ if (Array.isArray(value)) {
571
+ return value.map((v) => getElementMappingValues(source, v, stepIdToVarName))
572
+ } else {
573
+ const obj = {}
574
+ for (const key in value) {
575
+ obj[key] = getElementMappingValues(source, value[key], stepIdToVarName)
576
+ }
577
+ return obj
578
+ }
579
+ }
580
+
581
+ const potentialGemExpression = typeof value === 'string' ? value : undefined
582
+ if (!potentialGemExpression) {
583
+ return value
584
+ }
585
+
586
+ const [matched] = Array.from(potentialGemExpression.matchAll(GemRegex))
587
+ const simpleGemExpression = matched && matched[0] === potentialGemExpression
588
+ if (!matched) {
589
+ return value
590
+ }
591
+
592
+ // If the GEM expression is simple, it only contains the GEM
593
+ // expression and nothing else. This means we can transform it
594
+ // a PropertyAccessExpression, otherwise we'll need to create
595
+ // a TemplateExpression
596
+ if (simpleGemExpression) {
597
+ const stepId = matched.groups!['stepId']!
598
+ const elementPath = matched.groups?.['elementPath']
599
+ const varName = stepIdToVarName.get(stepId)
600
+ if (!varName) {
601
+ return undefined
602
+ }
603
+ const lastIdentifier = elementPath?.split('.')[0]
604
+ if (!lastIdentifier) {
605
+ throw new Error(`Invalid GEM expression found in: '${potentialGemExpression}'`)
606
+ }
607
+
608
+ return variableElementPathToPropertyAccess(source, `${varName}.${elementPath}`)
609
+ }
610
+
611
+ const matches = Array.from(potentialGemExpression.matchAll(GemRegex))
612
+ if (!matches[0]) {
613
+ return undefined
614
+ }
615
+
616
+ const spans: TemplateSpanShape[] = []
617
+ const head = potentialGemExpression.substring(0, matches[0].index)
618
+
619
+ for (let i = 0; i < matches.length; i++) {
620
+ const m = matches[i]!
621
+ const gem = m[0]
622
+
623
+ const nextGemIndex = matches[i + 1]?.index
624
+ const tail = potentialGemExpression.substring(m.index + gem.length, nextGemIndex)
625
+ const stepId = m.groups?.['stepId'] as string
626
+ const elementPath = m.groups?.['elementPath'] ?? ''
627
+ const varName = stepIdToVarName.get(stepId)
628
+
629
+ spans.push(
630
+ new TemplateSpanShape({
631
+ source,
632
+ literalText: tail,
633
+ expression: variableElementPathToPropertyAccess(source, `${varName}.${elementPath}`),
634
+ })
635
+ )
636
+ }
637
+
638
+ return new TemplateExpressionShape({
639
+ source,
640
+ literalText: head,
641
+ spans: spans,
642
+ })
643
+ }
644
+
645
+ function objectToEncodedQuery(objectShape: Record<string, any>) {
646
+ return Object.entries(objectShape)
647
+ .map(([key, value]) => {
648
+ const escapedValue = value.toString().replaceAll('^', '^^')
649
+ return `${key}=${escapedValue}`
650
+ })
651
+ .concat('EQ')
652
+ .join('^')
653
+ }
654
+
655
+ export function serializeValueToRecord(value: any, type: string, defaultValue: any) {
656
+ value = value === undefined ? defaultValue : value
657
+
658
+ switch (type) {
659
+ case 'field_list':
660
+ case 'glide_list':
661
+ return Array.isArray(value) ? value.join(',') : value
662
+ case 'string': {
663
+ return value ? value : undefined
664
+ }
665
+ case 'simple_name_values': {
666
+ if (typeof value !== 'object' || value === null || Object.keys(value).length === 0) {
667
+ return ''
668
+ }
669
+ return JSON.stringify(value)
670
+ }
671
+ case 'template_value':
672
+ return value && objectToEncodedQuery(value)
673
+ case 'boolean':
674
+ return value ? 1 : 0
675
+ default:
676
+ return value
677
+ }
678
+ }
679
+
680
+ function convertToPrimitiveValue(value: string) {
681
+ if (value === '') {
682
+ return value
683
+ }
684
+
685
+ if (value === 'true') {
686
+ return true
687
+ }
688
+
689
+ if (value === 'false') {
690
+ return false
691
+ }
692
+
693
+ const maybeNumber = Number(value)
694
+ if (!isNaN(maybeNumber)) {
695
+ return maybeNumber
696
+ }
697
+
698
+ return value
699
+ }
700
+
701
+ function queryToFieldValues(query: string) {
702
+ const caratReplacement = '__CARATREPLACEMENTSTRING__'
703
+ return query
704
+ .replaceAll('^^', caratReplacement)
705
+ .split('^')
706
+ .filter((term) => term !== 'EQ')
707
+ .map((term) => term.split('='))
708
+ .filter(([, value]) => value !== undefined)
709
+ .map(([key, value]) => ({ [key as string]: convertToPrimitiveValue(value!.replaceAll(caratReplacement, '^')) }))
710
+ .reduce((acc, obj) => ({ ...acc, ...obj }), {})
711
+ }
712
+
713
+ // returning undefined here means the value won't appear on an initial transform
714
+ export function serializeValueToShape(value: string | undefined, type: string, mandatory: boolean = false) {
715
+ if (value === undefined) {
716
+ return value
717
+ }
718
+ switch (type) {
719
+ case 'integer':
720
+ return value ? parseInt(value, 10) : undefined
721
+ case 'glide_list':
722
+ case 'field_list':
723
+ if (!value) {
724
+ return mandatory ? [] : undefined
725
+ }
726
+ return value.split(',')
727
+ case 'simple_name_values':
728
+ if (!value && mandatory) {
729
+ return {}
730
+ }
731
+ return value ? JSON.parse(value) : undefined
732
+ case 'template_value':
733
+ return queryToFieldValues(value)
734
+ case 'boolean':
735
+ return value === '1'
736
+ default:
737
+ return mandatory ? value : value || undefined
738
+ }
739
+ }