mcdev 5.0.2 → 5.2.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 (237) hide show
  1. package/.coverage-comment-template.svelte +177 -161
  2. package/.eslintrc.json +4 -4
  3. package/.github/ISSUE_TEMPLATE/bug.yml +2 -0
  4. package/.github/PULL_REQUEST_TEMPLATE.md +2 -2
  5. package/.github/dependabot.yml +8 -0
  6. package/.github/workflows/coverage-base-update.yml +6 -2
  7. package/.github/workflows/coverage-develop-branch.yml +7 -8
  8. package/.github/workflows/coverage-main-branch.yml +7 -8
  9. package/.github/workflows/coverage.yml +7 -4
  10. package/.husky/post-checkout +4 -2
  11. package/.husky/post-merge +1 -0
  12. package/.vscode/extensions.json +4 -0
  13. package/docs/dist/documentation.md +756 -294
  14. package/lib/Deployer.js +28 -28
  15. package/lib/MetadataTypeDefinitions.js +1 -1
  16. package/lib/MetadataTypeInfo.js +1 -1
  17. package/lib/Retriever.js +1 -1
  18. package/lib/cli.js +184 -6
  19. package/lib/index.js +493 -22
  20. package/lib/metadataTypes/Asset.js +10 -11
  21. package/lib/metadataTypes/AttributeGroup.js +76 -2
  22. package/lib/metadataTypes/AttributeSet.js +260 -0
  23. package/lib/metadataTypes/Automation.js +771 -247
  24. package/lib/metadataTypes/DataExtension.js +7 -7
  25. package/lib/metadataTypes/DataExtensionField.js +1 -1
  26. package/lib/metadataTypes/Event.js +2 -3
  27. package/lib/metadataTypes/Folder.js +1 -1
  28. package/lib/metadataTypes/Journey.js +5 -6
  29. package/lib/metadataTypes/MetadataType.js +187 -60
  30. package/lib/metadataTypes/MobileKeyword.js +8 -8
  31. package/lib/metadataTypes/MobileMessage.js +5 -5
  32. package/lib/metadataTypes/Query.js +47 -5
  33. package/lib/metadataTypes/Script.js +3 -3
  34. package/lib/metadataTypes/TransactionalSMS.js +5 -5
  35. package/lib/metadataTypes/TriggeredSend.js +25 -50
  36. package/lib/metadataTypes/User.js +7 -4
  37. package/lib/metadataTypes/definitions/Asset.definition.js +1 -0
  38. package/lib/metadataTypes/definitions/AttributeGroup.definition.js +117 -106
  39. package/lib/metadataTypes/definitions/{SetDefinition.definition.js → AttributeSet.definition.js} +54 -27
  40. package/lib/metadataTypes/definitions/Automation.definition.js +74 -21
  41. package/lib/metadataTypes/definitions/DataExtension.definition.js +1 -0
  42. package/lib/metadataTypes/definitions/DataExtract.definition.js +1 -0
  43. package/lib/metadataTypes/definitions/EmailSend.definition.js +1 -0
  44. package/lib/metadataTypes/definitions/Event.definition.js +1 -0
  45. package/lib/metadataTypes/definitions/Filter.definition.js +1 -0
  46. package/lib/metadataTypes/definitions/ImportFile.definition.js +37 -6
  47. package/lib/metadataTypes/definitions/MobileKeyword.definition.js +1 -0
  48. package/lib/metadataTypes/definitions/Query.definition.js +1 -0
  49. package/lib/metadataTypes/definitions/Role.definition.js +1 -0
  50. package/lib/metadataTypes/definitions/TriggeredSend.definition.js +2 -0
  51. package/lib/metadataTypes/definitions/User.definition.js +1 -0
  52. package/lib/util/cache.js +9 -4
  53. package/lib/util/cli.js +40 -0
  54. package/lib/util/devops.js +13 -11
  55. package/lib/util/file.js +2 -2
  56. package/lib/util/init.js +84 -0
  57. package/lib/util/util.js +268 -137
  58. package/package.json +11 -11
  59. package/test/general.test.js +26 -0
  60. package/test/mockRoot/.mcdevrc.json +1 -1
  61. package/test/mockRoot/deploy/testInstance/testBU/automation/testExisting_automation.automation-meta.json +52 -0
  62. package/test/mockRoot/deploy/testInstance/testBU/automation/testNew_automation.automation-meta.json +45 -0
  63. package/test/mockRoot/deploy/testInstance/testBU/dataExtract/testExisting_dataExtract.dataExtract-meta.json +35 -0
  64. package/test/mockRoot/deploy/testInstance/testBU/dataExtract/testNew_dataExtract.dataExtract-meta.json +35 -0
  65. package/test/mockRoot/deploy/testInstance/testBU/fileTransfer/testExisting_fileTransfer.fileTransfer-meta.json +17 -0
  66. package/test/mockRoot/deploy/testInstance/testBU/fileTransfer/testNew_fileTransfer.fileTransfer-meta.json +17 -0
  67. package/test/mockRoot/deploy/testInstance/testBU/importFile/testExisting_importFile.importFile-meta.json +29 -0
  68. package/test/mockRoot/deploy/testInstance/testBU/importFile/testNew_importFile.importFile-meta.json +29 -0
  69. package/test/mockRoot/deploy/testInstance/testBU/query/{testExistingQuery.query-meta.json → testExisting_query.query-meta.json} +2 -2
  70. package/test/mockRoot/deploy/testInstance/testBU/query/testExisting_query_fixKeys.query-meta.json +11 -0
  71. package/test/mockRoot/deploy/testInstance/testBU/query/testExisting_query_fixKeys.query-meta.sql +6 -0
  72. package/test/mockRoot/deploy/testInstance/testBU/query/{testNewQuery.query-meta.json → testNew_query.query-meta.json} +2 -2
  73. package/test/mockRoot/deploy/testInstance/testBU/script/testExisting_script.script-meta.json +6 -0
  74. package/test/mockRoot/deploy/testInstance/testBU/script/testExisting_script.script-meta.ssjs +1 -0
  75. package/test/mockRoot/deploy/testInstance/testBU/script/testNew_script.script-meta.json +6 -0
  76. package/test/mockRoot/deploy/testInstance/testBU/script/testNew_script.script-meta.ssjs +1 -0
  77. package/test/mockRoot/deploy/testInstance/testBU/triggeredSend/testExisting_triggeredSend.triggeredSend-meta.json +29 -0
  78. package/test/mockRoot/deploy/testInstance/testBU/triggeredSend/testNew_triggeredSend.triggeredSend-meta.json +29 -0
  79. package/test/resourceFactory.js +132 -24
  80. package/test/resources/1111111/accountUser/retrieve-ActiveFlag=falseANDCustomerKey=testExisting_userANDEmaillike@-response.xml +27 -0
  81. package/test/resources/1111111/accountUser/retrieve-ActiveFlag=falseANDEmaillike@-response.xml +156 -0
  82. package/test/resources/1111111/accountUser/retrieve-ActiveFlag=trueANDEmailisNullORNamelikeapp userANDMustChangePassword=false-response.xml +87 -0
  83. package/test/resources/1111111/accountUser/retrieve-ActiveFlag=trueANDEmaillike@-response.xml +156 -0
  84. package/test/resources/1111111/accountUser/retrieve-CustomerKey=testExisting_userANDActiveFlag=trueANDEmailisNullORNamelikeapp userANDMustChangePassword=false-response.xml +27 -0
  85. package/test/resources/1111111/accountUserAccount/retrieve-AccountUser.AccountUserID=700301950-response.xml +60 -0
  86. package/test/resources/1111111/user/retrieve-expected.md +4 -2
  87. package/test/resources/9999999/attributeGroup/retrieve-expected.json +25 -0
  88. package/test/resources/9999999/attributeSet/retrieve-expected.json +748 -0
  89. package/test/resources/9999999/automation/build-expected.json +57 -0
  90. package/test/resources/9999999/automation/create-expected.json +45 -0
  91. package/test/resources/9999999/automation/create-testNew_automation-expected.md +28 -0
  92. package/test/resources/9999999/automation/delete-response.xml +40 -0
  93. package/test/resources/9999999/automation/patch_fixKeys-pause-expected.json +44 -0
  94. package/test/resources/9999999/automation/patch_fixKeys-schedule-expected.json +44 -0
  95. package/test/resources/9999999/automation/perform-08afb0e2-b00a-4c88-ad2e-1f7f8788c560-response.xml +42 -0
  96. package/test/resources/9999999/automation/perform-08afb0e2-b00a-4c88-fixKey_pause-response.xml +42 -0
  97. package/test/resources/9999999/automation/perform-08afb0e2-b00a-4c88-fixKey_schedule-response.xml +42 -0
  98. package/test/resources/9999999/automation/perform-a8afb0e2-b00a-4c88-ad2e-1f7f8788c560-response.xml +42 -0
  99. package/test/resources/9999999/automation/retrieve-expected.json +57 -0
  100. package/test/resources/9999999/automation/retrieve-testExisting_automation-expected.md +30 -0
  101. package/test/resources/9999999/automation/schedule-08afb0e2-b00a-4c88-ad2e-1f7f8788c560-response.xml +52 -0
  102. package/test/resources/9999999/automation/schedule-08afb0e2-b00a-4c88-ad2e-pause-response.xml +38 -0
  103. package/test/resources/9999999/automation/schedule-08afb0e2-b00a-4c88-fixKey_pause-response.xml +52 -0
  104. package/test/resources/9999999/automation/schedule-08afb0e2-b00a-4c88-fixKey_schedule-response.xml +52 -0
  105. package/test/resources/9999999/automation/schedule-a8afb0e2-b00a-4c88-ad2e-1f7f8788c560-response.xml +52 -0
  106. package/test/resources/9999999/automation/template-expected.json +57 -0
  107. package/test/resources/9999999/automation/update-expected.json +45 -0
  108. package/test/resources/9999999/automation/update-testExisting_automation-expected.md +28 -0
  109. package/test/resources/9999999/automation/v1/automations/08afb0e2-b00a-4c88-ad2e-1f7f8788c560/get-response.json +85 -0
  110. package/test/resources/9999999/automation/v1/automations/08afb0e2-b00a-4c88-ad2e-1f7f8788c560/patch-response.json +85 -0
  111. package/test/resources/9999999/automation/v1/automations/08afb0e2-b00a-4c88-ad2e-pause/get-response.json +85 -0
  112. package/test/resources/9999999/automation/v1/automations/08afb0e2-b00a-4c88-ad2e-pause/patch-response.json +85 -0
  113. package/test/resources/9999999/automation/v1/automations/08afb0e2-b00a-4c88-fixKey_pause/get-response.json +85 -0
  114. package/test/resources/9999999/automation/v1/automations/08afb0e2-b00a-4c88-fixKey_pause/patch-response.json +85 -0
  115. package/test/resources/9999999/automation/v1/automations/08afb0e2-b00a-4c88-fixKey_schedule/get-response.json +85 -0
  116. package/test/resources/9999999/automation/v1/automations/08afb0e2-b00a-4c88-fixKey_schedule/patch-response.json +85 -0
  117. package/test/resources/9999999/automation/v1/automations/a8afb0e2-b00a-4c88-ad2e-1f7f8788c560/get-response.json +85 -0
  118. package/test/resources/9999999/automation/v1/automations/post-response.json +86 -0
  119. package/test/resources/9999999/automation/v1/dataextracts/56c5370a-f988-4f36-b0ee-0f876573f6d7/get-response.json +38 -0
  120. package/test/resources/9999999/automation/v1/dataextracts/56c5370a-f988-4f36-b0ee-0f876573f6d7/patch-response.json +38 -0
  121. package/test/resources/9999999/automation/v1/dataextracts/get-response.json +20 -0
  122. package/test/resources/9999999/automation/v1/dataextracts/post-response.json +38 -0
  123. package/test/resources/9999999/automation/v1/dataextracttypes/get-response.json +50 -0
  124. package/test/resources/9999999/automation/v1/filetransfers/72c328ac-f5b0-4e37-91d3-a775666f15a6/get-response.json +18 -0
  125. package/test/resources/9999999/automation/v1/filetransfers/72c328ac-f5b0-4e37-91d3-a775666f15a6/patch-response.json +18 -0
  126. package/test/resources/9999999/automation/v1/filetransfers/get-response.json +15 -0
  127. package/test/resources/9999999/automation/v1/filetransfers/post-response.json +18 -0
  128. package/test/resources/9999999/automation/v1/ftplocations/get-response.json +18 -0
  129. package/test/resources/9999999/automation/v1/imports/9d16f42c-2260-ed11-b849-48df37d1de8b/patch-response.json +31 -0
  130. package/test/resources/9999999/automation/v1/imports/get-response.json +38 -0
  131. package/test/resources/9999999/automation/v1/imports/post-response.json +30 -0
  132. package/test/resources/9999999/automation/v1/queries/549f0568-607c-4940-afef-437965094dae/actions/start/post-response.txt +1 -0
  133. package/test/resources/9999999/automation/v1/queries/549f0568-607c-4940-afef-437965094dat/actions/start/post-response.txt +1 -0
  134. package/test/resources/9999999/automation/v1/queries/549f0568-607c-4940-afef-437965094dat/get-response.json +2 -2
  135. package/test/resources/9999999/automation/v1/queries/549f0568-607c-4940-afef-437965094dat/patch-response.json +2 -2
  136. package/test/resources/9999999/automation/v1/queries/549f0568-607c-4940-afef-437965094dat_fixKeys/get-response.json +17 -0
  137. package/test/resources/9999999/automation/v1/queries/549f0568-607c-4940-afef-437965094dat_fixKeys/patch-response.json +18 -0
  138. package/test/resources/9999999/automation/v1/queries/get-response.json +22 -5
  139. package/test/resources/9999999/automation/v1/queries/post-response.json +2 -2
  140. package/test/resources/9999999/automation/v1/scripts/39f6a488-20eb-4ba0-b0b9-023725b574e4/patch-response.json +10 -0
  141. package/test/resources/9999999/automation/v1/scripts/get-response.json +27 -0
  142. package/test/resources/9999999/automation/v1/scripts/post-response.json +10 -0
  143. package/test/resources/9999999/dataExtension/retrieve-Name=testExisting_dataExtension-response.xml +52 -0
  144. package/test/resources/9999999/dataExtensionField/retrieve-DataExtension.CustomerKey=testExisting_dataExtension-response.xml +98 -0
  145. package/test/resources/9999999/dataExtensionField/retrieve-DataExtension.CustomerKey=testNew_dataExtensionORDataExtension.CustomerKey=testExisting_dataExtension-response.xml +99 -0
  146. package/test/resources/9999999/dataExtract/build-expected.json +35 -0
  147. package/test/resources/9999999/dataExtract/get-expected.json +39 -0
  148. package/test/resources/9999999/dataExtract/patch-expected.json +37 -0
  149. package/test/resources/9999999/dataExtract/post-expected.json +37 -0
  150. package/test/resources/9999999/dataExtract/template-expected.json +35 -0
  151. package/test/resources/9999999/dataFolder/retrieve-ContentType=automations-response.xml +48 -0
  152. package/test/resources/9999999/dataFolder/retrieve-ContentType=contextual_suppression_listORContentType=publicationORContentType=suppression_listORContentType=mysubsORContentType=list-response.xml +136 -0
  153. package/test/resources/9999999/dataFolder/retrieve-ContentType=queryactivity-response.xml +48 -0
  154. package/test/resources/9999999/dataFolder/retrieve-ContentType=ssjsactivity-response.xml +48 -0
  155. package/test/resources/9999999/dataFolder/retrieve-ContentType=triggered_send_journeybuilderORContentType=triggered_sendORContentType=hidden-response.xml +276 -0
  156. package/test/resources/9999999/dataFolder/retrieve-response.xml +45 -0
  157. package/test/resources/9999999/email/retrieve-response.xml +203 -0
  158. package/test/resources/9999999/emailSendDefinition/retrieve-IsPlatformObject=falseANDDescriptionnotEqualsSFSendDefinition-response.xml +85 -0
  159. package/test/resources/9999999/fileTransfer/build-expected.json +15 -0
  160. package/test/resources/9999999/fileTransfer/get-expected.json +17 -0
  161. package/test/resources/9999999/fileTransfer/patch-expected.json +17 -0
  162. package/test/resources/9999999/fileTransfer/post-expected.json +17 -0
  163. package/test/resources/9999999/fileTransfer/template-expected.json +15 -0
  164. package/test/resources/9999999/hub/v1/contacts/schema/attributeGroups/get-response.json +585 -0
  165. package/test/resources/9999999/hub/v1/contacts/schema/setDefinitions/get-response.json +19807 -0
  166. package/test/resources/9999999/importFile/build-expected.json +27 -0
  167. package/test/resources/9999999/importFile/get-expected.json +29 -0
  168. package/test/resources/9999999/importFile/patch-expected.json +29 -0
  169. package/test/resources/9999999/importFile/post-expected.json +29 -0
  170. package/test/resources/9999999/importFile/template-expected.json +27 -0
  171. package/test/resources/9999999/legacy/v1/beta/automations/notifications/RkpOcE9qSVh2VUdnYTVJbWFfWW14dzoyNTow/get-response.json +21 -0
  172. package/test/resources/9999999/legacy/v1/beta/automations/notifications/RkpOcE9qSVh2VUdnYTVJbWFfWW14dzoyNTow/post-response.json +0 -0
  173. package/test/resources/9999999/legacy/v1/beta/bulk/automations/automation/definition/get-response.json +30 -0
  174. package/test/resources/9999999/program/retrieve-CustomerKey=testExisting_automation-response.xml +30 -0
  175. package/test/resources/9999999/program/retrieve-CustomerKey=testExisting_automation_fixKey_pause-response.xml +32 -0
  176. package/test/resources/9999999/program/retrieve-CustomerKey=testExisting_automation_fixKey_schedule-response.xml +32 -0
  177. package/test/resources/9999999/program/retrieve-CustomerKey=testExisting_automation_fixedKey_paused-response.xml +32 -0
  178. package/test/resources/9999999/program/retrieve-CustomerKey=testExisting_automation_fixedKey_scheduled-response.xml +32 -0
  179. package/test/resources/9999999/program/retrieve-CustomerKey=testExisting_automation_pause-response.xml +30 -0
  180. package/test/resources/9999999/program/retrieve-CustomerKey=testNew_automation-response.xml +30 -0
  181. package/test/resources/9999999/program/retrieve-Name=testExisting_automation-response.xml +31 -0
  182. package/test/resources/9999999/program/retrieve-response.xml +50 -0
  183. package/test/resources/9999999/query/build-expected.json +2 -2
  184. package/test/resources/9999999/query/get-expected.json +2 -2
  185. package/test/resources/9999999/query/get2-expected.json +2 -2
  186. package/test/resources/9999999/query/patch-expected.json +2 -2
  187. package/test/resources/9999999/query/patch_fixKeys-expected.json +11 -0
  188. package/test/resources/9999999/query/patch_fixKeys-expected.sql +6 -0
  189. package/test/resources/9999999/query/post-expected.json +2 -2
  190. package/test/resources/9999999/query/template-expected.json +2 -2
  191. package/test/resources/9999999/queryDefinition/retrieve-CustomerKey=testExisting_query_fixKeysANDStatus=Active-response.xml +30 -0
  192. package/test/resources/9999999/queryDefinition/retrieve-CustomerKey=testExisting_query_fixedKeysANDStatus=Active-response.xml +30 -0
  193. package/test/resources/9999999/queryDefinition/retrieve-CustomerKey=testNew_queryANDStatus=Active-response.xml +30 -0
  194. package/test/resources/9999999/script/build-expected.json +6 -0
  195. package/test/resources/9999999/script/build-expected.ssjs +1 -0
  196. package/test/resources/9999999/script/get-expected.json +8 -0
  197. package/test/resources/9999999/script/get-expected.ssjs +1 -0
  198. package/test/resources/9999999/script/get_noScriptTag-expected.html +1 -0
  199. package/test/resources/9999999/script/get_noScriptTag-expected.json +8 -0
  200. package/test/resources/9999999/script/patch-expected.json +8 -0
  201. package/test/resources/9999999/script/patch-expected.ssjs +1 -0
  202. package/test/resources/9999999/script/post-expected.json +8 -0
  203. package/test/resources/9999999/script/post-expected.ssjs +1 -0
  204. package/test/resources/9999999/script/template-expected.json +6 -0
  205. package/test/resources/9999999/script/template-expected.ssjs +1 -0
  206. package/test/resources/9999999/triggeredSend/build-expected.json +29 -0
  207. package/test/resources/9999999/triggeredSend/get-expected.json +29 -0
  208. package/test/resources/9999999/triggeredSend/patch-expected.json +29 -0
  209. package/test/resources/9999999/triggeredSend/post-expected.json +29 -0
  210. package/test/resources/9999999/triggeredSend/template-expected.json +29 -0
  211. package/test/resources/9999999/triggeredSendDefinition/create-response.xml +75 -0
  212. package/test/resources/9999999/triggeredSendDefinition/delete-response.xml +36 -0
  213. package/test/resources/9999999/triggeredSendDefinition/{retrieve-response.xml → retrieve-TriggeredSendStatusINNew,Active,Inactive,Moved,Canceled-response.xml} +4 -4
  214. package/test/resources/9999999/triggeredSendDefinition/update-response.xml +74 -0
  215. package/test/type.attributeGroup.test.js +55 -0
  216. package/test/type.attributeSet.test.js +55 -0
  217. package/test/type.automation.test.js +886 -0
  218. package/test/type.dataExtension.test.js +3 -1
  219. package/test/type.dataExtract.test.js +187 -0
  220. package/test/type.fileTransfer.test.js +185 -0
  221. package/test/type.importFile.test.js +186 -0
  222. package/test/type.mobileKeyword.test.js +0 -1
  223. package/test/type.query.test.js +497 -33
  224. package/test/type.script.test.js +367 -0
  225. package/test/type.triggeredSend.test.js +152 -0
  226. package/test/type.user.test.js +37 -11
  227. package/test/utils.js +10 -6
  228. package/.coverage-comment-template.md +0 -20
  229. package/lib/metadataTypes/SetDefinition.js +0 -37
  230. /package/test/mockRoot/deploy/testInstance/testBU/query/{testExistingQuery.query-meta.sql → testExisting_query.query-meta.sql} +0 -0
  231. /package/test/mockRoot/deploy/testInstance/testBU/query/{testNewQuery.query-meta.sql → testNew_query.query-meta.sql} +0 -0
  232. /package/test/resources/1111111/accountUser/{retrieve-response.xml → retrieve-ActiveFlag=trueANDCustomerKey=testExisting_userANDEmaillike@-response.xml} +0 -0
  233. /package/test/resources/1111111/accountUserAccount/{retrieve-response.xml → retrieve-AccountUser.AccountUserIDIN700301950,700301951,7471228-response.xml} +0 -0
  234. /package/test/resources/1111111/businessUnit/{retrieve-response.xml → retrieve-ID=1111111-response.xml} +0 -0
  235. /package/test/resources/1111111/list/{retrieve-response.xml → retrieve-CustomerKey=All SubscribersORListName=All Subscribers-response.xml} +0 -0
  236. /package/test/resources/1111111/role/{retrieve-response.xml → retrieve-IsPrivate=false-response.xml} +0 -0
  237. /package/test/resources/9999999/queryDefinition/{retrieve-response.xml → retrieve-CustomerKey=testExisting_queryANDStatus=Active-response.xml} +0 -0
