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,8 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  'use strict';
3
-
3
+ /* eslint-disable unicorn/prefer-top-level-await */
4
4
  /**
5
5
  * sample file on how to retrieve a simple changelog to use in GUIs or automated processing of any kind
6
+ *
6
7
  * @example
7
8
  [{
8
9
  name: 'deName',
@@ -45,10 +46,10 @@ const customDefinition = {
45
46
  const userList = (await mcdev.retrieve('ACN-Learning/_ParentBU_', 'accountUser', true))
46
47
  .accountUser;
47
48
  // reduce userList to simple id-name map
48
- Object.keys(userList).forEach((key) => {
49
+ for (const key of Object.keys(userList)) {
49
50
  userList[userList[key].ID] = userList[key].Name;
50
51
  delete userList[key];
51
- });
52
+ }
52
53
 
53
54
  // get changed metadata
54
55
  const changelogList = await mcdev.retrieve('ACN-Learning/MCDEV_Training_Source', null, true);
@@ -81,13 +82,13 @@ const customDefinition = {
81
82
  }
82
83
  });
83
84
  const finalResult = allMetadata.filter((item) => undefined !== item);
84
- console.log('finalResult', finalResult);
85
+ console.log('finalResult', finalResult); // eslint-disable-line no-console
85
86
  })();
86
87
 
87
88
  /**
88
89
  *
89
- * @param {object<string,string>} userList user-id > user-name map
90
- * @param {object<string,string>} item single metadata item
90
+ * @param {Object.<string, string>} userList user-id > user-name map
91
+ * @param {Object.<string, string>} item single metadata item
91
92
  * @param {string} fieldname name of field containing the info
92
93
  * @returns {string} username or user id or 'n/a'
93
94
  */
@@ -0,0 +1,117 @@
1
+ const TYPE = require('../../types/mcdev.d');
2
+ const Util = require('./util');
3
+ const File = require('./file');
4
+ const SDK = require('sfmc-sdk');
5
+ const Conf = require('conf');
6
+ const credentialStore = new Conf({ configName: 'sessions', clearInvalidConfig: true });
7
+ // const currentMID = null;
8
+ const initializedSDKs = {};
9
+ let authfile;
10
+
11
+ const Auth = {
12
+ /**
13
+ * For each business unit, set up base credentials to be used.
14
+ *
15
+ * @param {TYPE.AuthObject} authObject details for
16
+ * @param {string} credential of the instance
17
+ * @returns {void}
18
+ */
19
+ async saveCredential(authObject, credential) {
20
+ const sdk = setupSDK(credential, authObject);
21
+ try {
22
+ // check credentials to allow clear log output and stop execution
23
+ const test = await sdk.auth.getAccessToken();
24
+ if (test.error) {
25
+ throw new Error(test.error_description);
26
+ } else if (test.scope) {
27
+ // find missing rights
28
+ const missingAccess = sdk.auth
29
+ .getSupportedScopes()
30
+ .filter((element) => !test.scope.includes(element));
31
+
32
+ if (missingAccess.length) {
33
+ Util.logger.warn(
34
+ 'Installed package has insufficient access. You might encounter malfunctions!'
35
+ );
36
+ Util.logger.warn('Missing scope: ' + missingAccess.join(', '));
37
+ }
38
+ const existingAuth = (await File.pathExists(Util.authFileName))
39
+ ? await File.readJson(Util.authFileName)
40
+ : {};
41
+ existingAuth[credential] = authObject;
42
+ await File.writeJSONToFile('./', Util.authFileName.split('.json')[0], existingAuth);
43
+ authfile = existingAuth;
44
+ }
45
+ } catch (ex) {
46
+ throw new Error(ex.message);
47
+ }
48
+ },
49
+ /**
50
+ * Returns an SDK instance to be used for API calls
51
+ *
52
+ * @param {TYPE.BuObject} buObject information about current context
53
+ * @returns {SDK} auth object
54
+ */
55
+ getSDK(buObject) {
56
+ const credentialKey = `${buObject.credential}/${buObject.businessUnit}`;
57
+ if (initializedSDKs[credentialKey]) {
58
+ // return initialied SDK if available
59
+ return initializedSDKs[credentialKey];
60
+ } else {
61
+ // check existing credentials cached
62
+ authfile = authfile || File.readJsonSync(Util.authFileName);
63
+ const newAuthObj = authfile[buObject.credential];
64
+ // use client_id + MID to ensure a unique combination across instances
65
+ const sessionKey = newAuthObj.client_id + '|' + buObject.mid;
66
+ const existingAuthObj = credentialStore.get(sessionKey);
67
+ if (!existingAuthObj) {
68
+ newAuthObj.account_id = buObject.mid;
69
+ }
70
+ initializedSDKs[credentialKey] = setupSDK(credentialKey, existingAuthObj || newAuthObj);
71
+ return initializedSDKs[credentialKey];
72
+ }
73
+ },
74
+ /**
75
+ * helper to clear all auth sessions
76
+ *
77
+ * @returns {void}
78
+ */
79
+ clearSessions() {
80
+ credentialStore.clear();
81
+ Util.logger.info(`Auth sessions cleared`);
82
+ },
83
+ };
84
+ /**
85
+ * Returns an SDK instance to be used for API calls
86
+ *
87
+ * @param {string} sessionKey key for specific BU
88
+ * @param {TYPE.AuthObject} authObject credentials for specific BU
89
+ * @returns {SDK} auth object
90
+ */
91
+ function setupSDK(sessionKey, authObject) {
92
+ return new SDK(authObject, {
93
+ eventHandlers: {
94
+ onLoop: (type, req) => {
95
+ Util.logger.info(
96
+ `- Requesting next batch (currently ${req.Results.length} records)`
97
+ );
98
+ },
99
+ onRefresh: (authObject) => {
100
+ authObject.scope = authObject.scope.split(' '); // Scope is usually not an array, but we enforce conversion here for simplicity
101
+ credentialStore.set(sessionKey, authObject);
102
+ },
103
+ onConnectionError: (ex, remainingAttempts) => {
104
+ Util.logger.warn(
105
+ `- Connection problem (Code: ${ex.code}). Retrying ${remainingAttempts} time${
106
+ remainingAttempts > 1 ? 's' : ''
107
+ }`
108
+ );
109
+ Util.logger.errorStack(ex);
110
+ },
111
+ },
112
+ requestAttempts: 4,
113
+ retryOnConnectionError: true,
114
+ });
115
+ }
116
+
117
+ module.exports = Auth;
@@ -1,8 +1,9 @@
1
1
  'use strict';
