mcdev 6.0.2 → 7.0.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 (602) hide show
  1. package/.beautyamp.json +13 -0
  2. package/.eslintrc.json +7 -1
  3. package/.github/ISSUE_TEMPLATE/bug.yml +1 -0
  4. package/.github/PULL_REQUEST_TEMPLATE/pr_template_release.md +10 -3
  5. package/.github/workflows/close_issues_on_merge.yml +1 -1
  6. package/.github/workflows/code-test.yml +51 -3
  7. package/.github/workflows/coverage-base-update.yml +1 -1
  8. package/.github/workflows/coverage-develop-branch.yml +1 -1
  9. package/.github/workflows/coverage-main-branch.yml +1 -1
  10. package/.github/workflows/coverage.yml +2 -2
  11. package/.github/workflows/npm-publish.yml +3 -2
  12. package/.github/workflows/pr-labeler.yml +1 -1
  13. package/.husky/commit-msg +0 -2
  14. package/.husky/post-checkout +0 -3
  15. package/.husky/post-merge +2 -7
  16. package/.husky/pre-commit +5 -5
  17. package/.prettierrc +0 -8
  18. package/.vscode/extensions.json +2 -0
  19. package/.vscode/settings.json +15 -3
  20. package/@types/lib/Builder.d.ts +97 -0
  21. package/@types/lib/Builder.d.ts.map +1 -0
  22. package/@types/lib/Deployer.d.ts +99 -0
  23. package/@types/lib/Deployer.d.ts.map +1 -0
  24. package/@types/lib/MetadataTypeDefinitions.d.ts +80 -0
  25. package/@types/lib/MetadataTypeDefinitions.d.ts.map +1 -0
  26. package/@types/lib/MetadataTypeInfo.d.ts +78 -0
  27. package/@types/lib/MetadataTypeInfo.d.ts.map +1 -0
  28. package/@types/lib/Retriever.d.ts +66 -0
  29. package/@types/lib/Retriever.d.ts.map +1 -0
  30. package/@types/lib/cli.d.ts +3 -0
  31. package/@types/lib/cli.d.ts.map +1 -0
  32. package/@types/lib/index.d.ts +383 -0
  33. package/@types/lib/index.d.ts.map +1 -0
  34. package/@types/lib/metadataTypes/Asset.d.ts +1082 -0
  35. package/@types/lib/metadataTypes/Asset.d.ts.map +1 -0
  36. package/@types/lib/metadataTypes/AttributeGroup.d.ts +290 -0
  37. package/@types/lib/metadataTypes/AttributeGroup.d.ts.map +1 -0
  38. package/@types/lib/metadataTypes/AttributeSet.d.ts +968 -0
  39. package/@types/lib/metadataTypes/AttributeSet.d.ts.map +1 -0
  40. package/@types/lib/metadataTypes/Automation.d.ts +921 -0
  41. package/@types/lib/metadataTypes/Automation.d.ts.map +1 -0
  42. package/@types/lib/metadataTypes/Campaign.d.ts +190 -0
  43. package/@types/lib/metadataTypes/Campaign.d.ts.map +1 -0
  44. package/@types/lib/metadataTypes/ContentArea.d.ts +250 -0
  45. package/@types/lib/metadataTypes/ContentArea.d.ts.map +1 -0
  46. package/@types/lib/metadataTypes/DataExtension.d.ts +571 -0
  47. package/@types/lib/metadataTypes/DataExtension.d.ts.map +1 -0
  48. package/@types/lib/metadataTypes/DataExtensionField.d.ts +236 -0
  49. package/@types/lib/metadataTypes/DataExtensionField.d.ts.map +1 -0
  50. package/@types/lib/metadataTypes/DataExtensionTemplate.d.ts +175 -0
  51. package/@types/lib/metadataTypes/DataExtensionTemplate.d.ts.map +1 -0
  52. package/@types/lib/metadataTypes/DataExtract.d.ts +217 -0
  53. package/@types/lib/metadataTypes/DataExtract.d.ts.map +1 -0
  54. package/@types/lib/metadataTypes/DataExtractType.d.ts +80 -0
  55. package/@types/lib/metadataTypes/DataExtractType.d.ts.map +1 -0
  56. package/@types/lib/metadataTypes/DeliveryProfile.d.ts +102 -0
  57. package/@types/lib/metadataTypes/DeliveryProfile.d.ts.map +1 -0
  58. package/@types/lib/metadataTypes/Discovery.d.ts +189 -0
  59. package/@types/lib/metadataTypes/Discovery.d.ts.map +1 -0
  60. package/@types/lib/metadataTypes/Email.d.ts +384 -0
  61. package/@types/lib/metadataTypes/Email.d.ts.map +1 -0
  62. package/@types/lib/metadataTypes/EmailSend.d.ts +652 -0
  63. package/@types/lib/metadataTypes/EmailSend.d.ts.map +1 -0
  64. package/@types/lib/metadataTypes/Event.d.ts +958 -0
  65. package/@types/lib/metadataTypes/Event.d.ts.map +1 -0
  66. package/@types/lib/metadataTypes/FileLocation.d.ts +101 -0
  67. package/@types/lib/metadataTypes/FileLocation.d.ts.map +1 -0
  68. package/@types/lib/metadataTypes/FileTransfer.d.ts +228 -0
  69. package/@types/lib/metadataTypes/FileTransfer.d.ts.map +1 -0
  70. package/@types/lib/metadataTypes/Filter.d.ts +145 -0
  71. package/@types/lib/metadataTypes/Filter.d.ts.map +1 -0
  72. package/@types/lib/metadataTypes/Folder.d.ts +287 -0
  73. package/@types/lib/metadataTypes/Folder.d.ts.map +1 -0
  74. package/@types/lib/metadataTypes/ImportFile.d.ts +409 -0
  75. package/@types/lib/metadataTypes/ImportFile.d.ts.map +1 -0
  76. package/@types/lib/metadataTypes/Journey.d.ts +541 -0
  77. package/@types/lib/metadataTypes/Journey.d.ts.map +1 -0
  78. package/@types/lib/metadataTypes/List.d.ts +191 -0
  79. package/@types/lib/metadataTypes/List.d.ts.map +1 -0
  80. package/@types/lib/metadataTypes/MetadataType.d.ts +680 -0
  81. package/@types/lib/metadataTypes/MetadataType.d.ts.map +1 -0
  82. package/@types/lib/metadataTypes/MobileCode.d.ts +225 -0
  83. package/@types/lib/metadataTypes/MobileCode.d.ts.map +1 -0
  84. package/@types/lib/metadataTypes/MobileKeyword.d.ts +432 -0
  85. package/@types/lib/metadataTypes/MobileKeyword.d.ts.map +1 -0
  86. package/@types/lib/metadataTypes/MobileMessage.d.ts +931 -0
  87. package/@types/lib/metadataTypes/MobileMessage.d.ts.map +1 -0
  88. package/@types/lib/metadataTypes/Query.d.ts +299 -0
  89. package/@types/lib/metadataTypes/Query.d.ts.map +1 -0
  90. package/@types/lib/metadataTypes/Role.d.ts +164 -0
  91. package/@types/lib/metadataTypes/Role.d.ts.map +1 -0
  92. package/@types/lib/metadataTypes/Script.d.ts +305 -0
  93. package/@types/lib/metadataTypes/Script.d.ts.map +1 -0
  94. package/@types/lib/metadataTypes/SendClassification.d.ts +221 -0
  95. package/@types/lib/metadataTypes/SendClassification.d.ts.map +1 -0
  96. package/@types/lib/metadataTypes/SenderProfile.d.ts +257 -0
  97. package/@types/lib/metadataTypes/SenderProfile.d.ts.map +1 -0
  98. package/@types/lib/metadataTypes/TransactionalEmail.d.ts +230 -0
  99. package/@types/lib/metadataTypes/TransactionalEmail.d.ts.map +1 -0
  100. package/@types/lib/metadataTypes/TransactionalMessage.d.ts +163 -0
  101. package/@types/lib/metadataTypes/TransactionalMessage.d.ts.map +1 -0
  102. package/@types/lib/metadataTypes/TransactionalPush.d.ts +175 -0
  103. package/@types/lib/metadataTypes/TransactionalPush.d.ts.map +1 -0
  104. package/@types/lib/metadataTypes/TransactionalSMS.d.ts +205 -0
  105. package/@types/lib/metadataTypes/TransactionalSMS.d.ts.map +1 -0
  106. package/@types/lib/metadataTypes/TriggeredSend.d.ts +671 -0
  107. package/@types/lib/metadataTypes/TriggeredSend.d.ts.map +1 -0
  108. package/@types/lib/metadataTypes/User.d.ts +677 -0
  109. package/@types/lib/metadataTypes/User.d.ts.map +1 -0
  110. package/@types/lib/metadataTypes/Verification.d.ts +188 -0
  111. package/@types/lib/metadataTypes/Verification.d.ts.map +1 -0
  112. package/@types/lib/metadataTypes/definitions/Asset.definition.d.ts +692 -0
  113. package/@types/lib/metadataTypes/definitions/Asset.definition.d.ts.map +1 -0
  114. package/@types/lib/metadataTypes/definitions/AttributeGroup.definition.d.ts +246 -0
  115. package/@types/lib/metadataTypes/definitions/AttributeGroup.definition.d.ts.map +1 -0
  116. package/@types/lib/metadataTypes/definitions/AttributeSet.definition.d.ts +893 -0
  117. package/@types/lib/metadataTypes/definitions/AttributeSet.definition.d.ts.map +1 -0
  118. package/@types/lib/metadataTypes/definitions/Automation.definition.d.ts +616 -0
  119. package/@types/lib/metadataTypes/definitions/Automation.definition.d.ts.map +1 -0
  120. package/@types/lib/metadataTypes/definitions/Campaign.definition.d.ts +126 -0
  121. package/@types/lib/metadataTypes/definitions/Campaign.definition.d.ts.map +1 -0
  122. package/@types/lib/metadataTypes/definitions/ContentArea.definition.d.ts +182 -0
  123. package/@types/lib/metadataTypes/definitions/ContentArea.definition.d.ts.map +1 -0
  124. package/@types/lib/metadataTypes/definitions/DataExtension.definition.d.ts +237 -0
  125. package/@types/lib/metadataTypes/definitions/DataExtension.definition.d.ts.map +1 -0
  126. package/@types/lib/metadataTypes/definitions/DataExtensionField.definition.d.ts +121 -0
  127. package/@types/lib/metadataTypes/definitions/DataExtensionField.definition.d.ts.map +1 -0
  128. package/@types/lib/metadataTypes/definitions/DataExtensionTemplate.definition.d.ts +133 -0
  129. package/@types/lib/metadataTypes/definitions/DataExtensionTemplate.definition.d.ts.map +1 -0
  130. package/@types/lib/metadataTypes/definitions/DataExtract.definition.d.ts +156 -0
  131. package/@types/lib/metadataTypes/definitions/DataExtract.definition.d.ts.map +1 -0
  132. package/@types/lib/metadataTypes/definitions/DataExtractType.definition.d.ts +34 -0
  133. package/@types/lib/metadataTypes/definitions/DataExtractType.definition.d.ts.map +1 -0
  134. package/@types/lib/metadataTypes/definitions/DeliveryProfile.definition.d.ts +80 -0
  135. package/@types/lib/metadataTypes/definitions/DeliveryProfile.definition.d.ts.map +1 -0
  136. package/@types/lib/metadataTypes/definitions/Discovery.definition.d.ts +146 -0
  137. package/@types/lib/metadataTypes/definitions/Discovery.definition.d.ts.map +1 -0
  138. package/@types/lib/metadataTypes/definitions/Email.definition.d.ts +314 -0
  139. package/@types/lib/metadataTypes/definitions/Email.definition.d.ts.map +1 -0
  140. package/@types/lib/metadataTypes/definitions/EmailSend.definition.d.ts +582 -0
  141. package/@types/lib/metadataTypes/definitions/EmailSend.definition.d.ts.map +1 -0
  142. package/@types/lib/metadataTypes/definitions/Event.definition.d.ts +867 -0
  143. package/@types/lib/metadataTypes/definitions/Event.definition.d.ts.map +1 -0
  144. package/@types/lib/metadataTypes/definitions/FileLocation.definition.d.ts +68 -0
  145. package/@types/lib/metadataTypes/definitions/FileLocation.definition.d.ts.map +1 -0
  146. package/@types/lib/metadataTypes/definitions/FileTransfer.definition.d.ts +191 -0
  147. package/@types/lib/metadataTypes/definitions/FileTransfer.definition.d.ts.map +1 -0
  148. package/@types/lib/metadataTypes/definitions/Filter.definition.d.ts +147 -0
  149. package/@types/lib/metadataTypes/definitions/Filter.definition.d.ts.map +1 -0
  150. package/@types/lib/metadataTypes/definitions/Folder.definition.d.ts +174 -0
  151. package/@types/lib/metadataTypes/definitions/Folder.definition.d.ts.map +1 -0
  152. package/@types/lib/metadataTypes/definitions/ImportFile.definition.d.ts +306 -0
  153. package/@types/lib/metadataTypes/definitions/ImportFile.definition.d.ts.map +1 -0
  154. package/@types/lib/metadataTypes/definitions/Journey.definition.d.ts +426 -0
  155. package/@types/lib/metadataTypes/definitions/Journey.definition.d.ts.map +1 -0
  156. package/@types/lib/metadataTypes/definitions/List.definition.d.ts +118 -0
  157. package/@types/lib/metadataTypes/definitions/List.definition.d.ts.map +1 -0
  158. package/@types/lib/metadataTypes/definitions/MobileCode.definition.d.ts +167 -0
  159. package/@types/lib/metadataTypes/definitions/MobileCode.definition.d.ts.map +1 -0
  160. package/@types/lib/metadataTypes/definitions/MobileKeyword.definition.d.ts +276 -0
  161. package/@types/lib/metadataTypes/definitions/MobileKeyword.definition.d.ts.map +1 -0
  162. package/@types/lib/metadataTypes/definitions/MobileMessage.definition.d.ts +783 -0
  163. package/@types/lib/metadataTypes/definitions/MobileMessage.definition.d.ts.map +1 -0
  164. package/@types/lib/metadataTypes/definitions/Query.definition.d.ts +203 -0
  165. package/@types/lib/metadataTypes/definitions/Query.definition.d.ts.map +1 -0
  166. package/@types/lib/metadataTypes/definitions/Role.definition.d.ts +108 -0
  167. package/@types/lib/metadataTypes/definitions/Role.definition.d.ts.map +1 -0
  168. package/@types/lib/metadataTypes/definitions/Script.definition.d.ts +153 -0
  169. package/@types/lib/metadataTypes/definitions/Script.definition.d.ts.map +1 -0
  170. package/@types/lib/metadataTypes/definitions/SendClassification.definition.d.ts +151 -0
  171. package/@types/lib/metadataTypes/definitions/SendClassification.definition.d.ts.map +1 -0
  172. package/@types/lib/metadataTypes/definitions/SenderProfile.definition.d.ts +180 -0
  173. package/@types/lib/metadataTypes/definitions/SenderProfile.definition.d.ts.map +1 -0
  174. package/@types/lib/metadataTypes/definitions/TransactionalEmail.definition.d.ts +167 -0
  175. package/@types/lib/metadataTypes/definitions/TransactionalEmail.definition.d.ts.map +1 -0
  176. package/@types/lib/metadataTypes/definitions/TransactionalMessage.definition.d.ts +99 -0
  177. package/@types/lib/metadataTypes/definitions/TransactionalMessage.definition.d.ts.map +1 -0
  178. package/@types/lib/metadataTypes/definitions/TransactionalPush.definition.d.ts +119 -0
  179. package/@types/lib/metadataTypes/definitions/TransactionalPush.definition.d.ts.map +1 -0
  180. package/@types/lib/metadataTypes/definitions/TransactionalSMS.definition.d.ts +113 -0
  181. package/@types/lib/metadataTypes/definitions/TransactionalSMS.definition.d.ts.map +1 -0
  182. package/@types/lib/metadataTypes/definitions/TriggeredSend.definition.d.ts +560 -0
  183. package/@types/lib/metadataTypes/definitions/TriggeredSend.definition.d.ts.map +1 -0
  184. package/@types/lib/metadataTypes/definitions/User.definition.d.ts +423 -0
  185. package/@types/lib/metadataTypes/definitions/User.definition.d.ts.map +1 -0
  186. package/@types/lib/metadataTypes/definitions/Verification.definition.d.ts +129 -0
  187. package/@types/lib/metadataTypes/definitions/Verification.definition.d.ts.map +1 -0
  188. package/@types/lib/retrieveChangelog.d.ts +3 -0
  189. package/@types/lib/retrieveChangelog.d.ts.map +1 -0
  190. package/@types/lib/util/auth.d.ts +41 -0
  191. package/@types/lib/util/auth.d.ts.map +1 -0
  192. package/@types/lib/util/businessUnit.d.ts +21 -0
  193. package/@types/lib/util/businessUnit.d.ts.map +1 -0
  194. package/@types/lib/util/cache.d.ts +64 -0
  195. package/@types/lib/util/cache.d.ts.map +1 -0
  196. package/@types/lib/util/cli.d.ts +125 -0
  197. package/@types/lib/util/cli.d.ts.map +1 -0
  198. package/@types/lib/util/config.d.ts +45 -0
  199. package/@types/lib/util/config.d.ts.map +1 -0
  200. package/@types/lib/util/devops.d.ts +62 -0
  201. package/@types/lib/util/devops.d.ts.map +1 -0
  202. package/@types/lib/util/file.d.ts +20 -0
  203. package/@types/lib/util/file.d.ts.map +1 -0
  204. package/@types/lib/util/init.config.d.ts +66 -0
  205. package/@types/lib/util/init.config.d.ts.map +1 -0
  206. package/@types/lib/util/init.d.ts +72 -0
  207. package/@types/lib/util/init.d.ts.map +1 -0
  208. package/@types/lib/util/init.git.d.ts +40 -0
  209. package/@types/lib/util/init.git.d.ts.map +1 -0
  210. package/@types/lib/util/init.npm.d.ts +24 -0
  211. package/@types/lib/util/init.npm.d.ts.map +1 -0
  212. package/@types/lib/util/replaceContentBlockReference.d.ts +105 -0
  213. package/@types/lib/util/replaceContentBlockReference.d.ts.map +1 -0
  214. package/@types/lib/util/util.d.ts +322 -0
  215. package/@types/lib/util/util.d.ts.map +1 -0
  216. package/@types/types/mcdev.d.d.ts +1282 -0
  217. package/@types/types/mcdev.d.d.ts.map +1 -0
  218. package/LICENSE +1 -1
  219. package/README.md +7 -3
  220. package/boilerplate/files/.beautyamp.json +13 -0
  221. package/boilerplate/files/.prettierrc +3 -0
  222. package/boilerplate/files/.vscode/extensions.json +6 -1
  223. package/boilerplate/files/.vscode/settings.json +16 -4
  224. package/boilerplate/forcedUpdates.json +9 -0
  225. package/jsconfig.json +7 -2
  226. package/lib/Builder.js +49 -45
  227. package/lib/Deployer.js +100 -45
  228. package/lib/MetadataTypeDefinitions.js +6 -0
  229. package/lib/MetadataTypeInfo.js +4 -0
  230. package/lib/Retriever.js +33 -27
  231. package/lib/cli.js +363 -28
  232. package/lib/index.js +615 -55
  233. package/lib/metadataTypes/Asset.js +811 -159
  234. package/lib/metadataTypes/AttributeGroup.js +17 -12
  235. package/lib/metadataTypes/AttributeSet.js +20 -15
  236. package/lib/metadataTypes/Automation.js +125 -93
  237. package/lib/metadataTypes/Campaign.js +18 -6
  238. package/lib/metadataTypes/ContentArea.js +21 -18
  239. package/lib/metadataTypes/DataExtension.js +229 -113
  240. package/lib/metadataTypes/DataExtensionField.js +52 -53
  241. package/lib/metadataTypes/DataExtensionTemplate.js +17 -5
  242. package/lib/metadataTypes/DataExtract.js +62 -27
  243. package/lib/metadataTypes/DataExtractType.js +17 -5
  244. package/lib/metadataTypes/DeliveryProfile.js +47 -0
  245. package/lib/metadataTypes/Discovery.js +15 -4
  246. package/lib/metadataTypes/Email.js +22 -19
  247. package/lib/metadataTypes/EmailSend.js +135 -35
  248. package/lib/metadataTypes/Event.js +95 -60
  249. package/lib/metadataTypes/FileLocation.js +17 -5
  250. package/lib/metadataTypes/FileTransfer.js +62 -26
  251. package/lib/metadataTypes/Filter.js +16 -4
  252. package/lib/metadataTypes/Folder.js +67 -39
  253. package/lib/metadataTypes/ImportFile.js +341 -91
  254. package/lib/metadataTypes/Journey.js +681 -324
  255. package/lib/metadataTypes/List.js +26 -14
  256. package/lib/metadataTypes/MetadataType.js +501 -265
  257. package/lib/metadataTypes/MobileCode.js +17 -5
  258. package/lib/metadataTypes/MobileKeyword.js +59 -43
  259. package/lib/metadataTypes/MobileMessage.js +67 -40
  260. package/lib/metadataTypes/Query.js +46 -38
  261. package/lib/metadataTypes/Role.js +34 -23
  262. package/lib/metadataTypes/Script.js +127 -39
  263. package/lib/metadataTypes/SendClassification.js +120 -5
  264. package/lib/metadataTypes/SenderProfile.js +179 -0
  265. package/lib/metadataTypes/TransactionalEmail.js +30 -17
  266. package/lib/metadataTypes/TransactionalMessage.js +25 -11
  267. package/lib/metadataTypes/TransactionalPush.js +24 -9
  268. package/lib/metadataTypes/TransactionalSMS.js +78 -46
  269. package/lib/metadataTypes/TriggeredSend.js +191 -43
  270. package/lib/metadataTypes/User.js +90 -62
  271. package/lib/metadataTypes/Verification.js +39 -21
  272. package/lib/metadataTypes/definitions/Asset.definition.js +3 -3
  273. package/lib/metadataTypes/definitions/AttributeGroup.definition.js +7 -1
  274. package/lib/metadataTypes/definitions/AttributeSet.definition.js +2 -2
  275. package/lib/metadataTypes/definitions/Automation.definition.js +4 -1
  276. package/lib/metadataTypes/definitions/Campaign.definition.js +1 -1
  277. package/lib/metadataTypes/definitions/ContentArea.definition.js +1 -1
  278. package/lib/metadataTypes/definitions/DataExtension.definition.js +17 -1
  279. package/lib/metadataTypes/definitions/DataExtensionTemplate.definition.js +1 -1
  280. package/lib/metadataTypes/definitions/DataExtractType.definition.js +2 -2
  281. package/lib/metadataTypes/definitions/DeliveryProfile.definition.js +59 -0
  282. package/lib/metadataTypes/definitions/Discovery.definition.js +1 -1
  283. package/lib/metadataTypes/definitions/Email.definition.js +1 -1
  284. package/lib/metadataTypes/definitions/EmailSend.definition.js +19 -4
  285. package/lib/metadataTypes/definitions/Event.definition.js +140 -128
  286. package/lib/metadataTypes/definitions/FileLocation.definition.js +1 -1
  287. package/lib/metadataTypes/definitions/Filter.definition.js +1 -1
  288. package/lib/metadataTypes/definitions/Folder.definition.js +25 -2
  289. package/lib/metadataTypes/definitions/ImportFile.definition.js +52 -7
  290. package/lib/metadataTypes/definitions/Journey.definition.js +12 -0
  291. package/lib/metadataTypes/definitions/List.definition.js +1 -1
  292. package/lib/metadataTypes/definitions/MobileCode.definition.js +1 -1
  293. package/lib/metadataTypes/definitions/MobileMessage.definition.js +11 -5
  294. package/lib/metadataTypes/definitions/Query.definition.js +6 -0
  295. package/lib/metadataTypes/definitions/Script.definition.js +14 -14
  296. package/lib/metadataTypes/definitions/SendClassification.definition.js +60 -20
  297. package/lib/metadataTypes/definitions/SenderProfile.definition.js +185 -0
  298. package/lib/metadataTypes/definitions/TransactionalEmail.definition.js +2 -2
  299. package/lib/metadataTypes/definitions/TransactionalMessage.definition.js +69 -0
  300. package/lib/metadataTypes/definitions/TransactionalPush.definition.js +6 -0
  301. package/lib/metadataTypes/definitions/TransactionalSMS.definition.js +6 -0
  302. package/lib/metadataTypes/definitions/TriggeredSend.definition.js +15 -4
  303. package/lib/metadataTypes/definitions/Verification.definition.js +1 -1
  304. package/lib/retrieveChangelog.js +7 -2
  305. package/lib/util/auth.js +56 -21
  306. package/lib/util/businessUnit.js +20 -2
  307. package/lib/util/cache.js +37 -18
  308. package/lib/util/cli.js +72 -29
  309. package/lib/util/config.js +27 -9
  310. package/lib/util/devops.js +45 -24
  311. package/lib/util/file.js +58 -33
  312. package/lib/util/init.config.js +55 -24
  313. package/lib/util/init.git.js +6 -6
  314. package/lib/util/init.js +36 -14
  315. package/lib/util/init.npm.js +2 -2
  316. package/lib/util/replaceContentBlockReference.js +278 -0
  317. package/lib/util/util.js +152 -54
  318. package/package.json +33 -30
  319. package/test/general.test.js +1327 -4
  320. package/test/mockRoot/.mcdevrc.json +26 -4
  321. package/test/mockRoot/deploy/testInstance/_ParentBU_/dataExtension/testExisting_dataExtensionShared.dataExtension-meta.json +3 -4
  322. package/test/mockRoot/deploy/testInstance/_ParentBU_/dataExtension/testNew_dataExtensionShared.dataExtension-meta.json +1 -4
  323. package/test/mockRoot/deploy/testInstance/_ParentBU_/query/testNew_query.query-meta.json +11 -0
  324. package/test/mockRoot/deploy/testInstance/_ParentBU_/query/testNew_query.query-meta.sql +4 -0
  325. package/test/mockRoot/deploy/testInstance/testBU/asset/block/testNew_asset.asset-block-meta.html +12 -0
  326. package/test/mockRoot/deploy/testInstance/testBU/asset/block/testNew_asset.asset-block-meta.json +39 -0
  327. package/test/mockRoot/deploy/testInstance/testBU/automation/testExisting_automation.automation-meta.json +6 -6
  328. package/test/mockRoot/deploy/testInstance/testBU/automation/testNew_automation.automation-meta.json +7 -7
  329. package/test/mockRoot/deploy/testInstance/testBU/dataExtension/testExisting_dataExtension.dataExtension-meta.json +3 -4
  330. package/test/mockRoot/deploy/testInstance/testBU/dataExtension/testNew_dataExtension.dataExtension-meta.json +1 -4
  331. package/test/mockRoot/deploy/testInstance/testBU/emailSend/testExisting_emailSend.emailSend-meta.json +36 -0
  332. package/test/mockRoot/deploy/testInstance/testBU/emailSend/testNew_emailSend.emailSend-meta.json +36 -0
  333. package/test/mockRoot/deploy/testInstance/testBU/importFile/testExisting_importFile.importFile-meta.json +10 -4
  334. package/test/mockRoot/deploy/testInstance/testBU/importFile/testNew_importFile.importFile-meta.json +8 -4
  335. package/test/mockRoot/deploy/testInstance/testBU/journey/testExisting_journey_Quicksend.journey-meta.json +232 -0
  336. package/test/mockRoot/deploy/testInstance/testBU/mobileMessage/NTIzOjc4OjA.mobileMessage-meta.json +2 -4
  337. package/test/mockRoot/deploy/testInstance/testBU/mobileMessage/new.mobileMessage-meta.json +2 -4
  338. package/test/mockRoot/deploy/testInstance/testBU/query/testExisting_query.query-meta.json +1 -1
  339. package/test/mockRoot/deploy/testInstance/testBU/query/testExisting_query_fixKeys.query-meta.json +1 -1
  340. package/test/mockRoot/deploy/testInstance/testBU/query/testNew_query.query-meta.json +1 -1
  341. package/test/mockRoot/deploy/testInstance/testBU/sendClassification/testExisting_sendClassification.sendClassification-meta.json +8 -0
  342. package/test/mockRoot/deploy/testInstance/testBU/sendClassification/testNew_sendClassification.sendClassification-meta.json +8 -0
  343. package/test/mockRoot/deploy/testInstance/testBU/senderProfile/testExisting_senderProfile.senderProfile-meta.json +14 -0
  344. package/test/mockRoot/deploy/testInstance/testBU/senderProfile/testNew_senderProfile.senderProfile-meta.json +14 -0
  345. package/test/mockRoot/deploy/testInstance/testBU/transactionalEmail/testExisting_temail.transactionalEmail-meta.json +1 -1
  346. package/test/mockRoot/deploy/testInstance/testBU/transactionalEmail/testNew_temail.transactionalEmail-meta.json +1 -1
  347. package/test/mockRoot/deploy/testInstance/testBU/transactionalPush/testExisting_tpush.transactionalPush-meta.json +1 -3
  348. package/test/mockRoot/deploy/testInstance/testBU/transactionalPush/testNew_tpush.transactionalPush-meta.json +1 -3
  349. package/test/mockRoot/deploy/testInstance/testBU/transactionalSMS/testExisting_tsms.transactionalSMS-meta.json +1 -2
  350. package/test/mockRoot/deploy/testInstance/testBU/transactionalSMS/testNew_tsms.transactionalSMS-meta.json +1 -2
  351. package/test/mockRoot/deploy/testInstance/testBU/triggeredSend/testExisting_triggeredSend.triggeredSend-meta.json +4 -5
  352. package/test/mockRoot/deploy/testInstance/testBU/triggeredSend/testNew_triggeredSend.triggeredSend-meta.json +4 -5
  353. package/test/mockRoot/deploy/testInstance/testBU/verification/testExisting_39f6a488-20eb-4ba0-b0b9.verification-meta.json +1 -1
  354. package/test/mockRoot/deploy/testInstance/testBU/verification/testNew_39f6a488-20eb-4ba0-b0b9.verification-meta.json +1 -1
  355. package/test/resourceFactory.js +118 -7
  356. package/test/resources/1111111/automation/v1/queries/get-response.json +6 -0
  357. package/test/resources/1111111/automation/v1/queries/post-response.json +18 -0
  358. package/test/resources/1111111/dataExtension/create-expected.json +4 -7
  359. package/test/resources/1111111/dataExtension/retrieve-expected.json +2 -4
  360. package/test/resources/1111111/dataExtension/update-expected.json +7 -7
  361. package/test/resources/1111111/dataExtension/update-response.xml +3 -1
  362. package/test/resources/1111111/dataFolder/retrieve-ContentType=queryactivity-response.xml +48 -0
  363. package/test/resources/1111111/query/patch_keySuffix-expected.json +11 -0
  364. package/test/resources/1111111/query/patch_keySuffix-expected.sql +4 -0
  365. package/test/resources/9999999/asset/block-1157-retrieve-expected.html +4 -3
  366. package/test/resources/9999999/asset/build-templatebasedemail-expected.json +81 -0
  367. package/test/resources/9999999/asset/build-templatebasedemail-html-expected.html +20 -0
  368. package/test/resources/9999999/asset/build-templatebasedemail-preheader-expected.amp +1 -0
  369. package/test/resources/9999999/asset/create-expected.json +18 -0
  370. package/test/resources/9999999/asset/resolveId-1234-notFound-expected.json +1 -0
  371. package/test/resources/9999999/asset/resolveId-1295064-noPath-expected.json +8 -0
  372. package/test/resources/9999999/asset/resolveId-1295064-withPath-expected.json +8 -0
  373. package/test/resources/9999999/asset/retrieve-templatebasedemail-expected.json +84 -0
  374. package/test/resources/9999999/asset/retrieve-templatebasedemail-html-expected.html +20 -0
  375. package/test/resources/9999999/asset/retrieve-templatebasedemail-preheader-expected.amp +1 -0
  376. package/test/resources/9999999/asset/template-templatebasedemail-expected.json +81 -0
  377. package/test/resources/9999999/asset/template-templatebasedemail-html-expected.html +20 -0
  378. package/test/resources/9999999/asset/template-templatebasedemail-preheader-expected.amp +1 -0
  379. package/test/resources/9999999/asset/testExisting_asset_message-html-rcb-id-expected.html +33 -0
  380. package/test/resources/9999999/asset/testExisting_asset_message-html-rcb-key-expected.html +33 -0
  381. package/test/resources/9999999/asset/testExisting_asset_message-html-rcb-name-expected.html +35 -0
  382. package/test/resources/9999999/asset/testExisting_asset_message-preheader-rcb-id-expected.amp +4 -0
  383. package/test/resources/9999999/asset/testExisting_asset_message-preheader-rcb-key-expected.amp +4 -0
  384. package/test/resources/9999999/asset/testExisting_asset_message-preheader-rcb-name-expected.amp +4 -0
  385. package/test/resources/9999999/asset/testExisting_asset_message-text-rcb-id-expected.amp +4 -0
  386. package/test/resources/9999999/asset/testExisting_asset_message-text-rcb-key-expected.amp +4 -0
  387. package/test/resources/9999999/asset/testExisting_asset_message-text-rcb-name-expected.amp +4 -0
  388. package/test/resources/9999999/asset/v1/content/assets/1295064/get-response.json +1 -1
  389. package/test/resources/9999999/asset/v1/content/assets/5286/get-response.json +48 -0
  390. package/test/resources/9999999/asset/v1/content/assets/5289/get-response.json +198 -0
  391. package/test/resources/9999999/asset/v1/content/assets/808714/get-response.json +4 -3
  392. package/test/resources/9999999/asset/v1/content/assets/950143/delete-response.txt +1 -0
  393. package/test/resources/9999999/asset/v1/content/assets/get-response-customerKey=testExisting_asset.json +105 -0
  394. package/test/resources/9999999/asset/v1/content/assets/post-response.json +59 -0
  395. package/test/resources/9999999/asset/v1/content/assets/query/post-response-assetType.idIN174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,14.json +7 -0
  396. package/test/resources/9999999/asset/v1/content/assets/query/post-response-assetType.idIN193,194,15.json +7 -0
  397. package/test/resources/9999999/asset/v1/content/assets/query/post-response-assetType.idIN195,196,197,198,199,200,201,202,203,210,211,212,213,3.json +46 -0
  398. package/test/resources/9999999/asset/v1/content/assets/query/post-response-assetType.idIN205,206,230,232,1.json +32 -0
  399. package/test/resources/9999999/asset/v1/content/assets/query/{post-response.json → post-response-assetType.idIN207,208,209,5.json} +45 -47
  400. package/test/resources/9999999/asset/v1/content/assets/query/post-response-assetType.idIN214,4.json +35 -0
  401. package/test/resources/9999999/asset/v1/content/assets/query/post-response-assetType.idIN215,216,217,218,219,220,221,222,223,224,225,226,227,228.json +7 -0
  402. package/test/resources/9999999/asset/v1/content/assets/query/post-response-customerKey=mcdev-issue-1157.json +46 -0
  403. package/test/resources/9999999/attributeGroup/retrieve-expected.json +1 -1
  404. package/test/resources/9999999/attributeSet/retrieve-expected.json +3 -3
  405. package/test/resources/9999999/automation/build-expected.json +7 -7
  406. package/test/resources/9999999/automation/create-expected.json +7 -7
  407. package/test/resources/9999999/automation/patch_fixKeys-pause-expected.json +6 -6
  408. package/test/resources/9999999/automation/patch_fixKeys-schedule-expected.json +6 -6
  409. package/test/resources/9999999/automation/retrieve-expected.json +7 -7
  410. package/test/resources/9999999/automation/template-expected.json +7 -7
  411. package/test/resources/9999999/automation/update-expected.json +6 -6
  412. package/test/resources/9999999/automation/v1/dataextracts/56c5370a-f988-4f36-b0ee-0f876573f6d7/delete-response.txt +1 -0
  413. package/test/resources/9999999/automation/v1/filetransfers/72c328ac-f5b0-4e37-91d3-a775666f15a6/delete-response.json +1 -0
  414. package/test/resources/9999999/automation/v1/imports/1ebf557b-372e-eb11-b81b-48df37d1dbd7/get-response.json +78 -0
  415. package/test/resources/9999999/automation/v1/imports/9d16f42c-2260-ed11-b849-48df37d1de8b/delete-response.txt +0 -0
  416. package/test/resources/9999999/automation/v1/imports/9d16f42c-2260-ed11-b849-48df37d1de8b/get-response.json +35 -0
  417. package/test/resources/9999999/automation/v1/imports/9d16f42c-2260-ed11-b849-48df37d1de8b/patch-response.json +14 -10
  418. package/test/resources/9999999/automation/v1/imports/get-response.json +78 -1
  419. package/test/resources/9999999/automation/v1/queries/549f0568-607c-4940-afef-437965094dat/get-response.json +1 -1
  420. package/test/resources/9999999/automation/v1/queries/549f0568-607c-4940-afef-437965094dat_fixKeysSuffix/get-response.json +17 -0
  421. package/test/resources/9999999/automation/v1/queries/549f0568-607c-4940-afef-437965094dat_fixKeysSuffix/patch-response.json +18 -0
  422. package/test/resources/9999999/automation/v1/queries/abcde-607c-4940-afef-437965094dat/get-response.json +17 -0
  423. package/test/resources/9999999/automation/v1/queries/get-response.json +20 -3
  424. package/test/resources/9999999/automation/v1/scripts/39f6a488-20eb-4ba0-b0b9-023725b574e4/delete-response.txt +1 -0
  425. package/test/resources/9999999/automation/v1/scripts/get-response.json +3 -3
  426. package/test/resources/9999999/dataExtension/build-expected.json +3 -4
  427. package/test/resources/9999999/dataExtension/create-expected.json +1 -4
  428. package/test/resources/9999999/dataExtension/retrieve-Name=testExisting_dataExtension-response.xml +4 -4
  429. package/test/resources/9999999/dataExtension/retrieve-expected.json +3 -4
  430. package/test/resources/9999999/dataExtension/retrieve-response.xml +96 -1
  431. package/test/resources/9999999/dataExtension/template-expected.json +3 -4
  432. package/test/resources/9999999/dataExtension/update-expected.json +4 -3
  433. package/test/resources/9999999/dataExtension/update-response.xml +5 -3
  434. package/test/resources/9999999/dataExtensionField/retrieve-response.xml +72 -0
  435. package/test/resources/9999999/dataFolder/retrieve-ContentType=userinitiatedsends-response.xml +48 -0
  436. package/test/resources/9999999/deliveryProfile/get-expected.json +7 -0
  437. package/test/resources/9999999/emailSend/build-expected.json +43 -0
  438. package/test/resources/9999999/emailSend/get-expected.json +43 -0
  439. package/test/resources/9999999/emailSend/patch-expected.json +41 -0
  440. package/test/resources/9999999/emailSend/post-expected.json +41 -0
  441. package/test/resources/9999999/emailSend/template-expected.json +43 -0
  442. package/test/resources/9999999/emailSendDefinition/create-response.xml +98 -0
  443. package/test/resources/9999999/emailSendDefinition/delete-response.xml +36 -0
  444. package/test/resources/9999999/emailSendDefinition/retrieve-IsPlatformObject=falseANDDescriptionnotEqualsSFSendDefinition-response.xml +18 -8
  445. package/test/resources/9999999/emailSendDefinition/update-response.xml +97 -0
  446. package/test/resources/9999999/importDefinition/retrieve-CustomerKey=testExisting_importFile-response.xml +30 -0
  447. package/test/resources/9999999/importDefinition/retrieve-Name=testExisting_importFile-response.xml +30 -0
  448. package/test/resources/9999999/importFile/build-expected.json +11 -6
  449. package/test/resources/9999999/importFile/get-expected.json +13 -7
  450. package/test/resources/9999999/importFile/get-sms-expected.json +79 -0
  451. package/test/resources/9999999/importFile/patch-expected.json +12 -7
  452. package/test/resources/9999999/importFile/post-expected.json +8 -5
  453. package/test/resources/9999999/importFile/template-expected.json +10 -5
  454. package/test/resources/9999999/interaction/v1/eventDefinitions/get-response.json +124 -0
  455. package/test/resources/9999999/interaction/v1/interactions/3c3f4112-9b43-43ca-8a89-aa0375b2c1a2/delete-response.txt +1 -0
  456. package/test/resources/9999999/interaction/v1/interactions/3c3f4112-9b43-43ca-8a89-aa0375b2c1a2/get-response.json +253 -0
  457. package/test/resources/9999999/interaction/v1/interactions/get-response.json +83 -779
  458. package/test/resources/9999999/interaction/v1/interactions/key_testExisting_journey_Multistep/get-response.json +457 -0
  459. package/test/resources/9999999/interaction/v1/interactions/key_testExisting_journey_Quicksend/get-response.json +253 -0
  460. package/test/resources/9999999/interaction/v1/interactions/{key_0b76dccf-594c-b6dc-1acf-10c4493dcb84 → key_testExisting_temail}/get-response.json +5 -5
  461. package/test/resources/9999999/journey/build-expected.json +105 -449
  462. package/test/resources/9999999/journey/get-multistep-expected.json +413 -0
  463. package/test/resources/9999999/journey/get-quicksend-expected.json +232 -0
  464. package/test/resources/9999999/journey/get-quicksend-rcb-id-expected.json +232 -0
  465. package/test/resources/9999999/journey/get-quicksend-rcb-key-expected.json +232 -0
  466. package/test/resources/9999999/journey/get-quicksend-rcb-name-expected.json +232 -0
  467. package/test/resources/9999999/journey/get-transactionalEmail-expected.json +211 -0
  468. package/test/resources/9999999/journey/template-expected.json +105 -449
  469. package/test/resources/9999999/legacy/v1/beta/messaging/deliverypolicy/get-response.json +15 -0
  470. package/test/resources/9999999/legacy/v1/beta/mobile/imports/get-response.json +112 -0
  471. package/test/resources/9999999/legacy/v1/beta/mobile/message/NTQ3Ojc4OjA/get-response.json +1 -1
  472. package/test/resources/9999999/legacy/v1/beta/object/NWQwdnhEU3dFZWVBekJRQzdISWl0QTo0NTow/get-response.json +12 -0
  473. package/test/resources/9999999/list/retrieve-response.xml +13 -0
  474. package/test/resources/9999999/messaging/v1/email/definitions/testExisting_temail/get-response.json +1 -1
  475. package/test/resources/9999999/messaging/v1/email/definitions/testExisting_temail/patch-response.json +1 -1
  476. package/test/resources/9999999/mobileMessage/build-expected.json +2 -5
  477. package/test/resources/9999999/mobileMessage/get-expected.json +2 -5
  478. package/test/resources/9999999/mobileMessage/post-create-expected.json +2 -4
  479. package/test/resources/9999999/mobileMessage/post-update-expected.json +2 -5
  480. package/test/resources/9999999/mobileMessage/template-expected.json +2 -5
  481. package/test/resources/9999999/query/build-expected.json +1 -1
  482. package/test/resources/9999999/query/build-expected.sql +2 -1
  483. package/test/resources/9999999/query/get-expected.json +1 -1
  484. package/test/resources/9999999/query/get-expected.sql +2 -1
  485. package/test/resources/9999999/query/get2-expected.json +1 -1
  486. package/test/resources/9999999/query/patch-expected.json +1 -1
  487. package/test/resources/9999999/query/patch_fixKeys-expected.json +1 -1
  488. package/test/resources/9999999/query/patch_fixKeysSuffix-expected.json +11 -0
  489. package/test/resources/9999999/query/patch_fixKeysSuffix-expected.sql +6 -0
  490. package/test/resources/9999999/query/post-expected.json +1 -1
  491. package/test/resources/9999999/query/template-expected.json +1 -1
  492. package/test/resources/9999999/query/template-expected.sql +2 -1
  493. package/test/resources/9999999/queryDefinition/retrieve-CustomerKey=testExisting_query2ANDStatus=Active-response.xml +30 -0
  494. package/test/resources/9999999/queryDefinition/retrieve-CustomerKey=testExisting_query_fixKeysSuffixANDStatus=Active-response.xml +30 -0
  495. package/test/resources/9999999/script/get_ampincluded-expected.html +5 -0
  496. package/test/resources/9999999/script/get_ampincluded-rcb-id-expected.html +5 -0
  497. package/test/resources/9999999/script/get_ampincluded-rcb-key-expected.html +5 -0
  498. package/test/resources/9999999/script/get_ampincluded-rcb-name-expected.html +5 -0
  499. package/test/resources/9999999/script/get_ampscript-expected.html +6 -1
  500. package/test/resources/9999999/script/get_ampscript-rcb-id-expected.html +8 -0
  501. package/test/resources/9999999/script/get_ampscript-rcb-key-expected.html +8 -0
  502. package/test/resources/9999999/script/get_ampscript-rcb-name-expected.html +10 -0
  503. package/test/resources/9999999/script/get_mixed-expected.html +5 -2
  504. package/test/resources/9999999/script/get_mixed-rcb-id-expected.html +12 -0
  505. package/test/resources/9999999/script/get_mixed-rcb-key-expected.html +12 -0
  506. package/test/resources/9999999/script/get_mixed-rcb-name-expected.html +14 -0
  507. package/test/resources/9999999/sendClassification/build-expected.json +8 -0
  508. package/test/resources/9999999/sendClassification/create-response.xml +51 -0
  509. package/test/resources/9999999/sendClassification/delete-response.xml +36 -0
  510. package/test/resources/9999999/sendClassification/get-expected.json +10 -0
  511. package/test/resources/9999999/sendClassification/patch-expected.json +8 -0
  512. package/test/resources/9999999/sendClassification/post-expected.json +8 -0
  513. package/test/resources/9999999/sendClassification/retrieve-response.xml +86 -0
  514. package/test/resources/9999999/sendClassification/template-expected.json +8 -0
  515. package/test/resources/9999999/sendClassification/update-response.xml +49 -0
  516. package/test/resources/9999999/senderProfile/build-expected.json +14 -0
  517. package/test/resources/9999999/senderProfile/create-response.xml +49 -0
  518. package/test/resources/9999999/senderProfile/delete-response.xml +36 -0
  519. package/test/resources/9999999/senderProfile/get-expected.json +16 -0
  520. package/test/resources/9999999/senderProfile/get-rcb-id-expected.json +16 -0
  521. package/test/resources/9999999/senderProfile/get-rcb-key-expected.json +16 -0
  522. package/test/resources/9999999/senderProfile/get-rcb-name-expected.json +16 -0
  523. package/test/resources/9999999/senderProfile/patch-expected.json +14 -0
  524. package/test/resources/9999999/senderProfile/post-expected.json +14 -0
  525. package/test/resources/9999999/senderProfile/retrieve-CustomerKey=Default-response.xml +44 -0
  526. package/test/resources/9999999/senderProfile/retrieve-CustomerKey=wrong-key-response.xml +26 -0
  527. package/test/resources/9999999/senderProfile/retrieve-response.xml +80 -0
  528. package/test/resources/9999999/senderProfile/template-expected.json +14 -0
  529. package/test/resources/9999999/senderProfile/update-response.xml +47 -0
  530. package/test/resources/9999999/transactionalEmail/build-expected.json +3 -3
  531. package/test/resources/9999999/transactionalEmail/get-expected.json +3 -3
  532. package/test/resources/9999999/transactionalEmail/patch-expected.json +3 -3
  533. package/test/resources/9999999/transactionalEmail/post-expected.json +2 -2
  534. package/test/resources/9999999/transactionalEmail/template-expected.json +3 -3
  535. package/test/resources/9999999/transactionalPush/build-expected.json +1 -1
  536. package/test/resources/9999999/transactionalPush/get-expected.json +1 -1
  537. package/test/resources/9999999/transactionalPush/patch-expected.json +1 -3
  538. package/test/resources/9999999/transactionalPush/post-expected.json +1 -3
  539. package/test/resources/9999999/transactionalPush/template-expected.json +1 -1
  540. package/test/resources/9999999/transactionalSMS/build-expected.amp +1 -1
  541. package/test/resources/9999999/transactionalSMS/build-expected.json +1 -2
  542. package/test/resources/9999999/transactionalSMS/get-expected.amp +1 -1
  543. package/test/resources/9999999/transactionalSMS/get-expected.json +1 -2
  544. package/test/resources/9999999/transactionalSMS/patch-expected.amp +1 -1
  545. package/test/resources/9999999/transactionalSMS/patch-expected.json +1 -2
  546. package/test/resources/9999999/transactionalSMS/post-expected.amp +1 -1
  547. package/test/resources/9999999/transactionalSMS/post-expected.json +1 -2
  548. package/test/resources/9999999/transactionalSMS/template-expected.amp +1 -1
  549. package/test/resources/9999999/transactionalSMS/template-expected.json +1 -2
  550. package/test/resources/9999999/triggeredSend/build-expected.json +5 -6
  551. package/test/resources/9999999/triggeredSend/get-expected.json +5 -6
  552. package/test/resources/9999999/triggeredSend/get-rcb-id-expected.json +29 -0
  553. package/test/resources/9999999/triggeredSend/get-rcb-key-expected.json +29 -0
  554. package/test/resources/9999999/triggeredSend/get-rcb-name-expected.json +29 -0
  555. package/test/resources/9999999/triggeredSend/patch-expected.json +5 -6
  556. package/test/resources/9999999/triggeredSend/post-expected.json +5 -6
  557. package/test/resources/9999999/triggeredSend/template-expected.json +5 -6
  558. package/test/resources/9999999/triggeredSendDefinition/create-response.xml +6 -1
  559. package/test/resources/9999999/triggeredSendDefinition/retrieve-TriggeredSendStatusINNew,Active,Inactive,Moved,Canceled-response.xml +53 -1
  560. package/test/resources/9999999/triggeredSendDefinition/update-response.xml +6 -1
  561. package/test/resources/9999999/verification/build-expected.json +1 -1
  562. package/test/resources/9999999/verification/get-expected.json +1 -1
  563. package/test/resources/9999999/verification/patch-expected.json +1 -1
  564. package/test/resources/9999999/verification/post-expected.json +1 -1
  565. package/test/resources/9999999/verification/template-expected.json +1 -1
  566. package/test/type.asset.test.js +733 -17
  567. package/test/type.attributeGroup.test.js +6 -2
  568. package/test/type.attributeSet.test.js +6 -2
  569. package/test/type.automation.test.js +174 -162
  570. package/test/type.dataExtension.test.js +41 -45
  571. package/test/type.dataExtract.test.js +22 -29
  572. package/test/type.deliveryProfile.test.js +45 -0
  573. package/test/type.emailSend.test.js +144 -0
  574. package/test/type.event.test.js +62 -0
  575. package/test/type.fileTransfer.test.js +21 -29
  576. package/test/type.importFile.test.js +61 -35
  577. package/test/type.journey.test.js +251 -45
  578. package/test/type.mobileKeyword.test.js +46 -54
  579. package/test/type.mobileMessage.test.js +28 -27
  580. package/test/type.query.test.js +303 -124
  581. package/test/type.script.test.js +288 -69
  582. package/test/type.sendClassification.test.js +156 -0
  583. package/test/type.senderProfile.test.js +254 -0
  584. package/test/type.transactionalEmail.test.js +15 -11
  585. package/test/type.transactionalPush.test.js +15 -11
  586. package/test/type.transactionalSMS.test.js +30 -23
  587. package/test/type.triggeredSend.test.js +130 -17
  588. package/test/type.user.test.js +22 -14
  589. package/test/type.verification.test.js +13 -10
  590. package/test/utils.js +76 -21
  591. package/tsconfig.json +21 -0
  592. package/types/mcdev.d.js +190 -66
  593. package/docs/dist/documentation.md +0 -8878
  594. package/test/mockRoot/deploy/testInstance/testBU/journey/testExisting_interaction.interaction-meta.json +0 -576
  595. package/test/mockRoot/deploy/testInstance/testBU/journey/testNew_interaction.interaction-meta.json +0 -266
  596. package/test/resources/9999999/interaction/v1/EventDefinitions/get-response.json +0 -43
  597. package/test/resources/9999999/interaction/v1/interactions/233d4413-922c-4568-85a5-e5cc77efc3be/delete-response.json +0 -1
  598. package/test/resources/9999999/interaction/v1/interactions/key_testExisting_interaction/get-response.json +0 -592
  599. package/test/resources/9999999/interaction/v1/interactions/key_testExisting_interaction/put-response.json +0 -592
  600. package/test/resources/9999999/interaction/v1/interactions/post-response.json +0 -280
  601. package/test/resources/9999999/journey/get-expected.json +0 -576
  602. package/test/resources/9999999/script/get_ampincluded-expected.ssjs +0 -5
