mcdev 4.1.3 → 4.1.4

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.
@@ -39,6 +39,7 @@ body:
39
39
  label: Version
40
40
  description: What version of our software are you running? (mcdev --version)
41
41
  options:
42
+ - 4.1.4
42
43
  - 4.1.3
43
44
  - 4.1.2
44
45
  - 4.1.1
@@ -8,7 +8,7 @@ updates:
8
8
  - package-ecosystem: 'npm' # See documentation for possible values
9
9
  directory: '/' # Location of package manifests
10
10
  schedule:
11
- interval: 'daily'
11
+ interval: 'weekly'
12
12
  target-branch: 'develop'
13
13
  labels:
14
14
  - 'dependencies'
@@ -34,9 +34,9 @@ jobs:
34
34
 
35
35
  steps:
36
36
  - name: Checkout repository
37
- uses: actions/checkout@v2
37
+ uses: actions/checkout@v3
38
38
 
39
- - uses: actions/setup-node@v2
39
+ - uses: actions/setup-node@v3
40
40
  with:
41
41
  node-version: 16
42
42
  registry-url: https://registry.npmjs.org/
@@ -11,8 +11,8 @@ jobs:
11
11
  build:
12
12
  runs-on: ubuntu-latest
13
13
  steps:
14
- - uses: actions/checkout@v2
15
- - uses: actions/setup-node@v1
14
+ - uses: actions/checkout@v3
15
+ - uses: actions/setup-node@v3
16
16
  with:
17
17
  node-version: 16
18
18
  - run: npm ci
@@ -22,8 +22,8 @@ jobs:
22
22
  needs: build
23
23
  runs-on: ubuntu-latest
24
24
  steps:
25
- - uses: actions/checkout@v2
26
- - uses: actions/setup-node@v1
25
+ - uses: actions/checkout@v3
26
+ - uses: actions/setup-node@v3
27
27
  with:
28
28
  node-version: 16
29
29
  registry-url: https://registry.npmjs.org/
package/README.md CHANGED
@@ -123,7 +123,7 @@ If you experience issues installing Accenture SFMC DevTools, please check out th
123
123
  1. Install Accenture SFMC DevTools by running `npm install -g mcdev` (prefix with `sudo` on MacOS)
124
124
  - If you get an error, please see the below troubleshooting section.
125
125
 
126
- When completed run `mcdev --version` and it will show you which version you installed (e.g. `4.1.3`).
126
+ When completed run `mcdev --version` and it will show you which version you installed (e.g. `4.1.4`).
127
127
 
128
128
  > **_Side note for proud nerds_:**
129
129
  >
@@ -277,10 +277,10 @@ _Note: Regardless of which tag or branch you install_
277
277
  **Install specific version (using a version tag on npm):**
278
278
 
279
279
  ```bash
280
- npm install -g mcdev@4.1.3
280
+ npm install -g mcdev@4.1.4
281
281
  ```
282
282
 