2
2
 
3
+ const TYPE = require('../../types/mcdev.d');
3
4
  const Util = require('./util');
4
5
  const File = require('./file');
5
- const Retriever = require('../Retriever');
6
+ const auth = require('./auth');
6
7
 
7
8
  /**
8
9
  * Helper that handles retrieval of BU info
@@ -10,57 +11,42 @@ const Retriever = require('../Retriever');
10
11
  const BusinessUnit = {
11
12
  /**
12
13
  * Refreshes BU names and ID's from MC instance
13
- * @param {object} properties current properties that have to be refreshed
14
+ *
15
+ * @param {TYPE.Mcdevrc} properties current properties that have to be refreshed
14
16
  * @param {string} credentialsName identifying name of the installed package / project
15
- * @returns {Promise<boolean>} success of refresh
17
+ * @returns {Promise.<boolean>} success of refresh
16
18
  */
17
19
  refreshBUProperties: async function (properties, credentialsName) {
18
20
  const currentCredentials = properties.credentials[credentialsName];
19
- const buObject = {
20
- clientId: currentCredentials.clientId,
21
- clientSecret: currentCredentials.clientSecret,
22
- tenant: currentCredentials.tenant,
23
- };
24
- let client;
25
- Util.logger.info(`Testing credentials`);
26
- try {
27
- client = await Util.getETClient(buObject);
28
- } catch (ex) {
29
- Util.logger.error(ex.message);
30
- return false;
31
- }
32
- const retriever = new Retriever(properties, buObject, client);
33
21
  Util.logger.info(`Loading BUs`);
34
-
35
- const buResult = await new Promise((resolve) => {
36
- retriever.client.SoapClient.retrieve(
22
+ try {
23
+ const client = auth.getSDK({
24
+ mid: currentCredentials.eid,
25
+ eid: currentCredentials.eid,
26
+ credential: credentialsName,
27
+ businessUnit: '_ParentBU_',
28
+ });
29
+ const buResult = await client.soap.retrieve(
37
30
  'BusinessUnit',
38
31
  ['Name', 'ID', 'ParentName', 'ParentID', 'IsActive'],
39
- { queryAllAccounts: true },
40
- (error, response) => {
41
- if (error) {
42
- Util.logger.error(`Credentials failure. ${error}`);
43
- resolve(null);
44
- // throw new Error(error);
45
- } else {
46
- resolve(response.body.Results);
47
- }
48
- }
32
+ { QueryAllAccounts: true }
49
33
  );
50
- });
51
- if (buResult !== null && !buResult.length) {
52
- Util.logger.error(`Credentials worked but no BUs found. Check access rights!`);
53
- } else if (buResult !== null) {
54
- Util.logger.info(`Found ${buResult.length} BUs:`);
55
- // create shortcut and reset BU list at the same time. we don't want old entries clutter the new list
56
- const myBuList = (currentCredentials.businessUnits = {});
57
- // sort array by name for better display (wont affect object in settings)
58
- buResult
59
- .sort((a, b) => {
60
- if (a.ParentID === '0') {
34
+ if (buResult !== null && !buResult.Results) {
35
+ Util.logger.error(`Credentials worked but no BUs found. Check access rights!`);
36
+ } else if (buResult !== null) {
37
+ Util.logger.info(`Found ${buResult.Results.length} BUs:`);
38
+ // create shortcut and reset BU list at the same time. we don't want old entries clutter the new list
39
+ const myBuList = (currentCredentials.businessUnits = {});
40
+ // sort array by name for better display (wont affect object in settings)
41
+ for (const element of buResult.Results.map((element) => {
42
+ element.ID = Number.parseInt(element.ID);
43
+ element.ParentID = Number.parseInt(element.ParentID);
44
+ return element;
45
+ }).sort((a, b) => {
46
+ if (a.ParentID === 0) {
61
47
  return -1;
62
48
  }
63
- if (b.ParentID === '0') {
49
+ if (b.ParentID === 0) {
64
50
  return 1;
65
51
  }
66
52
  if (a.Name.toLowerCase() < b.Name.toLowerCase()) {
@@ -70,9 +56,8 @@ const BusinessUnit = {
70
56
  return 1;
71
57
  }
72
58
  return 0;
73
- })
74
- .forEach((element) => {
75
- if (element.ParentID === '0') {
59
+ })) {
60
+ if (element.ParentID === 0) {
76
61
  myBuList[Util.parentBuName] = element.ID;
77
62
  currentCredentials.eid = element.ID;
78
63
  Util.logger.info(` - ${Util.parentBuName} (${element.Name})`);
@@ -87,29 +72,33 @@ const BusinessUnit = {
87
72
  }`
88
73
  );
89
74
  }
90
- });
91
- Util.logger.debug(`EID: ${currentCredentials.eid}`);
92
- if (currentCredentials.eid === null) {
93
- Util.logger.warn(
94
- `It seems your 'installed package' was not created on the Parent BU of your instance.`
95
- );
96
- Util.logger.warn(
97
- `While basic functionality will work, it is strongly recommended that you create a new 'installed package' there to enable support for shared Data Extensions and automatic retrieval of the BU list.`
98
- );
99
- Util.logger.warn(
100
- `If you cannot create a package on the Parent BU, please open your ./.mcdevrc.json and update the list of BUs and their MIDs manually.`
75
+ }
76
+ Util.logger.debug(`EID: ${currentCredentials.eid}`);
77
+ if (currentCredentials.eid === null) {
78
+ Util.logger.warn(
79
+ `It seems your 'installed package' was not created on the Parent BU of your instance.`
80
+ );
81
+ Util.logger.warn(
82
+ `While basic functionality will work, it is strongly recommended that you create a new 'installed package' there to enable support for shared Data Extensions and automatic retrieval of the BU list.`
83
+ );
84
+ Util.logger.warn(
85
+ `If you cannot create a package on the Parent BU, please open your ./.mcdevrc.json and update the list of BUs and their MIDs manually.`
86
+ );
87
+ // allow user to work by setting this to an obviously false value which nonetheless doesn't block execution
88
+ currentCredentials.eid = -1;
89
+ }
90
+ // store BU list for repo
91
+ await File.writeJSONToFile(
92
+ properties.directories.businessUnits,
93
+ File.filterIllegalFilenames(credentialsName + '.businessUnits'),
94
+ buResult.Results
101
95
  );
102
- // allow user to work by setting this to an obviously false value which nonetheless doesn't block execution
103
- currentCredentials.eid = -1;
96
+ // update config
97
+ await File.saveConfigFile(properties);
104
98
  }
105
- // store BU list for repo
106
- await File.writeJSONToFile(
107
- properties.directories.businessUnits,
108
- File.filterIllegalFilenames(credentialsName + '.businessUnits'),
109
- buResult
110
- );
111
- // update config
112
- await File.saveConfigFile(properties);
99
+ } catch (ex) {
100
+ Util.logger.error(`Credentials failure. ${ex}`);
101
+ return null;
113
102
  }
114
103
  return true;
115
104
  },
@@ -0,0 +1,194 @@
1
+ const TYPE = require('../../types/mcdev.d');
2
+ const Util = require('./util');
3
+
4
+ /** @type {TYPE.Cache} */
5
+ const dataStore = {};
6
+ let currentMID = null;
7
+
8
+ module.exports = {
9
+ /**
10
+ * Method to setup buObject
11
+ * NOTE: in future this may need to restore, rather than wipe the cache
12
+ *
13
+ * @param {TYPE.BuObject} buObject for current Business unit
14
+ * @returns {void}
15
+ */
16
+ initCache: (buObject) => {
17
+ if (buObject?.mid) {
18
+ currentMID = buObject.mid;
19
+ dataStore[currentMID] = {};
20
+ // If the EID is not setup, also do this for required types (ie. Folders)
21
+ if (!dataStore[buObject.eid]) {
22
+ dataStore[buObject.eid] = {};
23
+ }
24
+ } else {
25
+ throw new Error('Business Unit (buObject) used when initialzing cache was missing MID');
26
+ }
27
+ },
28
+ /**
29
+ * return entire cache for current MID
30
+ *
31
+ * @returns {TYPE.MultiMetadataTypeMap} cache for one Business Unit
32
+ */
33
+ getCache: () => dataStore[currentMID],
34
+
35
+ /* eslint-disable unicorn/no-array-for-each */
36
+ /**
37
+ * clean cache for one BU if mid provided, otherwise whole cache
38
+ *
39
+ * @param {number} [mid] of business unit
40
+ * @returns {void}
41
+ */
42
+ clearCache: (mid) =>
43
+ mid
44
+ ? Object.keys(dataStore[mid]).forEach((key) => delete dataStore[mid][key])
45
+ : Object.keys(dataStore).forEach((key) => delete dataStore[key]),
46
+ /* eslint-enable unicorn/no-array-for-each */
47
+
48
+ /**
49
+ * return a specific item from cache
50
+ *
51
+ * @param {TYPE.SupportedMetadataTypes} type of Metadata to retrieve from cache
52
+ * @param {string} key of the specific metadata
53
+ * @returns {TYPE.MetadataTypeItem} cached metadata item
54
+ */
55
+ getByKey: (type, key) => dataStore[currentMID]?.[type]?.[key],
56
+ /**
57
+ * override cache for given metadata type with new data
58
+ *
59
+ * @param {TYPE.SupportedMetadataTypes} type of Metadata to retrieve from cache
60
+ * @param {TYPE.MetadataTypeMap} metadataMap map to be set
61
+ * @returns {void}
62
+ */
63
+ setMetadata: (type, metadataMap) => {
64
+ dataStore[currentMID][type] = metadataMap;
65
+ },
66
+ /**
67
+ * merges entire metadata type with existing cache
68
+ *
69
+ * @param {TYPE.SupportedMetadataTypes} type of Metadata to retrieve from cache
70
+ * @param {TYPE.MetadataTypeMap} metadataMap map to be merged
71
+ * @param {number} overrideMID which should be used for merging
72
+ * @returns {void}
73
+ */
74
+ mergeMetadata: (type, metadataMap, overrideMID) => {
75
+ dataStore[overrideMID || currentMID][type] = Object.assign(
76
+ metadataMap,
77
+ dataStore[currentMID][type]
78
+ );
79
+ },
80
+ /**
81
+ * standardized method for getting data from cache.
82
+ *
83
+ * @param {TYPE.SupportedMetadataTypes} metadataType metadata type ie. query
84
+ * @param {string|number|boolean} searchValue unique identifier of metadata being looked for
85
+ * @param {string} searchField field name (key in object) which contains the unique identifer
86
+ * @param {string} returnField field which should be returned
87
+ * @param {number} [overrideMID] ignore currentMID and use alternative (for example parent MID)
88
+ * @returns {string|number|boolean} value of specified field. Error is thrown if not found
89
+ */
90
+ searchForField(metadataType, searchValue, searchField, returnField, overrideMID) {
91
+ for (const key in dataStore[overrideMID || currentMID]?.[metadataType]) {
92
+ if (
93
+ Util.resolveObjPath(
94
+ searchField,
95
+ dataStore[overrideMID || currentMID][metadataType][key]
96
+ ) == searchValue
97
+ ) {
98
+ try {
99
+ if (
100
+ Util.resolveObjPath(
101
+ returnField,
102
+ dataStore[overrideMID || currentMID][metadataType][key]
103
+ )
104
+ ) {
105
+ return Util.resolveObjPath(
106
+ returnField,
107
+ dataStore[overrideMID || currentMID][metadataType][key]
108
+ );
109
+ } else {
110
+ throw new Error(); // eslint-disable-line unicorn/error-message
111
+ }
112
+ } catch {
113
+ throw new Error(
114
+ `${metadataType} with ${searchField} '${searchValue}' does not have field '${returnField}'`
115
+ );
116
+ }
117
+ }
118
+ }
119
+ throw new Error(
120
+ `Dependent ${metadataType} with ${searchField}='${searchValue}' was not found on your BU`
121
+ );
122
+ },
123
+ /**
124
+ * standardized method for getting data from cache - adapted for special case of lists
125
+ * ! keeping this in util/cache.js rather than in metadataTypes/List.js to avoid potential circular dependencies
126
+ *
127
+ * @param {string} searchValue unique identifier of metadata being looked for
128
+ * @param {string} searchField ObjectID or ID
129
+ * @returns {string} unique folderPath/ListName combo of list
130
+ */
131
+ getListPathName(searchValue, searchField) {
132
+ const returnField1 = 'r__folder_Path';
133
+ const returnField2 = 'ListName';
134
+ for (const key in dataStore[currentMID]['list']) {
135
+ if (dataStore[currentMID]['list'][key][searchField] === searchValue) {
136
+ try {
137
+ if (
138
+ dataStore[currentMID]['list'][key][returnField1] &&
139
+ dataStore[currentMID]['list'][key][returnField2]
140
+ ) {
141
+ return (
142
+ dataStore[currentMID]['list'][key][returnField1] +
143
+ '/' +
144
+ dataStore[currentMID]['list'][key][returnField2]
145
+ );
146
+ } else {
147
+ throw new Error(); // eslint-disable-line unicorn/error-message
148
+ }
149
+ } catch {
150
+ throw new Error(
151
+ `${'list'} with ${searchField}='${searchValue}' does not have the fields ${returnField1} and ${returnField2}`
152
+ );
153
+ }
154
+ }
155
+ }
156
+ throw new Error(
157
+ `Dependent list with ${searchField}='${searchValue}' was not found on your BU`
158
+ );
159
+ },
160
+ /**
161
+ * standardized method for getting data from cache - adapted for special case of lists
162
+ * ! keeping this in util/cache.js rather than in metadataTypes/List.js to avoid potential circular dependencies
163
+ *
164
+ * @param {string} listPathName folderPath/ListName combo of list
165
+ * @param {string} returnField ObjectID or ID
166
+ * @returns {string} unique ObjectId of list
167
+ */
168
+ getListObjectId(listPathName, returnField) {
169
+ let folderPath = listPathName.split('/');
170
+ const listName = folderPath.pop();
171
+ folderPath = folderPath.join('/');
172
+ for (const key in dataStore[currentMID]['list']) {
173
+ if (
174
+ dataStore[currentMID]['list'][key].ListName === listName &&
175
+ dataStore[currentMID]['list'][key].r__folder_Path === folderPath
176
+ ) {
177
+ try {
178
+ if (dataStore[currentMID]['list'][key][returnField]) {
179
+ return dataStore[currentMID]['list'][key][returnField];
180
+ } else {
181
+ throw new Error(); // eslint-disable-line unicorn/error-message
182
+ }
183
+ } catch {
184
+ throw new Error(
185
+ `${'list'} with ListName='${listName}' and r__folder_Path='${folderPath}' does not have field '${returnField}'`
186
+ );
187
+ }
188
+ }
189
+ }
190
+ throw new Error(
191
+ `Dependent list with ListName='${listName}' and r__folder_Path='${folderPath}' was not found on your BU`
192
+ );
193
+ },
194
+ };