@@ -7,14 +7,31 @@
7
7
  * in the generic version of the method
8
8
  */
9
9
 
10
- import TYPE from '../../types/mcdev.d.js';
11
-
12
10
  import { Util } from '../util/util.js';
13
11
  import File from '../util/file.js';
14
12
  import cache from '../util/cache.js';
15
13
  import deepEqual from 'deep-equal';
16
14
  import pLimit from 'p-limit';
17
15
  import Mustache from 'mustache';
16
+
17
+ /**
18
+ * @typedef {import('../../types/mcdev.d.js').BuObject} BuObject
19
+ * @typedef {import('../../types/mcdev.d.js').CodeExtract} CodeExtract
20
+ * @typedef {import('../../types/mcdev.d.js').CodeExtractItem} CodeExtractItem
21
+ * @typedef {import('../../types/mcdev.d.js').Mcdevrc} Mcdevrc
22
+ * @typedef {import('../../types/mcdev.d.js').MetadataTypeItem} MetadataTypeItem
23
+ * @typedef {import('../../types/mcdev.d.js').MetadataTypeItemDiff} MetadataTypeItemDiff
24
+ * @typedef {import('../../types/mcdev.d.js').MetadataTypeItemObj} MetadataTypeItemObj
25
+ * @typedef {import('../../types/mcdev.d.js').MetadataTypeMap} MetadataTypeMap
26
+ * @typedef {import('../../types/mcdev.d.js').MetadataTypeMapObj} MetadataTypeMapObj
27
+ * @typedef {import('../../types/mcdev.d.js').SoapRequestParams} SoapRequestParams
28
+ * @typedef {import('../../types/mcdev.d.js').TemplateMap} TemplateMap
29
+ * @typedef {import('../../types/mcdev.d.js').SDK} SDK
30
+ * @typedef {import('../../types/mcdev.d.js').SDKError} SDKError
31
+ * @typedef {import('../../types/mcdev.d.js').SOAPError} SOAPError
32
+ * @typedef {import('../../types/mcdev.d.js').RestError} RestError
33
+ */
34
+
18
35
  /**
19
36
  * ensure that Mustache does not escape any characters
20
37
  *
@@ -36,16 +53,17 @@ class MetadataType {
36
53
  *
37
54
  * @param {string} dir directory that contains '.json' files to be read
38
55
  * @param {boolean} [listBadKeys] do not print errors, used for badKeys()
39
- * @returns {TYPE.MetadataTypeMap} fileName => fileContent map
56
+ * @param {string[]} [selectedSubType] asset, message, ...
57
+ * @returns {Promise.<MetadataTypeMap>} fileName => fileContent map
40
58
  */
