@contentstack/cli-cm-import 1.10.1 → 1.11.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.
package/README.md CHANGED
@@ -47,7 +47,7 @@ $ npm install -g @contentstack/cli-cm-import
47
47
  $ csdx COMMAND
48
48
  running command...
49
49
  $ csdx (--version)
50
- @contentstack/cli-cm-import/1.10.1 linux-x64 node-v18.18.2
50
+ @contentstack/cli-cm-import/1.11.0 linux-x64 node-v18.18.2
51
51
  $ csdx --help [COMMAND]
52
52
  USAGE
53
53
  $ csdx COMMAND
@@ -18,7 +18,6 @@ const config = {
18
18
  'https://eu-api.contentstack.com': 'https://eu-developerhub-api.contentstack.com',
19
19
  'https://azure-na-api.contentstack.com': 'https://azure-na-developerhub-api.contentstack.com',
20
20
  'https://azure-eu-api.contentstack.com': 'https://azure-eu-developerhub-api.contentstack.com',
21
- 'https://stag-api.csnonprod.com': 'https://stag-developerhub-api.csnonprod.com',
22
21
  },
23
22
  modules: {
24
23
  apiConcurrency: 5,
@@ -26,6 +25,7 @@ const config = {
26
25
  'locales',
27
26
  'environments',
28
27
  'assets',
28
+ 'taxonomies',
29
29
  'extensions',
30
30
  'marketplace-apps',
31
31
  'global-fields',
@@ -142,6 +142,14 @@ const config = {
142
142
  dirName: 'marketplace_apps',
143
143
  fileName: 'marketplace_apps.json',
144
144
  },
145
+ taxonomies: {
146
+ dirName: 'taxonomies',
147
+ fileName: 'taxonomies.json',
148
+ },
149
+ terms: {
150
+ dirName: 'terms',
151
+ fileName: 'terms.json',
152
+ },
145
153
  },
146
154
  languagesCode: [
147
155
  'af-za',
@@ -380,5 +388,6 @@ const config = {
380
388
  getEncryptionKeyMaxRetry: 3,
381
389
  // useBackedupDir: '',
382
390
  // backupConcurrency: 10,
391
+ onlyTSModules: ['taxonomies'],
383
392
  };
384
393
  exports.default = config;
@@ -68,11 +68,16 @@ class ModuleImporter {
68
68
  moduleName,
69
69
  });
70
70
  }
71
- return (0, modules_js_1.default)({
72
- stackAPIClient: this.stackAPIClient,
73
- importConfig: this.importConfig,
74
- moduleName,
75
- });
71
+ else {
72
+ //NOTE - new modules support only ts
73
+ if (this.importConfig.onlyTSModules.indexOf(moduleName) === -1) {
74
+ return (0, modules_js_1.default)({
75
+ stackAPIClient: this.stackAPIClient,
76
+ importConfig: this.importConfig,
77
+ moduleName,
78
+ });
79
+ }
80
+ }
76
81
  }
