mcdev 3.1.3 → 4.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. package/.eslintrc.json +67 -7
  2. package/.github/ISSUE_TEMPLATE/bug.yml +2 -1
  3. package/.github/PULL_REQUEST_TEMPLATE.md +5 -3
  4. package/.github/dependabot.yml +14 -0
  5. package/.github/workflows/code-analysis.yml +57 -0
  6. package/.husky/commit-msg +10 -0
  7. package/.husky/post-checkout +5 -0
  8. package/.husky/pre-commit +2 -1
  9. package/.prettierrc +8 -0
  10. package/.vscode/settings.json +1 -1
  11. package/LICENSE +2 -2
  12. package/README.md +134 -45
  13. package/boilerplate/config.json +5 -11
  14. package/boilerplate/files/.prettierrc +8 -0
  15. package/boilerplate/files/.vscode/extensions.json +0 -1
  16. package/boilerplate/files/.vscode/settings.json +30 -2
  17. package/boilerplate/files/README.md +2 -2
  18. package/boilerplate/forcedUpdates.json +10 -0
  19. package/boilerplate/npm-dependencies.json +5 -5
  20. package/docs/dist/documentation.md +2807 -1730
  21. package/jsconfig.json +1 -1
  22. package/lib/Builder.js +171 -74
  23. package/lib/Deployer.js +244 -96
  24. package/lib/MetadataTypeDefinitions.js +2 -0
  25. package/lib/MetadataTypeInfo.js +2 -0
  26. package/lib/Retriever.js +61 -84
  27. package/lib/cli.js +116 -11
  28. package/lib/index.js +241 -561
  29. package/lib/metadataTypes/AccountUser.js +117 -103
  30. package/lib/metadataTypes/Asset.js +705 -255
  31. package/lib/metadataTypes/AttributeGroup.js +23 -12
  32. package/lib/metadataTypes/Automation.js +489 -392
  33. package/lib/metadataTypes/Campaign.js +33 -93
  34. package/lib/metadataTypes/ContentArea.js +31 -11
  35. package/lib/metadataTypes/DataExtension.js +387 -372
  36. package/lib/metadataTypes/DataExtensionField.js +131 -54
  37. package/lib/metadataTypes/DataExtensionTemplate.js +22 -4
  38. package/lib/metadataTypes/DataExtract.js +61 -48
  39. package/lib/metadataTypes/DataExtractType.js +14 -8
  40. package/lib/metadataTypes/Discovery.js +21 -16
  41. package/lib/metadataTypes/Email.js +32 -12
  42. package/lib/metadataTypes/EmailSendDefinition.js +85 -80
  43. package/lib/metadataTypes/EventDefinition.js +61 -43
  44. package/lib/metadataTypes/FileTransfer.js +72 -52
  45. package/lib/metadataTypes/Filter.js +11 -4
  46. package/lib/metadataTypes/Folder.js +149 -117
  47. package/lib/metadataTypes/FtpLocation.js +14 -8
  48. package/lib/metadataTypes/ImportFile.js +61 -64
  49. package/lib/metadataTypes/Interaction.js +19 -4
  50. package/lib/metadataTypes/List.js +54 -13
  51. package/lib/metadataTypes/MetadataType.js +664 -454
  52. package/lib/metadataTypes/MobileCode.js +46 -0
  53. package/lib/metadataTypes/MobileKeyword.js +114 -0
  54. package/lib/metadataTypes/Query.js +206 -105
  55. package/lib/metadataTypes/Role.js +76 -61
  56. package/lib/metadataTypes/Script.js +147 -83
  57. package/lib/metadataTypes/SetDefinition.js +20 -8
  58. package/lib/metadataTypes/TriggeredSendDefinition.js +78 -58
  59. package/lib/metadataTypes/definitions/Asset.definition.js +21 -10
  60. package/lib/metadataTypes/definitions/AttributeGroup.definition.js +12 -0
  61. package/lib/metadataTypes/definitions/Automation.definition.js +10 -5
  62. package/lib/metadataTypes/definitions/Campaign.definition.js +44 -1
  63. package/lib/metadataTypes/definitions/DataExtension.definition.js +4 -0
  64. package/lib/metadataTypes/definitions/DataExtensionTemplate.definition.js +6 -0
  65. package/lib/metadataTypes/definitions/DataExtract.definition.js +18 -14
  66. package/lib/metadataTypes/definitions/Discovery.definition.js +12 -0
  67. package/lib/metadataTypes/definitions/EmailSendDefinition.definition.js +4 -0
  68. package/lib/metadataTypes/definitions/EventDefinition.definition.js +22 -0
  69. package/lib/metadataTypes/definitions/FileTransfer.definition.js +4 -0
  70. package/lib/metadataTypes/definitions/Filter.definition.js +4 -0
  71. package/lib/metadataTypes/definitions/Folder.definition.js +6 -0
  72. package/lib/metadataTypes/definitions/FtpLocation.definition.js +4 -0
  73. package/lib/metadataTypes/definitions/ImportFile.definition.js +10 -5
  74. package/lib/metadataTypes/definitions/Interaction.definition.js +4 -0
  75. package/lib/metadataTypes/definitions/MobileCode.definition.js +163 -0
  76. package/lib/metadataTypes/definitions/MobileKeyword.definition.js +253 -0
  77. package/lib/metadataTypes/definitions/Query.definition.js +4 -0
  78. package/lib/metadataTypes/definitions/Role.definition.js +5 -0
  79. package/lib/metadataTypes/definitions/Script.definition.js +4 -0
  80. package/lib/metadataTypes/definitions/SetDefinition.definition.js +28 -0
  81. package/lib/metadataTypes/definitions/TriggeredSendDefinition.definition.js +4 -0
  82. package/lib/retrieveChangelog.js +7 -6
  83. package/lib/util/auth.js +117 -0
  84. package/lib/util/businessUnit.js +55 -66
  85. package/lib/util/cache.js +194 -0
  86. package/lib/util/cli.js +90 -116
  87. package/lib/util/config.js +302 -0
  88. package/lib/util/devops.js +250 -50
  89. package/lib/util/file.js +141 -201
  90. package/lib/util/init.config.js +208 -75
  91. package/lib/util/init.git.js +45 -50
  92. package/lib/util/init.js +72 -59
  93. package/lib/util/init.npm.js +48 -39
  94. package/lib/util/util.js +280 -564
  95. package/package.json +45 -34
  96. package/test/dataExtension.test.js +152 -0
  97. package/test/mockRoot/.mcdev-auth.json +8 -0
  98. package/test/mockRoot/.mcdevrc.json +67 -0
  99. package/test/mockRoot/deploy/testInstance/testBU/dataExtension/childBU_dataextension_test.dataExtension-meta.json +39 -0
  100. package/test/mockRoot/deploy/testInstance/testBU/dataExtension/testDataExtension.dataExtension-meta.json +23 -0
  101. package/test/mockRoot/deploy/testInstance/testBU/query/testExistingQuery.query-meta.json +11 -0
  102. package/test/mockRoot/deploy/testInstance/testBU/query/testExistingQuery.query-meta.sql +4 -0
  103. package/test/mockRoot/deploy/testInstance/testBU/query/testQuery.query-meta.json +11 -0
  104. package/test/mockRoot/deploy/testInstance/testBU/query/testQuery.query-meta.sql +4 -0
  105. package/test/query.test.js +149 -0
  106. package/test/resourceFactory.js +142 -0
  107. package/test/resources/1111111/dataFolder/retrieve-response.xml +43 -0
  108. package/test/resources/9999999/automation/v1/queries/549f0568-607c-4940-afef-437965094dat/patch-response.json +18 -0
  109. package/test/resources/9999999/automation/v1/queries/get-response.json +24 -0
  110. package/test/resources/9999999/automation/v1/queries/post-response.json +18 -0
  111. package/test/resources/9999999/dataExtension/build-expected.json +51 -0
  112. package/test/resources/9999999/dataExtension/create-expected.json +23 -0
  113. package/test/resources/9999999/dataExtension/create-response.xml +54 -0
  114. package/test/resources/9999999/dataExtension/retrieve-expected.json +51 -0
  115. package/test/resources/9999999/dataExtension/retrieve-response.xml +47 -0
  116. package/test/resources/9999999/dataExtension/template-expected.json +51 -0
  117. package/test/resources/9999999/dataExtension/update-expected.json +55 -0
  118. package/test/resources/9999999/dataExtension/update-response.xml +52 -0
  119. package/test/resources/9999999/dataExtensionField/retrieve-response.xml +93 -0
  120. package/test/resources/9999999/dataExtensionTemplate/retrieve-response.xml +303 -0
  121. package/test/resources/9999999/dataFolder/retrieve-response.xml +65 -0
  122. package/test/resources/9999999/query/build-expected.json +8 -0
  123. package/test/resources/9999999/query/get-expected.json +11 -0
  124. package/test/resources/9999999/query/patch-expected.json +11 -0
  125. package/test/resources/9999999/query/post-expected.json +11 -0
  126. package/test/resources/9999999/query/template-expected.json +8 -0
  127. package/test/resources/auth.json +32 -0
  128. package/test/resources/rest404-response.json +5 -0
  129. package/test/resources/retrieve-response.xml +21 -0
  130. package/test/utils.js +107 -0
  131. package/types/mcdev.d.js +301 -0
  132. package/CHANGELOG.md +0 -126
  133. package/PULL_REQUEST_TEMPLATE.md +0 -19
  134. package/test/util/file.js +0 -51