41
- static getJsonFromFS(dir, listBadKeys) {
59
+ static async getJsonFromFS(dir, listBadKeys, selectedSubType) {
42
60
  const fileName2FileContent = {};
43
61
  try {
44
- const files = File.readdirSync(dir);
62
+ const files = await File.readdir(dir);
45
63
  for (const fileName of files) {
46
64
  try {
47
65
  if (fileName.endsWith('.json')) {
48
- const fileContent = File.readJSONFile(dir, fileName, true, false);
66
+ const fileContent = await File.readJSONFile(dir, fileName, false);
49
67
  const fileNameWithoutEnding = File.reverseFilterIllegalFilenames(
50
68
  fileName.split(/\.(\w|-)+-meta.json/)[0]
51
69
  );
@@ -105,10 +123,10 @@ class MetadataType {
105
123
  /**
106
124
  * Deploys metadata
107
125
  *
108
- * @param {TYPE.MetadataTypeMap} metadata metadata mapped by their keyField
126
+ * @param {MetadataTypeMap} metadata metadata mapped by their keyField
109
127
  * @param {string} deployDir directory where deploy metadata are saved
110
128
  * @param {string} retrieveDir directory where metadata after deploy should be saved
111
- * @returns {Promise.<TYPE.MetadataTypeMap>} Promise of keyField => metadata map
129
+ * @returns {Promise.<MetadataTypeMap>} Promise of keyField => metadata map
112
130
  */
113
131
  static async deploy(metadata, deployDir, retrieveDir) {
114
132
  const upsertResults = await this.upsert(metadata, deployDir);
@@ -127,8 +145,8 @@ class MetadataType {
127
145
  /**
128
146
  * Gets executed after deployment of metadata type
129
147
  *
130
- * @param {TYPE.MetadataTypeMap} upsertResults metadata mapped by their keyField as returned by update/create
131
- * @param {TYPE.MetadataTypeMap} originalMetadata metadata to be updated (contains additioanl fields)
148
+ * @param {MetadataTypeMap} upsertResults metadata mapped by their keyField as returned by update/create
149
+ * @param {MetadataTypeMap} originalMetadata metadata to be updated (contains additioanl fields)
132
150
  * @param {{created: number, updated: number}} createdUpdated counter representing successful creates/updates
133
151
  * @returns {void}
134
152
  */
@@ -137,9 +155,9 @@ class MetadataType {
137
155
  /**
138
156
  * helper for {@link MetadataType.createREST}
139
157
  *
140
- * @param {TYPE.MetadataTypeItem} metadataEntry a single metadata Entry
158
+ * @param {MetadataTypeItem} metadataEntry a single metadata Entry
141
159
  * @param {object} apiResponse varies depending on the API call
142
- * @param {TYPE.MetadataTypeItem} metadataEntryWithAllFields like metadataEntry but before non-creatable fields were stripped
160
+ * @param {MetadataTypeItem} metadataEntryWithAllFields like metadataEntry but before non-creatable fields were stripped
143
161
  * @returns {void}
144
162
  */
145
163
  static postCreateTasks(metadataEntry, apiResponse, metadataEntryWithAllFields) {}
@@ -147,7 +165,7 @@ class MetadataType {
147
165
  /**
148
166
  * helper for {@link MetadataType.updateREST}
149
167
  *
150
- * @param {TYPE.MetadataTypeItem} metadataEntry a single metadata Entry
168
+ * @param {MetadataTypeItem} metadataEntry a single metadata Entry
151
169
  * @param {object} apiResponse varies depending on the API call
152
170
  * @returns {void}
153
171
  */
@@ -156,7 +174,7 @@ class MetadataType {
156
174
  /**
157
175
  * helper for {@link MetadataType.createREST} when legacy API endpoints as these do not return the created item but only their new id
158
176
  *
159
- * @param {TYPE.MetadataTypeItem} metadataEntry a single metadata Entry
177
+ * @param {MetadataTypeItem} metadataEntry a single metadata Entry
160
178
  * @param {object} apiResponse varies depending on the API call
161
179
  * @returns {Promise.<void>} -
162
180
  */
@@ -185,18 +203,18 @@ class MetadataType {
185
203
  /**
186
204
  * Gets executed after retreive of metadata type
187
205
  *
188
- * @param {TYPE.MetadataTypeItem} metadata a single item
206
+ * @param {MetadataTypeItem} metadata a single item
189
207
  * @param {string} targetDir folder where retrieves should be saved
190
208
  * @param {boolean} [isTemplating] signals that we are retrieving templates
191
- * @returns {TYPE.MetadataTypeItem} cloned metadata
209
+ * @returns {MetadataTypeItem} cloned metadata
192
210
  */
193
211
  static postRetrieveTasks(metadata, targetDir, isTemplating) {
194
- return JSON.parse(JSON.stringify(metadata));
212
+ return structuredClone(metadata);
195
213
  }
196
214
  /**
197
215
  * generic script that retrieves the folder path from cache and updates the given metadata with it after retrieve
198
216
  *
199
- * @param {TYPE.MetadataTypeItem} metadata a single item
217
+ * @param {MetadataTypeItem} metadata a single item
200
218
  */
201
219
  static setFolderPath(metadata) {
202
220
  if (!this.definition.folderIdField) {
@@ -221,7 +239,7 @@ class MetadataType {
221
239
  /**
222
240
  * generic script that retrieves the folder ID from cache and updates the given metadata with it before deploy
223
241
  *
224
- * @param {TYPE.MetadataTypeItem} metadata a single item
242
+ * @param {MetadataTypeItem} metadata a single item
225
243
  */
226
244
  static setFolderId(metadata) {
227
245
  if (!this.definition.folderIdField) {
@@ -243,19 +261,19 @@ class MetadataType {
243
261
  * @param {string[]} [additionalFields] Returns specified fields even if their retrieve definition is not set to true
244
262
  * @param {string[]} [subTypeArr] optionally limit to a single subtype
245
263
  * @param {string} [key] customer key of single item to retrieve
246
- * @returns {Promise.<TYPE.MetadataTypeMapObj>} metadata
264
+ * @returns {Promise.<MetadataTypeMapObj>} metadata
247
265
  */
248
- static retrieve(retrieveDir, additionalFields, subTypeArr, key) {
266
+ static async retrieve(retrieveDir, additionalFields, subTypeArr, key) {
249
267
  Util.metadataLogger('error', this.definition.type, 'retrieve', `Not Supported`);
250
268
  const metadata = {};
251
- return { metadata: null, type: this.definition.type };
269
+ return { metadata: {}, type: this.definition.type };
252
270
  }
253
271
  /**
254
272
  * Gets metadata from Marketing Cloud
255
273
  *
256
274
  * @param {string[]} [additionalFields] Returns specified fields even if their retrieve definition is not set to true
257
275
  * @param {string[]} [subTypeArr] optionally limit to a single subtype
258
- * @returns {Promise.<TYPE.MetadataTypeMapObj>} metadata
276
+ * @returns {Promise.<MetadataTypeMapObj>} metadata
259
277
  */
260
278
  static retrieveChangelog(additionalFields, subTypeArr) {
261
279
  return this.retrieveForCache(additionalFields, subTypeArr);
@@ -266,21 +284,22 @@ class MetadataType {
266
284
  *
267
285
  * @param {string[]} [additionalFields] Returns specified fields even if their retrieve definition is not set to true
268
286
  * @param {string[]} [subTypeArr] optionally limit to a single subtype
269
- * @returns {Promise.<TYPE.MetadataTypeMapObj>} metadata
287
+ * @param {string} [key] customer key of single item to retrieve
288
+ * @returns {Promise.<MetadataTypeMapObj>} metadata
270
289
  */
271
- static async retrieveForCache(additionalFields, subTypeArr) {
272
- return this.retrieve(null, additionalFields, subTypeArr);
290
+ static async retrieveForCache(additionalFields, subTypeArr, key) {
291
+ return this.retrieve(null, additionalFields, subTypeArr, key);
273
292
  }
274
293
  /**
275
294
  * Gets metadata cache with limited fields and does not store value to disk
276
295
  *
277
296
  * @param {string} templateDir Directory where retrieved metadata directory will be saved
278
297
  * @param {string} name name of the metadata file
279
- * @param {TYPE.TemplateMap} templateVariables variables to be replaced in the metadata
298
+ * @param {TemplateMap} templateVariables variables to be replaced in the metadata
280
299
  * @param {string} [subType] optionally limit to a single subtype
281
- * @returns {Promise.<TYPE.MetadataTypeItemObj>} metadata
300
+ * @returns {Promise.<MetadataTypeItemObj>} metadata
282
301
  */
283
- static retrieveAsTemplate(templateDir, name, templateVariables, subType) {
302
+ static async retrieveAsTemplate(templateDir, name, templateVariables, subType) {
284
303
  Util.logger.error('retrieveAsTemplate is not supported yet for ' + this.definition.type);
285
304
  Util.metadataLogger(
286
305
  'debug',
@@ -295,9 +314,9 @@ class MetadataType {
295
314
  *
296
315
  * @param {string} templateDir Directory where retrieved metadata directory will be saved
297
316
  * @param {string} uri rest endpoint for GET
298
- * @param {TYPE.TemplateMap} templateVariables variables to be replaced in the metadata
317
+ * @param {TemplateMap} templateVariables variables to be replaced in the metadata
299
318
  * @param {string} name name (not key) of the metadata item
300
- * @returns {Promise.<{metadata: TYPE.MetadataTypeItem, type: string}>} Promise
319
+ * @returns {Promise.<{metadata: MetadataTypeItem, type: string}>} Promise
301
320
  */
302
321
  static async retrieveTemplateREST(templateDir, uri, templateVariables, name) {
303
322
  return this.retrieveREST(templateDir, uri, templateVariables, name);
@@ -309,8 +328,8 @@ class MetadataType {
309
328
  * @param {string} retrieveDir Directory where retrieved metadata directory will be saved
310
329
  * @param {string} templateDir (List of) Directory where built definitions will be saved
311
330
  * @param {string} key name of the metadata file
312
- * @param {TYPE.TemplateMap} templateVariables variables to be replaced in the metadata
313
- * @returns {Promise.<TYPE.MetadataTypeItemObj>} single metadata
331
+ * @param {TemplateMap} templateVariables variables to be replaced in the metadata
332
+ * @returns {Promise.<MetadataTypeItemObj>} single metadata
314
333
  */
315
334
  static async buildTemplate(retrieveDir, templateDir, key, templateVariables) {
316
335
  // retrieve metadata template
@@ -330,6 +349,9 @@ class MetadataType {
330
349
  fileName,
331
350
  'json'
332
351
  );
352
+ if (!metadataStr) {
353
+ throw new Error('File not found');
354
+ }
333
355
  } catch (ex) {
334
356
  try {
335
357
  metadataStr = await this.readSecondaryFolder(
@@ -340,16 +362,17 @@ class MetadataType {
340
362
  ex
341
363
  );
342
364
  } catch {
343
- throw new Error(
344
- `${this.definition.type}:: Could not find ./${File.normalizePath([
345
- retrieveDir,
346
- ...typeDirArr,
347
- fileName + '.json',
348
- ])}.`
365
+ // only happening for types that use readSecondaryFolder (e.g. asset)
366
+ // if we still have no metadataStr then we have to skip this metadata for all types and hence handle it outside of this catch
367
+ }
368
+ if (!metadataStr) {
369
+ Util.logger.warn(
370
+ Util.getGrayMsg(`- skipped ${this.definition.type} ${key}: not found`)
349
371
  );
372
+ return;
350
373
  }
351
- // return;
352
374
  }
375
+
353
376
  if (this.definition.stringifyFieldsBeforeTemplate) {
354
377
  // numeric fields are returned as numbers by the SDK/API. If we try to replace them in buildTemplate it would break the JSON format - but not if we stringify them first because then the {{{var}}} is in quotes
355
378
  metadataStr = JSON.parse(metadataStr);
@@ -370,6 +393,12 @@ class MetadataType {
370
393
  }
371
394
  metadataStr = JSON.stringify(metadataStr);
372
395
  }
396
+ if (this.definition.type === 'asset') {
397
+ // turn memberId integer to string to ensure it does not get replaced with a templateVariable
398
+ const temp = JSON.parse(metadataStr);
399
+ temp.memberId = temp.memberId.toString();
400
+ metadataStr = JSON.stringify(temp);
401
+ }
373
402
  const metadata = JSON.parse(Util.replaceByObject(metadataStr, templateVariables));
374
403
  this.keepTemplateFields(metadata);
375
404
 
@@ -401,9 +430,9 @@ class MetadataType {
401
430
  /**
402
431
  * Gets executed before deploying metadata
403
432
  *
404
- * @param {TYPE.MetadataTypeItem} metadata a single metadata item
433
+ * @param {MetadataTypeItem} metadata a single metadata item
405
434
  * @param {string} deployDir folder where files for deployment are stored
406
- * @returns {Promise.<TYPE.MetadataTypeItem>} Promise of a single metadata item
435
+ * @returns {Promise.<MetadataTypeItem>} Promise of a single metadata item
407
436
  */
408
437
  static async preDeployTasks(metadata, deployDir) {
409
438
  return metadata;
@@ -412,11 +441,11 @@ class MetadataType {
412
441
  /**
413
442
  * Abstract create method that needs to be implemented in child metadata type
414
443
  *
415
- * @param {TYPE.MetadataTypeItem} metadata single metadata entry
444
+ * @param {MetadataTypeItem} metadata single metadata entry
416
445
  * @param {string} deployDir directory where deploy metadata are saved
417
- * @returns {void}
446
+ * @returns {Promise.<object> | null} Promise of API response or null in case of an error
418
447
  */
419
- static create(metadata, deployDir) {
448
+ static async create(metadata, deployDir) {
420
449
  Util.logger.error(
421
450
  ` ☇ skipping ${this.definition.type} ${metadata[this.definition.keyField]} / ${
422
451
  metadata[this.definition.nameField]
@@ -428,11 +457,11 @@ class MetadataType {
428
457
  /**
429
458
  * Abstract update method that needs to be implemented in child metadata type
430
459
  *
431
- * @param {TYPE.MetadataTypeItem} metadata single metadata entry
432
- * @param {TYPE.MetadataTypeItem} [metadataBefore] metadata mapped by their keyField
433
- * @returns {void}
460
+ * @param {MetadataTypeItem} metadata single metadata entry
461
+ * @param {MetadataTypeItem} [metadataBefore] metadata mapped by their keyField
462
+ * @returns {Promise.<object> | null} Promise of API response or null in case of an error
434
463
  */
435
- static update(metadata, metadataBefore) {
464
+ static async update(metadata, metadataBefore) {
436
465
  Util.logger.error(
437
466
  ` ☇ skipping ${this.definition.type} ${metadata[this.definition.keyField]} / ${
438
467
  metadata[this.definition.nameField]
@@ -452,12 +481,86 @@ class MetadataType {
452
481
  return;
453
482
  }
454
483
 
484
+ /**
485
+ * this iterates over all items found in the retrieve folder and executes the type-specific method for replacing references
486
+ *
487
+ * @param {MetadataTypeMap} metadataMap list of metadata (keyField => metadata)
488
+ * @param {string} retrieveDir retrieve dir including cred and bu
489
+ * @returns {Promise.<string[]>} Returns list of keys for which references were replaced
490
+ */
491
+ static async replaceCbReferenceLoop(metadataMap, retrieveDir) {
492
+ const keysForDeploy = [];
493
+ if (!metadataMap) {
494
+ // if a type was skipped e.g. because it shall only be looked at on the parent then we would expect metadataMap to be undefined
495
+ return keysForDeploy;
496
+ }
497
+
498
+ const fromDescription = Util.OPTIONS.referenceFrom
499
+ .map((from) => 'ContentBlockBy' + Util.capitalizeFirstLetter(from))
500
+ .join(' and ');
501
+
502
+ if (Object.keys(metadataMap).length) {
503
+ Util.logger.info(`Searching ${this.definition.type} for ${fromDescription}:`);
504
+ const baseDir = [retrieveDir, ...this.definition.type.split('-')];
505
+ const deployMap = {};
506
+
507
+ for (const key in metadataMap) {
508
+ const item = metadataMap[key];
509
+ if (this.isFiltered(item, true) || this.isFiltered(item, false)) {
510
+ // we would not have saved these items to disk but they exist in the cache and hence need to be skipped here
511
+
512
+ continue;
513
+ }
514
+
515
+ try {
516
+ // add key but make sure to turn it into string or else numeric keys will be filtered later
517
+ deployMap[key] = await this.replaceCbReference(item, retrieveDir);
518
+ await this.saveToDisk(deployMap, key, baseDir);
519
+
520
+ keysForDeploy.push(key + '');
521
+ Util.logger.info(` - added ${this.definition.type} to update queue: ${key}`);
522
+ } catch (ex) {
523
+ if (ex.code !== 200) {
524
+ // dont print error if we simply did not find relevant content blocks
525
+ Util.logger.errorStack(ex, ex.message);
526
+ }
527
+ Util.logger.info(
528
+ Util.getGrayMsg(
529
+ ` ☇ skipping ${this.definition.type} ${
530
+ item[this.definition.keyField]
531
+ }: no ${fromDescription} found`
532
+ )
533
+ );
534
+ }
535
+ }
536
+
537
+ Util.logger.info(
538
+ `Found ${keysForDeploy.length} ${this.definition.type}${keysForDeploy.length === 1 ? '' : 's'} to update`
539
+ );
540
+ }
541
+ return keysForDeploy;
542
+ }
455
543
  /**
456
544
  * Abstract execute method that needs to be implemented in child metadata type
457
545
  *
458
- * @returns {void}
546
+ * @param {MetadataTypeItem} item single metadata item
547
+ * @param {string} [retrieveDir] directory where metadata is saved
548
+ * @returns {Promise.<MetadataTypeItem | CodeExtractItem>} key of the item that was updated
549
+ */
550
+ static async replaceCbReference(item, retrieveDir) {
551
+ Util.logger.error(
552
+ ` ☇ skipping ${this.definition.type}: replaceCbReference is not supported yet for ${this.definition.type}`
553
+ );
554
+ return [];
555
+ }
556
+
557
+ /**
558
+ * Abstract execute method that needs to be implemented in child metadata type
559
+ *
560
+ * @param {string[]} keyArr customerkey of the metadata
561
+ * @returns {Promise.<string[]>} Returns list of keys that were executed
459
562
  */
460
- static execute() {
563
+ static async execute(keyArr) {
461
564
  Util.logger.error(
462
565
  ` ☇ skipping ${this.definition.type}: execute is not supported yet for ${this.definition.type}`
463
566
  );
@@ -466,9 +569,10 @@ class MetadataType {
466
569
  /**
467
570
  * Abstract pause method that needs to be implemented in child metadata type
468
571
  *
469
- * @returns {void}
572
+ * @param {string[]} keyArr customerkey of the metadata
573
+ * @returns {Promise.<string[]>} Returns list of keys that were paused
470
574
  */
471
- static pause() {
575
+ static async pause(keyArr) {
472
576
  Util.logger.error(
473
577
  ` ☇ skipping ${this.definition.type}: pause is not supported yet for ${this.definition.type}`
474
578
  );
@@ -478,8 +582,8 @@ class MetadataType {
478
582
  /**
479
583
  * test if metadata was actually changed or not to potentially skip it during deployment
480
584
  *
481
- * @param {TYPE.MetadataTypeItem} cachedVersion cached version from the server
482
- * @param {TYPE.MetadataTypeItem} metadata item to upload
585
+ * @param {MetadataTypeItem} cachedVersion cached version from the server
586
+ * @param {MetadataTypeItem} metadata item to upload
483
587
  * @param {string} [fieldName] optional field name to use for identifying the record in logs
484
588
  * @returns {boolean} true if metadata was changed
485
589
  */
@@ -490,8 +594,8 @@ class MetadataType {
490
594
  /**
491
595
  * test if metadata was actually changed or not to potentially skip it during deployment
492
596
  *
493
- * @param {TYPE.MetadataTypeItem} cachedVersion cached version from the server
494
- * @param {TYPE.MetadataTypeItem} metadata item to upload
597
+ * @param {MetadataTypeItem} cachedVersion cached version from the server
598
+ * @param {MetadataTypeItem} metadata item to upload
495
599
  * @param {string} [fieldName] optional field name to use for identifying the record in logs
496
600
  * @param {boolean} [silent] optionally suppress logging
497
601
  * @returns {boolean} true on first identified deviation or false if none are found
@@ -501,7 +605,7 @@ class MetadataType {
501
605
  return true;
502
606
  }
503
607
  // we do need the full set in other places and hence need to work with a clone here
504
- const clonedMetada = JSON.parse(JSON.stringify(metadata));
608
+ const clonedMetada = structuredClone(metadata);
505
609
  this.removeNotUpdateableFields(clonedMetada);
506
610
  // iterate over what we want to upload rather than what we cached to avoid false positives
507
611
  for (const prop in clonedMetada) {
@@ -544,12 +648,12 @@ class MetadataType {
544
648
  /**
545
649
  * MetadataType upsert, after retrieving from target and comparing to check if create or update operation is needed.
546
650
  *
547
- * @param {TYPE.MetadataTypeMap} metadataMap metadata mapped by their keyField
651
+ * @param {MetadataTypeMap} metadataMap metadata mapped by their keyField
548
652
  * @param {string} deployDir directory where deploy metadata are saved
549
- * @returns {Promise.<TYPE.MetadataTypeMap>} keyField => metadata map
653
+ * @returns {Promise.<MetadataTypeMap>} keyField => metadata map
550
654
  */
551
655
  static async upsert(metadataMap, deployDir) {
552
- const orignalMetadataMap = JSON.parse(JSON.stringify(metadataMap));
656
+ const orignalMetadataMap = structuredClone(metadataMap);
553
657
  const metadataToUpdate = [];
554
658
  const metadataToCreate = [];
555
659
  let filteredByPreDeploy = 0;
@@ -624,7 +728,6 @@ class MetadataType {
624
728
  // if Results then parse as SOAP
625
729
  // put in Retrieve Format for parsing
626
730
  // todo add handling when response does not contain items.
627
- // @ts-ignore
628
731
  const metadataResults = createResults
629
732
  .concat(updateResults)
630
733
  // TODO remove Object.keys check after create/update SOAP methods stop returning empty objects instead of null
@@ -636,7 +739,6 @@ class MetadataType {
636
739
  // likely comming from one of the many REST APIs
637
740
  // put in Retrieve Format for parsing
638
741
  // todo add handling when response does not contain items.
639
- // @ts-ignore
640
742
  const metadataResults = createResults.concat(updateResults).filter(Boolean);
641
743
  upsertResults = this.parseResponseBody(metadataResults);
642
744
  }
@@ -650,19 +752,39 @@ class MetadataType {
650
752
  /**
651
753
  * helper for {@link MetadataType.upsert}
652
754
  *
653
- * @param {TYPE.MetadataTypeMap} metadataMap list of metadata
755
+ * @param {MetadataTypeMap} metadataMap list of metadata
654
756
  * @param {string} metadataKey key of item we are looking at
655
757
  * @param {boolean} hasError error flag from previous code
656
- * @param {TYPE.MetadataTypeItemDiff[]} metadataToUpdate list of items to update
657
- * @param {TYPE.MetadataTypeItem[]} metadataToCreate list of items to create
658
- * @returns {'create' | 'update' | 'skip'} action to take
659
- */
660
- static createOrUpdate(metadataMap, metadataKey, hasError, metadataToUpdate, metadataToCreate) {
661
- const normalizedKey = File.reverseFilterIllegalFilenames(
758
+ * @param {MetadataTypeItemDiff[]} metadataToUpdate list of items to update
759
+ * @param {MetadataTypeItem[]} metadataToCreate list of items to create
760
+ * @returns {Promise.<'create' | 'update' | 'skip'>} action to take
761
+ */
762
+ static async createOrUpdate(
763
+ metadataMap,
764
+ metadataKey,
765
+ hasError,
766
+ metadataToUpdate,
767
+ metadataToCreate
768
+ ) {
769
+ let normalizedKey = File.reverseFilterIllegalFilenames(
662
770
  metadataMap[metadataKey][this.definition.keyField]
663
771
  );
772
+
664
773
  // Update if it already exists; Create it if not
665
774
  const maxKeyLength = this.definition.maxKeyLength || 36;
775
+
776
+ // make sure keySuffix always has a string value
777
+ Util.OPTIONS.keySuffix = Util.OPTIONS.keySuffix ? Util.OPTIONS.keySuffix.trim() : '';
778
+ if (Util.OPTIONS.keySuffix && !cache.getByKey(this.definition.type, normalizedKey)) {
779
+ // to ensure we go into update mode like we would with appending the MID to asset-keys, recreated the normalized key here
780
+ const newKey = this.getNewKey(
781
+ this.definition.keyField,
782
+ metadataMap[metadataKey],
783
+ maxKeyLength
784
+ );
785
+
786
+ normalizedKey = File.reverseFilterIllegalFilenames(newKey);
787
+ }
666
788
  if (
667
789
  Util.logger.level === 'debug' &&
668
790
  metadataMap[metadataKey][this.definition.idField] &&
@@ -691,6 +813,7 @@ class MetadataType {
691
813
  if (!this.hasChanged(cachedVersion, metadataMap[metadataKey])) {
692
814
  hasError = true;
693
815
  }
816
+
694
817
  if (Util.OPTIONS.changeKeyField) {
695
818
  if (this.definition.keyField == this.definition.idField) {
696
819
  Util.logger.error(
@@ -713,12 +836,18 @@ class MetadataType {
713
836
  ` - --changeKeyField is set to the same value as the keyField for ${this.definition.type}. Skipping change.`
714
837
  );
715
838
  } else if (metadataMap[metadataKey][Util.OPTIONS.changeKeyField]) {
716
- // NOTE: trim twice while getting the newKey value to remove leading spaces before limiting the length
717
- const newKey = (metadataMap[metadataKey][Util.OPTIONS.changeKeyField] + '')
718
- .trim()
719
- .slice(0, maxKeyLength)
720
- .trim();
721
- if (metadataMap[metadataKey][Util.OPTIONS.changeKeyField] + '' > maxKeyLength) {
839
+ const newKey = this.getNewKey(
840
+ Util.OPTIONS.changeKeyField,
841
+ metadataMap[metadataKey],
842
+ maxKeyLength
843
+ );
844
+
845
+ if (
846
+ metadataMap[metadataKey][Util.OPTIONS.changeKeyField] +
847
+ '' +
848
+ Util.OPTIONS.keySuffix >
849
+ maxKeyLength
850
+ ) {
722
851
  Util.logger.warn(
723
852
  `${this.definition.type} ${this.definition.keyField} may not exceed ${maxKeyLength} characters. Truncated the value in field ${Util.OPTIONS.changeKeyField} to ${newKey}`
724
853
  );
@@ -739,6 +868,9 @@ class MetadataType {
739
868
  }
740
869
  }
741
870
  } else if (Util.OPTIONS.changeKeyValue) {
871
+ if (Util.OPTIONS.keySuffix !== '') {
872
+ Util.logger.warn(`Ignoring --keySuffix as --changeKeyValue is set.`);
873
+ }
742
874
  // NOTE: trim twice while getting the newKey value to remove leading spaces before limiting the length
743
875
  const newKey = Util.OPTIONS.changeKeyValue.trim().slice(0, maxKeyLength).trim();
744
876
  if (Util.OPTIONS.changeKeyValue.trim().length > maxKeyLength) {
@@ -770,6 +902,21 @@ class MetadataType {
770
902
  Util.changedKeysMap[this.definition.type] ||= {};
771
903
  Util.changedKeysMap[this.definition.type][newKey] = metadataKey;
772
904
  }
905
+ } else if (Util.OPTIONS.keySuffix && Util.OPTIONS.keySuffix !== '') {
906
+ // assume we simply want to append a suffix
907
+ const newKey = this.getNewKey(
908
+ this.definition.keyField,
909
+ metadataMap[metadataKey],
910
+ maxKeyLength
911
+ );
912
+ Util.logger.info(
913
+ ` - Changing ${this.definition.type} key from ${metadataKey} to ${newKey} via --keySuffix=${Util.OPTIONS.keySuffix}`
914
+ );
915
+ metadataMap[metadataKey][this.definition.keyField] = newKey;
916
+
917
+ // ensure we can delete the old file(s) after the successful update
918
+ Util.changedKeysMap[this.definition.type] ||= {};
919
+ Util.changedKeysMap[this.definition.type][newKey] = metadataKey;
773
920
  }
774
921
 
775
922
  if (hasError) {
@@ -794,6 +941,19 @@ class MetadataType {
794
941
  metadataToCreate.push(null);
795
942
  return 'skip';
796
943
  } else {
944
+ if (Util.OPTIONS.keySuffix && Util.OPTIONS.keySuffix !== '') {
945
+ // assume we simply want to append a suffix
946
+ const newKey = this.getNewKey(
947
+ this.definition.keyField,
948
+ metadataMap[metadataKey],
949
+ maxKeyLength
950
+ );
951
+ Util.logger.info(
952
+ ` - Changing ${this.definition.type} key from ${metadataKey} to ${newKey} via --keySuffix=${Util.OPTIONS.keySuffix}`
953
+ );
954
+ metadataMap[metadataKey][this.definition.keyField] = newKey;
955
+ }
956
+
797
957
  metadataToCreate.push(metadataMap[metadataKey]);
798
958
  return 'create';
799
959
  }
@@ -803,23 +963,26 @@ class MetadataType {
803
963
  /**
804
964
  * Creates a single metadata entry via REST
805
965
  *
806
- * @param {TYPE.MetadataTypeItem} metadataEntry a single metadata Entry
966
+ * @param {MetadataTypeItem} metadataEntry a single metadata Entry
807
967
  * @param {string} uri rest endpoint for POST
968
+ * @param {boolean} [handleOutside] if the API reponse is irregular this allows you to handle it outside of this generic method
808
969
  * @returns {Promise.<object> | null} Promise of API response or null in case of an error
809
970
  */
810
- static async createREST(metadataEntry, uri) {
811
- const metadataClone = JSON.parse(JSON.stringify(metadataEntry));
971
+ static async createREST(metadataEntry, uri, handleOutside) {
972
+ const metadataClone = structuredClone(metadataEntry);
812
973
  this.removeNotCreateableFields(metadataEntry);
813
974
  try {
814
975
  // set to empty object in case API returned nothing to be able to update it in helper classes
815
976
  const response = (await this.client.rest.post(uri, metadataEntry)) || {};
816
977
  await this.postCreateTasks(metadataEntry, response, metadataClone);
817
- Util.logger.info(
818
- ` - created ${this.definition.type}: ${
819
- metadataEntry[this.definition.keyField] ||
820
- metadataEntry[this.definition.nameField]
821
- } / ${metadataEntry[this.definition.nameField]}`
822
- );
978
+ if (!handleOutside) {
979
+ Util.logger.info(
980
+ ` - created ${this.definition.type}: ${
981
+ metadataEntry[this.definition.keyField] ||
982
+ metadataEntry[this.definition.nameField]
983
+ } / ${metadataEntry[this.definition.nameField]}`
984
+ );
985
+ }
823
986
  return response;
824
987
  } catch (ex) {
825
988
  const parsedErrors = this.getErrorsREST(ex);
@@ -843,7 +1006,7 @@ class MetadataType {
843
1006
  /**
844
1007
  * Creates a single metadata entry via fuel-soap (generic lib not wrapper)
845
1008
  *
846
- * @param {TYPE.MetadataTypeItem} metadataEntry single metadata entry
1009
+ * @param {MetadataTypeItem} metadataEntry single metadata entry
847
1010
  * @param {boolean} [handleOutside] if the API reponse is irregular this allows you to handle it outside of this generic method
848
1011
  * @returns {Promise.<object> | null} Promise of API response or null in case of an error
849
1012
  */
@@ -874,7 +1037,7 @@ class MetadataType {
874
1037
  /**
875
1038
  * Updates a single metadata entry via REST
876
1039
  *
877
- * @param {TYPE.MetadataTypeItem} metadataEntry a single metadata Entry
1040
+ * @param {MetadataTypeItem} metadataEntry a single metadata Entry
878
1041
  * @param {string} uri rest endpoint for PATCH
879
1042
  * @param {'patch'|'post'|'put'} [httpMethod] defaults to 'patch'; some update requests require PUT instead of PATCH
880
1043
  * @returns {Promise.<object> | null} Promise of API response or null in case of an error
@@ -913,10 +1076,9 @@ class MetadataType {
913
1076
  /**
914
1077
  * helper for {@link MetadataType.updateREST} and {@link MetadataType.updateSOAP} that removes old files after the key was changed
915
1078
  *
916
- * @private
917
- * @param {TYPE.MetadataTypeItem} metadataEntry a single metadata Entry
1079
+ * @param {MetadataTypeItem} metadataEntry a single metadata Entry
918
1080
  * @param {boolean} [keepMap] some types require to check the old-key new-key relationship in their postDeployTasks; currently used by dataExtension only
919
- * @returns {void}
1081
+ * @returns {Promise.<void>} -
920
1082
  */
921
1083
  static async _postChangeKeyTasks(metadataEntry, keepMap = false) {
922
1084
  if (
@@ -948,7 +1110,7 @@ class MetadataType {
948
1110
  /**
949
1111
  * Updates a single metadata entry via fuel-soap (generic lib not wrapper)
950
1112
  *
951
- * @param {TYPE.MetadataTypeItem} metadataEntry single metadata entry
1113
+ * @param {MetadataTypeItem} metadataEntry single metadata entry
952
1114
  * @param {boolean} [handleOutside] if the API reponse is irregular this allows you to handle it outside of this generic method
953
1115
  * @returns {Promise.<object> | null} Promise of API response or null in case of an error
954
1116
  */
@@ -977,9 +1139,9 @@ class MetadataType {
977
1139
  }
978
1140
  /**
979
1141
  *
980
- * @param {Error} ex error that occured
981
- * @param {'creating'|'updating'} msg what to print in the log
982
- * @param {TYPE.MetadataTypeItem} [metadataEntry] single metadata entry
1142
+ * @param {SOAPError} ex error that occured
1143
+ * @param {'creating'|'updating'|'retrieving'|'executing'|'pausing'} msg what to print in the log
1144
+ * @param {MetadataTypeItem} [metadataEntry] single metadata entry
983
1145
  * @param {boolean} [handleOutside] if the API reponse is irregular this allows you to handle it outside of this generic method
984
1146
  */
985
1147
  static _handleSOAPErrors(ex, msg, metadataEntry, handleOutside) {
@@ -994,7 +1156,7 @@ class MetadataType {
994
1156
  /**
995
1157
  * helper for {@link MetadataType._handleSOAPErrors}
996
1158
  *
997
- * @param {Error} ex error that occured
1159
+ * @param {SOAPError} ex error that occured
998
1160
  * @returns {string} error message
999
1161
  */
1000
1162
  static getSOAPErrorMsg(ex) {
@@ -1010,11 +1172,11 @@ class MetadataType {
1010
1172
  /**
1011
1173
  * Retrieves SOAP via generic fuel-soap wrapper based metadata of metadata type into local filesystem. executes callback with retrieved metadata
1012
1174
  *
1013
- * @param {string} retrieveDir Directory where retrieved metadata directory will be saved
1014
- * @param {TYPE.SoapRequestParams} [requestParams] required for the specific request (filter for example)
1015
- * @param {string|number} [singleRetrieve] key of single item to filter by
1175
+ * @param {string} [retrieveDir] Directory where retrieved metadata directory will be saved
1176
+ * @param {SoapRequestParams} [requestParams] required for the specific request (filter for example)
1177
+ * @param {string} [singleRetrieve] key of single item to filter by
1016
1178
  * @param {string[]} [additionalFields] Returns specified fields even if their retrieve definition is not set to true
1017
- * @returns {Promise.<TYPE.MetadataTypeMapObj>} Promise of item map
1179
+ * @returns {Promise.<MetadataTypeMapObj>} Promise of item map
1018
1180
  */
1019
1181
  static async retrieveSOAP(retrieveDir, requestParams, singleRetrieve, additionalFields) {
1020
1182
  requestParams ||= {};
@@ -1029,7 +1191,7 @@ class MetadataType {
1029
1191
  );
1030
1192
  } catch (ex) {
1031
1193
  this._handleSOAPErrors(ex, 'retrieving');
1032
- return {};
1194
+ return;
1033
1195
  }
1034
1196
  const metadata = this.parseResponseBody(response);
1035
1197
 
@@ -1049,9 +1211,9 @@ class MetadataType {
1049
1211
  *
1050
1212
  * @param {string} retrieveDir Directory where retrieved metadata directory will be saved
1051
1213
  * @param {string} uri rest endpoint for GET
1052
- * @param {TYPE.TemplateMap} [templateVariables] variables to be replaced in the metadata
1053
- * @param {string|number} [singleRetrieve] key of single item to filter by
1054
- * @returns {Promise.<{metadata: (TYPE.MetadataTypeMap | TYPE.MetadataTypeItem), type: string}>} Promise of item map (single item for templated result)
1214
+ * @param {TemplateMap} [templateVariables] variables to be replaced in the metadata
1215
+ * @param {string} [singleRetrieve] key of single item to filter by
1216
+ * @returns {Promise.<{metadata: (MetadataTypeMap | MetadataTypeItem), type: string}>} Promise of item map (single item for templated result)
1055
1217
  */
1056
1218
  static async retrieveREST(retrieveDir, uri, templateVariables, singleRetrieve) {
1057
1219
  const response =
@@ -1063,7 +1225,13 @@ class MetadataType {
1063
1225
  if (this.definition.hasExtended) {
1064
1226
  Util.logger.debug(' - retrieving extended metadata');
1065
1227
  const extended = await this.client.rest.getCollection(
1066
- Object.keys(results).map((key) => uri + results[key][this.definition.idField])
1228
+ Object.keys(results)
1229
+ .map((key) =>
1230
+ uri.endsWith(results[key][this.definition.idField])
1231
+ ? null
1232
+ : uri + results[key][this.definition.idField]
1233
+ )
1234
+ .filter(Boolean)
1067
1235
  );
1068
1236
  for (const ext of extended) {
1069
1237
  const key = ext[this.definition.keyField];
@@ -1095,7 +1263,7 @@ class MetadataType {
1095
1263
  * @param {object[]} urlArray {uri: string, id: string} combo of URL and ID/key of metadata
1096
1264
  * @param {number} [concurrentRequests] optionally set a different amount of concurrent requests
1097
1265
  * @param {boolean} [logAmountOfUrls] if true, prints an info message about to-be loaded amount of metadata
1098
- * @returns {Promise.<{metadata: (TYPE.MetadataTypeMap | TYPE.MetadataTypeItem), type: string}>} Promise of item map (single item for templated result)
1266
+ * @returns {Promise.<{metadata: (MetadataTypeMap | MetadataTypeItem), type: string}>} Promise of item map (single item for templated result)
1099
1267
  */
1100
1268
  static async retrieveRESTcollection(urlArray, concurrentRequests = 10, logAmountOfUrls = true) {
1101
1269
  if (logAmountOfUrls) {
@@ -1136,11 +1304,11 @@ class MetadataType {
1136
1304
  /**
1137
1305
  * helper for {@link this.retrieveRESTcollection}
1138
1306
  *
1139
- * @param {Error} ex exception
1307
+ * @param {RestError} ex exception
1140
1308
  * @param {string} id id or key of item
1141
- * @returns {null} -
1309
+ * @returns {Promise.<any>} -
1142
1310
  */
1143
- static handleRESTErrors(ex, id) {
1311
+ static async handleRESTErrors(ex, id) {
1144
1312
  // if the ID is too short, the system will throw the 400 error
1145
1313
  Util.logger.debug(` ☇ skipping ${this.definition.type} ${id}: ${ex.message} ${ex.code}`);
1146
1314
 
@@ -1170,7 +1338,7 @@ class MetadataType {
1170
1338
  /**
1171
1339
  * Used to execute a query/automation etc.
1172
1340
  *
1173
- * @param {TYPE.MetadataTypeItem} [metadataEntry] single metadata entry
1341
+ * @param {MetadataTypeItem} [metadataEntry] single metadata entry
1174
1342
  * @returns {Promise.<{key:string, response:object}>} metadata key and API response
1175
1343
  */
1176
1344
  static async executeSOAP(metadataEntry) {
@@ -1202,8 +1370,8 @@ class MetadataType {
1202
1370
  /**
1203
1371
  * helper for {@link MetadataType.retrieveREST} and {@link MetadataType.retrieveSOAP}
1204
1372
  *
1205
- * @param {string|number} [singleRetrieve] key of single item to filter by
1206
- * @param {TYPE.MetadataTypeMap} metadataMap saved metadata
1373
+ * @param {string|number} singleRetrieve key of single item to filter by
1374
+ * @param {MetadataTypeMap} metadataMap saved metadata
1207
1375
  * @returns {Promise.<void>} -
1208
1376
  */
1209
1377
  static async runDocumentOnRetrieve(singleRetrieve, metadataMap) {
@@ -1231,8 +1399,8 @@ class MetadataType {
1231
1399
  * Builds map of metadata entries mapped to their keyfields
1232
1400
  *
1233
1401
  * @param {object} body json of response body
1234
- * @param {string|number} [singleRetrieve] key of single item to filter by
1235
- * @returns {TYPE.MetadataTypeMap} keyField => metadata map
1402
+ * @param {string} [singleRetrieve] key of single item to filter by
1403
+ * @returns {MetadataTypeMap} keyField => metadata map
1236
1404
  */
1237
1405
  static parseResponseBody(body, singleRetrieve) {
1238
1406
  const bodyIteratorField = this.definition.bodyIteratorField;
@@ -1253,7 +1421,7 @@ class MetadataType {
1253
1421
  } else if (singleRetrieve) {
1254
1422
  // some types will return a single item intead of an array if the key is supported by their api
1255
1423
  // ! currently, the id: prefix is only supported by journey (interaction)
1256
- if (singleRetrieve.startsWith('id:')) {
1424
+ if ('string' === typeof singleRetrieve && singleRetrieve.startsWith('id:')) {
1257
1425
  singleRetrieve = body[keyField];
1258
1426
  }
1259
1427
  metadataStructure[singleRetrieve] = body;
@@ -1280,9 +1448,9 @@ class MetadataType {
1280
1448
  * @example
1281
1449
  * Removes field (or nested fields childs) that are not updateable
1282
1450
  * deleteFieldByDefinition(metadataEntry, 'CustomerKey', 'isUpdateable');
1283
- * @param {TYPE.MetadataTypeItem} metadataEntry One entry of a metadataType
1451
+ * @param {MetadataTypeItem} metadataEntry One entry of a metadataType
1284
1452
  * @param {string} fieldPath field path to be checked if it conforms to the definition (dot seperated if nested): 'fuu.bar'
1285
- * @param {'isCreateable'|'isUpdateable'|'retrieving'|'templating'} definitionProperty delete field if definitionProperty equals false for specified field. Options: [isCreateable | isUpdateable]
1453
+ * @param {'isCreateable'|'isUpdateable'|'retrieving'|'template'} definitionProperty delete field if definitionProperty equals false for specified field. Options: [isCreateable | isUpdateable]
1286
1454
  * @param {string} origin string of parent object, required when using arrays as these are parsed slightly differently.
1287
1455
  * @returns {void}
1288
1456
  */
@@ -1353,7 +1521,7 @@ class MetadataType {
1353
1521
  /**
1354
1522
  * Remove fields from metadata entry that are not createable
1355
1523
  *
1356
- * @param {TYPE.MetadataTypeItem} metadataEntry metadata entry
1524
+ * @param {MetadataTypeItem} metadataEntry metadata entry
1357
1525
  * @returns {void}
1358
1526
  */
1359
1527
  static removeNotCreateableFields(metadataEntry) {
@@ -1365,7 +1533,7 @@ class MetadataType {
1365
1533
  /**
1366
1534
  * Remove fields from metadata entry that are not updateable
1367
1535
  *
1368
- * @param {TYPE.MetadataTypeItem} metadataEntry metadata entry
1536
+ * @param {MetadataTypeItem} metadataEntry metadata entry
1369
1537
  * @returns {void}
1370
1538
  */
1371
1539
  static removeNotUpdateableFields(metadataEntry) {
@@ -1377,7 +1545,7 @@ class MetadataType {
1377
1545
  /**
1378
1546
  * Remove fields from metadata entry that are not needed in the template
1379
1547
  *
1380
- * @param {TYPE.MetadataTypeItem} metadataEntry metadata entry
1548
+ * @param {MetadataTypeItem} metadataEntry metadata entry
1381
1549
  * @returns {void}
1382
1550
  */
1383
1551
  static keepTemplateFields(metadataEntry) {
@@ -1389,7 +1557,7 @@ class MetadataType {
1389
1557
  /**
1390
1558
  * Remove fields from metadata entry that are not needed in the stored metadata
1391
1559
  *
1392
- * @param {TYPE.MetadataTypeItem} metadataEntry metadata entry
1560
+ * @param {MetadataTypeItem} metadataEntry metadata entry
1393
1561
  * @returns {void}
1394
1562
  */
1395
1563
  static keepRetrieveFields(metadataEntry) {
@@ -1402,7 +1570,7 @@ class MetadataType {
1402
1570
  * checks if the current metadata entry should be saved on retrieve or not
1403
1571
  *
1404
1572
  * @static
1405
- * @param {TYPE.MetadataTypeItem} metadataEntry metadata entry
1573
+ * @param {MetadataTypeItem} metadataEntry metadata entry
1406
1574
  * @param {boolean} [include] true: use definition.include / options.include; false=exclude: use definition.filter / options.exclude
1407
1575
  * @returns {boolean} true: skip saving == filtered; false: continue with saving
1408
1576
  * @memberof MetadataType
@@ -1551,7 +1719,7 @@ class MetadataType {
1551
1719
  * @returns {?boolean} true: filter value found; false: filter value not found; null: no filter defined
1552
1720
  */
1553
1721
  static _filterOther(myFilter, metadataEntry) {
1554
- // not possible to check r__folder_Path before parseMetadata was run; handled in `isFilteredFolder()`
1722
+ // not possible to check r__folder_Path before postRetrieveTasks was run; handled in `isFilteredFolder()`
1555
1723
  if (
1556
1724
  !myFilter ||
1557
1725
  !Object.keys(myFilter).filter((item) => item !== 'r__folder_Path').length
@@ -1577,11 +1745,11 @@ class MetadataType {
1577
1745
  /**
1578
1746
  * Helper for writing Metadata to disk, used for Retrieve and deploy
1579
1747
  *
1580
- * @param {TYPE.MetadataTypeMap} results metadata results from deploy
1748
+ * @param {MetadataTypeMap} results metadata results from deploy
1581
1749
  * @param {string} retrieveDir directory where metadata should be stored after deploy/retrieve
1582
1750
  * @param {string} [overrideType] for use when there is a subtype (such as folder-queries)
1583
- * @param {TYPE.TemplateMap} [templateVariables] variables to be replaced in the metadata
1584
- * @returns {Promise.<TYPE.MetadataTypeMap>} Promise of saved metadata
1751
+ * @param {TemplateMap} [templateVariables] variables to be replaced in the metadata
1752
+ * @returns {Promise.<MetadataTypeMap>} Promise of saved metadata
1585
1753
  */
1586
1754
  static async saveResults(results, retrieveDir, overrideType, templateVariables) {
1587
1755
  const savedResults = {};
@@ -1633,95 +1801,13 @@ class MetadataType {
1633
1801
  continue;
1634
1802
  }
1635
1803
 
1636
- // for complex types like asset, script, query we need to save the scripts that were extracted from the JSON
1637
- if (results[originalKey].json && results[originalKey].codeArr) {
1638
- // replace market values with template variable placeholders (do not do it on .codeArr)
1639
- if (templateVariables) {
1640
- results[originalKey].json = Util.replaceByObject(
1641
- results[originalKey].json,
1642
- templateVariables
1643
- );
1644
- results[originalKey].subFolder = Util.replaceByObject(
1645
- results[originalKey].subFolder,
1646
- templateVariables
1647
- );
1648
- }
1649
-
1650
- const postRetrieveData = results[originalKey];
1651
- // normalize results[metadataEntry]
1652
- results[originalKey] = postRetrieveData.json;
1653
-
1654
- if (Util.OPTIONS.like && !Util.fieldsLike(results[originalKey])) {
1655
- Util.logger.debug(`Filtered ${originalKey} because of --like option`);
1656
- continue;
1657
- }
1658
-
1659
- if (postRetrieveData.subFolder) {
1660
- // very complex types have their own subfolder
1661
- baseDir.push(...postRetrieveData.subFolder);
1662
- }
1663
- // save extracted scripts
1664
- await Promise.all(
1665
- postRetrieveData.codeArr.map(async (script) => {
1666
- const dir = [...baseDir];
1667
- if (script.subFolder) {
1668
- // some files shall be saved in yet a deeper subfolder
1669
- dir.push(...script.subFolder);
1670
- }
1671
- return File.writePrettyToFile(
1672
- dir,
1673
- script.fileName + subtypeExtension,
1674
- script.fileExt,
1675
- script.content,
1676
- templateVariables
1677
- );
1678
- })
1679
- );
1680
- } else {
1681
- // not a complex type, run the the entire JSON through templating
1682
- // replace market values with template variable placeholders
1683
- if (templateVariables) {
1684
- results[originalKey] = Util.replaceByObject(
1685
- results[originalKey],
1686
- templateVariables
1687
- );
1688
- }
1689
- if (Util.OPTIONS.like && !Util.fieldsLike(results[originalKey])) {
1690
- Util.logger.debug(`Filtered ${originalKey} because of --like option`);
1691
- continue;
1692
- }
1693
- }
1694
-
1695
- // we dont store Id on local disk, but we need it for caching logic,
1696
- // so its in retrieve but not in save. Here we put into the clone so that the original
1697
- // object used for caching doesnt have the Id removed.
1698
- const saveClone = JSON.parse(JSON.stringify(results[originalKey]));
1699
- if (
1700
- !this.definition.keepId &&
1701
- this.definition.idField !== this.definition.keyField
1702
- ) {
1703
- delete saveClone[this.definition.idField];
1704
- }
1705
-
1706
- if (templateVariables) {
1707
- this.keepTemplateFields(saveClone);
1708
- } else {
1709
- this.keepRetrieveFields(saveClone);
1710
- }
1711
- savedResults[originalKey] = saveClone;
1712
- await File.writeJSONToFile(
1713
- // manage subtypes
1804
+ savedResults[originalKey] = await this.saveToDisk(
1805
+ results,
1806
+ originalKey,
1714
1807
  baseDir,
1715
- originalKey + subtypeExtension,
1716
- saveClone
1808
+ subtypeExtension,
1809
+ templateVariables
1717
1810
  );
1718
- if (templateVariables) {
1719
- Util.logger.info(
1720
- `- templated ${this.definition.type}: ${
1721
- saveClone[this.definition.nameField]
1722
- }`
1723
- );
1724
- }
1725
1811
  } catch (ex) {
1726
1812
  Util.logger.errorStack(
1727
1813
  ex,
@@ -1737,12 +1823,112 @@ class MetadataType {
1737
1823
  }
1738
1824
  return savedResults;
1739
1825
  }
1826
+
1827
+ /**
1828
+ *
1829
+ * @param {MetadataTypeMap} results metadata results from deploy
1830
+ * @param {string} originalKey key of metadata
1831
+ * @param {string[]} baseDir [retrieveDir, ...overrideType.split('-')]
1832
+ * @param {string} [subtypeExtension] e.g. ".asset-meta" or ".query-meta"
1833
+ * @param {TemplateMap} [templateVariables] variables to be replaced in the metadata
1834
+ * @returns {MetadataTypeItem} saved metadata
1835
+ */
1836
+ static async saveToDisk(results, originalKey, baseDir, subtypeExtension, templateVariables) {
1837
+ subtypeExtension ||= '.' + this.definition.type + '-meta';
1838
+ // for complex types like asset, script, query we need to save the scripts that were extracted from the JSON
1839
+ if (results[originalKey].json && results[originalKey].codeArr) {
1840
+ // replace market values with template variable placeholders (do not do it on .codeArr)
1841
+ if (templateVariables) {
1842
+ results[originalKey].json = Util.replaceByObject(
1843
+ results[originalKey].json,
1844
+ templateVariables
1845
+ );
1846
+ results[originalKey].subFolder = Util.replaceByObject(
1847
+ results[originalKey].subFolder,
1848
+ templateVariables
1849
+ );
1850
+ }
1851
+
1852
+ const postRetrieveData = results[originalKey];
1853
+ // normalize results[metadataEntry]
1854
+ results[originalKey] = postRetrieveData.json;
1855
+
1856
+ if (Util.OPTIONS.like && !Util.fieldsLike(results[originalKey])) {
1857
+ Util.logger.debug(`Filtered ${originalKey} because of --like option`);
1858
+ return;
1859
+ }
1860
+
1861
+ if (postRetrieveData.subFolder) {
1862
+ // very complex types have their own subfolder
1863
+ baseDir.push(...postRetrieveData.subFolder);
1864
+ }
1865
+ // save extracted scripts
1866
+ await Promise.all(
1867
+ postRetrieveData.codeArr.map(async (script) => {
1868
+ const dir = [...baseDir];
1869
+ if (script.subFolder) {
1870
+ // some files shall be saved in yet a deeper subfolder
1871
+ dir.push(...script.subFolder);
1872
+ }
1873
+ return File.writePrettyToFile(
1874
+ dir,
1875
+ script.fileName + subtypeExtension,
1876
+ script.fileExt,
1877
+ script.content,
1878
+ templateVariables
1879
+ );
1880
+ })
1881
+ );
1882
+ } else {
1883
+ // not a complex type, run the the entire JSON through templating
1884
+ // replace market values with template variable placeholders
1885
+ if (templateVariables) {
1886
+ results[originalKey] = Util.replaceByObject(
1887
+ results[originalKey],
1888
+ templateVariables
1889
+ );
1890
+ }
1891
+ if (Util.OPTIONS.like && !Util.fieldsLike(results[originalKey])) {
1892
+ Util.logger.debug(`Filtered ${originalKey} because of --like option`);
1893
+ return;
1894
+ }
1895
+ }
1896
+
1897
+ // we dont store Id on local disk, but we need it for caching logic,
1898
+ // so its in retrieve but not in save. Here we put into the clone so that the original
1899
+ // object used for caching doesnt have the Id removed.
1900
+
1901
+ const saveClone = structuredClone(results[originalKey]);
1902
+ if (!this.definition.keepId && this.definition.idField !== this.definition.keyField) {
1903
+ delete saveClone[this.definition.idField];
1904
+ }
1905
+
1906
+ if (templateVariables) {
1907
+ this.keepTemplateFields(saveClone);
1908
+ } else {
1909
+ this.keepRetrieveFields(saveClone);
1910
+ }
1911
+
1912
+ await File.writeJSONToFile(
1913
+ // manage subtypes
1914
+ baseDir,
1915
+ originalKey + subtypeExtension,
1916
+ saveClone
1917
+ );
1918
+ if (templateVariables) {
1919
+ Util.logger.info(
1920
+ `- templated ${this.definition.type}: ${saveClone[this.definition.nameField]}`
1921
+ );
1922
+ }
1923
+
1924
+ return saveClone;
1925
+ }
1740
1926
  /**
1741
1927
  * helper for {@link MetadataType.buildDefinitionForNested}
1742
1928
  * searches extracted file for template variable names and applies the market values
1743
1929
  *
1744
1930
  * @param {string} code code from extracted code
1745
- * @param {TYPE.TemplateMap} templateVariables variables to be replaced in the metadata
1931
+ * @param {TemplateMap} templateVariables variables to be replaced in the metadata
1746
1932
  * @returns {string} code with markets applied
1747
1933
  */
1748
1934
  static applyTemplateValues(code, templateVariables) {
@@ -1754,7 +1940,7 @@ class MetadataType {
1754
1940
  * searches extracted file for template variable values and applies the market variable names
1755
1941
  *
1756
1942
  * @param {string} code code from extracted code
1757
- * @param {TYPE.TemplateMap} templateVariables variables to be replaced in the metadata
1943
+ * @param {TemplateMap} templateVariables variables to be replaced in the metadata
1758
1944
  * @returns {string} code with markets applied
1759
1945
  */
1760
1946
  static applyTemplateNames(code, templateVariables) {
@@ -1766,9 +1952,9 @@ class MetadataType {
1766
1952
  * handles extracted code if any are found for complex types (e.g script, asset, query)
1767
1953
  *
1768
1954
  * @param {string} templateDir Directory where metadata templates are stored
1769
- * @param {string} targetDir Directory where built definitions will be saved
1770
- * @param {TYPE.MetadataTypeItem} metadata main JSON file that was read from file system
1771
- * @param {TYPE.TemplateMap} variables variables to be replaced in the metadata
1955
+ * @param {string | string[]} targetDir Directory where built definitions will be saved
1956
+ * @param {MetadataTypeItem} metadata main JSON file that was read from file system
1957
+ * @param {TemplateMap} variables variables to be replaced in the metadata
1772
1958
  * @param {string} templateName name of the template to be built
1773
1959
  * @returns {Promise.<string[][]>} list of extracted files with path-parts provided as an array
1774
1960
  */
@@ -1788,8 +1974,8 @@ class MetadataType {
1788
1974
  *
1789
1975
  * @param {string} templateDir Directory where metadata templates are stored
1790
1976
  * @param {string|string[]} targetDir (List of) Directory where built definitions will be saved
1791
- * @param {TYPE.MetadataTypeItem} metadata main JSON file that was read from file system
1792
- * @param {TYPE.TemplateMap} templateVariables variables to be replaced in the metadata
1977
+ * @param {MetadataTypeItem} metadata main JSON file that was read from file system
1978
+ * @param {TemplateMap} templateVariables variables to be replaced in the metadata
1793
1979
  * @param {string} templateName name of the template to be built
1794
1980
  * @returns {Promise.<string[][]>} list of extracted files with path-parts provided as an array
1795
1981
  */
@@ -1821,11 +2007,11 @@ class MetadataType {
1821
2007
  * @param {string} templateName name of the metadata template
1822
2008
  * @param {string} fileName name of the metadata template file w/o extension
1823
2009
  * @param {Error} ex error from first attempt
1824
- * @returns {object} metadata
2010
+ * @returns {Promise.<string>} metadata in string form
1825
2011
  */
1826
2012
  static async readSecondaryFolder(templateDir, typeDirArr, templateName, fileName, ex) {
1827
2013
  // we just want to push the method into the catch here
1828
- throw new Error(ex);
2014
+ return;
1829
2015
  }
1830
2016
  /**
1831
2017
  * Builds definition based on template
@@ -1835,8 +2021,8 @@ class MetadataType {
1835
2021
  * @param {string} templateDir Directory where metadata templates are stored
1836
2022
  * @param {string | string[]} targetDir (List of) Directory where built definitions will be saved
1837
2023
  * @param {string} templateName name of the metadata file
1838
- * @param {TYPE.TemplateMap} variables variables to be replaced in the metadata
1839
- * @returns {Promise.<TYPE.MetadataTypeMapObj>} Promise of item map
2024
+ * @param {TemplateMap} variables variables to be replaced in the metadata
2025
+ * @returns {Promise.<MetadataTypeMapObj>} Promise of item map
1840
2026
  */
1841
2027
  static async buildDefinition(templateDir, targetDir, templateName, variables) {
1842
2028
  // retrieve metadata template
@@ -1856,6 +2042,9 @@ class MetadataType {
1856
2042
  fileName,
1857
2043
  'json'
1858
2044
  );
2045
+ if (!metadataStr) {
2046
+ throw new Error('File not found');
2047
+ }
1859
2048
  } catch (ex) {
1860
2049
  try {
1861
2050
  metadataStr = await this.readSecondaryFolder(
@@ -1866,22 +2055,26 @@ class MetadataType {
1866
2055
  ex
1867
2056
  );
1868
2057
  } catch {
1869
- throw new Error(
1870
- `${this.definition.type}:: Could not find ./${File.normalizePath([
1871
- templateDir,
1872
- ...typeDirArr,
1873
- fileName + '.json',
1874
- ])}.`
2058
+ // only happening for types that use readSecondaryFolder (e.g. asset)
2059
+ // if we still have no metadataStr then we have to skip this metadata for all types and hence handle it outside of this catch
2060
+ }
2061
+ if (!metadataStr) {
2062
+ Util.logger.warn(
2063
+ Util.getGrayMsg(
2064
+ `- skipped ${this.definition.type} ${templateName}: template not found`
2065
+ )
1875
2066
  );
2067
+ return;
1876
2068
  }
1877
- // return;
1878
2069
  }
1879
2070
 
1880
2071
  let metadata;
1881
2072
  try {
1882
2073
  // update all initial variables & create metadata object
1883
- metadata = JSON.parse(Mustache.render(metadataStr, variables, {}, ['{{{', '}}}']));
1884
- typeDirArr = typeDirArr.map((el) => Mustache.render(el, variables, {}, ['{{{', '}}}']));
2074
+ metadata = JSON.parse(this.applyTemplateValues(metadataStr, variables));
2075
+ typeDirArr = typeDirArr
2076
+ .map((el) => (el === templateName ? metadata[this.definition.keyField] : el))
2077
+ .map((el) => this.applyTemplateValues(el, variables));
1885
2078
  } catch {
1886
2079
  throw new Error(
1887
2080
  `${this.definition.type}:: Error applying template variables on ${
@@ -1904,7 +2097,6 @@ class MetadataType {
1904
2097
  try {
1905
2098
  // write to file
1906
2099
  const targetDirArr = Array.isArray(targetDir) ? targetDir : [targetDir];
1907
-
1908
2100
  for (const targetDir of targetDirArr) {
1909
2101
  await File.writeJSONToFile(
1910
2102
  [targetDir, ...typeDirArr],
@@ -1927,7 +2119,7 @@ class MetadataType {
1927
2119
  * Standardizes a check for multiple messages
1928
2120
  *
1929
2121
  * @param {object} ex response payload from REST API
1930
- * @returns {string[] | void} formatted Error Message
2122
+ * @returns {string[]} formatted Error Message
1931
2123
  */
1932
2124
  static getErrorsREST(ex) {
1933
2125
  const errors = [];
@@ -1966,7 +2158,7 @@ class MetadataType {
1966
2158
  /**
1967
2159
  * Gets metadata cache with limited fields and does not store value to disk
1968
2160
  *
1969
- * @param {TYPE.MetadataTypeMap} [metadata] a list of type definitions
2161
+ * @param {MetadataTypeMap} [metadata] a list of type definitions
1970
2162
  * @param {boolean} [isDeploy] used to skip non-supported message during deploy
1971
2163
  * @returns {void}
1972
2164
  */
@@ -1976,13 +2168,24 @@ class MetadataType {
1976
2168
  }
1977
2169
  }
1978
2170
 
2171
+ /**
2172
+ * get name & key for provided id
2173
+ *
2174
+ * @param {string} id Identifier of metadata
2175
+ * @returns {Promise.<{key:string, name:string}>} key, name and path of metadata; null if not found
2176
+ */
2177
+ static async resolveId(id) {
2178
+ Util.logger.error(`resolveId type ${this.definition.type} is not supported.`);
2179
+ return;
2180
+ }
2181
+
1979
2182
  /**
1980
2183
  * Delete a metadata item from the specified business unit
1981
2184
  *
1982
2185
  * @param {string} customerKey Identifier of data extension
1983
- * @returns {boolean} deletion success status
2186
+ * @returns {Promise.<boolean>} deletion success status
1984
2187
  */
1985
- static deleteByKey(customerKey) {
2188
+ static async deleteByKey(customerKey) {
1986
2189
  Util.logger.error(`Deletion is not yet supported for ${this.definition.typeName}!`);
1987
2190
  return false;
1988
2191
  }
@@ -2014,13 +2217,14 @@ class MetadataType {
2014
2217
  * @param {string} customerKey Identifier of metadata
2015
2218
  * @param {string} [overrideKeyField] optionally change the name of the key field if the api uses a different name
2016
2219
  * @param {boolean} [handleOutside] if the API reponse is irregular this allows you to handle it outside of this generic method
2017
- * @returns {boolean} deletion success flag
2220
+ * @returns {Promise.<boolean>} deletion success flag
2018
2221
  */
2019
2222
  static async deleteByKeySOAP(customerKey, overrideKeyField, handleOutside) {
2020
2223
  const metadata = {};
2021
2224
  metadata[overrideKeyField || this.definition.keyField] = customerKey;
2022
2225
  const soapType = this.definition.soapType || this.definition.type;
2023
2226
  try {
2227
+ // @ts-expect-error - wrong jsdoc in SFMC-SDK
2024
2228
  await this.client.soap.delete(Util.capitalizeFirstLetter(soapType), metadata, null);
2025
2229
  if (!handleOutside) {
2026
2230
  Util.logger.info(` - deleted ${this.definition.type}: ${customerKey}`);
@@ -2049,7 +2253,7 @@ class MetadataType {
2049
2253
  * @param {string} url endpoint
2050
2254
  * @param {string} key Identifier of metadata
2051
2255
  * @param {boolean} [handleOutside] if the API reponse is irregular this allows you to handle it outside of this generic method
2052
- * @returns {boolean} deletion success flag
2256
+ * @returns {Promise.<boolean>} deletion success flag
2053
2257
  */
2054
2258
  static async deleteByKeyREST(url, key, handleOutside) {
2055
2259
  try {
@@ -2076,15 +2280,15 @@ class MetadataType {
2076
2280
  * @param {string} readDir root directory of metadata.
2077
2281
  * @param {boolean} [listBadKeys] do not print errors, used for badKeys()
2078
2282
  * @param {object} [buMetadata] Metadata of BU in local directory
2079
- * @returns {object} Metadata of BU in local directory
2283
+ * @returns {Promise.<object>} Metadata of BU in local directory
2080
2284
  */
2081
- static readBUMetadataForType(readDir, listBadKeys, buMetadata) {
2285
+ static async readBUMetadataForType(readDir, listBadKeys, buMetadata) {
2082
2286
  buMetadata ||= {};
2083
2287
  readDir = File.normalizePath([readDir, this.definition.type]);
2084
2288
  try {
2085
- if (File.pathExistsSync(readDir)) {
2289
+ if (await File.pathExists(readDir)) {
2086
2290
  // check if folder name is a valid metadataType, then check if the user limited to a certain type in the command params
2087
- buMetadata[this.definition.type] = this.getJsonFromFS(readDir, listBadKeys);
2291
+ buMetadata[this.definition.type] = await this.getJsonFromFS(readDir, listBadKeys);
2088
2292
  return buMetadata;
2089
2293
  } else {
2090
2294
  throw new Error(`Directory '${readDir}' does not exist.`);
@@ -2100,7 +2304,7 @@ class MetadataType {
2100
2304
  * @param {string[]} keyArr customerkey of the metadata
2101
2305
  * @returns {Promise.<string[]>} list of all files that need to be committed in a flat array ['path/file1.ext', 'path/file2.ext']
2102
2306
  */
2103
- static getFilesToCommit(keyArr) {
2307
+ static async getFilesToCommit(keyArr) {
2104
2308
  const typeExtension = '.' + this.definition.type + '-meta.json';
2105
2309
  const path = File.normalizePath([
2106
2310
  this.properties.directories.retrieve,
@@ -2115,39 +2319,49 @@ class MetadataType {
2115
2319
 
2116
2320
  /**
2117
2321
  *
2118
- * @param {TYPE.MetadataTypeMap} metadataMap metadata mapped by their keyField
2322
+ * @param {MetadataTypeMap} metadataMap metadata mapped by their keyField
2119
2323
  * @returns {string[]} list of keys
2120
2324
  */
2121
2325
  static getKeysForFixing(metadataMap) {
2122
2326
  const keysForDeploy = [];
2327
+ if (!metadataMap) {
2328
+ // if a type was skipped e.g. because it shall only be looked at on the parent then we would expect metadataMap to be undefined
2329
+ return keysForDeploy;
2330
+ }
2123
2331
  if (Object.keys(metadataMap).length) {
2124
2332
  Util.logger.info(
2125
2333
  `Searching for ${this.definition.type} keys among downloaded items that need fixing:`
2126
2334
  );
2335
+ Util.OPTIONS.keySuffix = Util.OPTIONS.keySuffix ? Util.OPTIONS.keySuffix.trim() : '';
2336
+ const maxKeyLength = this.definition.maxKeyLength || 36;
2337
+
2127
2338
  for (const item of Object.values(metadataMap)) {
2128
- if (item[this.definition.nameField].length > this.definition.maxKeyLength) {
2129
- Util.logger.warn(
2130
- `Name of the item ${
2131
- item[this.definition.keyField]
2132
- } is too long for a key. Consider renaming your item. Key will be equal first ${
2133
- this.definition.maxKeyLength
2134
- } characters of the name`
2135
- );
2136
- item[this.definition.nameField] = item[this.definition.nameField].slice(
2137
- 0,
2138
- this.definition.maxKeyLength
2139
- );
2140
- }
2339
+ if (this.isFiltered(item, true) || this.isFiltered(item, false)) {
2340
+ // we would not have saved these items to disk but they exist in the cache and hence need to be skipped here
2141
2341
 
2342
+ continue;
2343
+ }
2142
2344
  if (
2143
- item[this.definition.nameField] != item[this.definition.keyField] &&
2144
- !this.definition.keyIsFixed
2345
+ (item[this.definition.nameField].endsWith(Util.OPTIONS.keySuffix) &&
2346
+ item[this.definition.nameField].length > maxKeyLength) ||
2347
+ (!item[this.definition.nameField].endsWith(Util.OPTIONS.keySuffix) &&
2348
+ item[this.definition.nameField].length + Util.OPTIONS.keySuffix.length >
2349
+ maxKeyLength)
2145
2350
  ) {
2146
- keysForDeploy.push(item[this.definition.keyField]);
2351
+ Util.logger.warn(
2352
+ `Name of the item ${item[this.definition.keyField]} (${
2353
+ item[this.definition.nameField]
2354
+ }) is too long for a key${Util.OPTIONS.keySuffix.length ? ' (including the suffix ' + Util.OPTIONS.keySuffix + ')' : ''}. Consider renaming your item. Key will be equal first ${maxKeyLength} characters of the name`
2355
+ );
2356
+ }
2357
+ const newKey = this.getNewKey(this.definition.nameField, item, maxKeyLength);
2358
+ if (newKey != item[this.definition.keyField] && !this.definition.keyIsFixed) {
2359
+ // add key but make sure to turn it into string or else numeric keys will be filtered later
2360
+ keysForDeploy.push(item[this.definition.keyField] + '');
2147
2361
  Util.logger.info(
2148
2362
  ` - added ${this.definition.type} to fixKey queue: ${
2149
2363
  item[this.definition.keyField]
2150
- }`
2364
+ } >> ${newKey}`
2151
2365
  );
2152
2366
  } else {
2153
2367
  Util.logger.info(
@@ -2163,6 +2377,28 @@ class MetadataType {
2163
2377
  }
2164
2378
  return keysForDeploy;
2165
2379
  }
2380
+ /**
2381
+ * helper for getKeysForFixing and createOrUpdate
2382
+ *
2383
+ * @param {string} baseField name of the field to start the new key with
2384
+ * @param {MetadataTypeItem} metadataItem -
2385
+ * @param {number} maxKeyLength -
2386
+ * @returns {string} newKey
2387
+ */
2388
+ static getNewKey(baseField, metadataItem, maxKeyLength) {
2389
+ const keySuffix = Util.OPTIONS.keySuffix;
2390
+ let newKey;
2391
+ newKey = (metadataItem[baseField] + '').trim().slice(0, maxKeyLength).trim();
2392
+ if (keySuffix.length && !newKey.endsWith(keySuffix)) {
2393
+ newKey =
2394
+ (metadataItem[baseField] + '')
2395
+ .trim()
2396
+ .slice(0, maxKeyLength - keySuffix.length)
2397
+ .trim() + keySuffix;
2398
+ }
2399
+
2400
+ return newKey;
2401
+ }
2166
2402
  }
2167
2403
 
2168
2404
  MetadataType.definition = {
@@ -2176,11 +2412,11 @@ MetadataType.definition = {
2176
2412
  type: '',
2177
2413
  };
2178
2414
  /**
2179
- * @type {TYPE.SDK}
2415
+ * @type {SDK}
2180
2416
  */
2181
2417
  MetadataType.client = undefined;
2182
2418
  /**
2183
- * @type {TYPE.Mcdevrc}
2419
+ * @type {Mcdevrc}
2184
2420
  */
2185
2421
  MetadataType.properties = null;
2186
2422
  /**
@@ -2188,7 +2424,7 @@ MetadataType.properties = null;
2188
2424
  */
2189
2425
  MetadataType.subType = null;
2190
2426
  /**
2191
- * @type {TYPE.BuObject}
2427
+ * @type {BuObject}
2192
2428
  */
2193
2429
  MetadataType.buObject = null;
2194
2430