mcdev 4.3.4 → 5.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (228) hide show
  1. package/.coverage-comment-template.md +20 -0
  2. package/.coverage-comment-template.svelte +178 -0
  3. package/.eslintrc.json +2 -0
  4. package/.github/ISSUE_TEMPLATE/bug.yml +2 -0
  5. package/.github/workflows/code-test.yml +36 -0
  6. package/.github/workflows/coverage-base-update.yml +57 -0
  7. package/.github/workflows/coverage-develop-branch.yml +41 -0
  8. package/.github/workflows/coverage-main-branch.yml +41 -0
  9. package/.github/workflows/coverage.yml +77 -0
  10. package/.husky/post-checkout +1 -1
  11. package/.prettierrc +1 -1
  12. package/.vscode/extensions.json +0 -4
  13. package/README.md +1 -1
  14. package/boilerplate/config.json +1 -1
  15. package/boilerplate/files/.prettierrc +1 -1
  16. package/boilerplate/files/.vscode/extensions.json +1 -1
  17. package/boilerplate/forcedUpdates.json +4 -0
  18. package/docs/dist/documentation.md +1196 -430
  19. package/lib/Builder.js +6 -1
  20. package/lib/Deployer.js +30 -5
  21. package/lib/MetadataTypeDefinitions.js +8 -6
  22. package/lib/MetadataTypeInfo.js +8 -6
  23. package/lib/cli.js +54 -42
  24. package/lib/index.js +82 -8
  25. package/lib/metadataTypes/Asset.js +73 -1
  26. package/lib/metadataTypes/AttributeGroup.js +0 -1
  27. package/lib/metadataTypes/Automation.js +48 -5
  28. package/lib/metadataTypes/Campaign.js +20 -7
  29. package/lib/metadataTypes/ContentArea.js +1 -1
  30. package/lib/metadataTypes/DataExtension.js +221 -184
  31. package/lib/metadataTypes/DataExtensionField.js +12 -19
  32. package/lib/metadataTypes/DataExtensionTemplate.js +1 -1
  33. package/lib/metadataTypes/DataExtract.js +1 -1
  34. package/lib/metadataTypes/DataExtractType.js +1 -1
  35. package/lib/metadataTypes/Email.js +1 -1
  36. package/lib/metadataTypes/{EmailSendDefinition.js → EmailSend.js} +5 -5
  37. package/lib/metadataTypes/{EventDefinition.js → Event.js} +17 -35
  38. package/lib/metadataTypes/{FtpLocation.js → FileLocation.js} +2 -2
  39. package/lib/metadataTypes/FileTransfer.js +8 -7
  40. package/lib/metadataTypes/Filter.js +1 -1
  41. package/lib/metadataTypes/Folder.js +8 -3
  42. package/lib/metadataTypes/ImportFile.js +6 -6
  43. package/lib/metadataTypes/{Interaction.js → Journey.js} +311 -147
  44. package/lib/metadataTypes/List.js +2 -2
  45. package/lib/metadataTypes/MetadataType.js +318 -90
  46. package/lib/metadataTypes/MobileCode.js +0 -1
  47. package/lib/metadataTypes/MobileKeyword.js +336 -40
  48. package/lib/metadataTypes/MobileMessage.js +473 -0
  49. package/lib/metadataTypes/Query.js +114 -32
  50. package/lib/metadataTypes/Role.js +60 -21
  51. package/lib/metadataTypes/Script.js +2 -3
  52. package/lib/metadataTypes/SendClassification.js +40 -0
  53. package/lib/metadataTypes/SetDefinition.js +1 -7
  54. package/lib/metadataTypes/TransactionalEmail.js +2 -3
  55. package/lib/metadataTypes/TransactionalMessage.js +1 -2
  56. package/lib/metadataTypes/TransactionalSMS.js +8 -15
  57. package/lib/metadataTypes/{TriggeredSendDefinition.js → TriggeredSend.js} +35 -27
  58. package/lib/metadataTypes/User.js +1185 -0
  59. package/lib/metadataTypes/definitions/Asset.definition.js +1 -0
  60. package/lib/metadataTypes/definitions/AttributeGroup.definition.js +1 -0
  61. package/lib/metadataTypes/definitions/Automation.definition.js +3 -2
  62. package/lib/metadataTypes/definitions/Campaign.definition.js +79 -4
  63. package/lib/metadataTypes/definitions/ContentArea.definition.js +1 -0
  64. package/lib/metadataTypes/definitions/DataExtension.definition.js +2 -1
  65. package/lib/metadataTypes/definitions/DataExtensionField.definition.js +1 -0
  66. package/lib/metadataTypes/definitions/DataExtensionTemplate.definition.js +1 -0
  67. package/lib/metadataTypes/definitions/DataExtract.definition.js +1 -0
  68. package/lib/metadataTypes/definitions/DataExtractType.definition.js +1 -0
  69. package/lib/metadataTypes/definitions/Discovery.definition.js +1 -0
  70. package/lib/metadataTypes/definitions/Email.definition.js +1 -0
  71. package/lib/metadataTypes/definitions/{EmailSendDefinition.definition.js → EmailSend.definition.js} +4 -2
  72. package/lib/metadataTypes/definitions/{EventDefinition.definition.js → Event.definition.js} +2 -1
  73. package/lib/metadataTypes/definitions/{FtpLocation.definition.js → FileLocation.definition.js} +4 -3
  74. package/lib/metadataTypes/definitions/FileTransfer.definition.js +3 -2
  75. package/lib/metadataTypes/definitions/Filter.definition.js +1 -0
  76. package/lib/metadataTypes/definitions/Folder.definition.js +2 -0
  77. package/lib/metadataTypes/definitions/ImportFile.definition.js +4 -3
  78. package/lib/metadataTypes/definitions/{Interaction.definition.js → Journey.definition.js} +11 -2
  79. package/lib/metadataTypes/definitions/List.definition.js +1 -0
  80. package/lib/metadataTypes/definitions/MobileCode.definition.js +3 -1
  81. package/lib/metadataTypes/definitions/MobileKeyword.definition.js +27 -17
  82. package/lib/metadataTypes/definitions/MobileMessage.definition.js +743 -0
  83. package/lib/metadataTypes/definitions/Query.definition.js +3 -2
  84. package/lib/metadataTypes/definitions/Role.definition.js +5 -0
  85. package/lib/metadataTypes/definitions/Script.definition.js +1 -0
  86. package/lib/metadataTypes/definitions/SendClassification.definition.js +114 -0
  87. package/lib/metadataTypes/definitions/SetDefinition.definition.js +1 -0
  88. package/lib/metadataTypes/definitions/TransactionalEmail.definition.js +2 -1
  89. package/lib/metadataTypes/definitions/TransactionalPush.definition.js +1 -0
  90. package/lib/metadataTypes/definitions/TransactionalSMS.definition.js +1 -0
  91. package/lib/metadataTypes/definitions/{TriggeredSendDefinition.definition.js → TriggeredSend.definition.js} +5 -3
  92. package/lib/metadataTypes/definitions/User.definition.js +365 -0
  93. package/lib/retrieveChangelog.js +1 -2
  94. package/lib/util/auth.js +38 -9
  95. package/lib/util/businessUnit.js +3 -3
  96. package/lib/util/cli.js +55 -7
  97. package/lib/util/devops.js +6 -4
  98. package/lib/util/file.js +55 -13
  99. package/lib/util/init.config.js +1 -2
  100. package/lib/util/init.npm.js +3 -3
  101. package/lib/util/util.js +23 -14
  102. package/package.json +16 -15
  103. package/test/general.test.js +62 -0
  104. package/test/mockRoot/.mcdevrc.json +7 -5
  105. package/test/mockRoot/deploy/testInstance/_ParentBU_/user/testBlocked_user.user-meta.json +23 -0
  106. package/test/mockRoot/deploy/testInstance/_ParentBU_/user/testExisting_user.user-meta.json +31 -0
  107. package/test/mockRoot/deploy/testInstance/_ParentBU_/user/testNew_user.user-meta.json +27 -0
  108. package/test/mockRoot/deploy/testInstance/testBU/dataExtension/{childBU_dataextension_test.dataExtension-meta.json → testExisting_dataExtension.dataExtension-meta.json} +2 -2
  109. package/test/mockRoot/deploy/testInstance/testBU/dataExtension/{testDataExtension.dataExtension-meta.json → testNew_dataExtension.dataExtension-meta.json} +2 -2
  110. package/test/mockRoot/deploy/testInstance/testBU/journey/testExisting_interaction.interaction-meta.json +576 -0
  111. package/test/mockRoot/deploy/testInstance/testBU/mobileKeyword/testNew_keyword.mobileKeyword-meta.amp +2 -0
  112. package/test/mockRoot/deploy/testInstance/testBU/mobileKeyword/testNew_keyword.mobileKeyword-meta.json +10 -0
  113. package/test/mockRoot/deploy/testInstance/testBU/mobileKeyword/testNew_keyword_blocked.mobileKeyword-meta.amp +2 -0
  114. package/test/mockRoot/deploy/testInstance/testBU/mobileKeyword/testNew_keyword_blocked.mobileKeyword-meta.json +10 -0
  115. package/test/mockRoot/deploy/testInstance/testBU/mobileMessage/NTIzOjc4OjA.mobileMessage-meta.amp +1 -0
  116. package/test/mockRoot/deploy/testInstance/testBU/mobileMessage/NTIzOjc4OjA.mobileMessage-meta.json +61 -0
  117. package/test/mockRoot/deploy/testInstance/testBU/mobileMessage/new.mobileMessage-meta.amp +1 -0
  118. package/test/mockRoot/deploy/testInstance/testBU/mobileMessage/new.mobileMessage-meta.json +60 -0
  119. package/test/mockRoot/deploy/testInstance/testBU/query/testExistingQuery.query-meta.json +1 -1
  120. package/test/mockRoot/deploy/testInstance/testBU/query/testNewQuery.query-meta.json +1 -1
  121. package/test/mockRoot/deploy/testInstance/testBU/query/testNewQuery.query-meta.sql +1 -1
  122. package/test/mockRoot/deploy/testInstance/testBU/transactionalEmail/testExisting_temail.transactionalEmail-meta.json +1 -1
  123. package/test/mockRoot/deploy/testInstance/testBU/transactionalEmail/testNew_temail.transactionalEmail-meta.json +1 -1
  124. package/test/resourceFactory.js +13 -0
  125. package/test/resources/1111111/accountUser/configure-response.xml +70 -0
  126. package/test/resources/1111111/accountUser/create-response.xml +97 -0
  127. package/test/resources/1111111/accountUser/retrieve-response.xml +156 -0
  128. package/test/resources/1111111/accountUser/update-response.xml +111 -0
  129. package/test/resources/1111111/accountUserAccount/retrieve-response.xml +77 -0
  130. package/test/resources/1111111/platform/v1/setup/quickflow/data/get-response.json +455 -0
  131. package/test/resources/1111111/role/retrieve-response.xml +76 -0
  132. package/test/resources/1111111/user/build-expected.json +16 -0
  133. package/test/resources/1111111/user/create-expected.json +21 -0
  134. package/test/resources/1111111/user/retrieve-expected.json +24 -0
  135. package/test/resources/1111111/user/template-expected.json +16 -0
  136. package/test/resources/1111111/user/update-expected.json +21 -0
  137. package/test/resources/9999999/automation/v1/queries/549f0568-607c-4940-afef-437965094dat/delete-response.json +1 -0
  138. package/test/resources/9999999/automation/v1/queries/549f0568-607c-4940-afef-437965094dat/get-response.json +17 -0
  139. package/test/resources/9999999/automation/v1/queries/549f0568-607c-4940-afef-437965094dat/patch-response.json +3 -3
  140. package/test/resources/9999999/automation/v1/queries/get-response.json +21 -4
  141. package/test/resources/9999999/automation/v1/queries/post-response.json +4 -4
  142. package/test/resources/9999999/data/v1/customobjectdata/key/{childBU_dataextension_test → testExisting_dataExtension}/rowset/get-response.json +1 -1
  143. package/test/resources/9999999/dataExtension/build-expected.json +3 -3
  144. package/test/resources/9999999/dataExtension/create-expected.json +2 -2
  145. package/test/resources/9999999/dataExtension/create-response.xml +8 -3
  146. package/test/resources/9999999/dataExtension/retrieve-expected.json +3 -3
  147. package/test/resources/9999999/dataExtension/retrieve-response.xml +9 -4
  148. package/test/resources/9999999/dataExtension/template-expected.json +3 -3
  149. package/test/resources/9999999/dataExtension/update-expected.json +3 -3
  150. package/test/resources/9999999/dataExtension/update-response.xml +9 -4
  151. package/test/resources/9999999/dataExtensionField/retrieve-response.xml +14 -9
  152. package/test/resources/9999999/interaction/v1/interactions/get-response.json +312 -0
  153. package/test/resources/9999999/interaction/v1/interactions/key_testExisting_interaction/get-response.json +312 -0
  154. package/test/resources/9999999/interaction/v1/interactions/key_testExisting_interaction/put-response.json +592 -0
  155. package/test/resources/9999999/journey/build-expected.json +572 -0
  156. package/test/resources/9999999/journey/get-expected.json +576 -0
  157. package/test/resources/9999999/journey/put-expected.json +576 -0
  158. package/test/resources/9999999/journey/template-expected.json +572 -0
  159. package/test/resources/9999999/legacy/v1/beta/mobile/keyword/NXV4ZFMwTEFwRVczd3RaLUF5X3p5dzo4Njow/get-response.json +42 -0
  160. package/test/resources/9999999/legacy/v1/beta/mobile/keyword/cTVJaG5oSDJPVUNHcUh6Z3pQT2tVdzo4Njow/delete-response.json +0 -0
  161. package/test/resources/9999999/legacy/v1/beta/mobile/keyword/get-response.json +1 -0
  162. package/test/resources/9999999/legacy/v1/beta/mobile/keyword/post-response.json +3 -0
  163. package/test/resources/9999999/legacy/v1/beta/mobile/message/NTIzOjc4OjA/delete-response.json +0 -0
  164. package/test/resources/9999999/legacy/v1/beta/mobile/message/NTIzOjc4OjA/get-response.json +106 -0
  165. package/test/resources/9999999/legacy/v1/beta/mobile/message/NTIzOjc4OjA/post-response.json +0 -0
  166. package/test/resources/9999999/legacy/v1/beta/mobile/message/NTQ3Ojc4OjA/get-response.json +127 -0
  167. package/test/resources/9999999/legacy/v1/beta/mobile/message/get-response.json +129 -0
  168. package/test/resources/9999999/legacy/v1/beta/mobile/message/post-response.json +3 -0
  169. package/test/resources/9999999/legacy/v1/beta2/data/campaign/get-response.json +29 -0
  170. package/test/resources/9999999/messaging/v1/email/definitions/post-response.json +1 -1
  171. package/test/resources/9999999/messaging/v1/email/definitions/testExisting_temail/get-response.json +1 -1
  172. package/test/resources/9999999/messaging/v1/email/definitions/testExisting_temail/patch-response.json +1 -1
  173. package/test/resources/9999999/mobileKeyword/build-expected.amp +2 -0
  174. package/test/resources/9999999/mobileKeyword/build-expected.json +9 -0
  175. package/test/resources/9999999/mobileKeyword/get-expected.amp +2 -0
  176. package/test/resources/9999999/mobileKeyword/get-expected.json +15 -0
  177. package/test/resources/9999999/mobileKeyword/post-create-expected.amp +2 -0
  178. package/test/resources/9999999/mobileKeyword/post-create-expected.json +17 -0
  179. package/test/resources/9999999/mobileKeyword/template-expected.amp +2 -0
  180. package/test/resources/9999999/mobileKeyword/template-expected.json +9 -0
  181. package/test/resources/9999999/mobileMessage/build-expected.amp +1 -0
  182. package/test/resources/9999999/mobileMessage/build-expected.json +60 -0
  183. package/test/resources/9999999/mobileMessage/get-expected.amp +1 -0
  184. package/test/resources/9999999/mobileMessage/get-expected.json +61 -0
  185. package/test/resources/9999999/mobileMessage/post-create-expected.amp +1 -0
  186. package/test/resources/9999999/mobileMessage/post-create-expected.json +63 -0
  187. package/test/resources/9999999/mobileMessage/post-update-expected.amp +1 -0
  188. package/test/resources/9999999/mobileMessage/post-update-expected.json +61 -0
  189. package/test/resources/9999999/mobileMessage/template-expected.amp +1 -0
  190. package/test/resources/9999999/mobileMessage/template-expected.json +60 -0
  191. package/test/resources/9999999/query/build-expected.json +1 -1
  192. package/test/resources/9999999/query/get-expected.json +1 -1
  193. package/test/resources/9999999/query/get2-expected.json +11 -0
  194. package/test/resources/9999999/query/patch-expected.json +1 -1
  195. package/test/resources/9999999/query/post-expected.json +1 -1
  196. package/test/resources/9999999/query/template-expected.json +1 -1
  197. package/test/resources/9999999/queryDefinition/retrieve-response.xml +30 -0
  198. package/test/resources/9999999/transactionalEmail/build-expected.json +5 -5
  199. package/test/resources/9999999/transactionalEmail/get-expected.json +1 -1
  200. package/test/resources/9999999/transactionalEmail/patch-expected.json +1 -1
  201. package/test/resources/9999999/transactionalEmail/post-expected.json +1 -1
  202. package/test/resources/9999999/transactionalEmail/template-expected.json +5 -5
  203. package/test/resources/9999999/transactionalPush/build-expected.json +2 -2
  204. package/test/resources/9999999/transactionalPush/template-expected.json +2 -2
  205. package/test/resources/9999999/transactionalSMS/build-expected.json +3 -3
  206. package/test/resources/9999999/transactionalSMS/template-expected.json +3 -3
  207. package/test/{dataExtension.test.js → type.dataExtension.test.js} +78 -21
  208. package/test/{interaction.test.js → type.journey.test.js} +64 -30
  209. package/test/type.mobileKeyword.test.js +250 -0
  210. package/test/type.mobileMessage.test.js +205 -0
  211. package/test/{query.test.js → type.query.test.js} +102 -5
  212. package/test/{transactionalEmail.test.js → type.transactionalEmail.test.js} +40 -2
  213. package/test/{transactionalPush.test.js → type.transactionalPush.test.js} +41 -2
  214. package/test/{transactionalSMS.test.js → type.transactionalSMS.test.js} +73 -3
  215. package/test/type.user.test.js +160 -0
  216. package/test/utils.js +17 -5
  217. package/types/mcdev.d.js +48 -15
  218. package/.github/workflows/code-analysis.yml +0 -57
  219. package/lib/metadataTypes/AccountUser.js +0 -426
  220. package/lib/metadataTypes/definitions/AccountUser.definition.js +0 -227
  221. package/test/mockRoot/deploy/testInstance/testBU/interaction/testExisting_interaction.interaction-meta.json +0 -266
  222. package/test/resources/9999999/interaction/build-expected.json +0 -260
  223. package/test/resources/9999999/interaction/get-expected.json +0 -264
  224. package/test/resources/9999999/interaction/put-expected.json +0 -264
  225. package/test/resources/9999999/interaction/template-expected.json +0 -260
  226. package/test/resources/9999999/interaction/v1/interactions/put-response.json +0 -280
  227. /package/test/mockRoot/deploy/testInstance/testBU/{interaction → journey}/testNew_interaction.interaction-meta.json +0 -0
  228. /package/test/resources/9999999/{interaction → journey}/post-expected.json +0 -0
