mcdev 3.1.1 → 4.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 (135) hide show
  1. package/.eslintrc.json +67 -7
  2. package/.github/ISSUE_TEMPLATE/bug.yml +5 -1
  3. package/.github/ISSUE_TEMPLATE/task.md +1 -1
  4. package/.github/PULL_REQUEST_TEMPLATE.md +5 -3
  5. package/.github/dependabot.yml +14 -0
  6. package/.github/workflows/code-analysis.yml +57 -0
  7. package/.husky/commit-msg +10 -0
  8. package/.husky/post-checkout +5 -0
  9. package/.husky/pre-commit +2 -1
  10. package/.prettierrc +8 -0
  11. package/.vscode/settings.json +1 -1
  12. package/LICENSE +2 -2
  13. package/README.md +134 -45
  14. package/boilerplate/config.json +5 -11
  15. package/boilerplate/files/.prettierrc +8 -0
  16. package/boilerplate/files/.vscode/extensions.json +0 -1
  17. package/boilerplate/files/.vscode/settings.json +28 -2
  18. package/boilerplate/files/README.md +2 -2
  19. package/boilerplate/forcedUpdates.json +10 -0
  20. package/boilerplate/npm-dependencies.json +5 -5
  21. package/docs/dist/documentation.md +2795 -1724
  22. package/jsconfig.json +1 -1
  23. package/lib/Builder.js +166 -75
  24. package/lib/Deployer.js +244 -96
  25. package/lib/MetadataTypeDefinitions.js +2 -0
  26. package/lib/MetadataTypeInfo.js +2 -0
  27. package/lib/Retriever.js +61 -84
  28. package/lib/cli.js +133 -25
  29. package/lib/index.js +242 -563
  30. package/lib/metadataTypes/AccountUser.js +101 -95
  31. package/lib/metadataTypes/Asset.js +677 -248
  32. package/lib/metadataTypes/AttributeGroup.js +23 -12
  33. package/lib/metadataTypes/Automation.js +456 -357
  34. package/lib/metadataTypes/Campaign.js +33 -93
  35. package/lib/metadataTypes/ContentArea.js +31 -11
  36. package/lib/metadataTypes/DataExtension.js +391 -376
  37. package/lib/metadataTypes/DataExtensionField.js +131 -54
  38. package/lib/metadataTypes/DataExtensionTemplate.js +22 -4
  39. package/lib/metadataTypes/DataExtract.js +67 -50
  40. package/lib/metadataTypes/DataExtractType.js +14 -8
  41. package/lib/metadataTypes/Discovery.js +21 -16
  42. package/lib/metadataTypes/Email.js +32 -12
  43. package/lib/metadataTypes/EmailSendDefinition.js +85 -80
  44. package/lib/metadataTypes/EventDefinition.js +69 -47
  45. package/lib/metadataTypes/FileTransfer.js +78 -54
  46. package/lib/metadataTypes/Filter.js +11 -4
  47. package/lib/metadataTypes/Folder.js +149 -117
  48. package/lib/metadataTypes/FtpLocation.js +14 -8
  49. package/lib/metadataTypes/ImportFile.js +69 -69
  50. package/lib/metadataTypes/Interaction.js +19 -4
  51. package/lib/metadataTypes/List.js +54 -13
  52. package/lib/metadataTypes/MetadataType.js +687 -479
  53. package/lib/metadataTypes/MobileCode.js +46 -0
  54. package/lib/metadataTypes/MobileKeyword.js +114 -0
  55. package/lib/metadataTypes/Query.js +204 -103
  56. package/lib/metadataTypes/Role.js +76 -61
  57. package/lib/metadataTypes/Script.js +146 -82
  58. package/lib/metadataTypes/SetDefinition.js +20 -8
  59. package/lib/metadataTypes/TriggeredSendDefinition.js +78 -58
  60. package/lib/metadataTypes/definitions/Asset.definition.js +21 -10
  61. package/lib/metadataTypes/definitions/AttributeGroup.definition.js +12 -0
  62. package/lib/metadataTypes/definitions/Automation.definition.js +10 -5
  63. package/lib/metadataTypes/definitions/Campaign.definition.js +44 -1
  64. package/lib/metadataTypes/definitions/DataExtension.definition.js +4 -0
  65. package/lib/metadataTypes/definitions/DataExtensionTemplate.definition.js +6 -0
  66. package/lib/metadataTypes/definitions/DataExtract.definition.js +18 -14
  67. package/lib/metadataTypes/definitions/Discovery.definition.js +12 -0
  68. package/lib/metadataTypes/definitions/EmailSendDefinition.definition.js +4 -0
  69. package/lib/metadataTypes/definitions/EventDefinition.definition.js +22 -0
  70. package/lib/metadataTypes/definitions/FileTransfer.definition.js +4 -0
  71. package/lib/metadataTypes/definitions/Filter.definition.js +4 -0
  72. package/lib/metadataTypes/definitions/Folder.definition.js +6 -0
  73. package/lib/metadataTypes/definitions/FtpLocation.definition.js +4 -0
  74. package/lib/metadataTypes/definitions/ImportFile.definition.js +10 -5
  75. package/lib/metadataTypes/definitions/Interaction.definition.js +4 -0
  76. package/lib/metadataTypes/definitions/MobileCode.definition.js +163 -0
  77. package/lib/metadataTypes/definitions/MobileKeyword.definition.js +253 -0
  78. package/lib/metadataTypes/definitions/Query.definition.js +4 -0
  79. package/lib/metadataTypes/definitions/Role.definition.js +5 -0
  80. package/lib/metadataTypes/definitions/Script.definition.js +4 -0
  81. package/lib/metadataTypes/definitions/SetDefinition.definition.js +28 -0
  82. package/lib/metadataTypes/definitions/TriggeredSendDefinition.definition.js +4 -0
  83. package/lib/retrieveChangelog.js +7 -6
  84. package/lib/util/auth.js +117 -0
  85. package/lib/util/businessUnit.js +55 -66
  86. package/lib/util/cache.js +194 -0
  87. package/lib/util/cli.js +90 -116
  88. package/lib/util/config.js +302 -0
  89. package/lib/util/devops.js +240 -50
  90. package/lib/util/file.js +120 -191
  91. package/lib/util/init.config.js +195 -69
  92. package/lib/util/init.git.js +45 -50
  93. package/lib/util/init.js +72 -59
  94. package/lib/util/init.npm.js +48 -39
  95. package/lib/util/util.js +280 -564
  96. package/package.json +44 -33
  97. package/test/dataExtension.test.js +152 -0
  98. package/test/mockRoot/.mcdev-auth.json +8 -0
  99. package/test/mockRoot/.mcdevrc.json +67 -0
  100. package/test/mockRoot/deploy/testInstance/testBU/dataExtension/childBU_dataextension_test.dataExtension-meta.json +39 -0
  101. package/test/mockRoot/deploy/testInstance/testBU/dataExtension/testDataExtension.dataExtension-meta.json +23 -0
  102. package/test/mockRoot/deploy/testInstance/testBU/query/testExistingQuery.query-meta.json +11 -0
  103. package/test/mockRoot/deploy/testInstance/testBU/query/testExistingQuery.query-meta.sql +4 -0
  104. package/test/mockRoot/deploy/testInstance/testBU/query/testQuery.query-meta.json +11 -0
  105. package/test/mockRoot/deploy/testInstance/testBU/query/testQuery.query-meta.sql +4 -0
  106. package/test/query.test.js +149 -0
  107. package/test/resourceFactory.js +142 -0
  108. package/test/resources/1111111/dataFolder/retrieve-response.xml +43 -0
  109. package/test/resources/9999999/automation/v1/queries/549f0568-607c-4940-afef-437965094dat/patch-response.json +18 -0
  110. package/test/resources/9999999/automation/v1/queries/get-response.json +24 -0
  111. package/test/resources/9999999/automation/v1/queries/post-response.json +18 -0
  112. package/test/resources/9999999/dataExtension/build-expected.json +51 -0
  113. package/test/resources/9999999/dataExtension/create-expected.json +23 -0
  114. package/test/resources/9999999/dataExtension/create-response.xml +54 -0
  115. package/test/resources/9999999/dataExtension/retrieve-expected.json +51 -0
  116. package/test/resources/9999999/dataExtension/retrieve-response.xml +47 -0
  117. package/test/resources/9999999/dataExtension/template-expected.json +51 -0
  118. package/test/resources/9999999/dataExtension/update-expected.json +55 -0
  119. package/test/resources/9999999/dataExtension/update-response.xml +52 -0
  120. package/test/resources/9999999/dataExtensionField/retrieve-response.xml +93 -0
  121. package/test/resources/9999999/dataExtensionTemplate/retrieve-response.xml +303 -0
  122. package/test/resources/9999999/dataFolder/retrieve-response.xml +65 -0
  123. package/test/resources/9999999/query/build-expected.json +8 -0
  124. package/test/resources/9999999/query/get-expected.json +11 -0
  125. package/test/resources/9999999/query/patch-expected.json +11 -0
  126. package/test/resources/9999999/query/post-expected.json +11 -0
  127. package/test/resources/9999999/query/template-expected.json +8 -0
  128. package/test/resources/auth.json +32 -0
  129. package/test/resources/rest404-response.json +5 -0
  130. package/test/resources/retrieve-response.xml +21 -0
  131. package/test/utils.js +107 -0
  132. package/types/mcdev.d.js +301 -0
  133. package/CHANGELOG.md +0 -126
  134. package/PULL_REQUEST_TEMPLATE.md +0 -19
  135. package/test/util/file.js +0 -51