283
- **Warning**: When you used the above method to install Accenture SFMC DevTools for a specific version or tag, trying to [update Accenture SFMC DevTools](#updating-mcdev) might not download the most recently published official version but instead stay on the version or branch you previously selected (in the above examples: develop, 4.1.3)!
283
+ **Warning**: When you used the above method to install Accenture SFMC DevTools for a specific version or tag, trying to [update Accenture SFMC DevTools](#updating-mcdev) might not download the most recently published official version but instead stay on the version or branch you previously selected (in the above examples: develop, 4.1.4)!
284
284
 
285
285
  > **Note**: The version is currently _not_ updated on the developer branch until a new release is published. Hence, you will not see a change if you run `mcdev --version`.
286
286
 
@@ -1493,7 +1493,7 @@ Assuming you cloned Accenture SFMC DevTools into `C:\repos\sfmc-devtools\` (or `
1493
1493
 
1494
1494
  This should tell npm to create a symlink to your cloned local directoty, allowing you to see updates you make in your mcdev repo instantly.
1495
1495
 
1496
- To test your new **global** developer setup, run `mcdev --version` in CLI which should return the current version (e.g. `4.1.3`). Then, go into your mcdev repo and update the version with the suffix `-dev`, e.g. to `4.1.3-dev` and then run `mcdev --version` again to verify that your change propagates instantly.
1496
+ To test your new **global** developer setup, run `mcdev --version` in CLI which should return the current version (e.g. `4.1.4`). Then, go into your mcdev repo and update the version with the suffix `-dev`, e.g. to `4.1.4-dev` and then run `mcdev --version` again to verify that your change propagates instantly.
1497
1497
 
1498
1498
  > **Not recommended:** Alternatively, you can install it locally only by opening a terminal in your project directory and executing `npm install --save-dev "C:\repos\sfmc-devtools"`
1499
1499
  > To run the local version you need to prepend "npx" before your commands, e.g. `npx mcdev --version`
@@ -1531,7 +1531,7 @@ The following explains how you _could_ install it locally for certain edge cases
1531
1531
  4. Afterwards, install Accenture SFMC DevTools by running `npm install --save-dev mcdev`
1532
1532
  - If you get an error, please see the below troubleshooting section.
1533
1533
 
1534
- When completed run `mcdev --version` and it will show you which version you installed (e.g. `4.1.3`).
1534
+ When completed run `mcdev --version` and it will show you which version you installed (e.g. `4.1.4`).
1535
1535
 
1536
1536
  ### 9.3. NPM Scripts
1537
1537
 
@@ -836,6 +836,7 @@ FileTransfer MetadataType
836
836
  * [.buildDefinitionForNested(templateDir, targetDir, metadata, templateVariables, templateName)](#Asset.buildDefinitionForNested) ⇒ <code>Promise.&lt;void&gt;</code>
837
837
  * [.buildTemplateForNested(templateDir, targetDir, metadata, templateVariables, templateName)](#Asset.buildTemplateForNested) ⇒ <code>Promise.&lt;void&gt;</code>
838
838
  * [._buildForNested(templateDir, targetDir, metadata, templateVariables, templateName, mode)](#Asset._buildForNested) ⇒ <code>Promise.&lt;void&gt;</code>
839
+ * [.setFolderPath(metadata)](#Asset.setFolderPath)
839
840
  * [.parseMetadata(metadata)](#Asset.parseMetadata) ⇒ <code>TYPE.CodeExtractItem</code>
840
841
  * [._mergeCode(metadata, deployDir, subType, [templateName], [fileListOnly])](#Asset._mergeCode) ⇒ <code>Promise.&lt;Array.&lt;TYPE.CodeExtract&gt;&gt;</code>
841
842
  * [._mergeCode_slots(prefix, metadataSlots, readDirArr, subtypeExtension, subDirArr, fileList, customerKey, [templateName], [fileListOnly])](#Asset._mergeCode_slots) ⇒ <code>Promise.&lt;void&gt;</code>
@@ -1072,6 +1073,17 @@ handles extracted code if any are found for complex types
1072
1073
  | templateName | <code>string</code> | name of the template to be built |
1073
1074
  | mode | <code>&#x27;definition&#x27;</code> \| <code>&#x27;template&#x27;</code> | defines what we use this helper for |
1074
1075
 
1076
+ <a name="Asset.setFolderPath"></a>
1077
+
1078
+ ### Asset.setFolderPath(metadata)
1079
+ generic script that retrieves the folder path from cache and updates the given metadata with it after retrieve
1080
+
1081
+ **Kind**: static method of [<code>Asset</code>](#Asset)
1082
+
1083
+ | Param | Type | Description |
1084
+ | --- | --- | --- |
1085
+ | metadata | <code>TYPE.MetadataTypeItem</code> | a single script activity definition |
1086
+
1075
1087
  <a name="Asset.parseMetadata"></a>
1076
1088
 
1077
1089
  ### Asset.parseMetadata(metadata) ⇒ <code>TYPE.CodeExtractItem</code>
@@ -1254,6 +1266,7 @@ Automation MetadataType
1254
1266
  * [.preDeployTasks(metadata)](#Automation.preDeployTasks) ⇒ <code>Promise.&lt;TYPE.AutomationItem&gt;</code>
1255
1267
  * [.validateDeployMetadata(metadata)](#Automation.validateDeployMetadata) ⇒ <code>boolean</code>
1256
1268
  * [.postDeployTasks(metadata, originalMetadata)](#Automation.postDeployTasks) ⇒ <code>Promise.&lt;void&gt;</code>
1269
+ * [.setFolderPath(metadata)](#Automation.setFolderPath)
1257
1270
  * [.parseMetadata(metadata)](#Automation.parseMetadata) ⇒ <code>TYPE.AutomationItem</code>
1258
1271
  * [._buildSchedule(scheduleObject)](#Automation._buildSchedule) ⇒ <code>TYPE.AutomationScheduleSoap</code>
1259
1272
  * [._calcTime(offsetServer, dateInput, [offsetInput])](#Automation._calcTime) ⇒ <code>string</code>
@@ -1393,6 +1406,17 @@ Gets executed after deployment of metadata type
1393
1406
  | metadata | <code>TYPE.AutomationMap</code> | metadata mapped by their keyField |
1394
1407
  | originalMetadata | <code>TYPE.AutomationMap</code> | metadata to be updated (contains additioanl fields) |
1395
1408
 
1409
+ <a name="Automation.setFolderPath"></a>
1410
+
1411
+ ### Automation.setFolderPath(metadata)
1412
+ generic script that retrieves the folder path from cache and updates the given metadata with it after retrieve
1413
+
1414
+ **Kind**: static method of [<code>Automation</code>](#Automation)
1415
+
1416
+ | Param | Type | Description |
1417
+ | --- | --- | --- |
1418
+ | metadata | <code>TYPE.MetadataTypeItem</code> | a single script activity definition |
1419
+
1396
1420
  <a name="Automation.parseMetadata"></a>
1397
1421
 
1398
1422
  ### Automation.parseMetadata(metadata) ⇒ <code>TYPE.AutomationItem</code>
@@ -1511,6 +1535,7 @@ ContentArea MetadataType
1511
1535
  * [ContentArea](#ContentArea) ⇐ [<code>MetadataType</code>](#MetadataType)
1512
1536
  * [.retrieve(retrieveDir, [_], [__], [___], [key])](#ContentArea.retrieve) ⇒ <code>Promise.&lt;TYPE.MetadataTypeMapObj&gt;</code>
1513
1537
  * [.postRetrieveTasks(metadata)](#ContentArea.postRetrieveTasks) ⇒ <code>TYPE.MetadataTypeItem</code>
1538
+ * [.setFolderPath(metadata)](#ContentArea.setFolderPath)
1514
1539
  * [.parseMetadata(metadata)](#ContentArea.parseMetadata) ⇒ <code>TYPE.MetadataTypeItem</code>
1515
1540
 
1516
1541
  <a name="ContentArea.retrieve"></a>
@@ -1541,6 +1566,17 @@ manages post retrieve steps
1541
1566
  | --- | --- | --- |
1542
1567
  | metadata | <code>TYPE.MetadataTypeItem</code> | a single item |
1543
1568
 
1569
+ <a name="ContentArea.setFolderPath"></a>
1570
+
1571
+ ### ContentArea.setFolderPath(metadata)
1572
+ generic script that retrieves the folder path from cache and updates the given metadata with it after retrieve
1573
+
1574
+ **Kind**: static method of [<code>ContentArea</code>](#ContentArea)
1575
+
1576
+ | Param | Type | Description |
1577
+ | --- | --- | --- |
1578
+ | metadata | <code>TYPE.MetadataTypeItem</code> | a single script activity definition |
1579
+
1544
1580
  <a name="ContentArea.parseMetadata"></a>
1545
1581
 
1546
1582
  ### ContentArea.parseMetadata(metadata) ⇒ <code>TYPE.MetadataTypeItem</code>
@@ -1576,6 +1612,7 @@ DataExtension MetadataType
1576
1612
  * [.postDeleteTasks(buObject, customerKey)](#DataExtension.postDeleteTasks) ⇒ <code>void</code>
1577
1613
  * [.retrieveForCache(buObject)](#DataExtension.retrieveForCache) ⇒ <code>Promise.&lt;{metadata: TYPE.DataExtensionMap, type: string}&gt;</code>
1578
1614
  * [.retrieveAsTemplate(templateDir, name, templateVariables)](#DataExtension.retrieveAsTemplate) ⇒ <code>Promise.&lt;{metadata: TYPE.DataExtensionMap, type: string}&gt;</code>
1615
+ * [.setFolderPath(metadata)](#DataExtension.setFolderPath)
1579
1616
  * [.getFilesToCommit(keyArr)](#DataExtension.getFilesToCommit) ⇒ <code>Array.&lt;string&gt;</code>
1580
1617
 
1581
1618
  <a name="DataExtension.upsert"></a>
@@ -1758,6 +1795,18 @@ Retrieves dataExtension metadata in template format.
1758
1795
  | name | <code>string</code> | name of the metadata item |
1759
1796
  | templateVariables | <code>TYPE.TemplateMap</code> | variables to be replaced in the metadata |
1760
1797
 
1798
+ <a name="DataExtension.setFolderPath"></a>
1799
+
1800
+ ### DataExtension.setFolderPath(metadata)
1801
+ dataExtension logic that retrieves the folder path from cache and updates the given metadata with it after retrieve
1802
+ it also sets the content type which is basically the subtype
1803
+
1804
+ **Kind**: static method of [<code>DataExtension</code>](#DataExtension)
1805
+
1806
+ | Param | Type | Description |
1807
+ | --- | --- | --- |
1808
+ | metadata | <code>TYPE.MetadataTypeItem</code> | a single script activity definition |
1809
+
1761
1810
  <a name="DataExtension.getFilesToCommit"></a>
1762
1811
 
1763
1812
  ### DataExtension.getFilesToCommit(keyArr) ⇒ <code>Array.&lt;string&gt;</code>
@@ -2946,6 +2995,7 @@ Provides default functionality that can be overwritten by child metadata type cl
2946
2995
  * [.deploy(metadata, deployDir, retrieveDir, buObject)](#MetadataType.deploy) ⇒ <code>Promise.&lt;TYPE.MetadataTypeMap&gt;</code>
2947
2996
  * [.postDeployTasks(metadata, originalMetadata)](#MetadataType.postDeployTasks) ⇒ <code>void</code>
2948
2997
  * [.postRetrieveTasks(metadata, targetDir, [isTemplating])](#MetadataType.postRetrieveTasks) ⇒ <code>TYPE.MetadataTypeItem</code>
2998
+ * [.setFolderPath(metadata)](#MetadataType.setFolderPath)
2949
2999
  * [.retrieve(retrieveDir, [additionalFields], buObject, [subType], [key])](#MetadataType.retrieve) ⇒ <code>Promise.&lt;TYPE.MetadataTypeMapObj&gt;</code>
2950
3000
  * [.retrieveChangelog([buObject], [additionalFields], [subType])](#MetadataType.retrieveChangelog) ⇒ <code>Promise.&lt;TYPE.MetadataTypeMapObj&gt;</code>
2951
3001
  * [.retrieveForCache(buObject, [subType])](#MetadataType.retrieveForCache) ⇒ <code>Promise.&lt;TYPE.MetadataTypeMapObj&gt;</code>
@@ -3069,6 +3119,17 @@ Gets executed after retreive of metadata type
3069
3119
  | targetDir | <code>string</code> | folder where retrieves should be saved |
3070
3120
  | [isTemplating] | <code>boolean</code> | signals that we are retrieving templates |
3071
3121
 
3122
+ <a name="MetadataType.setFolderPath"></a>
3123
+
3124
+ ### MetadataType.setFolderPath(metadata)
3125
+ generic script that retrieves the folder path from cache and updates the given metadata with it after retrieve
3126
+
3127
+ **Kind**: static method of [<code>MetadataType</code>](#MetadataType)
3128
+
3129
+ | Param | Type | Description |
3130
+ | --- | --- | --- |
3131
+ | metadata | <code>TYPE.MetadataTypeItem</code> | a single script activity definition |
3132
+
3072
3133
  <a name="MetadataType.retrieve"></a>
3073
3134
 
3074
3135
  ### MetadataType.retrieve(retrieveDir, [additionalFields], buObject, [subType], [key]) ⇒ <code>Promise.&lt;TYPE.MetadataTypeMapObj&gt;</code>
package/lib/Retriever.js CHANGED
@@ -74,8 +74,8 @@ class Retriever {
74
74
  try {
75
75
  let result;
76
76
  if (!metadataTypes.includes(type) && !metadataTypes.includes(metadataType)) {
77
- if (changelogOnly) {
78
- // no extra caching needed for list view
77
+ if (changelogOnly && type !== 'folder') {
78
+ // no extra caching needed for list view except for folders
79
79
  continue;
80
80
  }
81
81
  Util.logger.info(`Caching dependent Metadata: ${metadataType}`);
@@ -115,6 +115,12 @@ class Retriever {
115
115
  )
116
116
  )
117
117
  ));
118
+ if (changelogOnly) {
119
+ // add folder to changelog
120
+ for (const key of Object.keys(result.metadata)) {
121
+ MetadataTypeInfo[type].setFolderPath(result.metadata[key]);
122
+ }
123
+ }
118
124
  }
119
125
  if (result) {
120
126
  if (Array.isArray(result)) {
@@ -755,15 +755,12 @@ class Asset extends MetadataType {
755
755
  }
756
756
  }
757
757
  }
758
-
759
758
  /**
760
- * parses retrieved Metadata before saving
759
+ * generic script that retrieves the folder path from cache and updates the given metadata with it after retrieve
761
760
  *
762
- * @param {TYPE.AssetItem} metadata a single asset definition
763
- * @returns {TYPE.CodeExtractItem} parsed metadata definition
761
+ * @param {TYPE.MetadataTypeItem} metadata a single script activity definition
764
762
  */
765
- static parseMetadata(metadata) {
766
- // folder
763
+ static setFolderPath(metadata) {
767
764
  try {
768
765
  metadata.r__folder_Path = cache.searchForField(
769
766
  'folder',
@@ -773,12 +770,23 @@ class Asset extends MetadataType {
773
770
  );
774
771
  delete metadata.category;
775
772
  } catch (ex) {
776
- // ! if we don't catch this error here we end up saving the actual asset but not its corresponding JSON
777
- Util.logger.debug(ex.message);
778
773
  Util.logger.warn(
779
- ` - Could not find folder with ID ${metadata.category.id} for '${metadata.name}' (${metadata.customerKey})`
774
+ ` - ${this.definition.type} '${metadata[this.definition.nameField]}' (${
775
+ metadata[this.definition.keyField]
776
+ }): Could not find folder (${ex.message})`
780
777
  );
781
778
  }
779
+ }
780
+
781
+ /**
782
+ * parses retrieved Metadata before saving
783
+ *
784
+ * @param {TYPE.AssetItem} metadata a single asset definition
785
+ * @returns {TYPE.CodeExtractItem} parsed metadata definition
786
+ */
787
+ static parseMetadata(metadata) {
788
+ // folder
789
+ this.setFolderPath(metadata);
782
790
  // extract HTML for selected subtypes and convert payload for easier processing in MetadataType.saveResults()
783
791
  metadata = this._extractCode(metadata);
784
792
  return metadata;
@@ -73,6 +73,7 @@ class Automation extends MetadataType {
73
73
  'ProgramID',
74
74
  'Name',
75
75
  'CustomerKey',
76
+ 'CategoryID',
76
77
  'LastSaveDate',
77
78
  'LastSavedBy',
78
79
  'CreatedBy',
@@ -457,23 +458,23 @@ class Automation extends MetadataType {
457
458
  }
458
459
  }
459
460
  }
460
-
461
461
  /**
462
- * parses retrieved Metadata before saving
462
+ * generic script that retrieves the folder path from cache and updates the given metadata with it after retrieve
463
463
  *
464
- * @param {TYPE.AutomationItem} metadata a single automation definition
465
- * @returns {TYPE.AutomationItem} parsed item
464
+ * @param {TYPE.MetadataTypeItem} metadata a single script activity definition
466
465
  */
467
- static parseMetadata(metadata) {
468
- // automations are often skipped due to lack of support.
466
+ static setFolderPath(metadata) {
467
+ const folderIdField = metadata[this.definition.folderIdField]
468
+ ? this.definition.folderIdField
469
+ : 'CategoryID';
469
470
  try {
470
471
  metadata.r__folder_Path = cache.searchForField(
471
472
  'folder',
472
- metadata.categoryId,
473
+ metadata[folderIdField],
473
474
  'ID',
474
475
  'Path'
475
476
  );
476
- delete metadata.categoryId;
477
+ delete metadata[folderIdField];
477
478
  if (metadata.r__folder_Path !== 'my automations') {
478
479
  Util.logger.verbose(
479
480
  `- automation '${
@@ -484,13 +485,23 @@ class Automation extends MetadataType {
484
485
  );
485
486
  }
486
487
  } catch (ex) {
487
- // * don't exit on missing folder for automation
488
488
  Util.logger.warn(
489
- ` - ${this.definition.typeName} '${metadata[this.definition.nameField]}': ${
490
- ex.message
491
- }`
489
+ ` - ${this.definition.type} '${metadata[this.definition.nameField]}' (${
490
+ metadata[this.definition.keyField]
491
+ }): Could not find folder (${ex.message})`
492
492
  );
493
493
  }
494
+ }
495
+
496
+ /**
497
+ * parses retrieved Metadata before saving
498
+ *
499
+ * @param {TYPE.AutomationItem} metadata a single automation definition
500
+ * @returns {TYPE.AutomationItem} parsed item
501
+ */
502
+ static parseMetadata(metadata) {
503
+ this.setFolderPath(metadata);
504
+ // automations are often skipped due to lack of support.
494
505
  try {
495
506
  if (metadata.type === 'scheduled' && metadata.schedule?.startDate) {
496
507
  // Starting Source == 'Schedule'
@@ -49,27 +49,40 @@ class ContentArea extends MetadataType {
49
49
  return this.parseMetadata(metadata);
50
50
  }
51
51
  /**
52
- * parses retrieved Metadata before saving
52
+ * generic script that retrieves the folder path from cache and updates the given metadata with it after retrieve
53
53
  *
54
- * @param {TYPE.MetadataTypeItem} metadata a single item
55
- * @returns {TYPE.MetadataTypeItem} parsed item
54
+ * @param {TYPE.MetadataTypeItem} metadata a single script activity definition
56
55
  */
57
- static parseMetadata(metadata) {
58
- // folder
56
+ static setFolderPath(metadata) {
59
57
  try {
60
58
  metadata.r__folder_Path = cache.searchForField(
61
59
  'folder',
62
- metadata.CategoryID,
60
+ metadata[this.definition.folderIdField],
63
61
  'ID',
64
62
  'Path'
65
63
  );
64
+ delete metadata[this.definition.folderIdField];
66
65
  } catch (ex) {
67
- Util.logger.debug(`Classic Content Area '${metadata.CustomerKey}': ${ex.message}`);
66
+ Util.logger.debug(
67
+ ` - ${this.definition.type} '${metadata[this.definition.nameField]}' (${
68
+ metadata[this.definition.keyField]
69
+ }): Could not find folder (${ex.message})`
70
+ );
68
71
  // classic content blocks that reside in the main folder are
69
72
  // saved with CategoryID=0, instead of to the actual ID of
70
73
  // their parent root folder.
71
74
  metadata.r__folder_Path = 'my contents';
72
75
  }
76
+ }
77
+ /**
78
+ * parses retrieved Metadata before saving
79
+ *
80
+ * @param {TYPE.MetadataTypeItem} metadata a single item
81
+ * @returns {TYPE.MetadataTypeItem} parsed item
82
+ */
83
+ static parseMetadata(metadata) {
84
+ // folder
85
+ this.setFolderPath(metadata);
73
86
 
74
87
  // extract code
75
88
  const codeArr = [
@@ -914,22 +914,20 @@ class DataExtension extends MetadataType {
914
914
 
915
915
  return { metadata: metadata[customerKey], type: 'dataExtension' };
916
916
  }
917
-
918
917
  /**
919
- * parses retrieved Metadata before saving
918
+ * dataExtension logic that retrieves the folder path from cache and updates the given metadata with it after retrieve
919
+ * it also sets the content type which is basically the subtype
920
920
  *
921
- * @private
922
- * @param {TYPE.DataExtensionItem} metadata a single dataExtension definition
923
- * @returns {TYPE.DataExtensionItem} a single dataExtension definition
921
+ * @param {TYPE.MetadataTypeItem} metadata a single script activity definition
924
922
  */
925
- static _parseMetadata(metadata) {
923
+ static setFolderPath(metadata) {
926
924
  let error = false;
927
925
  let verbose = false;
928
926
  // data extension type (from folder)
929
927
  try {
930
928
  metadata.r__folder_ContentType = cache.searchForField(
931
929
  'folder',
932
- metadata.CategoryID,
930
+ metadata[this.definition.folderIdField],
933
931
  'ID',
934
932
  'ContentType'
935
933
  );
@@ -939,22 +937,26 @@ class DataExtension extends MetadataType {
939
937
  metadata.r__folder_ContentType = 'synchronizeddataextension';
940
938
  } else {
941
939
  error = true;
942
- Util.logger.warn(` - dataExtension '${metadata.Name}': ${ex.message}`);
940
+ Util.logger.warn(
941
+ ` - ${this.definition.type} '${metadata[this.definition.nameField]}' (${
942
+ metadata[this.definition.keyField]
943
+ }): Could not find folder (${ex.message})`
944
+ );
943
945
  }
944
946
  }
945
947
  // folder
946
948
  try {
947
949
  metadata.r__folder_Path = cache.searchForField(
948
950
  'folder',
949
- metadata.CategoryID,
951
+ metadata[this.definition.folderIdField],
950
952
  'ID',
951
953
  'Path'
952
954
  );
953
- delete metadata.CategoryID;
955
+ delete metadata[this.definition.folderIdField];
954
956
  } catch (ex) {
955
957
  if (/(_Salesforce)(_\d\d?\d?)?$/.test(metadata.Name)) {
956
958
  metadata.r__folder_Path = 'Synchronized Data Extensions';
957
- delete metadata.CategoryID;
959
+ delete metadata[this.definition.folderIdField];
958
960
 
959
961
  if (!verbose) {
960
962
  Util.logger.verbose(
@@ -962,9 +964,25 @@ class DataExtension extends MetadataType {
962
964
  );
963
965
  }
964
966
  } else if (!error) {
965
- Util.logger.error(`Data Extension '${metadata.Name}': ${ex.message}`);
967
+ Util.logger.error(
968
+ ` - ${this.definition.type} '${metadata[this.definition.nameField]}' (${
969
+ metadata[this.definition.keyField]
970
+ }): ${ex.message}`
971
+ );
966
972
  }
967
973
  }
974
+ }
975
+
976
+ /**
977
+ * parses retrieved Metadata before saving
978
+ *
979
+ * @private
980
+ * @param {TYPE.DataExtensionItem} metadata a single dataExtension definition
981
+ * @returns {TYPE.DataExtensionItem} a single dataExtension definition
982
+ */
983
+ static _parseMetadata(metadata) {
984
+ this.setFolderPath(metadata);
985
+
968
986
  // DataExtensionTemplate
969
987
  if (metadata.Template?.CustomerKey) {
970
988
  try {
@@ -3,7 +3,6 @@
3
3
  const TYPE = require('../../types/mcdev.d');
4
4
  const MetadataType = require('./MetadataType');
5
5
  const Util = require('../util/util');
6
- const cache = require('../util/cache');
7
6
 
8
7
  /**
9
8
  * Email MetadataType
@@ -56,19 +55,7 @@ class Email extends MetadataType {
56
55
  */
57
56
  static parseMetadata(metadata) {
58
57
  // folder
59
- try {
60
- metadata.r__folder_Path = cache.searchForField(
61
- 'folder',
62
- metadata.CategoryID,
63
- 'ID',
64
- 'Path'
65
- );
66
- delete metadata.CategoryID;
67
- } catch (ex) {
68
- Util.logger.warn(
69
- ` - Classic E-Mail '${metadata.Name}'/'${metadata.CustomerKey}': ${ex.message}`
70
- );
71
- }
58
+ super.setFolderPath(metadata);
72
59
 
73
60
  // extract code
74
61
  const codeArr = [
@@ -182,19 +182,8 @@ class EmailSendDefinition extends MetadataType {
182
182
  // remove IsPlatformObject, always has to be 'false'
183
183
  delete metadata.IsPlatformObject;
184
184
  // folder
185
- try {
186
- metadata.r__folder_Path = cache.searchForField(
187
- 'folder',
188
- metadata.CategoryID,
189
- 'ID',
190
- 'Path'
191
- );
192
- delete metadata.CategoryID;
193
- } catch (ex) {
194
- Util.logger.warn(
195
- ` - ${this.definition.typeName} '${metadata.Name}'/'${metadata.CustomerKey}': ${ex.message}`
196
- );
197
- }
185
+ super.setFolderPath(metadata);
186
+
198
187
  // email
199
188
  try {
200
189
  // classic
@@ -141,6 +141,32 @@ class MetadataType {
141
141
  static postRetrieveTasks(metadata, targetDir, isTemplating) {
142
142
  return JSON.parse(JSON.stringify(metadata));
143
143
  }
144
+ /**
145
+ * generic script that retrieves the folder path from cache and updates the given metadata with it after retrieve
146
+ *
147
+ * @param {TYPE.MetadataTypeItem} metadata a single script activity definition
148
+ */
149
+ static setFolderPath(metadata) {
150
+ if (!this.definition.folderIdField) {
151
+ return;
152
+ }
153
+ try {
154
+ metadata.r__folder_Path = cache.searchForField(
155
+ 'folder',
156
+ metadata[this.definition.folderIdField],
157
+ 'ID',
158
+ 'Path'
159
+ );
160
+ delete metadata[this.definition.folderIdField];
161
+ } catch (ex) {
162
+ Util.logger.warn(
163
+ ` - ${this.definition.type} '${metadata[this.definition.nameField]}' (${
164
+ metadata[this.definition.keyField]
165
+ }): Could not find folder (${ex.message})`
166
+ );
167
+ }
168
+ }
169
+
144
170
  /**
145
171
  * Gets metadata from Marketing Cloud
146
172
  *
@@ -2,7 +2,6 @@
2
2
 
3
3
  const TYPE = require('../../types/mcdev.d');
4
4
  const MetadataType = require('./MetadataType');
5
- const Util = require('../util/util');
6
5
  const File = require('../util/file');
7
6
  const cache = require('../util/cache');
8
7
  const Mustache = require('mustache');
@@ -287,17 +286,7 @@ class Query extends MetadataType {
287
286
  */
288
287
  static parseMetadata(metadata) {
289
288
  // folder
290
- try {
291
- metadata.r__folder_Path = cache.searchForField(
292
- 'folder',
293
- metadata.categoryId,
294
- 'ID',
295
- 'Path'
296
- );
297
- delete metadata.categoryId;
298
- } catch (ex) {
299
- Util.logger.warn(` - Query '${metadata.key}': ${ex.message}`);
300
- }
289
+ super.setFolderPath(metadata);
301
290
 
302
291
  // extract SQL
303
292
  const codeArr = [
@@ -261,17 +261,7 @@ class Script extends MetadataType {
261
261
  */
262
262
  static parseMetadata(metadata) {
263
263
  // folder
264
- try {
265
- metadata.r__folder_Path = cache.searchForField(
266
- 'folder',
267
- metadata.categoryId,
268
- 'ID',
269
- 'Path'
270
- );
271
- delete metadata.categoryId;
272
- } catch (ex) {
273
- Util.logger.warn(` - Script '${metadata.key}': ${ex.message}`);
274
- }
264
+ super.setFolderPath(metadata);
275
265
 
276
266
  // extract SSJS
277
267
  const codeArr = [];
@@ -137,19 +137,8 @@ class TriggeredSendDefinition extends MetadataType {
137
137
  // remove IsPlatformObject, always has to be 'false'
138
138
  delete metadata.IsPlatformObject;
139
139
  // folder
140
- try {
141
- metadata.r__folder_Path = cache.searchForField(
142
- 'folder',
143
- metadata.CategoryID,
144
- 'ID',
145
- 'Path'
146
- );
147
- delete metadata.CategoryID;
148
- } catch (ex) {
149
- Util.logger.warn(
150
- ` - Triggered Send '${metadata.Name}'/'${metadata.CustomerKey}': ${ex.message}`
151
- );
152
- }
140
+ super.setFolderPath(metadata);
141
+
153
142
  // email
154
143
  try {
155
144
  // classic
@@ -40,6 +40,7 @@ module.exports = {
40
40
  idField: 'id',
41
41
  keyField: 'key',
42
42
  nameField: 'name',
43
+ folderIdField: 'categoryId',
43
44
  createdDateField: 'createdDate',
44
45
  createdNameField: 'createdByName',
45
46
  lastmodDateField: 'lastSavedDate',
@@ -6,6 +6,7 @@ module.exports = {
6
6
  keepId: true,
7
7
  keyField: 'CustomerKey',
8
8
  nameField: 'Name',
9
+ folderIdField: 'CategoryID',
9
10
  restPagination: null,
10
11
  type: 'contentArea',
11
12
  typeDescription:
@@ -80,6 +80,7 @@ module.exports = {
80
80
  idField: 'ObjectID',
81
81
  keyField: 'CustomerKey',
82
82
  nameField: 'Name',
83
+ folderIdField: 'CategoryID',
83
84
  createdDateField: 'CreatedDate',
84
85
  createdNameField: null,
85
86
  lastmodDateField: 'ModifiedDate',
@@ -6,6 +6,7 @@ module.exports = {
6
6
  keepId: true,
7
7
  keyField: 'CustomerKey',
8
8
  nameField: 'Name',
9
+ folderIdField: 'CategoryID',
9
10
  restPagination: null,
10
11
  type: 'email',
11
12
  typeDescription:
@@ -7,6 +7,7 @@ module.exports = {
7
7
  keepId: true,
8
8
  keyField: 'CustomerKey',
9
9
  nameField: 'Name',
10
+ folderIdField: 'CategoryID',
10
11
  createdDateField: 'CreatedDate',
11
12
  createdNameField: null,
12
13
  lastmodDateField: 'ModifiedDate',
@@ -9,6 +9,7 @@ module.exports = {
9
9
  idField: 'queryDefinitionId',
10
10
  keyField: 'key',
11
11
  nameField: 'name',
12
+ folderIdField: 'categoryId',
12
13
  createdDateField: 'createdDate',
13
14
  createdNameField: null,
14
15
  lastmodDateField: 'modifiedDate',
@@ -6,6 +6,7 @@ module.exports = {
6
6
  idField: 'ssjsActivityId',
7
7
  keyField: 'key',
8
8
  nameField: 'name',
9
+ folderIdField: 'categoryId',
9
10
  createdDateField: 'createdDate',
10
11
  createdNameField: 'createdBy',
11
12
  lastmodDateField: 'modifiedDate',
@@ -7,6 +7,7 @@ module.exports = {
7
7
  keepId: true,
8
8
  keyField: 'CustomerKey',
9
9
  nameField: 'Name',
10
+ folderIdField: 'CategoryID',
10
11
  createdDateField: 'CreatedDate',
11
12
  createdNameField: null,
12
13
  lastmodDateField: 'ModifiedDate',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcdev",
3
- "version": "4.1.3",
3
+ "version": "4.1.4",
4
4
  "description": "Accenture Salesforce Marketing Cloud DevTools",
5
5
  "author": "joern.berkefeld, douglas.midgley, robert.zimmermann, maciej.barnas",
6
6
  "license": "MIT",
@@ -67,7 +67,7 @@
67
67
  "eslint": "8.26.0",
68
68
  "eslint-config-prettier": "8.5.0",
69
69
  "eslint-config-ssjs": "1.1.11",
70
- "eslint-plugin-jsdoc": "39.3.25",
70
+ "eslint-plugin-jsdoc": "39.4.0",
71
71
  "eslint-plugin-mocha": "10.1.0",
72
72
  "eslint-plugin-prettier": "4.2.1",
73
73
  "eslint-plugin-unicorn": "44.0.2",
@@ -63,5 +63,5 @@
63
63
  "triggeredSendDefinition"
64
64
  ]
65
65
  },
66
- "version": "4.1.3"
66
+ "version": "4.1.4"
67
67
  }