@@ -62,9 +62,9 @@ const BusinessUnit = {
62
62
  currentCredentials.eid = element.ID;
63
63
  Util.logger.info(` - ${Util.parentBuName} (${element.Name})`);
64
64
  } else {
65
- const equalizedName = element.Name.replace(/[^\w\s]/gi, '') // remove special chars
66
- .replace(/ +/g, '_') // convert spaces to underscore
67
- .replace(/__+/g, '_'); // make sure we never have more than one underscore in a row
65
+ const equalizedName = element.Name.replaceAll(/[^\w\s]/gi, '') // remove special chars
66
+ .replaceAll(/ +/g, '_') // convert spaces to underscore
67
+ .replaceAll(/__+/g, '_'); // make sure we never have more than one underscore in a row
68
68
  myBuList[equalizedName] = element.ID;
69
69
  Util.logger.info(
70
70
  ` - ${element.Name} ${
package/lib/util/cli.js CHANGED
@@ -8,6 +8,7 @@ const inquirer = require('inquirer');
8
8
  const MetadataDefinitions = require('./../MetadataTypeDefinitions');
9
9
  const Util = require('./util');
10
10
  const auth = require('./auth');
11
+ require('console.table');
11
12
 
12
13
  /**
13
14
  * CLI helper class
@@ -315,7 +316,7 @@ const Cli = {
315
316
  if (properties && properties.credentials[value]) {
316
317
  return `There already is an account with the name '${value}' in your config.`;
317
318
  }
318
- const converted = encodeURIComponent(value).replace(/[*]/g, '_STAR_');
319
+ const converted = encodeURIComponent(value).replaceAll(/[*]/g, '_STAR_');
319
320
  if (value != converted) {
320
321
  return 'Please do not use any special chars';
321
322
  }
@@ -526,15 +527,57 @@ const Cli = {
526
527
  /**
527
528
  * shows metadata type descriptions
528
529
  *
529
- * @returns {void}
530
+ * @returns {object[]} list of supported types with their apiNames
530
531
  */
531
532
  explainTypes() {
532
- // overwrites default layout of console.table
533
- require('console.table');
533
+ const MetadataTypeInfo = require('./../MetadataTypeInfo');
534
+ const TransactionalMessage = require('./../metadataTypes/TransactionalMessage');
535
+ const json = [];
536
+ const apiNameArr = Object.keys(MetadataDefinitions);
537
+
538
+ for (const apiName of apiNameArr) {
539
+ const details = MetadataDefinitions[apiName];
540
+ const supportCheckClass = apiName.startsWith('transactional')
541
+ ? TransactionalMessage
542
+ : MetadataTypeInfo[apiName];
543
+ json.push({
544
+ name: details.typeName,
545
+ apiName: details.type,
546
+ retrieveByDefault: details.typeRetrieveByDefault,
547
+ supports: {
548
+ retrieve: Object.prototype.hasOwnProperty.call(supportCheckClass, 'retrieve'),
549
+ create: Object.prototype.hasOwnProperty.call(supportCheckClass, 'create'),
550
+ update: Object.prototype.hasOwnProperty.call(supportCheckClass, 'update'),
551
+ delete: Object.prototype.hasOwnProperty.call(supportCheckClass, 'deleteByKey'),
552
+ changeKey:
553
+ supportCheckClass.definition.keyIsFixed === false &&
554
+ supportCheckClass.definition.keyField !==
555
+ supportCheckClass.definition.idField &&
556
+ supportCheckClass.definition.fields[supportCheckClass.definition.keyField]
557
+ .isUpdateable &&
558
+ Object.prototype.hasOwnProperty.call(supportCheckClass, 'update'),
559
+ buildTemplate: Object.prototype.hasOwnProperty.call(
560
+ supportCheckClass,
561
+ 'create'
562
+ ), // supported for all types that can be created
563
+ retrieveAsTemplate: Object.prototype.hasOwnProperty.call(
564
+ supportCheckClass,
565
+ 'retrieveAsTemplate'
566
+ ),
567
+ },
568
+ description: details.typeDescription,
569
+ });
570
+ }
571
+ if (Util.OPTIONS.json) {
572
+ if (Util.OPTIONS.loggerLevel !== 'error') {
573
+ console.log(json); // eslint-disable-line no-console
574
+ }
575
+ return json;
576
+ }
534
577
 
535
578
  const typeChoices = [];
536
579
  for (const el in MetadataDefinitions) {
537
- if (MetadataDefinitions[el].subTypes) {
580
+ if (MetadataDefinitions[el].subTypes && MetadataDefinitions[el].extendedSubTypes) {
538
581
  // used for assets to show whats available by default
539
582
  typeChoices.push({
540
583
  Name: MetadataDefinitions[el].typeName,
@@ -545,9 +588,11 @@ const Cli = {
545
588
  for (const subtype of MetadataDefinitions[el].subTypes) {
546
589
  lastCountdown--;
547
590
  const subTypeRetrieveByDefault =
591
+ Array.isArray(MetadataDefinitions[el].typeRetrieveByDefault) &&
548
592
  MetadataDefinitions[el].typeRetrieveByDefault.includes(subtype);
593
+
549
594
  const definition =
550
- ' ' + MetadataDefinitions[el].extendedSubTypes[subtype].join(', ');
595
+ ' ' + MetadataDefinitions[el].extendedSubTypes?.[subtype]?.join(', ');
551
596
  typeChoices.push({
552
597
  Name:
553
598
  MetadataDefinitions[el].typeName.replace('-[Subtype]', ': ') + subtype,
@@ -577,7 +622,10 @@ const Cli = {
577
622
  }
578
623
  return 0;
579
624
  });
580
- console.table(typeChoices); // eslint-disable-line no-console
625
+ if (Util.OPTIONS.loggerLevel !== 'error') {
626
+ console.table(typeChoices); // eslint-disable-line no-console
627
+ }
628
+ return json;
581
629
  },
582
630
  };
583
631
 
@@ -21,9 +21,10 @@ const DevOps = {
21
21
  * @param {string} [range] git commit range
22
22
  * @param {boolean} [saveToDeployDir] if true, copy metadata changes into deploy directory
23
23
  * @param {string} [filterPaths] filter file paths that start with any specified path (comma separated)
24
+ * @param {number} [commitHistory] cli option to override default commit history value in config
24
25
  * @returns {Promise.<TYPE.DeltaPkgItem[]>} -
25
26
  */
26
- async getDeltaList(properties, range, saveToDeployDir, filterPaths) {
27
+ async getDeltaList(properties, range, saveToDeployDir, filterPaths, commitHistory) {
27
28
  const rangeUserInput = range;
28
29
  filterPaths = filterPaths
29
30
  ? filterPaths.split(',').map((filePath) =>
@@ -47,7 +48,7 @@ const DevOps = {
47
48
  // Current commit is skipped due to no changes
48
49
  const commits = await git.log([
49
50
  '--skip=1',
50
- `-${properties.options.deployment.commitHistory || 10}`,
51
+ `-${commitHistory || properties.options.deployment.commitHistory || 10}`,
51
52
  ]);
52
53
  const display = commits.all.map((commit) => ({
53
54
  name: commit.date + ' / ' + commit.message + ' / ' + commit.author_name,
@@ -336,9 +337,10 @@ const DevOps = {
336
337
  * @param {TYPE.Mcdevrc} properties project config file
337
338
  * @param {string} range git commit range
338
339
  * @param {TYPE.DeltaPkgItem[]} [diffArr] instead of running git diff the method can also get a list of files to process
340
+ * @param {number} [commitHistory] cli option to override default commit history value in config
339
341
  * @returns {Promise.<TYPE.DeltaPkgItem[]>} -
340
342
  */
341
- async buildDeltaDefinitions(properties, range, diffArr) {
343
+ async buildDeltaDefinitions(properties, range, diffArr, commitHistory) {
342
344
  const skipInteraction = Util.skipInteraction;
343
345
  // check if sourceTargetMapping is valid
344
346
  if (
@@ -394,7 +396,7 @@ const DevOps = {
394
396
 
395
397
  const delta = Array.isArray(diffArr)
396
398
  ? diffArr
397
- : await DevOps.getDeltaList(properties, range, false, sourceBU);
399
+ : await DevOps.getDeltaList(properties, range, false, sourceBU, commitHistory);
398
400
  // If only chaing templating and buildDefinition if required
399
401
  if (!delta || delta.length === 0) {
400
402
  // info/error messages was printed by DevOps.createDeltaPkg() already
package/lib/util/file.js CHANGED
@@ -6,6 +6,7 @@ const fs = require('fs-extra');
6
6
  const packageJson = require('../../package.json');
7
7
  const path = require('node:path');
8
8
  const prettier = require('prettier');
9
+ const beautyAmp = require('beauty-amp-core');
9
10
  const Util = require('./util');
10
11
  const updateNotifier = require('update-notifier');
11
12
 
@@ -52,7 +53,7 @@ const File = {
52
53
  filterIllegalPathChars(path) {
53
54
  return (
54
55
  encodeURIComponent(path)
55
- .replace(/[*]/g, '_STAR_')
56
+ .replaceAll(/[*]/g, '_STAR_')
56
57
  // convert space back
57
58
  .split('%20')
58
59
  .join(' ')
@@ -74,6 +75,9 @@ const File = {
74
75
  // convert brackets back for asset blocks
75
76
  .split('%5D')
76
77
  .join(']')
78
+ // convert @ back for users
79
+ .split('%40')
80
+ .join('@')
77
81
  );
78
82
  },
79
83
 
@@ -86,7 +90,7 @@ const File = {
86
90
  filterIllegalFilenames(filename) {
87
91
  return (
88
92
  encodeURIComponent(filename)
89
- .replace(/[*]/g, '_STAR_')
93
+ .replaceAll(/[*]/g, '_STAR_')
90
94
  // convert space back
91
95
  .split('%20')
92
96
  .join(' ')
@@ -102,6 +106,9 @@ const File = {
102
106
  // convert brackets back for asset blocks
103
107
  .split('%5D')
104
108
  .join(']')
109
+ // convert @ back for users
110
+ .split('%40')
111
+ .join('@')
105
112
  );
106
113
  },
107
114
 
@@ -162,12 +169,47 @@ const File = {
162
169
  * @returns {Promise.<boolean>} Promise
163
170
  */
164
171
  writePrettyToFile: async function (directory, filename, filetype, content, templateVariables) {
165
- let formatted = await this._beautify_prettier(directory, filename, filetype, content);
172
+ let formatted =
173
+ filetype === 'amp'
174
+ ? this._beautify_beautyAmp(content)
175
+ : await this._beautify_prettier(directory, filename, filetype, content);
166
176
  if (templateVariables) {
167
177
  formatted = Util.replaceByObject(formatted, templateVariables);
168
178
  }
169
179
  return this.writeToFile(directory, filename, filetype, formatted);
170
180
  },
181
+ /**
182
+ * helper for {@link File.writePrettyToFile}, applying beautyAmp onto given stringified content
183
+ *
184
+ * @param {string} content filecontent
185
+ * @returns {string} original string on error; formatted string on success
186
+ */
187
+ _beautify_beautyAmp: function (content) {
188
+ // immutable at the moment:
189
+ const ampscript = {
190
+ capitalizeAndOrNot: true,
191
+ capitalizeIfFor: true,
192
+ capitalizeSet: true,
193
+ capitalizeVar: true,
194
+ maxParametersPerLine: 4,
195
+ };
196
+ // immutable at the moment:
197
+ const editor = {
198
+ insertSpaces: true,
199
+ tabSize: 4,
200
+ };
201
+ // logs trough console only for the moment.
202
+ const logs = {
203
+ loggerOn: false, // <= disable logging
204
+ };
205
+ try {
206
+ beautyAmp.setup(ampscript, editor, logs);
207
+ return beautyAmp.beautify(content);
208
+ } catch (ex) {
209
+ Util.logger.debug('File._beautify_beautyAmp:: error | ' + ex.message);
210
+ return content;
211
+ }
212
+ },
171
213
  /**
172
214
  * helper for {@link File.writePrettyToFile}, applying prettier onto given stringified content
173
215
  * ! Important: run 'await File.initPrettier()' in your MetadataType.retrieve() once before hitting this
@@ -179,16 +221,16 @@ const File = {
179
221
  * @returns {string} original string on error; formatted string on success
180
222
  */
181
223
  _beautify_prettier: function (directory, filename, filetype, content) {
182
- if (!FileFs.prettierConfig) {
183
- // either no prettier config in project directory or initPrettier was not run before this
184
- return content;
185
- } else if (content.includes('%%[') || content.includes('%%=')) {
186
- // in case we find AMPScript we need to abort beautifying as prettier
187
- // will throw an error falsely assuming bad syntax
188
- return content;
189
- }
190
224
  let formatted = '';
191
225
  try {
226
+ if (!FileFs.prettierConfig) {
227
+ // either no prettier config in project directory or initPrettier was not run before this
228
+ return content;
229
+ } else if (content.includes('%%[') || content.includes('%%=')) {
230
+ // in case we find AMPScript we need to abort beautifying as prettier
231
+ // will throw an error falsely assuming bad syntax
232
+ return this._beautify_beautyAmp(content);
233
+ }
192
234
  // load the right prettier config relative to our file
193
235
  switch (filetype) {
194
236
  case 'htm':
@@ -257,7 +299,7 @@ const File = {
257
299
  directory,
258
300
  filename + '.error',
259
301
  'log',
260
- `Error Log\nParser: ${FileFs.prettierConfig.parser}\n${ex.message.replace(
302
+ `Error Log\nParser: ${FileFs.prettierConfig.parser}\n${ex.message.replaceAll(
261
303
  /[\u001B\u009B][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g,
262
304
 
263
305
  ''
@@ -477,7 +519,7 @@ const File = {
477
519
  */
478
520
  async initPrettier(filetype) {
479
521
  if (FileFs.prettierConfig === null) {
480
- filetype = filetype || 'html';
522
+ filetype ||= 'html';
481
523
  try {
482
524
  // pass in project dir with fake index.html to avoid "no parser" error
483
525
  // by using process.cwd we are limiting ourselves to a config in the project root
@@ -337,8 +337,7 @@ const Init = {
337
337
  'files',
338
338
  fileName
339
339
  );
340
- boilerplateFileContent =
341
- boilerplateFileContent || (await File.readFile(boilerplateFileName, 'utf8'));
340
+ boilerplateFileContent ||= await File.readFile(boilerplateFileName, 'utf8');
342
341
 
343
342
  if (await File.pathExists(fileName)) {
344
343
  const existingFileContent = await File.readFile(fileName, 'utf8');
@@ -43,8 +43,8 @@ const Init = {
43
43
  repoName ||
44
44
  currentFolderName
45
45
  .toLowerCase()
46
- .replace(/[^a-z0-9 ]/gi, '')
47
- .replace(/ /gi, '-');
46
+ .replaceAll(/[^a-z0-9 ]/gi, '')
47
+ .replaceAll(/ /gi, '-');
48
48
  projectPackageJson = { name: standardNpmName };
49
49
  this._getDefaultPackageJson(projectPackageJson);
50
50
  await File.writeToFile('./', 'package', 'json', JSON.stringify(projectPackageJson));
@@ -128,7 +128,7 @@ const Init = {
128
128
  * @returns {Promise.<{script: object, author: string, license: string}>} extended currentContent
129
129
  */
130
130
  async _getDefaultPackageJson(currentContent) {
131
- currentContent = currentContent || {};
131
+ currentContent ||= {};
132
132
  // #1 scripts
133
133
  const predefinedCommandList = {
134
134
  build: 'sfmc-build all',
package/lib/util/util.js CHANGED
@@ -20,7 +20,8 @@ const Util = {
20
20
  /** @type {TYPE.skipInteraction} */
21
21
  skipInteraction: false,
22
22
  packageJsonMcdev: packageJsonMcdev,
23
-
23
+ OPTIONS: {},
24
+ changedKeysMap: {},
24
25
  /**
25
26
  * helper that allows filtering an object by its keys
26
27
  *
@@ -286,7 +287,7 @@ const Util = {
286
287
 
287
288
  sortable.sort((a, b) => b[1].length - a[1].length);
288
289
  for (const pair of sortable) {
289
- const escVal = pair[1].toString().replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
290
+ const escVal = pair[1].toString().replaceAll(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
290
291
  const regString = new RegExp(escVal, 'g');
291
292
  str = str.replace(regString, '{{{' + pair[0] + '}}}');
292
293
  }
@@ -418,20 +419,24 @@ const Util = {
418
419
  * @returns {string} output of command if hideOutput is true
419
420
  */
420
421
  execSync(cmd, args, hideOutput) {
421
- args = args || [];
422
+ args ||= [];
422
423
  Util.logger.info('⚡ ' + cmd + ' ' + args.join(' '));
423
424
 
424
- if (hideOutput) {
425
- // no output displayed to user but instead returned to parsed elsewhere
426
- return child_process
427
- .execSync(cmd + ' ' + args.join(' '))
428
- .toString()
429
- .trim();
430
- } else {
431
- // the following options ensure the user sees the same output and
432
- // interaction options as if the command was manually run
433
- child_process.execSync(cmd + ' ' + args.join(' '), { stdio: [0, 1, 2] });
434
- return null;
425
+ try {
426
+ if (hideOutput) {
427
+ // no output displayed to user but instead returned to parsed elsewhere
428
+ return child_process
429
+ .execSync(cmd + ' ' + args.join(' '))
430
+ .toString()
431
+ .trim();
432
+ } else {
433
+ // the following options ensure the user sees the same output and
434
+ // interaction options as if the command was manually run
435
+ child_process.execSync(cmd + ' ' + args.join(' '), { stdio: [0, 1, 2] });
436
+ return null;
437
+ }
438
+ } catch {
439
+ // avoid errors from execSync to bubble up
435
440
  }
436
441
  },
437
442
  /**
@@ -469,23 +474,27 @@ const Util = {
469
474
  if (argv.silent) {
470
475
  // only errors printed to CLI
471
476
  Util.logger.level = 'error';
477
+ Util.OPTIONS.loggerLevel = 'error';
472
478
  Util.loggerTransports.console.level = 'error';
473
479
  Util.logger.debug('CLI logger set to: silent');
474
480
  } else if (argv.verbose) {
475
481
  // chatty user cli logs
476
482
  Util.logger.level = 'verbose';
483
+ Util.OPTIONS.loggerLevel = 'verbose';
477
484
  Util.loggerTransports.console.level = 'verbose';
478
485
  Util.logger.debug('CLI logger set to: verbose');
479
486
  } else {
480
487
  // default user cli logs
481
488
  // TODO to be switched to "warn" when cli-process is integrated
482
489
  Util.logger.level = 'info';
490
+ Util.OPTIONS.loggerLevel = 'info';
483
491
  Util.loggerTransports.console.level = 'info';
484
492
  Util.logger.debug('CLI logger set to: info / default');
485
493
  }
486
494
  if (argv.debug) {
487
495
  // enables developer output & features. no change to actual logs
488
496
  Util.logger.level = 'debug';
497
+ Util.OPTIONS.loggerLevel = 'debug';
489
498
  Util.loggerTransports.console.level = 'debug';
490
499
  Util.logger.debug('CLI logger set to: debug');
491
500
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcdev",
3
- "version": "4.3.4",
3
+ "version": "5.0.1",
4
4
  "description": "Accenture Salesforce Marketing Cloud DevTools",
5
5
  "author": "Accenture: joern.berkefeld, douglas.midgley, robert.zimmermann, maciej.barnas",
6
6
  "license": "MIT",
@@ -35,7 +35,7 @@
35
35
  "mcdev": "./lib/cli.js"
36
36
  },
37
37
  "engines": {
38
- "node": ">=14.16"
38
+ "node": ">=15.0.0"
39
39
  },
40
40
  "scripts": {
41
41
  "start": "node lib/cli.js",
@@ -51,8 +51,8 @@
51
51
  "upgrade": "npm-check --update",
52
52
  "manual-prepare": "husky install",
53
53
  "lint-and-test": "run-s lint test",
54
- "test": "mocha",
55
- "coverage": "nyc mocha",
54
+ "test": "mocha --reporter-option maxDiffSize=25000",
55
+ "coverage": "nyc npm run test",
56
56
  "version:major": "npm version --no-commit-hooks major",
57
57
  "version:minor": "npm version --no-commit-hooks minor",
58
58
  "version:patch": "npm version --no-commit-hooks patch"
@@ -65,14 +65,14 @@
65
65
  "console.table": "0.10.0",
66
66
  "deep-equal": "2.1.0",
67
67
  "fs-extra": "11.1.0",
68
- "inquirer": "8.2.2",
68
+ "inquirer": "8.2.5",
69
69
  "json-to-table": "4.2.1",
70
70
  "mustache": "4.2.0",
71
71
  "p-limit": "3.1.0",
72
- "prettier": "2.8.3",
73
- "prettier-plugin-sql": "0.12.1",
74
- "semver": "7.3.8",
75
- "sfmc-sdk": "0.6.3",
72
+ "prettier": "2.8.8",
73
+ "prettier-plugin-sql": "0.14.0",
74
+ "semver": "7.5.0",
75
+ "sfmc-sdk": "1.0.0",
76
76
  "simple-git": "3.16.0",
77
77
  "toposort": "2.0.2",
78
78
  "update-notifier": "5.1.0",
@@ -81,19 +81,20 @@
81
81
  },
82
82
  "devDependencies": {
83
83
  "assert": "2.0.0",
84
- "axios-mock-adapter": "1.21.2",
84
+ "axios-mock-adapter": "1.21.3",
85
85
  "chai": "4.3.7",
86
86
  "chai-files": "1.4.0",
87
- "eslint": "8.32.0",
88
- "eslint-config-prettier": "8.6.0",
87
+ "eslint": "8.39.0",
88
+ "eslint-config-prettier": "8.7.0",
89
89
  "eslint-config-ssjs": "1.1.11",
90
- "eslint-plugin-jsdoc": "39.6.4",
90
+ "eslint-plugin-jsdoc": "43.1.1",
91
91
  "eslint-plugin-mocha": "10.1.0",
92
92
  "eslint-plugin-prettier": "4.2.1",
93
- "eslint-plugin-unicorn": "45.0.2",
93
+ "eslint-plugin-unicorn": "46.0.0",
94
+ "fast-xml-parser": "4.2.2",
94
95
  "husky": "8.0.3",
95
96
  "jsdoc-to-markdown": "8.0.0",
96
- "lint-staged": "13.1.0",
97
+ "lint-staged": "13.2.0",
97
98
  "mocha": "10.2.0",
98
99
  "mock-fs": "5.2.0",
99
100
  "npm-check": "6.0.1",
@@ -0,0 +1,62 @@
1
+ const chai = require('chai');
2
+ const chaiFiles = require('chai-files');
3
+ const assert = chai.assert;
4
+ const expect = chai.expect;
5
+ chai.use(chaiFiles);
6
+ const testUtils = require('./utils');
7
+ const handler = require('../lib/index');
8
+
9
+ describe('GENERAL', () => {
10
+ beforeEach(() => {
11
+ testUtils.mockSetup();
12
+ });
13
+ afterEach(() => {
14
+ testUtils.mockReset();
15
+ });
16
+
17
+ describe('explainTypes ================', () => {
18
+ it('without options', () => {
19
+ handler.explainTypes();
20
+ assert.equal(process.exitCode, false, 'explainTypes should not have thrown an error');
21
+
22
+ return;
23
+ });
24
+ it('with --json set', () => {
25
+ handler.setOptions({ json: true });
26
+ const typeArr = handler.explainTypes();
27
+
28
+ assert.equal(
29
+ process.exitCode,
30
+ false,
31
+ 'explainTypes --json should not have thrown an error'
32
+ );
33
+
34
+ // check if properties are all there
35
+ expect(typeArr[0]).to.have.all.keys(
36
+ 'name',
37
+ 'apiName',
38
+ 'retrieveByDefault',
39
+ 'description',
40
+ 'supports'
41
+ );
42
+ expect(typeArr[0].supports).to.have.all.keys(
43
+ 'retrieve',
44
+ 'create',
45
+ 'update',
46
+ 'delete',
47
+ 'changeKey',
48
+ 'buildTemplate',
49
+ 'retrieveAsTemplate'
50
+ );
51
+
52
+ // check if certain types were returned
53
+ assert.equal(
54
+ typeArr.find((type) => type.apiName === 'dataExtension').apiName,
55
+ 'dataExtension',
56
+ 'Expected to find dataExtension type'
57
+ );
58
+
59
+ return;
60
+ });
61
+ });
62
+ });
@@ -40,6 +40,7 @@
40
40
  "secret": "secret",
41
41
  "sharedFolder": "/Shared Data Extensions/test",
42
42
  "suffix": "_test",
43
+ "prefix": "testExisting_",
43
44
  "description": "bla bla",
44
45
  "countryCodeIn": "'test'"
45
46
  },
@@ -49,21 +50,22 @@
49
50
  "secret": "target secret",
50
51
  "sharedFolder": "/Shared Data Extensions/test target",
51
52
  "suffix": "_testTarget",
53
+ "prefix": "testTemplated_",
52
54
  "description": "foobar",
53
55
  "countryCodeIn": "'testTarget'"
54
56
  }
55
57
  },
56
58
  "marketList": {},
57
59
  "metaDataTypes": {
58
- "documentOnRetrieve": ["accountUser", "automation", "dataExtension", "role"],
60
+ "documentOnRetrieve": ["user", "automation", "dataExtension", "role"],
59
61
  "retrieve": [
60
62
  "asset",
61
63
  "automation",
62
64
  "dataExtension",
63
65
  "dataExtract",
64
- "emailSendDefinition",
66
+ "emailSend",
65
67
  "fileTransfer",
66
- "ftpLocation",
68
+ "fileLocation",
67
69
  "importFile",
68
70
  "list",
69
71
  "mobileCode",
@@ -71,8 +73,8 @@
71
73
  "query",
72
74
  "role",
73
75
  "script",
74
- "triggeredSendDefinition"
76
+ "triggeredSend"
75
77
  ]
76
78
  },
77
- "version": "4.3.4"
79
+ "version": "5.0.1"
78
80
  }
@@ -0,0 +1,23 @@
1
+ {
2
+ "CreatedDate": "2019-09-06T01:59:07.097",
3
+ "ModifiedDate": "2022-06-21T01:43:02.64",
4
+ "CustomerKey": "testBlocked_user",
5
+ "UserID": "user_test@accenture.asgr",
6
+ "Name": "user test",
7
+ "Email": "user_test@accenture.com",
8
+ "MustChangePassword": false,
9
+ "ActiveFlag": true,
10
+ "LastSuccessfulLogin": "2023-02-23T10:14:11.443",
11
+ "IsAPIUser": false,
12
+ "NotificationEmailAddress": "user_test@accenture.com",
13
+ "DefaultBusinessUnit": 9999999,
14
+ "c__type": "User",
15
+ "c__AssociatedBusinessUnits": [9999999],
16
+ "c__RoleNamesGlobal": [
17
+ "Administrator",
18
+ "Distributed Sending User",
19
+ "Marketing Cloud Administrator"
20
+ ],
21
+ "c__TimeZoneName": "(GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna *",
22
+ "c__LocaleCode": "en-GB"
23
+ }
@@ -0,0 +1,31 @@
1
+ {
2
+ "CreatedDate": "2019-09-06T01:59:07.097",
3
+ "ModifiedDate": "2022-06-21T01:43:02.64",
4
+ "CustomerKey": "testExisting_user",
5
+ "UserID": "user_test@accenture.asgr",
6
+ "Name": "user test",
7
+ "Email": "user_test@accenture.com",
8
+ "MustChangePassword": false,
9
+ "ActiveFlag": true,
10
+ "UserPermissions": [
11
+ {
12
+ "ID": 2
13
+ },
14
+ {
15
+ "ID": 3
16
+ }
17
+ ],
18
+ "LastSuccessfulLogin": "2023-02-23T10:14:11.443",
19
+ "IsAPIUser": false,
20
+ "NotificationEmailAddress": "user_test@accenture.com",
21
+ "DefaultBusinessUnit": 9999999,
22
+ "c__type": "User",
23
+ "c__AssociatedBusinessUnits": [9999999],
24
+ "c__RoleNamesGlobal": [
25
+ "Administrator",
26
+ "Distributed Sending User",
27
+ "Individual role for 700301950"
28
+ ],
29
+ "c__TimeZoneName": "(GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna *",
30
+ "c__LocaleCode": "en-GB"
31
+ }