@@ -1,58 +1,77 @@
1
1
  'use strict';
2
2
 
3
+ const TYPE = require('../../types/mcdev.d');
3
4
  const MetadataType = require('./MetadataType');
4
5
  const Util = require('../util/util');
5
6
  const File = require('../util/file');
6
7
 
7
8
  /**
8
9
  * MessageSendActivity MetadataType
10
+ *
9
11
  * @augments MetadataType
10
12
  */
11
13
  class AccountUser extends MetadataType {
12
14
  /**
13
15
  * Retrieves SOAP based metadata of metadata type into local filesystem. executes callback with retrieved metadata
14
- * @param {String} retrieveDir Directory where retrieved metadata directory will be saved
15
- * @param {String[]} _ Returns specified fields even if their retrieve definition is not set to true
16
- * @param {Object} buObject properties for auth
17
- * @returns {Promise<Object>} Promise of metadata
16
+ *
17
+ * @param {string} retrieveDir Directory where retrieved metadata directory will be saved
18
+ * @param {void} _ unused parameter
19
+ * @param {TYPE.BuObject} buObject properties for auth
20
+ * @param {void} [___] unused parameter
21
+ * @param {string} [key] customer key of single item to retrieve
22
+ * @returns {Promise.<TYPE.MetadataTypeMapObj>} Promise of metadata
18
23
  */
19
- static async retrieve(retrieveDir, _, buObject) {
24
+ static async retrieve(retrieveDir, _, buObject, ___, key) {
20
25
  if (buObject.eid !== buObject.mid) {
21
- Util.logger.info('Skipping User retrieval on non-parent BU');
26
+ Util.logger.info(' - Skipping User retrieval on non-parent BU');
22
27
  return;
23
28
  }
24
- Util.logger.info('- Caching dependent Metadata: AccountUserAccount');
29
+ return this._retrieve(retrieveDir, buObject, key);
30
+ }
31
+ /**
32
+ * Retrieves SOAP based metadata of metadata type into local filesystem. executes callback with retrieved metadata
33
+ *
34
+ * @param {TYPE.BuObject} buObject properties for auth
35
+ * @returns {Promise.<TYPE.MetadataTypeMapObj>} Promise of metadata
36
+ */
37
+ static async retrieveChangelog(buObject) {
38
+ return this._retrieve(null, buObject, null);
39
+ }
40
+ /**
41
+ * Retrieves SOAP based metadata of metadata type into local filesystem. executes callback with retrieved metadata
42
+ *
43
+ * @private
44
+ * @param {string} retrieveDir Directory where retrieved metadata directory will be saved
45
+ * @param {TYPE.BuObject} buObject properties for auth
46
+ * @param {string} [key] customer key of single item to retrieve
47
+ * @returns {Promise.<TYPE.MetadataTypeMapObj>} Promise of metadata
48
+ */
49
+ static async _retrieve(retrieveDir, buObject, key) {
50
+ Util.logger.info(' - Caching dependent Metadata: AccountUserAccount');
25
51
 
26
52
  // get BUs that each users have access to
27
53
  const optionsBUs = {};
28
- let resultsBatch;
29
- await Util.retryOnError(`Retrying ${this.definition.type}`, async () => {
30
- resultsBatch = await new Promise((resolve, reject) => {
31
- this.client.SoapClient.retrieve(
32
- 'AccountUserAccount',
33
- [
34
- 'AccountUser.AccountUserID',
35
- 'AccountUser.UserID',
36
- 'Account.ID',
37
- 'Account.Name',
38
- ],
39
- optionsBUs,
40
- (ex, response) => (ex ? reject(ex) : resolve(response.body.Results))
41
- );
42
- });
43
- });
54
+
55
+ const resultsBatch = (
56
+ await this.client.soap.retrieveBulk(
57
+ 'AccountUserAccount',
58
+ ['AccountUser.AccountUserID', 'AccountUser.UserID', 'Account.ID', 'Account.Name'],
59
+ optionsBUs
60
+ )
61
+ ).Results;
44
62
  this.userIdBuMap = {};
45
- resultsBatch.forEach((item) => {
63
+ for (const item of resultsBatch) {
46
64
  this.userIdBuMap[item.AccountUser.AccountUserID] =
47
65
  this.userIdBuMap[item.AccountUser.AccountUserID] || [];
48
66
  this.userIdBuMap[item.AccountUser.AccountUserID].push({
49
67
  ID: item.Account.ID,
50
68
  Name: item.Account.Name,
51
69
  });
52
- });
70
+ }
53
71
  // get actual user details
54
- const options = {
55
- queryAllAccounts: true,
72
+ /** @type {TYPE.SoapRequestParams} */
73
+ let requestParams = {
74
+ QueryAllAccounts: true,
56
75
 
57
76
  filter: {
58
77
  leftOperand: {
@@ -79,13 +98,26 @@ class AccountUser extends MetadataType {
79
98
  },
80
99
  },
81
100
  };
101
+ if (key) {
102
+ // move original filter down one level into rightOperand and add key filter into leftOperand
103
+ requestParams = {
104
+ filter: {
105
+ leftOperand: {
106
+ leftOperand: 'CustomerKey',
107
+ operator: 'equals',
108
+ rightOperand: key,
109
+ },
110
+ operator: 'AND',
111
+ rightOperand: requestParams.filter,
112
+ },
113
+ };
114
+ }
82
115
 
83
- return super.retrieveSOAPgeneric(retrieveDir, buObject, options);
116
+ return super.retrieveSOAP(retrieveDir, buObject, requestParams);
84
117
  }
85
118
  /**
86
119
  *
87
120
  * @param {string} date first date
88
- * @param {string} date2 second date
89
121
  * @returns {number} time difference
90
122
  */
91
123
  static timeSinceDate(date) {
@@ -98,8 +130,8 @@ class AccountUser extends MetadataType {
98
130
  date = new Date(date);
99
131
  const now = new Date();
100
132
  const timediff = now - date;
101
- if (isNaN(timediff)) {
102
- return NaN;
133
+ if (Number.isNaN(timediff)) {
134
+ return Number.NaN;
103
135
  }
104
136
  let result;
105
137
  switch (interval) {
@@ -128,31 +160,28 @@ class AccountUser extends MetadataType {
128
160
  result = Math.floor(timediff / second);
129
161
  break;
130
162
  default:
131
- return undefined;
163
+ return;
132
164
  }
133
165
  return result + ' ' + interval;
134
166
  }
135
167
  /**
136
168
  * helper to print bu names
137
- * @param {Util.BuObject} buObject needed for eid
169
+ *
170
+ * @param {TYPE.BuObject} buObject needed for eid
138
171
  * @param {string} buObject.eid needed to check for parent bu
139
- * @param {numeric} id bu id
172
+ * @param {number} id bu id
140
173
  * @returns {string} "bu name (bu id)""
141
174
  */
142
175
  static getBuName(buObject, id) {
143
- let name;
144
- if (buObject.eid == id) {
145
- name = '_ParentBU_';
146
- } else {
147
- name = this.buIdName[id];
148
- }
176
+ const name = buObject.eid == id ? '_ParentBU_' : this.buIdName[id];
149
177
  return `<nobr>${name} (${id})</nobr>`;
150
178
  }
151
179
  /**
152
180
  * Creates markdown documentation of all roles
153
- * @param {Util.BuObject} buObject properties for auth
154
- * @param {Object} [metadata] user list
155
- * @returns {Promise<void>} -
181
+ *
182
+ * @param {TYPE.BuObject} buObject properties for auth
183
+ * @param {TYPE.MetadataTypeMap} [metadata] user list
184
+ * @returns {Promise.<void>} -
156
185
  */
157
186
  static async document(buObject, metadata) {
158
187
  if (buObject.eid !== buObject.mid) {
@@ -182,6 +211,9 @@ class AccountUser extends MetadataType {
182
211
 
183
212
  // initialize permission object
184
213
  this.allPermissions = {};
214
+ /**
215
+ * @type {TYPE.AccountUserDocument[]}
216
+ */
185
217
  const users = [];
186
218
  // traverse all permissions recursively and write them into allPermissions object once it has reached the end
187
219
  for (const id in metadata) {
@@ -194,9 +226,7 @@ class AccountUser extends MetadataType {
194
226
  user.UserPermissions = [user.UserPermissions];
195
227
  }
196
228
  userPermissions = user.UserPermissions.map((item) => item.ID * 1)
197
- .sort(function (a, b) {
198
- return a < b ? -1 : a > b ? 1 : 0;
199
- })
229
+ .sort((a, b) => (a < b ? -1 : a > b ? 1 : 0))
200
230
  .join(', ');
201
231
  }
202
232
  // user roles
@@ -206,9 +236,7 @@ class AccountUser extends MetadataType {
206
236
  roles =
207
237
  '<nobr>' +
208
238
  user.Roles.map((item) => item.Name)
209
- .sort(function (a, b) {
210
- return a < b ? -1 : a > b ? 1 : 0;
211
- })
239
+ .sort((a, b) => (a < b ? -1 : a > b ? 1 : 0))
212
240
  .join(',</nobr><br> <nobr>') +
213
241
  '</nobr>';
214
242
  }
@@ -218,9 +246,7 @@ class AccountUser extends MetadataType {
218
246
  this.buIdName[item.ID] = item.Name;
219
247
  return this.getBuName(buObject, item.ID);
220
248
  })
221
- .sort(function (a, b) {
222
- return a < b ? -1 : a > b ? 1 : 0;
223
- })
249
+ .sort((a, b) => (a < b ? -1 : a > b ? 1 : 0))
224
250
  .join(',<br> ');
225
251
  }
226
252
  const defaultBUName = this.getBuName(buObject, user.DefaultBusinessUnit);
@@ -232,9 +258,9 @@ class AccountUser extends MetadataType {
232
258
  Name: user.Name,
233
259
  Email: user.Email,
234
260
  NotificationEmailAddress: user.NotificationEmailAddress,
235
- ActiveFlag: user.ActiveFlag === 'true' ? '✓' : '-',
236
- IsAPIUser: user.IsAPIUser === 'true' ? '✓' : '-',
237
- MustChangePassword: user.MustChangePassword === 'true' ? '✓' : '-',
261
+ ActiveFlag: user.ActiveFlag === true ? '✓' : '-',
262
+ IsAPIUser: user.IsAPIUser === true ? '✓' : '-',
263
+ MustChangePassword: user.MustChangePassword === true ? '✓' : '-',
238
264
  DefaultBusinessUnit: defaultBUName,
239
265
  AssociatedBusinessUnits__c: associatedBus,
240
266
  Roles: roles,
@@ -244,9 +270,7 @@ class AccountUser extends MetadataType {
244
270
  ModifiedDate: user.ModifiedDate.split('T').join(' '),
245
271
  });
246
272
  }
247
- users.sort(function (a, b) {
248
- return a.Name < b.Name ? -1 : a.Name > b.Name ? 1 : 0;
249
- });
273
+ users.sort((a, b) => (a.Name < b.Name ? -1 : a.Name > b.Name ? 1 : 0));
250
274
  const columnsToPrint = [
251
275
  ['Name', 'Name'],
252
276
  ['Last successful Login', 'LastSuccessfulLogin'],
@@ -281,72 +305,60 @@ class AccountUser extends MetadataType {
281
305
  'Installed Package',
282
306
  columnsToPrint
283
307
  );
284
- const docPath = File.normalizePath([this.properties.directories.users]);
308
+ const docPath = File.normalizePath([this.properties.directories.docs, 'user']);
285
309
 
286
310
  try {
287
311
  const filename = buObject.credential;
288
- // ensure docs/roles folder is existing (depends on setup in .mcdevrc.json)
289
- if (!File.existsSync(docPath)) {
290
- File.mkdirpSync(docPath);
291
- }
292
312
  // write to disk
293
- await File.writeToFile(docPath, filename + '.accountUser', 'md', output);
294
- Util.logger.info(`Created ${docPath}${filename}.accountUser.md`);
313
+ await File.writeToFile(docPath, filename + '.accountUsers', 'md', output);
314
+ Util.logger.info(`Created ${File.normalizePath([docPath, filename])}.accountUsers.md`);
295
315
  if (['html', 'both'].includes(this.properties.options.documentType)) {
296
316
  Util.logger.warn(
297
- 'HTML-based documentation of accountUser currently not supported.'
317
+ ' - HTML-based documentation of accountUser currently not supported.'
298
318
  );
299
319
  }
300
320
  } catch (ex) {
301
321
  Util.logger.error(`AccountUser.document():: error | `, ex.message);
302
322
  }
303
323
  }
304
- /**
305
- * Experimental: Only working for DataExtensions:
306
- * Saves json content to a html table in the local file system. Will create the parent directory if it does not exist.
307
- * The json's first level of keys must represent the rows and the secend level the columns
308
- * @private
309
- * @param {DataExtensionItem} json dataextension
310
- * @param {Array} tabled prepped array for output in tabular format
311
- * @returns {string} file content
312
- */
313
324
  /**
314
325
  *
315
- * @param {Object[]} users list of users and installed package
326
+ * @param {object[]} users list of users and installed package
316
327
  * @param {'Installed Package'|'User'} type choose what sub type to print
317
328
  * @param {Array[]} columnsToPrint helper array
318
- * @param {Object} buObject properties for auth
319
329
  * @returns {string} markdown
320
330
  */
321
331
  static _generateDocMd(users, type, columnsToPrint) {
322
332
  let output = `\n\n## ${type}s (${users.length})\n\n`;
323
333
  let tableSeparator = '';
324
- columnsToPrint.forEach((column) => {
334
+ for (const column of columnsToPrint) {
325
335
  output += `| ${column[0]} `;
326
336
  tableSeparator += '| --- ';
327
- });
337
+ }
328
338
  output += `|\n${tableSeparator}|\n`;
329
- users.forEach((user) => {
330
- columnsToPrint.forEach((column) => {
339
+ for (const user of users) {
340
+ for (const column of columnsToPrint) {
331
341
  output += `| ${user[column[1]]} `;
332
- });
342
+ }
333
343
  output += `|\n`;
334
- });
344
+ }
335
345
  return output;
336
346
  }
337
347
 
338
348
  /**
339
349
  * manages post retrieve steps
340
- * @param {Object} metadata a single query
341
- * @returns {Object[]} Array with one metadata object and one query string
350
+ *
351
+ * @param {TYPE.MetadataTypeItem} metadata a single query
352
+ * @returns {TYPE.MetadataTypeItem} Array with one metadata object and one query string
342
353
  */
343
354
  static postRetrieveTasks(metadata) {
344
355
  return this.parseMetadata(metadata);
345
356
  }
346
357
  /**
347
358
  * parses retrieved Metadata before saving
348
- * @param {Object} metadata a single query activity definition
349
- * @returns {Array} Array with one metadata object and one sql string
359
+ *
360
+ * @param {TYPE.MetadataTypeItem} metadata a single query activity definition
361
+ * @returns {TYPE.MetadataTypeItem} Array with one metadata object and one sql string
350
362
  */
351
363
  static parseMetadata(metadata) {
352
364
  metadata.type__c = 'Installed Package';
@@ -354,11 +366,7 @@ class AccountUser extends MetadataType {
354
366
  metadata.type__c = 'User';
355
367
  }
356
368
 
357
- if (this.userIdBuMap[metadata.ID]) {
358
- metadata.AssociatedBusinessUnits__c = this.userIdBuMap[metadata.ID];
359
- } else {
360
- metadata.AssociatedBusinessUnits__c = [];
361
- }
369
+ metadata.AssociatedBusinessUnits__c = this.userIdBuMap[metadata.ID] || [];
362
370
 
363
371
  let roles;
364
372
  if (metadata.Roles.Role) {
@@ -370,9 +378,7 @@ class AccountUser extends MetadataType {
370
378
  roles = metadata.Roles.Role.map((item) => ({
371
379
  Name: item.Name,
372
380
  CustomerKey: item.CustomerKey,
373
- })).sort(function (a, b) {
374
- return a.Name < b.Name ? -1 : a.Name > b.Name ? 1 : 0;
375
- });
381
+ })).sort((a, b) => (a.Name < b.Name ? -1 : a.Name > b.Name ? 1 : 0));
376
382
  } else {
377
383
  // set to empty array
378
384
  roles = [];