@@ -59,8 +59,8 @@ class DataExtension extends MetadataType {
59
59
  // output error & remove from deploy list
60
60
  Util.logger.error(
61
61
  ` ☇ skipping ${this.definition.type} ${
62
- metadataMap[this.definition.keyField]
63
- } / ${metadataMap[this.definition.nameField]}: ${ex.message}`
62
+ metadataMap[metadataKey][this.definition.keyField]
63
+ } / ${metadataMap[metadataKey][this.definition.nameField]}: ${ex.message}`
64
64
  );
65
65
  delete metadataMap[metadataKey];
66
66
  // skip rest of handling for this DE
@@ -203,7 +203,7 @@ class DataExtension extends MetadataType {
203
203
  }
204
204
  }
205
205
  /**
206
- * helper for {@link upsert}
206
+ * helper for {@link DataExtension.upsert}
207
207
  *
208
208
  * @private
209
209
  * @param {object} res -
@@ -607,7 +607,7 @@ class DataExtension extends MetadataType {
607
607
  metadata[customerKey].Fields = fieldArr;
608
608
  }
609
609
  /**
610
- * helper for {@link super.updateREST} and {@link super.updateSOAP} that removes old files after the key was changed
610
+ * helper for {@link MetadataType.updateREST} and {@link MetadataType.updateSOAP} that removes old files after the key was changed
611
611
  *
612
612
  * @private
613
613
  * @param {TYPE.MetadataTypeItem} metadataEntry a single metadata Entry
@@ -624,16 +624,16 @@ class DataExtension extends MetadataType {
624
624
  * @returns {Promise.<TYPE.DataExtensionItem>} Promise of updated single DE
625
625
  */
626
626
  static async preDeployTasks(metadata) {
627
- if (metadata.Name.startsWith('_')) {
627
+ if (metadata.Name?.startsWith('_')) {
628
628
  throw new Error(`Cannot Upsert Strongly Typed Data Extensions`);
629
629
  }
630
630
  if (
631
631
  this.buObject.eid !== this.buObject.mid &&
632
- metadata.r__folder_Path.startsWith('Shared Items')
632
+ metadata.r__folder_Path?.startsWith('Shared Items')
633
633
  ) {
634
634
  throw new Error(`Cannot Create/Update a Shared Data Extension from the Child BU`);
635
635
  }
636
- if (metadata.r__folder_Path.startsWith('Synchronized Data Extensions')) {
636
+ if (metadata.r__folder_Path?.startsWith('Synchronized Data Extensions')) {
637
637
  throw new Error(
638
638
  `Cannot Create/Update a Synchronized Data Extension. Please use Contact Builder to maintain these`
639
639
  );
@@ -31,7 +31,7 @@ class DataExtensionField extends MetadataType {
31
31
  return super.retrieveSOAP(null, requestParams, null, additionalFields);
32
32
  }
33
33
  /**
34
- * helper for {@link DataExtension._retrieveFieldsForSingleDe} that sorts the fields into an array
34
+ * helper for DataExtension.retrieveFieldsForSingleDe that sorts the fields into an array
35
35
  *
36
36
  * @param {TYPE.DataExtensionFieldMap} fieldsObj customerKey-based list of fields for one dataExtension
37
37
  * @returns {TYPE.DataExtensionFieldItem[]} sorted array of field objects
@@ -136,12 +136,11 @@ class Event extends MetadataType {
136
136
  * @param {TYPE.MetadataTypeMap} metadata metadata mapped by their keyField
137
137
  * @param {string} deployDir directory where deploy metadata are saved
138
138
  * @param {string} retrieveDir directory where metadata after deploy should be saved
139
- * @param {boolean} [isRefresh] optional flag - so far not used by eventDefinition
140
139
  * @returns {Promise.<TYPE.MetadataTypeMap>} Promise of keyField => metadata map
141
140
  */
142
- static async deploy(metadata, deployDir, retrieveDir, isRefresh) {
141
+ static async deploy(metadata, deployDir, retrieveDir) {
143
142
  Util.logBeta(this.definition.type);
144
- return super.deploy(metadata, deployDir, retrieveDir, isRefresh);
143
+ return super.deploy(metadata, deployDir, retrieveDir);
145
144
  }
146
145
 
147
146
  /**
@@ -452,7 +452,7 @@ class Folder extends MetadataType {
452
452
  * Returns file contents mapped to their filename without '.json' ending
453
453
  *
454
454
  * @param {string} dir directory that contains '.json' files to be read
455
- * @param {boolean} [listBadKeys=false] do not print errors, used for badKeys()
455
+ * @param {boolean} [listBadKeys] do not print errors, used for badKeys()
456
456
  * @returns {TYPE.MetadataTypeMap} fileName => fileContent map
457
457
  */
458
458
  static getJsonFromFS(dir, listBadKeys) {
@@ -216,12 +216,11 @@ class Journey extends MetadataType {
216
216
  * @param {TYPE.MetadataTypeMap} metadata metadata mapped by their keyField
217
217
  * @param {string} deployDir directory where deploy metadata are saved
218
218
  * @param {string} retrieveDir directory where metadata after deploy should be saved
219
- * @param {boolean} [isRefresh] optional flag - so far not used by interaction
220
219
  * @returns {Promise.<TYPE.MetadataTypeMap>} Promise of keyField => metadata map
221
220
  */
222
- static async deploy(metadata, deployDir, retrieveDir, isRefresh) {
221
+ static async deploy(metadata, deployDir, retrieveDir) {
223
222
  Util.logBeta(this.definition.type);
224
- return super.deploy(metadata, deployDir, retrieveDir, isRefresh);
223
+ return super.deploy(metadata, deployDir, retrieveDir);
225
224
  }
226
225
 
227
226
  /**
@@ -265,7 +264,7 @@ class Journey extends MetadataType {
265
264
  }
266
265
 
267
266
  /**
268
- * helper for Journey's {@link saveResults}. Gets executed after retreive of metadata type and
267
+ * helper for Journey's {@link Journey.saveResults}. Gets executed after retreive of metadata type and
269
268
  *
270
269
  * @param {TYPE.MetadataTypeMap} metadataMap key=customer key, value=metadata
271
270
  */
@@ -478,7 +477,7 @@ class Journey extends MetadataType {
478
477
  return metadata;
479
478
  }
480
479
  /**
481
- * helper for {@link postRetrieveTasks}
480
+ * helper for {@link Journey.postRetrieveTasks}
482
481
  *
483
482
  * @private
484
483
  * @param {TYPE.MetadataTypeItem} metadata a single item
@@ -800,7 +799,7 @@ class Journey extends MetadataType {
800
799
  }
801
800
 
802
801
  /**
803
- * helper for {@link preDeployTasks}
802
+ * helper for {@link Journey.preDeployTasks}
804
803
  *
805
804
  * @private
806
805
  * @param {TYPE.MetadataTypeItem} metadata a single item
@@ -35,7 +35,7 @@ class MetadataType {
35
35
  * Returns file contents mapped to their filename without '.json' ending
36
36
  *
37
37
  * @param {string} dir directory that contains '.json' files to be read
38
- * @param {boolean} [listBadKeys=false] do not print errors, used for badKeys()
38
+ * @param {boolean} [listBadKeys] do not print errors, used for badKeys()
39
39
  * @returns {TYPE.MetadataTypeMap} fileName => fileContent map
40
40
  */
41
41
  static getJsonFromFS(dir, listBadKeys) {
@@ -58,15 +58,9 @@ class MetadataType {
58
58
  if (key === fileNameWithoutEnding || listBadKeys) {
59
59
  fileName2FileContent[fileNameWithoutEnding] = fileContent;
60
60
  } else {
61
- Util.metadataLogger(
62
- 'error',
63
- this.definition.type,
64
- 'getJsonFromFS',
65
- 'Name of the Metadata and the External Identifier must match',
66
- JSON.stringify({
67
- Filename: fileNameWithoutEnding,
68
- ExternalIdentifier: key,
69
- })
61
+ Util.logger.error(
62
+ ` ${this.definition.type} ${key}: Name of the metadata file and the JSON-key (${this.definition.keyField}) must match` +
63
+ Util.getGrayMsg(` - ${dir}/${fileName}`)
70
64
  );
71
65
  }
72
66
  }
@@ -114,11 +108,10 @@ class MetadataType {
114
108
  * @param {TYPE.MetadataTypeMap} metadata metadata mapped by their keyField
115
109
  * @param {string} deployDir directory where deploy metadata are saved
116
110
  * @param {string} retrieveDir directory where metadata after deploy should be saved
117
- * @param {boolean} [isRefresh] optional flag to indicate that triggeredSend should be refreshed after deployment of assets
118
111
  * @returns {Promise.<TYPE.MetadataTypeMap>} Promise of keyField => metadata map
119
112
  */
120
- static async deploy(metadata, deployDir, retrieveDir, isRefresh) {
121
- const upsertResults = await this.upsert(metadata, deployDir, isRefresh);
113
+ static async deploy(metadata, deployDir, retrieveDir) {
114
+ const upsertResults = await this.upsert(metadata, deployDir);
122
115
  const savedMetadata = await this.saveResults(upsertResults, retrieveDir, null);
123
116
  if (
124
117
  this.properties.metaDataTypes.documentOnRetrieve.includes(this.definition.type) &&
@@ -137,13 +130,12 @@ class MetadataType {
137
130
  * @param {TYPE.MetadataTypeMap} upsertResults metadata mapped by their keyField as returned by update/create
138
131
  * @param {TYPE.MetadataTypeMap} originalMetadata metadata to be updated (contains additioanl fields)
139
132
  * @param {{created: number, updated: number}} createdUpdated counter representing successful creates/updates
140
- * @param {boolean} [isRefresh] optional flag to indicate that triggeredSend should be refreshed after deployment of assets
141
133
  * @returns {void}
142
134
  */
143
- static postDeployTasks(upsertResults, originalMetadata, createdUpdated, isRefresh) {}
135
+ static postDeployTasks(upsertResults, originalMetadata, createdUpdated) {}
144
136
 
145
137
  /**
146
- * helper for {@link createREST}
138
+ * helper for {@link MetadataType.createREST}
147
139
  *
148
140
  * @param {TYPE.MetadataTypeItem} metadataEntry a single metadata Entry
149
141
  * @param {object} apiResponse varies depending on the API call
@@ -152,7 +144,7 @@ class MetadataType {
152
144
  static postCreateTasks(metadataEntry, apiResponse) {}
153
145
 
154
146
  /**
155
- * helper for {@link updateREST}
147
+ * helper for {@link MetadataType.updateREST}
156
148
  *
157
149
  * @param {TYPE.MetadataTypeItem} metadataEntry a single metadata Entry
158
150
  * @param {object} apiResponse varies depending on the API call
@@ -161,7 +153,7 @@ class MetadataType {
161
153
  static postUpdateTasks(metadataEntry, apiResponse) {}
162
154
 
163
155
  /**
164
- * helper for {@link createREST} when legacy API endpoints as these do not return the created item but only their new id
156
+ * helper for {@link MetadataType.createREST} when legacy API endpoints as these do not return the created item but only their new id
165
157
  *
166
158
  * @param {TYPE.MetadataTypeItem} metadataEntry a single metadata Entry
167
159
  * @param {object} apiResponse varies depending on the API call
@@ -460,6 +452,29 @@ class MetadataType {
460
452
  return;
461
453
  }
462
454
 
455
+ /**
456
+ * Abstract execute method that needs to be implemented in child metadata type
457
+ *
458
+ * @returns {void}
459
+ */
460
+ static execute() {
461
+ Util.logger.error(
462
+ ` ☇ skipping ${this.definition.type}: execute is not supported yet for ${this.definition.type}`
463
+ );
464
+ return [];
465
+ }
466
+ /**
467
+ * Abstract pause method that needs to be implemented in child metadata type
468
+ *
469
+ * @returns {void}
470
+ */
471
+ static pause() {
472
+ Util.logger.error(
473
+ ` ☇ skipping ${this.definition.type}: pause is not supported yet for ${this.definition.type}`
474
+ );
475
+ return [];
476
+ }
477
+
463
478
  /**
464
479
  * test if metadata was actually changed or not to potentially skip it during deployment
465
480
  *
@@ -531,10 +546,9 @@ class MetadataType {
531
546
  *
532
547
  * @param {TYPE.MetadataTypeMap} metadataMap metadata mapped by their keyField
533
548
  * @param {string} deployDir directory where deploy metadata are saved
534
- * @param {boolean} [isRefresh] optional flag to indicate that triggeredSend should be refreshed after deployment of assets
535
549
  * @returns {Promise.<TYPE.MetadataTypeMap>} keyField => metadata map
536
550
  */
537
- static async upsert(metadataMap, deployDir, isRefresh) {
551
+ static async upsert(metadataMap, deployDir) {
538
552
  const orignalMetadataMap = JSON.parse(JSON.stringify(metadataMap));
539
553
  const metadataToUpdate = [];
540
554
  const metadataToCreate = [];
@@ -626,12 +640,10 @@ class MetadataType {
626
640
  const metadataResults = createResults.concat(updateResults).filter(Boolean);
627
641
  upsertResults = this.parseResponseBody(metadataResults);
628
642
  }
629
- await this.postDeployTasks(
630
- upsertResults,
631
- orignalMetadataMap,
632
- { created: createResults.length, updated: updateResults.length },
633
- isRefresh
634
- );
643
+ await this.postDeployTasks(upsertResults, orignalMetadataMap, {
644
+ created: createResults.length,
645
+ updated: updateResults.length,
646
+ });
635
647
  return upsertResults;
636
648
  }
637
649
 
@@ -650,6 +662,7 @@ class MetadataType {
650
662
  metadataMap[metadataKey][this.definition.keyField]
651
663
  );
652
664
  // Update if it already exists; Create it if not
665
+ const maxKeyLength = this.definition.maxKeyLength || 36;
653
666
  if (
654
667
  Util.logger.level === 'debug' &&
655
668
  metadataMap[metadataKey][this.definition.idField] &&
@@ -703,11 +716,11 @@ class MetadataType {
703
716
  // NOTE: trim twice while getting the newKey value to remove leading spaces before limiting the length
704
717
  const newKey = (metadataMap[metadataKey][Util.OPTIONS.changeKeyField] + '')
705
718
  .trim()
706
- .slice(0, 36)
719
+ .slice(0, maxKeyLength)
707
720
  .trim();
708
- if (metadataMap[metadataKey][Util.OPTIONS.changeKeyField] + '' > 36) {
721
+ if (metadataMap[metadataKey][Util.OPTIONS.changeKeyField] + '' > maxKeyLength) {
709
722
  Util.logger.warn(
710
- `Customer Keys may not exceed 36 characters. Truncated the value in field ${Util.OPTIONS.changeKeyField} to ${newKey}`
723
+ `${this.definition.type} ${this.definition.keyField} may not exceed ${maxKeyLength} characters. Truncated the value in field ${Util.OPTIONS.changeKeyField} to ${newKey}`
711
724
  );
712
725
  }
713
726
  if (metadataKey == newKey) {
@@ -727,10 +740,10 @@ class MetadataType {
727
740
  }
728
741
  } else if (Util.OPTIONS.changeKeyValue) {
729
742
  // NOTE: trim twice while getting the newKey value to remove leading spaces before limiting the length
730
- const newKey = Util.OPTIONS.changeKeyValue.trim().slice(0, 36).trim();
731
- if (Util.OPTIONS.changeKeyValue.trim().length > 36) {
743
+ const newKey = Util.OPTIONS.changeKeyValue.trim().slice(0, maxKeyLength).trim();
744
+ if (Util.OPTIONS.changeKeyValue.trim().length > maxKeyLength) {
732
745
  Util.logger.warn(
733
- `Customer Keys may not exceed 36 characters. Truncated your value to ${newKey}`
746
+ `${this.definition.type} ${this.definition.keyField} may not exceed ${maxKeyLength} characters. Truncated your value to ${newKey}`
734
747
  );
735
748
  }
736
749
  if (this.definition.keyField == this.definition.idField) {
@@ -808,7 +821,7 @@ class MetadataType {
808
821
  );
809
822
  return response;
810
823
  } catch (ex) {
811
- const parsedErrors = this.checkForErrors(ex);
824
+ const parsedErrors = this.getErrorsREST(ex);
812
825
  Util.logger.error(
813
826
  ` ☇ error creating ${this.definition.type} ${
814
827
  metadataEntry[this.definition.keyField] ||
@@ -838,7 +851,7 @@ class MetadataType {
838
851
  this.removeNotCreateableFields(metadataEntry);
839
852
  try {
840
853
  const response = await this.client.soap.create(
841
- soapType.charAt(0).toUpperCase() + soapType.slice(1),
854
+ Util.capitalizeFirstLetter(soapType),
842
855
  metadataEntry,
843
856
  null
844
857
  );
@@ -862,7 +875,7 @@ class MetadataType {
862
875
  *
863
876
  * @param {TYPE.MetadataTypeItem} metadataEntry a single metadata Entry
864
877
  * @param {string} uri rest endpoint for PATCH
865
- * @param {'patch'|'post'|'put'} [httpMethod='patch'] defaults to 'patch'; some update requests require PUT instead of PATCH
878
+ * @param {'patch'|'post'|'put'} [httpMethod] defaults to 'patch'; some update requests require PUT instead of PATCH
866
879
  * @returns {Promise.<object> | null} Promise of API response or null in case of an error
867
880
  */
868
881
  static async updateREST(metadataEntry, uri, httpMethod = 'patch') {
@@ -871,7 +884,7 @@ class MetadataType {
871
884
  // set to empty object in case API returned nothing to be able to update it in helper classes
872
885
  const response = (await this.client.rest[httpMethod](uri, metadataEntry)) || {};
873
886
  await this._postChangeKeyTasks(metadataEntry);
874
- this.checkForErrors(response);
887
+ this.getErrorsREST(response);
875
888
  await this.postUpdateTasks(metadataEntry, response);
876
889
  // some times, e.g. automation dont return a key in their update response and hence we need to fall back to name
877
890
  Util.logger.info(
@@ -882,7 +895,7 @@ class MetadataType {
882
895
  );
883
896
  return response;
884
897
  } catch (ex) {
885
- const parsedErrors = this.checkForErrors(ex);
898
+ const parsedErrors = this.getErrorsREST(ex);
886
899
  Util.logger.error(
887
900
  ` ☇ error updating ${this.definition.type} ${
888
901
  metadataEntry[this.definition.keyField] ||
@@ -897,7 +910,7 @@ class MetadataType {
897
910
  }
898
911
 
899
912
  /**
900
- * helper for {@link updateREST} and {@link updateSOAP} that removes old files after the key was changed
913
+ * helper for {@link MetadataType.updateREST} and {@link MetadataType.updateSOAP} that removes old files after the key was changed
901
914
  *
902
915
  * @private
903
916
  * @param {TYPE.MetadataTypeItem} metadataEntry a single metadata Entry
@@ -943,7 +956,7 @@ class MetadataType {
943
956
  this.removeNotUpdateableFields(metadataEntry);
944
957
  try {
945
958
  const response = await this.client.soap.update(
946
- soapType.charAt(0).toUpperCase() + soapType.slice(1),
959
+ Util.capitalizeFirstLetter(soapType),
947
960
  metadataEntry,
948
961
  null
949
962
  );
@@ -978,15 +991,20 @@ class MetadataType {
978
991
  }
979
992
  }
980
993
  /**
981
- * helper for {@link _handleSOAPErrors}
994
+ * helper for {@link MetadataType._handleSOAPErrors}
982
995
  *
983
996
  * @param {Error} ex error that occured
984
997
  * @returns {string} error message
985
998
  */
986
999
  static getSOAPErrorMsg(ex) {
987
- return ex?.json?.Results?.length
988
- ? `${ex.json.Results[0].StatusMessage} (Code ${ex.json.Results[0].ErrorCode})`
989
- : ex.message;
1000
+ if (ex?.json?.Results?.length) {
1001
+ if (ex?.json?.Results[0].StatusMessage) {
1002
+ return `${ex.json.Results[0].StatusMessage} (Code ${ex.json.Results[0].ErrorCode})`;
1003
+ } else if (ex?.json?.Results[0].Result.StatusMessage) {
1004
+ return `${ex.json.Results[0].Result.StatusMessage} (Code ${ex.json.Results[0].Result.ErrorCode})`;
1005
+ }
1006
+ }
1007
+ return ex.message;
990
1008
  }
991
1009
  /**
992
1010
  * Retrieves SOAP via generic fuel-soap wrapper based metadata of metadata type into local filesystem. executes callback with retrieved metadata
@@ -1003,7 +1021,11 @@ class MetadataType {
1003
1021
  const soapType = this.definition.soapType || this.definition.type;
1004
1022
  let response;
1005
1023
  try {
1006
- response = await this.client.soap.retrieveBulk(soapType, fields, requestParams);
1024
+ response = await this.client.soap.retrieveBulk(
1025
+ Util.capitalizeFirstLetter(soapType),
1026
+ fields,
1027
+ requestParams
1028
+ );
1007
1029
  } catch (ex) {
1008
1030
  this._handleSOAPErrors(ex, 'retrieving');
1009
1031
  return {};
@@ -1066,9 +1088,61 @@ class MetadataType {
1066
1088
  type: this.definition.type,
1067
1089
  };
1068
1090
  }
1091
+ /**
1092
+ * Used to execute a query/automation etc.
1093
+ *
1094
+ * @param {string} uri REST endpoint where the POST request should be sent
1095
+ * @param {string} key item key
1096
+ * @returns {Promise.<{key:string, response:string}>} metadata key and API response (OK or error)
1097
+ */
1098
+ static async executeREST(uri, key) {
1099
+ try {
1100
+ const response = await this.client.rest.post(uri, {}); // payload is empty for this request
1101
+ if (response === 'OK') {
1102
+ Util.logger.info(` - executed ${this.definition.type}: ${key}`);
1103
+ } else {
1104
+ throw new Error(response);
1105
+ }
1106
+ return { key, response };
1107
+ } catch (ex) {
1108
+ Util.logger.error(`Failed to execute ${this.definition.type} ${key}: ${ex.message}`);
1109
+ }
1110
+ }
1069
1111
 
1070
1112
  /**
1071
- * helper for {@link retrieveREST} and {@link retrieveSOAP}
1113
+ * Used to execute a query/automation etc.
1114
+ *
1115
+ * @param {TYPE.MetadataTypeItem} [metadataEntry] single metadata entry
1116
+ * @returns {Promise.<{key:string, response:object}>} metadata key and API response
1117
+ */
1118
+ static async executeSOAP(metadataEntry) {
1119
+ const soapType = this.definition.soapType || this.definition.type;
1120
+ try {
1121
+ const response = await this.client.soap.perform(
1122
+ Util.capitalizeFirstLetter(soapType),
1123
+ 'start',
1124
+ {
1125
+ ObjectID: metadataEntry[this.definition.idField],
1126
+ }
1127
+ );
1128
+ if (response?.OverallStatus === 'OK') {
1129
+ Util.logger.info(
1130
+ ` - executed ${this.definition.type}: ${
1131
+ metadataEntry[this.definition.keyField]
1132
+ }`
1133
+ );
1134
+ } else {
1135
+ throw new Error(response?.OverallStatus);
1136
+ }
1137
+ return { key: metadataEntry[this.definition.keyField], response };
1138
+ } catch (ex) {
1139
+ this._handleSOAPErrors(ex, 'executing', metadataEntry);
1140
+ return null;
1141
+ }
1142
+ }
1143
+
1144
+ /**
1145
+ * helper for {@link MetadataType.retrieveREST} and {@link MetadataType.retrieveSOAP}
1072
1146
  *
1073
1147
  * @param {string|number} [singleRetrieve] key of single item to filter by
1074
1148
  * @param {TYPE.MetadataTypeMap} metadataMap saved metadata
@@ -1271,7 +1345,7 @@ class MetadataType {
1271
1345
  *
1272
1346
  * @static
1273
1347
  * @param {TYPE.MetadataTypeItem} metadataEntry metadata entry
1274
- * @param {boolean} [include=false] true: use definition.include / options.include; false=exclude: use definition.filter / options.exclude
1348
+ * @param {boolean} [include] true: use definition.include / options.include; false=exclude: use definition.filter / options.exclude
1275
1349
  * @returns {boolean} true: skip saving == filtered; false: continue with saving
1276
1350
  * @memberof MetadataType
1277
1351
  */
@@ -1316,7 +1390,7 @@ class MetadataType {
1316
1390
  *
1317
1391
  * @static
1318
1392
  * @param {object} metadataEntry metadata entry
1319
- * @param {boolean} [include=false] true: use definition.include / options.include; false=exclude: use definition.filter / options.exclude
1393
+ * @param {boolean} [include] true: use definition.include / options.include; false=exclude: use definition.filter / options.exclude
1320
1394
  * @returns {boolean} true: filtered == do NOT save; false: not filtered == do save
1321
1395
  * @memberof MetadataType
1322
1396
  */
@@ -1548,6 +1622,10 @@ class MetadataType {
1548
1622
  }
1549
1623
  }
1550
1624
 
1625
+ if (Util.OPTIONS.like && !Util.fieldsLike(results[originalKey])) {
1626
+ Util.logger.debug(`Filtered ${originalKey} because of --like option`);
1627
+ continue;
1628
+ }
1551
1629
  // we dont store Id on local disk, but we need it for caching logic,
1552
1630
  // so its in retrieve but not in save. Here we put into the clone so that the original
1553
1631
  // object used for caching doesnt have the Id removed.
@@ -1594,7 +1672,7 @@ class MetadataType {
1594
1672
  return savedResults;
1595
1673
  }
1596
1674
  /**
1597
- * helper for {@link buildDefinitionForNested}
1675
+ * helper for {@link MetadataType.buildDefinitionForNested}
1598
1676
  * searches extracted file for template variable names and applies the market values
1599
1677
  *
1600
1678
  * @param {string} code code from extracted code
@@ -1606,7 +1684,7 @@ class MetadataType {
1606
1684
  return Mustache.render(code, templateVariables, {}, ['{{{', '}}}']);
1607
1685
  }
1608
1686
  /**
1609
- * helper for {@link buildTemplateForNested}
1687
+ * helper for {@link MetadataType.buildTemplateForNested}
1610
1688
  * searches extracted file for template variable values and applies the market variable names
1611
1689
  *
1612
1690
  * @param {string} code code from extracted code
@@ -1618,7 +1696,7 @@ class MetadataType {
1618
1696
  return Util.replaceByObject(code, templateVariables);
1619
1697
  }
1620
1698
  /**
1621
- * helper for {@link buildDefinition}
1699
+ * helper for {@link MetadataType.buildDefinition}
1622
1700
  * handles extracted code if any are found for complex types (e.g script, asset, query)
1623
1701
  *
1624
1702
  * @param {string} templateDir Directory where metadata templates are stored
@@ -1639,7 +1717,7 @@ class MetadataType {
1639
1717
  return null;
1640
1718
  }
1641
1719
  /**
1642
- * helper for {@link buildTemplate}
1720
+ * helper for {@link MetadataType.buildTemplate}
1643
1721
  * handles extracted code if any are found for complex types
1644
1722
  *
1645
1723
  * @param {string} templateDir Directory where metadata templates are stored
@@ -1785,7 +1863,7 @@ class MetadataType {
1785
1863
  * @param {object} ex response payload from REST API
1786
1864
  * @returns {string[] | void} formatted Error Message
1787
1865
  */
1788
- static checkForErrors(ex) {
1866
+ static getErrorsREST(ex) {
1789
1867
  const errors = [];
1790
1868
  if (ex?.response?.status >= 400 && ex?.response?.status < 600) {
1791
1869
  if (ex.response.data.errors) {
@@ -1808,11 +1886,13 @@ class MetadataType {
1808
1886
  }
1809
1887
  } else if (ex.response.data.message) {
1810
1888
  errors.push(ex.response.data.message);
1811
- } else {
1889
+ } else if (ex.response.data) {
1812
1890
  errors.push(`Undefined Errors: ${JSON.stringify(ex.response.data)}`);
1891
+ Util.logger.debug(JSON.stringify(ex.response.data));
1892
+ } else {
1893
+ errors.push(`${ex.response.status} ${ex.response.statusText}`);
1813
1894
  }
1814
1895
  Util.logger.debug(JSON.stringify(ex.config));
1815
- Util.logger.debug(JSON.stringify(ex.response.data));
1816
1896
  }
1817
1897
  return errors;
1818
1898
  }
@@ -1875,11 +1955,7 @@ class MetadataType {
1875
1955
  metadata[overrideKeyField || this.definition.keyField] = customerKey;
1876
1956
  const soapType = this.definition.soapType || this.definition.type;
1877
1957
  try {
1878
- await this.client.soap.delete(
1879
- soapType.charAt(0).toUpperCase() + soapType.slice(1),
1880
- metadata,
1881
- null
1882
- );
1958
+ await this.client.soap.delete(Util.capitalizeFirstLetter(soapType), metadata, null);
1883
1959
  if (!handleOutside) {
1884
1960
  Util.logger.info(` - deleted ${this.definition.type}: ${customerKey}`);
1885
1961
  }
@@ -1932,7 +2008,7 @@ class MetadataType {
1932
2008
  * Returns metadata of a business unit that is saved locally
1933
2009
  *
1934
2010
  * @param {string} readDir root directory of metadata.
1935
- * @param {boolean} [listBadKeys=false] do not print errors, used for badKeys()
2011
+ * @param {boolean} [listBadKeys] do not print errors, used for badKeys()
1936
2012
  * @param {object} [buMetadata] Metadata of BU in local directory
1937
2013
  * @returns {object} Metadata of BU in local directory
1938
2014
  */
@@ -1970,6 +2046,57 @@ class MetadataType {
1970
2046
  const fileList = keyArr.map((key) => File.normalizePath([path, key + typeExtension]));
1971
2047
  return fileList;
1972
2048
  }
2049
+
2050
+ /**
2051
+ *
2052
+ * @param {TYPE.MetadataTypeMap} metadataMap metadata mapped by their keyField
2053
+ * @returns {string[]} list of keys
2054
+ */
2055
+ static getKeysForFixing(metadataMap) {
2056
+ const keysForDeploy = [];
2057
+ if (Object.keys(metadataMap).length) {
2058
+ Util.logger.info(
2059
+ `Searching for ${this.definition.type} keys among downloaded items that need fixing:`
2060
+ );
2061
+ for (const item of Object.values(metadataMap)) {
2062
+ if (item[this.definition.nameField].length > this.definition.maxKeyLength) {
2063
+ Util.logger.warn(
2064
+ `Name of the item ${
2065
+ item[this.definition.keyField]
2066
+ } is too long for a key. Consider renaming your item. Key will be equal first ${
2067
+ this.definition.maxKeyLength
2068
+ } characters of the name`
2069
+ );
2070
+ item[this.definition.nameField] = item[this.definition.nameField].slice(
2071
+ 0,
2072
+ this.definition.maxKeyLength
2073
+ );
2074
+ }
2075
+
2076
+ if (
2077
+ item[this.definition.nameField] != item[this.definition.keyField] &&
2078
+ !this.definition.keyIsFixed
2079
+ ) {
2080
+ keysForDeploy.push(item[this.definition.keyField]);
2081
+ Util.logger.info(
2082
+ ` - added ${this.definition.type} to fixKey queue: ${
2083
+ item[this.definition.keyField]
2084
+ }`
2085
+ );
2086
+ } else {
2087
+ Util.logger.info(
2088
+ Util.getGrayMsg(
2089
+ ` ☇ skipping ${this.definition.type} ${
2090
+ item[this.definition.keyField]
2091
+ }: key does not need to be updated`
2092
+ )
2093
+ );
2094
+ }
2095
+ }
2096
+ Util.logger.info(`Found ${keysForDeploy.length} ${this.definition.type} keys to fix`);
2097
+ }
2098
+ return keysForDeploy;
2099
+ }
1973
2100
  }
1974
2101
 
1975
2102
  MetadataType.definition = {