77
82
  async importAllModules() {
78
83
  // use the algorithm to determine the parallel and sequential execution of modules
@@ -3,7 +3,7 @@ import { ImportConfig, ModuleClassParams } from '../../types';
3
3
  export type AdditionalKeys = {
4
4
  backupDir: string;
5
5
  };
6
- export type ApiModuleType = 'create-assets' | 'replace-assets' | 'publish-assets' | 'create-assets-folder' | 'create-extensions' | 'update-extensions' | 'create-locale' | 'update-locale' | 'create-gfs' | 'create-cts' | 'update-cts' | 'update-gfs' | 'create-environments' | 'create-labels' | 'update-labels' | 'create-webhooks' | 'create-workflows' | 'create-custom-role' | 'create-entries' | 'update-entries' | 'publish-entries' | 'delete-entries';
6
+ export type ApiModuleType = 'create-assets' | 'replace-assets' | 'publish-assets' | 'create-assets-folder' | 'create-extensions' | 'update-extensions' | 'create-locale' | 'update-locale' | 'create-gfs' | 'create-cts' | 'update-cts' | 'update-gfs' | 'create-environments' | 'create-labels' | 'update-labels' | 'create-webhooks' | 'create-workflows' | 'create-custom-role' | 'create-entries' | 'update-entries' | 'publish-entries' | 'delete-entries' | 'create-taxonomies' | 'create-terms';
7
7
  export type ApiOptions = {
8
8
  uid?: string;
9
9
  url?: string;
@@ -255,6 +255,17 @@ class BaseClass {
255
255
  .delete({ locale: additionalInfo.locale })
256
256
  .then(onSuccess)
257
257
  .catch(onReject);
258
+ case 'create-taxonomies':
259
+ return this.stack.taxonomy().create({ taxonomy: apiData }).then(onSuccess).catch(onReject);
260
+ case 'create-terms':
261
+ if (apiData === null || apiData === void 0 ? void 0 : apiData.taxonomy_uid) {
262
+ return this.stack
263
+ .taxonomy(apiData.taxonomy_uid)
264
+ .terms()
265
+ .create({ term: apiData })
266
+ .then(onSuccess)
267
+ .catch(onReject);
268
+ }
258
269
  default:
259
270
  return Promise.resolve();
260
271
  }
@@ -30,6 +30,8 @@ export default class ContentTypesImport extends BaseClass {
30
30
  private installedExtensions;
31
31
  private cTsConfig;
32
32
  private gFsConfig;
33
+ private taxonomiesPath;
34
+ taxonomies: Record<string, unknown>;
33
35
  constructor({ importConfig, stackAPIClient }: ModuleClassParams);
34
36
  start(): Promise<any>;
35
37
  seedCTs(): Promise<any>;
@@ -38,6 +38,7 @@ class ContentTypesImport extends base_class_1.default {
38
38
  this.gFs = [];
39
39
  this.createdGFs = [];
40
40
  this.pendingGFs = [];
41
+ this.taxonomiesPath = path.join(importConfig.data, 'mapper/taxonomies', 'success.json');
41
42
  }
42
43
  async start() {
43
44
  /**
@@ -54,6 +55,7 @@ class ContentTypesImport extends base_class_1.default {
54
55
  }
55
56
  await utils_1.fsUtil.makeDirectory(this.cTsMapperPath);
56
57
  this.installedExtensions = ((await utils_1.fsUtil.readFile(this.marketplaceAppMapperPath)) || { extension_uid: {} }).extension_uid;
58
+ this.taxonomies = utils_1.fsUtil.readFile(this.taxonomiesPath);
57
59
  await this.seedCTs();
58
60
  (0, utils_1.log)(this.importConfig, 'Created content types', 'success');
59
61
  await this.updateCTs();
@@ -108,7 +110,7 @@ class ContentTypesImport extends base_class_1.default {
108
110
  }
109
111
  async updateCTs() {
110
112
  const onSuccess = ({ response: contentType, apiData: { uid } }) => {
111
- (0, utils_1.log)(this.importConfig, `${uid} updated with references`, 'success');
113
+ (0, utils_1.log)(this.importConfig, `'${uid}' updated with references`, 'success');
112
114
  };
113
115
  const onReject = ({ error, apiData: { uid } }) => {
114
116
  (0, utils_1.log)(this.importConfig, (0, utils_1.formatError)(error), 'error');
@@ -141,6 +143,8 @@ class ContentTypesImport extends base_class_1.default {
141
143
  }
142
144
  this.fieldRules.push(contentType.uid);
143
145
  }
146
+ //will remove taxonomy if taxonomy doesn't exists in stack
147
+ (0, utils_1.lookUpTaxonomy)(this.importConfig, contentType.schema, this.taxonomies);
144
148
  (0, utils_1.lookupExtension)(this.importConfig, contentType.schema, this.importConfig.preserveStackVersion, this.installedExtensions);
145
149
  const contentTypePayload = this.stack.contentType(contentType.uid);
146
150
  Object.assign(contentTypePayload, (0, lodash_1.cloneDeep)(contentType));
@@ -34,6 +34,8 @@ export default class EntriesImport extends BaseClass {
34
34
  private entriesUidMapper;
35
35
  private envs;
36
36
  private autoCreatedEntries;
37
+ private taxonomiesPath;
38
+ taxonomies: Record<string, unknown>;
37
39
  constructor({ importConfig, stackAPIClient }: ModuleClassParams);
38
40
  start(): Promise<any>;
39
41
  disableMandatoryCTReferences(): Promise<void>;
@@ -23,6 +23,7 @@ class EntriesImport extends base_class_1.default {
23
23
  this.uniqueUidMapperPath = path.join(this.entriesMapperPath, 'unique-mapping.json');
24
24
  this.modifiedCTsPath = path.join(this.entriesMapperPath, 'modified-schemas.json');
25
25
  this.marketplaceAppMapperPath = path.join(this.importConfig.data, 'mapper', 'marketplace_apps', 'uid-mapping.json');
26
+ this.taxonomiesPath = path.join(this.importConfig.data, 'mapper', 'taxonomies', 'terms', 'success.json');
26
27
  this.entriesConfig = importConfig.modules.entries;
27
28
  this.entriesPath = path.resolve(importConfig.data, this.entriesConfig.dirName);
28
29
  this.cTsPath = path.resolve(importConfig.data, importConfig.modules['content-types'].dirName);
@@ -47,6 +48,7 @@ class EntriesImport extends base_class_1.default {
47
48
  this.installedExtensions = ((await utils_1.fsUtil.readFile(this.marketplaceAppMapperPath)) || { extension_uid: {} }).extension_uid;
48
49
  this.assetUidMapper = utils_1.fsUtil.readFile(this.assetUidMapperPath) || {};
49
50
  this.assetUrlMapper = utils_1.fsUtil.readFile(this.assetUrlMapperPath) || {};
51
+ this.taxonomies = utils_1.fsUtil.readFile(this.taxonomiesPath);
50
52
  utils_1.fsUtil.makeDirectory(this.entriesMapperPath);
51
53
  await this.disableMandatoryCTReferences();
52
54
  this.locales = (0, lodash_1.values)(utils_1.fsUtil.readFile(this.localesPath));
@@ -316,6 +318,8 @@ class EntriesImport extends base_class_1.default {
316
318
  if (this.jsonRteCTsWithRef.indexOf(cTUid) > -1) {
317
319
  entry = (0, utils_1.removeEntryRefsFromJSONRTE)(entry, contentType.schema);
318
320
  }
321
+ //will remove term if term doesn't exists in taxonomy
322
+ (0, utils_1.lookUpTerms)(contentType === null || contentType === void 0 ? void 0 : contentType.schema, entry, this.taxonomies, this.importConfig);
319
323
  // will replace all old asset uid/urls with new ones
320
324
  entry = (0, utils_1.lookupAssets)({
321
325
  content_type: contentType,
@@ -0,0 +1,63 @@
1
+ import BaseClass, { ApiOptions } from './base-class';
2
+ import { ModuleClassParams } from '../../types';
3
+ export default class ImportTaxonomies extends BaseClass {
4
+ private taxonomiesMapperDirPath;
5
+ private taxonomiesFolderPath;
6
+ private taxSuccessPath;
7
+ private taxFailsPath;
8
+ private taxonomiesConfig;
9
+ private taxonomies;
10
+ private termsFolderPath;
11
+ private termsMapperDirPath;
12
+ private termsConfig;
13
+ private termsSuccessPath;
14
+ private termsFailsPath;
15
+ taxonomiesSuccess: Record<string, unknown>;
16
+ taxonomiesFailed: Record<string, unknown>;
17
+ termsSuccess: Record<string, Record<string, unknown>>;
18
+ termsFailed: Record<string, Record<string, unknown>>;
19
+ terms: Record<string, any>;
20
+ taxonomyUIDs: string[];
21
+ constructor({ importConfig, stackAPIClient }: ModuleClassParams);
22
+ /**
23
+ * @method start
24
+ * @returns {Promise<void>} Promise<void>
25
+ */
26
+ start(): Promise<void>;
27
+ /**
28
+ * create taxonomy and enter success & failure related data into taxonomies mapper file
29
+ * @method importTaxonomies
30
+ * @async
31
+ * @returns {Promise<any>} Promise<any>
32
+ */
33
+ importTaxonomies(): Promise<any>;
34
+ /**
35
+ * @method serializeTaxonomy
36
+ * @param {ApiOptions} apiOptions ApiOptions
37
+ * @returns {ApiOptions} ApiOptions
38
+ */
39
+ serializeTaxonomy(apiOptions: ApiOptions): ApiOptions;
40
+ /**
41
+ * create taxonomies success and fail in (mapper/taxonomies)
42
+ * @method createTaxonomySuccessAndFailedFile
43
+ */
44
+ createTaxonomySuccessAndFailedFile(): void;
45
+ /**
46
+ * create terms and enter success & failure related data into terms mapper file
47
+ * @method importTerms
48
+ * @async
49
+ * @returns {Promise<any>} Promise<any>
50
+ */
51
+ importTerms(): Promise<any>;
52
+ /**
53
+ * @method serializeTerms
54
+ * @param {ApiOptions} apiOptions ApiOptions
55
+ * @returns {ApiOptions} ApiOptions
56
+ */
57
+ serializeTerms(apiOptions: ApiOptions): ApiOptions;
58
+ /**
59
+ * create terms success and fail in (mapper/taxonomies/terms)
60
+ * @method createTermSuccessAndFailedFile
61
+ */
62
+ createTermSuccessAndFailedFile(): void;
63
+ }
@@ -0,0 +1,217 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const keys_1 = tslib_1.__importDefault(require("lodash/keys"));
5
+ const pick_1 = tslib_1.__importDefault(require("lodash/pick"));
6
+ const node_path_1 = require("node:path");
7
+ const values_1 = tslib_1.__importDefault(require("lodash/values"));
8
+ const isEmpty_1 = tslib_1.__importDefault(require("lodash/isEmpty"));
9
+ const base_class_1 = tslib_1.__importDefault(require("./base-class"));
10
+ const utils_1 = require("../../utils");
11
+ class ImportTaxonomies extends base_class_1.default {
12
+ constructor({ importConfig, stackAPIClient }) {
13
+ super({ importConfig, stackAPIClient });
14
+ this.taxonomiesSuccess = {};
15
+ this.taxonomiesFailed = {};
16
+ this.termsSuccess = {};
17
+ this.termsFailed = {};
18
+ this.terms = [];
19
+ this.taxonomyUIDs = [];
20
+ this.taxonomiesConfig = importConfig.modules.taxonomies;
21
+ this.termsConfig = importConfig.modules.terms;
22
+ this.taxonomiesMapperDirPath = (0, node_path_1.join)(importConfig.backupDir, 'mapper', 'taxonomies');
23
+ this.termsMapperDirPath = (0, node_path_1.join)(this.taxonomiesMapperDirPath, 'terms');
24
+ this.taxonomiesFolderPath = (0, node_path_1.join)(importConfig.backupDir, this.taxonomiesConfig.dirName);
25
+ this.termsFolderPath = (0, node_path_1.join)(this.taxonomiesFolderPath, this.termsConfig.dirName);
26
+ this.taxSuccessPath = (0, node_path_1.join)(this.taxonomiesMapperDirPath, 'success.json');
27
+ this.taxFailsPath = (0, node_path_1.join)(this.taxonomiesMapperDirPath, 'fails.json');
28
+ this.termsSuccessPath = (0, node_path_1.join)(this.termsMapperDirPath, 'success.json');
29
+ this.termsFailsPath = (0, node_path_1.join)(this.termsMapperDirPath, 'fails.json');
30
+ }
31
+ /**
32
+ * @method start
33
+ * @returns {Promise<void>} Promise<void>
34
+ */
35
+ async start() {
36
+ (0, utils_1.log)(this.importConfig, 'Migrating taxonomies...', 'info');
37
+ //Step1 check folder exists or not
38
+ if (utils_1.fileHelper.fileExistsSync(this.taxonomiesFolderPath)) {
39
+ this.taxonomies = utils_1.fsUtil.readFile((0, node_path_1.join)(this.taxonomiesFolderPath, 'taxonomies.json'), true);
40
+ }
41
+ else {
42
+ (0, utils_1.log)(this.importConfig, `No such file or directory - '${this.taxonomiesFolderPath}'`, 'error');
43
+ return;
44
+ }
45
+ //Step 2 create taxonomies & terms mapper directory
46
+ await utils_1.fsUtil.makeDirectory(this.taxonomiesMapperDirPath);
47
+ await utils_1.fsUtil.makeDirectory(this.termsMapperDirPath);
48
+ //Step 3 import taxonomy and create success & failure file
49
+ await this.importTaxonomies();
50
+ this.createTaxonomySuccessAndFailedFile();
51
+ if (!utils_1.fileHelper.fileExistsSync(this.termsFolderPath)) {
52
+ (0, utils_1.log)(this.importConfig, `No such file or directory - '${this.termsFolderPath}'`, 'error');
53
+ return;
54
+ }
55
+ //Step 4 import terms and create success & failure file
56
+ await this.importTerms();
57
+ this.createTermSuccessAndFailedFile();
58
+ (0, utils_1.log)(this.importConfig, 'Taxonomies imported successfully!', 'success');
59
+ }
60
+ /**
61
+ * create taxonomy and enter success & failure related data into taxonomies mapper file
62
+ * @method importTaxonomies
63
+ * @async
64
+ * @returns {Promise<any>} Promise<any>
65
+ */
66
+ async importTaxonomies() {
67
+ if (this.taxonomies === undefined || (0, isEmpty_1.default)(this.taxonomies)) {
68
+ (0, utils_1.log)(this.importConfig, 'No Taxonomies Found!', 'info');
69
+ return;
70
+ }
71
+ const apiContent = (0, values_1.default)(this.taxonomies);
72
+ this.taxonomyUIDs = (0, keys_1.default)(this.taxonomies);
73
+ const onSuccess = ({ response }) => {
74
+ const { uid } = response;
75
+ this.taxonomiesSuccess[uid] = (0, pick_1.default)(response, ['name', 'description']);
76
+ (0, utils_1.log)(this.importConfig, `Taxonomy '${uid}' imported successfully!`, 'success');
77
+ };
78
+ const onReject = ({ error, apiData }) => {
79
+ var _a;
80
+ const err = (error === null || error === void 0 ? void 0 : error.message) ? JSON.parse(error.message) : error;
81
+ const { uid } = apiData;
82
+ if ((_a = err === null || err === void 0 ? void 0 : err.errors) === null || _a === void 0 ? void 0 : _a.taxonomy) {
83
+ this.taxonomiesFailed[uid] = apiData;
84
+ (0, utils_1.log)(this.importConfig, `Taxonomy '${uid}' failed to be import! ${err.errors.taxonomy}`, 'error');
85
+ }
86
+ else {
87
+ this.taxonomiesFailed[apiData.uid] = apiData;
88
+ (0, utils_1.log)(this.importConfig, `Taxonomy '${uid}' failed to be import! ${(0, utils_1.formatError)(error)}`, 'error');
89
+ }
90
+ };
91
+ await this.makeConcurrentCall({
92
+ apiContent,
93
+ processName: 'import taxonomies',
94
+ apiParams: {
95
+ serializeData: this.serializeTaxonomy.bind(this),
96
+ reject: onReject,
97
+ resolve: onSuccess,
98
+ entity: 'create-taxonomies',
99
+ includeParamOnCompletion: true,
100
+ },
101
+ concurrencyLimit: this.importConfig.concurrency || this.importConfig.fetchConcurrency || 1,
102
+ }, undefined, false);
103
+ }
104
+ /**
105
+ * @method serializeTaxonomy
106
+ * @param {ApiOptions} apiOptions ApiOptions
107
+ * @returns {ApiOptions} ApiOptions
108
+ */
109
+ serializeTaxonomy(apiOptions) {
110
+ const { apiData: taxonomy } = apiOptions;
111
+ apiOptions.apiData = taxonomy;
112
+ return apiOptions;
113
+ }
114
+ /**
115
+ * create taxonomies success and fail in (mapper/taxonomies)
116
+ * @method createTaxonomySuccessAndFailedFile
117
+ */
118
+ createTaxonomySuccessAndFailedFile() {
119
+ if (this.taxonomiesSuccess !== undefined && !(0, isEmpty_1.default)(this.taxonomiesSuccess)) {
120
+ utils_1.fsUtil.writeFile(this.taxSuccessPath, this.taxonomiesSuccess);
121
+ }
122
+ if (this.taxonomiesFailed !== undefined && !(0, isEmpty_1.default)(this.taxonomiesFailed)) {
123
+ utils_1.fsUtil.writeFile(this.taxFailsPath, this.taxonomiesFailed);
124
+ }
125
+ }
126
+ /**
127
+ * create terms and enter success & failure related data into terms mapper file
128
+ * @method importTerms
129
+ * @async
130
+ * @returns {Promise<any>} Promise<any>
131
+ */
132
+ async importTerms() {
133
+ var _a, _b;
134
+ if (!((_a = this.taxonomyUIDs) === null || _a === void 0 ? void 0 : _a.length)) {
135
+ return;
136
+ }
137
+ const onSuccess = ({ response, apiData: { taxonomy_uid } = { taxonomy_uid: null } }) => {
138
+ var _a;
139
+ const { uid } = response;
140
+ if (!((_a = this.termsSuccess) === null || _a === void 0 ? void 0 : _a[taxonomy_uid]))
141
+ this.termsSuccess[taxonomy_uid] = {};
142
+ this.termsSuccess[taxonomy_uid][uid] = (0, pick_1.default)(response, ['name']);
143
+ (0, utils_1.log)(this.importConfig, `Term '${uid}' imported successfully!`, 'success');
144
+ };
145
+ const onReject = ({ error, apiData }) => {
146
+ var _a, _b;
147
+ const { taxonomy_uid, uid } = apiData;
148
+ if (!((_a = this.termsFailed) === null || _a === void 0 ? void 0 : _a[taxonomy_uid]))
149
+ this.termsFailed[taxonomy_uid] = {};
150
+ const err = (error === null || error === void 0 ? void 0 : error.message) ? JSON.parse(error.message) : error;
151
+ if ((_b = err === null || err === void 0 ? void 0 : err.errors) === null || _b === void 0 ? void 0 : _b.term) {
152
+ this.termsFailed[taxonomy_uid][uid] = apiData;
153
+ (0, utils_1.log)(this.importConfig, `Term '${uid}' failed to be import! ${err.errors.term}`, 'error');
154
+ }
155
+ else {
156
+ this.termsFailed[taxonomy_uid][uid] = apiData;
157
+ (0, utils_1.log)(this.importConfig, `Term '${uid}' failed to be import! ${(0, utils_1.formatError)(error)}`, 'error');
158
+ }
159
+ };
160
+ for (const taxUID of this.taxonomyUIDs) {
161
+ //read terms from respective taxonomy
162
+ this.terms = utils_1.fsUtil.readFile((0, node_path_1.join)(this.termsFolderPath, `${taxUID}-${this.termsConfig.fileName}`), true);
163
+ if ((_b = this.terms) === null || _b === void 0 ? void 0 : _b.length) {
164
+ const apiContent = this.terms;
165
+ await this.makeConcurrentCall({
166
+ apiContent,
167
+ processName: 'import terms',
168
+ apiParams: {
169
+ serializeData: this.serializeTerms.bind(this),
170
+ reject: onReject,
171
+ resolve: onSuccess,
172
+ entity: 'create-terms',
173
+ includeParamOnCompletion: true,
174
+ },
175
+ concurrencyLimit: this.importConfig.concurrency || this.importConfig.fetchConcurrency || 1,
176
+ }, undefined, false);
177
+ }
178
+ }
179
+ }
180
+ /**
181
+ * @method serializeTerms
182
+ * @param {ApiOptions} apiOptions ApiOptions
183
+ * @returns {ApiOptions} ApiOptions
184
+ */
185
+ serializeTerms(apiOptions) {
186
+ var _a, _b;
187
+ const { apiData: term } = apiOptions;
188
+ const { parent_uid, taxonomy_uid } = term;
189
+ //check whether parent term exists or not in taxonomy
190
+ if (parent_uid !== null) {
191
+ if (!((_b = (_a = this.termsSuccess) === null || _a === void 0 ? void 0 : _a[taxonomy_uid]) === null || _b === void 0 ? void 0 : _b[parent_uid])) {
192
+ (0, utils_1.log)(this.importConfig, `Parent term '${term === null || term === void 0 ? void 0 : term.parent_uid}' does not exist! Skipping '${term.uid}' creation to avoid further issues.`, 'info');
193
+ apiOptions.apiData = undefined;
194
+ }
195
+ else {
196
+ apiOptions.apiData = term;
197
+ }
198
+ }
199
+ else {
200
+ apiOptions.apiData = term;
201
+ }
202
+ return apiOptions;
203
+ }
204
+ /**
205
+ * create terms success and fail in (mapper/taxonomies/terms)
206
+ * @method createTermSuccessAndFailedFile
207
+ */
208
+ createTermSuccessAndFailedFile() {
209
+ if (this.termsSuccess !== undefined && !(0, isEmpty_1.default)(this.termsSuccess)) {
210
+ utils_1.fsUtil.writeFile(this.termsSuccessPath, this.termsSuccess);
211
+ }
212
+ if (this.termsFailed !== undefined && !(0, isEmpty_1.default)(this.termsFailed)) {
213
+ utils_1.fsUtil.writeFile(this.termsFailsPath, this.termsFailed);
214
+ }
215
+ }
216
+ }
217
+ exports.default = ImportTaxonomies;
@@ -112,6 +112,16 @@ export default interface DefaultConfig {
112
112
  fileName: string;
113
113
  requiredKeys: string[];
114
114
  };
115
+ taxonomies: {
116
+ dirName: string;
117
+ fileName: string;
118
+ dependencies?: Modules[];
119
+ };
120
+ terms: {
121
+ dirName: string;
122
+ fileName: string;
123
+ dependencies?: Modules[];
124
+ };
115
125
  };
116
126
  languagesCode: string[];
117
127
  apis: {
@@ -140,4 +150,5 @@ export default interface DefaultConfig {
140
150
  getEncryptionKeyMaxRetry: number;
141
151
  createBackupDir?: string;
142
152
  overwriteSupportedModules: string[];
153
+ onlyTSModules: string[];
143
154
  }
@@ -20,7 +20,7 @@ export interface User {
20
20
  email: string;
21
21
  authtoken: string;
22
22
  }
23
- export type Modules = 'stack' | 'assets' | 'locales' | 'environments' | 'extensions' | 'webhooks' | 'global-fields' | 'entries' | 'content-types' | 'custom-roles' | 'workflows' | 'labels' | 'marketplace-apps';
23
+ export type Modules = 'stack' | 'assets' | 'locales' | 'environments' | 'extensions' | 'webhooks' | 'global-fields' | 'entries' | 'content-types' | 'custom-roles' | 'workflows' | 'labels' | 'marketplace-apps' | 'taxonomies';
24
24
  export type ModuleClassParams = {
25
25
  stackAPIClient: ReturnType<ContentstackClient['stack']>;
26
26
  importConfig: ImportConfig;
@@ -60,5 +60,15 @@ export interface CustomRoleConfig {
60
60
  fileName: string;
61
61
  customRolesLocalesFileName: string;
62
62
  }
63
+ export interface TaxonomiesConfig {
64
+ dirName: string;
65
+ fileName: string;
66
+ dependencies?: Modules[];
67
+ }
68
+ export interface TermsConfig {
69
+ dirName: string;
70
+ fileName: string;
71
+ dependencies?: Modules[];
72
+ }
63
73
  export { default as DefaultConfig } from './default-config';
64
74
  export { default as ImportConfig } from './import-config';
@@ -11,3 +11,4 @@ export { lookupExtension } from './extension-helper';
11
11
  export { lookupEntries, removeUidsFromJsonRteFields, removeEntryRefsFromJSONRTE, restoreJsonRteEntryRefs, } from './entries-helper';
12
12
  export * from './common-helper';
13
13
  export * from './log';
14
+ export { lookUpTaxonomy, lookUpTerms } from './taxonomies-helper';
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.restoreJsonRteEntryRefs = exports.removeEntryRefsFromJSONRTE = exports.removeUidsFromJsonRteFields = exports.lookupEntries = exports.lookupExtension = exports.removeReferenceFields = exports.suppressSchemaReference = exports.schemaTemplate = exports.updateAppConfig = exports.ifAppAlreadyExist = exports.getAllStackSpecificApps = exports.confirmToCloseProcess = exports.makeRedirectUrlCall = exports.installApp = exports.handleNameConflict = exports.createPrivateApp = exports.getConfirmationToCreateApps = exports.getOrgUid = exports.getDeveloperHubUrl = exports.lookupAssets = exports.uploadAssetHelper = exports.unlinkFileLogger = exports.log = exports.backupHandler = exports.fsUtil = exports.fileHelper = exports.setupImportConfig = exports.interactive = void 0;
3
+ exports.lookUpTerms = exports.lookUpTaxonomy = exports.restoreJsonRteEntryRefs = exports.removeEntryRefsFromJSONRTE = exports.removeUidsFromJsonRteFields = exports.lookupEntries = exports.lookupExtension = exports.removeReferenceFields = exports.suppressSchemaReference = exports.schemaTemplate = exports.updateAppConfig = exports.ifAppAlreadyExist = exports.getAllStackSpecificApps = exports.confirmToCloseProcess = exports.makeRedirectUrlCall = exports.installApp = exports.handleNameConflict = exports.createPrivateApp = exports.getConfirmationToCreateApps = exports.getOrgUid = exports.getDeveloperHubUrl = exports.lookupAssets = exports.uploadAssetHelper = exports.unlinkFileLogger = exports.log = exports.backupHandler = exports.fsUtil = exports.fileHelper = exports.setupImportConfig = exports.interactive = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  exports.interactive = tslib_1.__importStar(require("./interactive"));
6
6
  var import_config_handler_1 = require("./import-config-handler");
@@ -41,3 +41,6 @@ Object.defineProperty(exports, "removeEntryRefsFromJSONRTE", { enumerable: true,
41
41
  Object.defineProperty(exports, "restoreJsonRteEntryRefs", { enumerable: true, get: function () { return entries_helper_1.restoreJsonRteEntryRefs; } });
42
42
  tslib_1.__exportStar(require("./common-helper"), exports);
43
43
  tslib_1.__exportStar(require("./log"), exports);
44
+ var taxonomies_helper_1 = require("./taxonomies-helper");
45
+ Object.defineProperty(exports, "lookUpTaxonomy", { enumerable: true, get: function () { return taxonomies_helper_1.lookUpTaxonomy; } });
46
+ Object.defineProperty(exports, "lookUpTerms", { enumerable: true, get: function () { return taxonomies_helper_1.lookUpTerms; } });
@@ -72,7 +72,9 @@ function init(_logPath) {
72
72
  logger = winston.createLogger({
73
73
  transports: [
74
74
  new winston.transports.File(successTransport),
75
- new winston.transports.Console({ format: winston.format.simple() }),
75
+ new winston.transports.Console({
76
+ format: winston.format.combine(winston.format.simple(), winston.format.colorize({ all: true, colors: { warn: 'yellow', info: 'white' } })),
77
+ }),
76
78
  ],
77
79
  levels: myCustomLevels.levels,
78
80
  });
@@ -95,7 +97,7 @@ function init(_logPath) {
95
97
  logger.log('info', logString);
96
98
  }
97
99
  },
98
- warn: function () {
100
+ warn: function (message) {
99
101
  let args = slice.call(arguments);
100
102
  let logString = returnString(args);
101
103
  if (logString) {
@@ -123,7 +125,10 @@ const log = async (config, message, type) => {
123
125
  // ignoring the type argument, as we are not using it to create a logfile anymore
124
126
  if (type !== 'error') {
125
127
  // removed type argument from init method
126
- init(config.data).log(message);
128
+ if (type === 'warn')
129
+ init(config.data).warn(message); //logged warning message in log file
130
+ else
131
+ init(config.data).log(message);
127
132
  }
128
133
  else {
129
134
  init(config.data).error(message);
@@ -0,0 +1,16 @@
1
+ import { ImportConfig } from '../types';
2
+ /**
3
+ * check and remove if referenced taxonomy doesn't exists in stack
4
+ * @param {any} schema content type schema
5
+ * @param {Record<string, unknown>} taxonomies created taxonomies
6
+ * @param {ImportConfig} importConfig
7
+ */
8
+ export declare const lookUpTaxonomy: (importConfig: ImportConfig, schema: any, taxonomies: Record<string, unknown>) => void;
9
+ /**
10
+ * check and remove if referenced terms doesn't exists in taxonomy
11
+ * @param {Record<string, any>[]} ctSchema content type schema
12
+ * @param {any} entry
13
+ * @param {Record<string, any>} taxonomiesAndTermData created taxonomies and terms
14
+ * @param {ImportConfig} importConfig
15
+ */
16
+ export declare const lookUpTerms: (ctSchema: Record<string, any>[], entry: any, taxonomiesAndTermData: Record<string, any>, importConfig: ImportConfig) => void;
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.lookUpTerms = exports.lookUpTaxonomy = void 0;
4
+ /**
5
+ * taxonomy lookup
6
+ */
7
+ const _1 = require("./");
8
+ /**
9
+ * check and remove if referenced taxonomy doesn't exists in stack
10
+ * @param {any} schema content type schema
11
+ * @param {Record<string, unknown>} taxonomies created taxonomies
12
+ * @param {ImportConfig} importConfig
13
+ */
14
+ const lookUpTaxonomy = function (importConfig, schema, taxonomies) {
15
+ for (let i in schema) {
16
+ if (schema[i].data_type === 'taxonomy') {
17
+ const taxonomyFieldData = schema[i].taxonomies;
18
+ const { updatedTaxonomyData, isTaxonomyFieldRemoved } = verifyAndRemoveTaxonomy(taxonomyFieldData, taxonomies, importConfig);
19
+ //Handle API error -> The 'taxonomies' property must have atleast one taxonomy object. Remove taxonomy field from schema.
20
+ if (isTaxonomyFieldRemoved) {
21
+ schema.splice(i, 1);
22
+ }
23
+ else {
24
+ schema[i].taxonomies = updatedTaxonomyData;
25
+ }
26
+ }
27
+ }
28
+ };
29
+ exports.lookUpTaxonomy = lookUpTaxonomy;
30
+ /**
31
+ * verify and remove referenced taxonomy with warning from respective content type
32
+ * @param {Record<string, any>[]} taxonomyFieldData
33
+ * @param {Record<string, unknown>} taxonomies created taxonomies
34
+ * @param {ImportConfig} importConfig
35
+ * @returns
36
+ */
37
+ const verifyAndRemoveTaxonomy = function (taxonomyFieldData, taxonomies, importConfig) {
38
+ let isTaxonomyFieldRemoved = false;
39
+ for (let index = 0; index < (taxonomyFieldData === null || taxonomyFieldData === void 0 ? void 0 : taxonomyFieldData.length); index++) {
40
+ const taxonomyData = taxonomyFieldData[index];
41
+ if (taxonomies === undefined || !taxonomies.hasOwnProperty(taxonomyData === null || taxonomyData === void 0 ? void 0 : taxonomyData.taxonomy_uid)) {
42
+ // remove taxonomy from taxonomies field data with warning if respective taxonomy doesn't exists
43
+ (0, _1.log)(importConfig, `Taxonomy '${taxonomyData === null || taxonomyData === void 0 ? void 0 : taxonomyData.taxonomy_uid}' does not exist. Removing the data from the taxonomies field`, 'warn');
44
+ taxonomyFieldData.splice(index, 1);
45
+ --index;
46
+ }
47
+ }
48
+ if (!(taxonomyFieldData === null || taxonomyFieldData === void 0 ? void 0 : taxonomyFieldData.length)) {
49
+ (0, _1.log)(importConfig, 'Taxonomy does not exist. Removing the field from content type', 'warn');
50
+ isTaxonomyFieldRemoved = true;
51
+ }
52
+ return {
53
+ updatedTaxonomyData: taxonomyFieldData,
54
+ isTaxonomyFieldRemoved,
55
+ };
56
+ };
57
+ /**
58
+ * check and remove if referenced terms doesn't exists in taxonomy
59
+ * @param {Record<string, any>[]} ctSchema content type schema
60
+ * @param {any} entry
61
+ * @param {Record<string, any>} taxonomiesAndTermData created taxonomies and terms
62
+ * @param {ImportConfig} importConfig
63
+ */
64
+ const lookUpTerms = function (ctSchema, entry, taxonomiesAndTermData, importConfig) {
65
+ for (let index = 0; index < (ctSchema === null || ctSchema === void 0 ? void 0 : ctSchema.length); index++) {
66
+ if (ctSchema[index].data_type === 'taxonomy') {
67
+ const taxonomyFieldData = entry[ctSchema[index].uid];
68
+ const updatedTaxonomyData = verifyAndRemoveTerms(taxonomyFieldData, taxonomiesAndTermData, importConfig);
69
+ entry[ctSchema[index].uid] = updatedTaxonomyData;
70
+ }
71
+ }
72
+ };
73
+ exports.lookUpTerms = lookUpTerms;
74
+ /**
75
+ * verify and remove referenced term with warning from respective entry
76
+ * @param {Record<string, any>[]} taxonomyFieldData entry taxonomies data
77
+ * @param {Record<string, any>} taxonomiesAndTermData created taxonomies and terms
78
+ * @param {ImportConfig} importConfig
79
+ * @returns { Record<string, any>[]}
80
+ */
81
+ const verifyAndRemoveTerms = function (taxonomyFieldData, taxonomiesAndTermData, importConfig) {
82
+ for (let index = 0; index < (taxonomyFieldData === null || taxonomyFieldData === void 0 ? void 0 : taxonomyFieldData.length); index++) {
83
+ const taxonomyData = taxonomyFieldData[index];
84
+ const taxUID = taxonomyData === null || taxonomyData === void 0 ? void 0 : taxonomyData.taxonomy_uid;
85
+ const termUID = taxonomyData === null || taxonomyData === void 0 ? void 0 : taxonomyData.term_uid;
86
+ if (taxonomiesAndTermData === undefined ||
87
+ !taxonomiesAndTermData.hasOwnProperty(taxUID) ||
88
+ (taxonomiesAndTermData.hasOwnProperty(taxUID) && !taxonomiesAndTermData[taxUID].hasOwnProperty(termUID))) {
89
+ // remove term from taxonomies field data with warning if respective term doesn't exists
90
+ (0, _1.log)(importConfig, `Term '${termUID}' does not exist. Removing it from taxonomy - '${taxUID}'`, 'warn');
91
+ taxonomyFieldData.splice(index, 1);
92
+ --index;
93
+ }
94
+ }
95
+ return taxonomyFieldData;
96
+ };
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.10.1",
2
+ "version": "1.11.0",
3
3
  "commands": {
4
4
  "cm:stacks:import": {
5
5
  "id": "cm:stacks:import",
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@contentstack/cli-cm-import",
3
3
  "description": "Contentstack CLI plugin to import content into stack",
4
- "version": "1.10.1",
4
+ "version": "1.11.0",
5
5
  "author": "Contentstack",
6
6
  "bugs": "https://github.com/contentstack/cli/issues",
7
7
  "dependencies": {
8
8
  "@contentstack/cli-command": "~1.2.15",
9
9
  "@contentstack/cli-utilities": "~1.5.5",
10
- "@contentstack/management": "~1.11.0",
10
+ "@contentstack/management": "~1.12.0",
11
11
  "@oclif/core": "^2.9.3",
12
12
  "axios": "^1.6.0",
13
13
  "big-json": "^3.2.0",