@@ -1,25 +1,33 @@
1
1
  'use strict';
2
2
 
3
+ const TYPE = require('../../types/mcdev.d');
3
4
  const MetadataType = require('./MetadataType');
4
5
  const toposort = require('toposort');
5
6
  const Util = require('../util/util');
6
7
  const File = require('../util/file');
8
+ const cache = require('../util/cache');
7
9
 
8
10
  /**
9
11
  * Folder MetadataType
12
+ *
10
13
  * @augments MetadataType
11
14
  */
12
15
  class Folder extends MetadataType {
13
16
  /**
14
17
  * Retrieves metadata of metadata type into local filesystem. executes callback with retrieved metadata
15
- * @param {String} retrieveDir Directory where retrieved metadata directory will be saved
16
- * @param {String[]} [additionalFields] Returns specified fields even if their retrieve definition is not set to true
17
- * @param {Object} buObject properties for auth
18
+ *
19
+ * @param {string} retrieveDir Directory where retrieved metadata directory will be saved
20
+ * @param {string[]} [additionalFields] Returns specified fields even if their retrieve definition is not set to true
21
+ * @param {TYPE.BuObject} buObject properties for auth
22
+ * @param {void} [___] unused parameter
23
+ * @param {string} [key] customer key of single item to retrieve
18
24
  * @returns {Promise} Promise
19
25
  */
20
- static async retrieve(retrieveDir, additionalFields, buObject) {
26
+ static async retrieve(retrieveDir, additionalFields, buObject, ___, key) {
27
+ if (key) {
28
+ Util.logger.error(`Folder.retrieve() does not support key parameter`);
29
+ }
21
30
  const queryAllFolders = await this.retrieveHelper(additionalFields, true);
22
- // if this is the parent, no need to query twice as QueryAllAccounts works.
23
31
 
24
32
  if (buObject.eid !== buObject.mid) {
25
33
  queryAllFolders.push(...(await this.retrieveHelper(additionalFields, false)));
@@ -36,6 +44,8 @@ class Folder extends MetadataType {
36
44
  else if (!val.CustomerKey) {
37
45
  val.CustomerKey = [buObject.eid, val.ID].join('-');
38
46
  }
47
+ // ensure name is a string and not a number (SFMC-SDK workaround)
48
+ val.Name = val.Name + '';
39
49
 
40
50
  idMap[val.ID] = val;
41
51
  }
@@ -47,12 +57,9 @@ class Folder extends MetadataType {
47
57
  for (const id of sortPairs) {
48
58
  if (!idMap[id]) {
49
59
  Util.logger.debug(`Error: id ${id} not found in idMap-obj but in sortPairs-array.`);
50
- if (Util.logger.level === 'debug') {
51
- console.log(`Error: id ${id} not found in idMap-ob but in sortPairs-array.`);
52
- }
53
60
  } else if (
54
61
  idMap[id].ParentFolder &&
55
- idMap[id].ParentFolder.ID &&
62
+ Number.isSafeInteger(idMap[id].ParentFolder.ID) &&
56
63
  idMap[id].Name !== '<ROOT>'
57
64
  ) {
58
65
  // if the parent folder can be found by ID
@@ -69,16 +76,16 @@ class Folder extends MetadataType {
69
76
  idMap[id].Path = idMap[id].Name;
70
77
  }
71
78
  } else {
72
- Util.logger.error(
73
- `Skipping - Cannot find parent folder (${idMap[id].ParentFolder.ID}) of: ${idMap[id].Name} (${id}, type: ${idMap[id].ContentType})`
79
+ Util.logger.warn(
80
+ ` - Skipping folder ${idMap[id].Name} (${id}, type: ${idMap[id].ContentType}): Cannot find parent folder (${idMap[id].ParentFolder.ID})`
74
81
  );
75
82
  }
76
83
  }
77
84
  // All folders except the artificial root have ParentFolder attribute. If they dont something else is wrong
78
85
  else if (idMap[id].Name !== '<ROOT>') {
79
86
  idMap[id].Path = '';
80
- Util.logger.error(
81
- `Skipping - Folder ${idMap[id].Name} does not have a parent folder (type: ${idMap[id].ContentType})`
87
+ Util.logger.warn(
88
+ ` - Skipping folder ${idMap[id].Name} (${id}, type: ${idMap[id].ContentType}): Does not have a parent folder`
82
89
  );
83
90
  }
84
91
  }
@@ -97,8 +104,7 @@ class Folder extends MetadataType {
97
104
  for (const id in idMap) {
98
105
  // remove keys which are listed in other BUs and skip root
99
106
  if (
100
- idMap[id].Client &&
101
- idMap[id].Client.ID &&
107
+ idMap[id].Client?.ID &&
102
108
  (buObject.mid == idMap[id].Client.ID ||
103
109
  this.definition.folderTypesFromParent.includes(
104
110
  idMap[id].ContentType.toLowerCase()
@@ -142,7 +148,8 @@ class Folder extends MetadataType {
142
148
 
143
149
  /**
144
150
  * Retrieves folder metadata for caching
145
- * @param {Object} buObject properties for auth
151
+ *
152
+ * @param {TYPE.BuObject} buObject properties for auth
146
153
  * @returns {Promise} Promise
147
154
  */
148
155
  static retrieveForCache(buObject) {
@@ -153,12 +160,14 @@ class Folder extends MetadataType {
153
160
  * Folder upsert (copied from Metadata Upsert), after retrieving from target
154
161
  * and comparing to check if create or update operation is needed.
155
162
  * Copied due to having a dependency on itself, meaning the created need to be serial
156
- * @param {Object} metadata metadata mapped by their keyField
157
- * @returns {Promise<Object>} Promise of saved metadata
163
+ *
164
+ * @param {TYPE.MetadataTypeMap} metadata metadata mapped by their keyField
165
+ * @returns {Promise.<object>} Promise of saved metadata
158
166
  */
159
167
  static async upsert(metadata) {
160
168
  let updateCount = 0;
161
169
  let createCount = 0;
170
+ let filteredByPreDeploy = 0;
162
171
  const upsertResults = {};
163
172
  const sortPairs = toposort(
164
173
  Object.keys(metadata).map((customerKey) => [
@@ -180,18 +189,61 @@ class Folder extends MetadataType {
180
189
  let existingId;
181
190
  try {
182
191
  // perform a secondary check based on path
183
- existingId = Util.getFromCache(
184
- this.cache,
192
+ existingId = cache.searchForField(
185
193
  'folder',
186
194
  deployableMetadata.Path,
187
195
  'Path',
188
196
  'ID'
189
197
  );
190
- } catch (ex) {
198
+ const cachedVersion = cache.getByKey(
199
+ 'folder',
200
+ cache.searchForField(
201
+ 'folder',
202
+ deployableMetadata.Path,
203
+ 'Path',
204
+ this.definition.keyField
205
+ )
206
+ );
207
+ if (
208
+ existingId &&
209
+ !this.hasChangedGeneric(
210
+ cachedVersion,
211
+ metadata[metadataKey],
212
+ null,
213
+ true
214
+ )
215
+ ) {
216
+ Util.logger.verbose(
217
+ ` - skipping ${this.definition.type} ${
218
+ cachedVersion?.Path ||
219
+ metadata[metadataKey][this.definition.nameField]
220
+ }: no change detected`
221
+ );
222
+ filteredByPreDeploy++;
223
+ continue;
224
+ }
225
+ } catch {
191
226
  // In case no path matching, then try to use CustomerKey
192
- existingId = this.cache.folder[normalizedKey]
193
- ? this.cache.folder[normalizedKey].ID
194
- : null;
227
+ const cachedVersion = cache.getByKey('folder', normalizedKey);
228
+ existingId = cachedVersion?.ID;
229
+ if (
230
+ existingId &&
231
+ !this.hasChangedGeneric(
232
+ cachedVersion,
233
+ metadata[metadataKey],
234
+ null,
235
+ true
236
+ )
237
+ ) {
238
+ Util.logger.verbose(
239
+ ` - skipping ${this.definition.type} ${
240
+ cachedVersion?.Path ||
241
+ metadata[metadataKey][this.definition.nameField]
242
+ }: no change detected`
243
+ );
244
+ filteredByPreDeploy++;
245
+ continue;
246
+ }
195
247
  }
196
248
 
197
249
  let result;
@@ -206,48 +258,48 @@ class Folder extends MetadataType {
206
258
  result = await this.create(deployableMetadata);
207
259
  createCount++;
208
260
  }
209
- if (result && result.body && result.body.Results) {
261
+ if (result?.Results) {
210
262
  const parsed = this.parseResponseBody({
211
- Results: [result.body.Results[0].Object],
263
+ Results: [result.Results[0].Object],
212
264
  });
213
- if (
214
- !result.body.Results[0].Object.CustomerKey &&
215
- parsed['undefined']
216
- ) {
265
+ if (!result.Results[0].Object.CustomerKey && parsed['undefined']) {
217
266
  // when inserting folders without specifying a CustomerKey, this happens in parseResponseBody()
218
267
  parsed[normalizedKey] = parsed['undefined'];
219
268
  delete parsed['undefined'];
220
269
  }
221
- this.cache.folder[normalizedKey] = Object.assign(
270
+ const newObject = {};
271
+ newObject[normalizedKey] = Object.assign(
222
272
  beforeMetadata,
223
273
  parsed[normalizedKey]
224
274
  );
275
+ cache.mergeMetadata('folder', newObject);
225
276
 
226
277
  upsertResults[metadataKey] = beforeMetadata;
227
278
  } else {
228
279
  Util.logger.debug(result);
229
280
  throw new Error(
230
- `'${beforeMetadata[metadataKey].Path}' was not deployed correctly`
281
+ `'${beforeMetadata.Path}' was not deployed correctly`
231
282
  );
232
283
  }
233
284
  }
234
285
  } catch (ex) {
235
- Util.metadataLogger('error', 'folder', 'upsert', ex, metadataKey);
286
+ Util.logger.errorStack(
287
+ ex,
288
+ `Upserting ${this.definition.type} failed: ${ex.message}`
289
+ );
236
290
  }
237
291
  }
238
292
  }
239
293
  }
240
294
  // Logging
241
- Util.metadataLogger(
242
- 'info',
243
- this.definition.type,
244
- 'upsert',
245
- `${createCount} created / ${updateCount} updated`
295
+ Util.logger.info(
296
+ `${this.definition.type} upsert: ${createCount} created / ${updateCount} updated` +
297
+ (filteredByPreDeploy > 0 ? ` / ${filteredByPreDeploy} filtered` : '')
246
298
  );
247
299
 
248
300
  if (updateCount) {
249
301
  Util.logger.warn(
250
- `Folders are recognized for updates based on their CustomerKey or, if that is not given, their folder-path.`
302
+ ` - Folders are recognized for updates based on their CustomerKey or, if that is not given, their folder-path.`
251
303
  );
252
304
  }
253
305
  return upsertResults;
@@ -255,36 +307,37 @@ class Folder extends MetadataType {
255
307
 
256
308
  /**
257
309
  * creates a folder based on metatadata
258
- * @param {Object} metadata metadata of the folder
310
+ *
311
+ * @param {TYPE.MetadataTypeItem} metadataEntry metadata of the folder
259
312
  * @returns {Promise} Promise
260
313
  */
261
- static async create(metadata) {
262
- if (metadata.Parent && metadata.Parent.ID && metadata.Parent.ID === 0) {
314
+ static async create(metadataEntry) {
315
+ if (metadataEntry?.Parent?.ID === 0) {
263
316
  Util.logger.error(
264
- `${this.definition.type}-${metadata.ContentType}.create:: Cannot create Root Folder: ${metadata.Name}`
317
+ `${this.definition.type}-${metadataEntry.ContentType}.create:: Cannot create Root Folder: ${metadataEntry.Name}`
265
318
  );
266
319
  return {};
267
320
  }
268
- const path = metadata.Path;
321
+ const path = metadataEntry.Path;
269
322
  try {
270
- const response = await super.createSOAP(metadata, 'DataFolder', true);
323
+ const response = await super.createSOAP(metadataEntry, 'DataFolder', true);
271
324
  if (response) {
272
- response.body.Results[0].Object = metadata;
273
- response.body.Results[0].Object.ID = response.body.Results[0].NewID;
274
- response.body.Results[0].Object.CustomerKey = metadata.CustomerKey;
275
- delete response.body.Results[0].Object.$;
325
+ response.Results[0].Object = metadataEntry;
326
+ response.Results[0].Object.ID = response.Results[0].NewID;
327
+ response.Results[0].Object.CustomerKey = metadataEntry.CustomerKey;
328
+ delete response.Results[0].Object.$;
276
329
 
277
- Util.logger.info(`- created folder: ${path}`);
330
+ Util.logger.info(` - created folder: ${path}`);
278
331
  return response;
279
332
  }
280
333
  } catch (ex) {
281
- if (ex && ex.results) {
334
+ if (ex?.results) {
282
335
  Util.logger.error(
283
- `${this.definition.type}-${metadata.ContentType}.create:: error creating: '${path}'. ${ex.results[0].StatusMessage}`
336
+ `${this.definition.type}-${metadataEntry.ContentType}.create:: error creating: '${path}'. ${ex.results[0].StatusMessage}`
284
337
  );
285
338
  } else if (ex) {
286
339
  Util.logger.error(
287
- `${this.definition.type}-${metadata.ContentType}.create:: error creating: '${path}'. ${ex.message}`
340
+ `${this.definition.type}-${metadataEntry.ContentType}.create:: error creating: '${path}'. ${ex.message}`
288
341
  );
289
342
  }
290
343
  }
@@ -292,28 +345,29 @@ class Folder extends MetadataType {
292
345
 
293
346
  /**
294
347
  * Updates a single Folder.
295
- * @param {Object} metadata single metadata entry
348
+ *
349
+ * @param {TYPE.MetadataTypeItem} metadataEntry single metadata entry
296
350
  * @returns {Promise} Promise
297
351
  */
298
- static async update(metadata) {
299
- const path = metadata.Path;
352
+ static async update(metadataEntry) {
353
+ const path = metadataEntry.Path;
300
354
  try {
301
- const response = await super.updateSOAP(metadata, 'DataFolder', true);
355
+ const response = await super.updateSOAP(metadataEntry, 'DataFolder', true);
302
356
  if (response) {
303
- response.body.Results[0].Object = metadata;
304
- response.body.Results[0].Object.CustomerKey = metadata.CustomerKey;
305
- delete response.body.Results[0].Object.$;
306
- Util.logger.info(`- updated folder: ${path}`);
357
+ response.Results[0].Object = metadataEntry;
358
+ response.Results[0].Object.CustomerKey = metadataEntry.CustomerKey;
359
+ delete response.Results[0].Object.$;
360
+ Util.logger.info(` - updated folder: ${path}`);
307
361
  return response;
308
362
  }
309
363
  } catch (ex) {
310
- if (ex && ex.results) {
364
+ if (ex?.results) {
311
365
  Util.logger.error(
312
- `${this.definition.type}-${metadata.ContentType}.update:: error updating: '${path}'. ${ex.results[0].StatusMessage}`
366
+ `${this.definition.type}-${metadataEntry.ContentType}.update:: error updating: '${path}'. ${ex.results[0].StatusMessage}`
313
367
  );
314
368
  } else if (ex) {
315
369
  Util.logger.error(
316
- `${this.definition.type}-${metadata.ContentType}.update:: error updating: '${path}'. ${ex.message}`
370
+ `${this.definition.type}-${metadataEntry.ContentType}.update:: error updating: '${path}'. ${ex.message}`
317
371
  );
318
372
  }
319
373
  }
@@ -321,13 +375,14 @@ class Folder extends MetadataType {
321
375
 
322
376
  /**
323
377
  * prepares a folder for deployment
324
- * @param {Object} metadata a single folder definition
325
- * @returns {Promise} Promise
378
+ *
379
+ * @param {TYPE.MetadataTypeItem} metadata a single folder definition
380
+ * @returns {Promise.<TYPE.MetadataTypeItem>} Promise of parsed folder metadata
326
381
  */
327
382
  static async preDeployTasks(metadata) {
328
383
  if (!this.definition.deployFolderTypes.includes(metadata.ContentType.toLowerCase())) {
329
384
  Util.logger.warn(
330
- `Folder ${metadata.Name} is of a type which does not support deployment (Type: ${metadata.ContentType}). Please create this manually in the Web-Interface.`
385
+ ` - Folder ${metadata.Name} is of a type which does not support deployment (Type: ${metadata.ContentType}). Please create this manually in the Web-Interface.`
331
386
  );
332
387
  return;
333
388
  }
@@ -353,9 +408,8 @@ class Folder extends MetadataType {
353
408
  return;
354
409
  }
355
410
  // retreive ID based on the matching Path of the parent folder
356
- else if (metadata.ParentFolder && metadata.ParentFolder.Path) {
357
- metadata.ParentFolder.ID = Util.getFromCache(
358
- this.cache,
411
+ else if (metadata?.ParentFolder?.Path) {
412
+ metadata.ParentFolder.ID = cache.searchForField(
359
413
  'folder',
360
414
  metadata.ParentFolder.Path,
361
415
  'Path',
@@ -375,9 +429,10 @@ class Folder extends MetadataType {
375
429
 
376
430
  /**
377
431
  * Returns file contents mapped to their filename without '.json' ending
378
- * @param {String} dir directory that contains '.json' files to be read
432
+ *
433
+ * @param {string} dir directory that contains '.json' files to be read
379
434
  * @param {boolean} [listBadKeys=false] do not print errors, used for badKeys()
380
- * @returns {Object} fileName => fileContent map
435
+ * @returns {TYPE.MetadataTypeMap} fileName => fileContent map
381
436
  */
382
437
  static getJsonFromFS(dir, listBadKeys) {
383
438
  try {
@@ -407,9 +462,7 @@ class Folder extends MetadataType {
407
462
  fileContent.ParentFolder = {
408
463
  Path: standardSubDir,
409
464
  };
410
- const key = fileContent.CustomerKey
411
- ? fileContent.CustomerKey
412
- : `new-${++newCounter}`;
465
+ const key = fileContent.CustomerKey || `new-${++newCounter}`;
413
466
  if (fileName2FileContent[key]) {
414
467
  Util.logger.error(
415
468
  `Your have multiple folder-JSONs with the same CustomerKey '${key}' - skipping ${fileName}`
@@ -445,58 +498,38 @@ class Folder extends MetadataType {
445
498
 
446
499
  /**
447
500
  * Helper to retrieve the folders as promise
448
- * @param {String[]} [additionalFields] Returns specified fields even if their retrieve definition is not set to true
449
- * @param {Boolean} [queryAllAccounts] which queryAllAccounts setting to use
450
- * @returns {Promise<Object>} soap object
501
+ *
502
+ * @param {string[]} [additionalFields] Returns specified fields even if their retrieve definition is not set to true
503
+ * @param {boolean} [queryAllAccounts] which queryAllAccounts setting to use
504
+ * @returns {Promise.<object>} soap object
451
505
  */
452
506
  static async retrieveHelper(additionalFields, queryAllAccounts) {
453
- const options = { queryAllAccounts: !!queryAllAccounts };
454
- let status = 'MoreDataAvailable';
455
- const Results = [];
456
- do {
457
- let response;
458
- await Util.retryOnError(`Retrying ${this.definition.type}`, async () => {
459
- response = await new Promise((resolve, reject) => {
460
- // filtered out path as we need them to be stored locally, but do not want to try and retrieve
461
- this.client.SoapClient.retrieve(
462
- 'DataFolder',
463
- this.getFieldNamesToRetrieve(additionalFields).filter(
464
- (field) => !field.includes('Path')
465
- ),
466
- options,
467
- (ex, response) => (ex ? reject(ex) : resolve(response))
468
- );
469
- });
470
- });
471
- // merge results with existing
472
- Results.push(...response.body.Results);
473
- // set status for calling again if required
474
- status = response.body.OverallStatus;
475
- options.continueRequest = response.body.RequestID;
476
- if (status === 'MoreDataAvailable') {
477
- Util.logger.info(
478
- '- more than ' +
479
- Results.length +
480
- ' folders in Business Unit - loading next batch...'
481
- );
482
- }
483
- } while (status === 'MoreDataAvailable');
484
- return Results;
507
+ const options = { QueryAllAccounts: !!queryAllAccounts };
508
+ const response = await this.client.soap.retrieveBulk(
509
+ 'DataFolder',
510
+ this.getFieldNamesToRetrieve(additionalFields).filter(
511
+ (field) => !field.includes('Path')
512
+ ),
513
+ options
514
+ );
515
+ return response.Results;
485
516
  }
486
517
  /**
487
518
  * Gets executed after retreive of metadata type
488
- * @param {Object} metadata metadata mapped by their keyField
489
- * @returns {Object[]} cloned metadata
519
+ *
520
+ * @param {TYPE.MetadataTypeItem} metadata metadata mapped by their keyField
521
+ * @returns {TYPE.MetadataTypeItem} cloned metadata
490
522
  */
491
523
  static postRetrieveTasks(metadata) {
492
524
  return JSON.parse(JSON.stringify(metadata));
493
525
  }
494
526
  /**
495
527
  * Helper for writing Metadata to disk, used for Retrieve and deploy
496
- * @param {Object} results metadata results from deploy
497
- * @param {String} retrieveDir directory where metadata should be stored after deploy/retrieve
498
- * @param {Number} mid current mid for this credential / business unit
499
- * @returns {Promise<Object>} Promise of saved metadata
528
+ *
529
+ * @param {object} results metadata results from deploy
530
+ * @param {string} retrieveDir directory where metadata should be stored after deploy/retrieve
531
+ * @param {number} mid current mid for this credential / business unit
532
+ * @returns {Promise.<object>} Promise of saved metadata
500
533
  */
501
534
  static async saveResults(results, retrieveDir, mid) {
502
535
  const savedResults = {};
@@ -556,6 +589,5 @@ class Folder extends MetadataType {
556
589
 
557
590
  // Assign definition to static attributes
558
591
  Folder.definition = require('../MetadataTypeDefinitions').folder;
559
- Folder.client = undefined;
560
592
 
561
593
  module.exports = Folder;
@@ -1,34 +1,40 @@
1
1
  'use strict';
2
2
 
3
+ const TYPE = require('../../types/mcdev.d');
3
4
  const MetadataType = require('./MetadataType');
4
5
 
5
6
  /**
6
7
  * ImportFile MetadataType
8
+ *
7
9
  * @augments MetadataType
8
10
  */
9
11
  class FtpLocation extends MetadataType {
10
12
  /**
11
13
  * Retrieves Metadata of FtpLocation
12
14
  * Endpoint /automation/v1/ftplocations/ return all FtpLocations
13
- * @param {String} retrieveDir Directory where retrieved metadata directory will be saved
14
- * @returns {Promise} Promise
15
+ *
16
+ * @param {string} retrieveDir Directory where retrieved metadata directory will be saved
17
+ * @param {void} [_] unused parameter
18
+ * @param {void} [__] unused parameter
19
+ * @param {void} [___] unused parameter
20
+ * @param {string} [key] customer key of single item to retrieve
21
+ * @returns {Promise.<TYPE.MetadataTypeMapObj>} Promise
15
22
  */
16
- static retrieve(retrieveDir) {
17
- return super.retrieveREST(retrieveDir, '/automation/v1/ftplocations/', null);
23
+ static retrieve(retrieveDir, _, __, ___, key) {
24
+ return super.retrieveREST(retrieveDir, '/automation/v1/ftplocations/', null, null, key);
18
25
  }
19
26
 
20
27
  /**
21
28
  * Retrieves folder metadata into local filesystem. Also creates a uniquePath attribute for each folder.
22
- * @returns {Promise} Promise
29
+ *
30
+ * @returns {Promise.<TYPE.MetadataTypeMapObj>} Promise
23
31
  */
24
32
  static async retrieveForCache() {
25
- return super.retrieveREST(null, '/automation/v1/ftplocations/', null);
33
+ return super.retrieveREST(null, '/automation/v1/ftplocations/');
26
34
  }
27
35
  }
28
36
 
29
37
  // Assign definition to static attributes
30
38
  FtpLocation.definition = require('../MetadataTypeDefinitions').ftpLocation;
31
- FtpLocation.cache = {};
32
- FtpLocation.client = undefined;
33
39
 
34
40
  module.exports = FtpLocation;