@contentstack/cli-cm-import 1.11.1 → 1.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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.11.1 linux-x64 node-v18.18.2
50
+ @contentstack/cli-cm-import/1.12.1 linux-x64 node-v18.19.0
51
51
  $ csdx --help [COMMAND]
52
52
  USAGE
53
53
  $ csdx COMMAND
@@ -4,7 +4,6 @@ const tslib_1 = require("tslib");
4
4
  const node_path_1 = tslib_1.__importDefault(require("node:path"));
5
5
  const cli_command_1 = require("@contentstack/cli-command");
6
6
  const cli_utilities_1 = require("@contentstack/cli-utilities");
7
- const log_1 = require("../../../utils/log");
8
7
  const import_1 = require("../../../import");
9
8
  const utils_1 = require("../../../utils");
10
9
  class ImportCommand extends cli_command_1.Command {
@@ -26,7 +25,6 @@ class ImportCommand extends cli_command_1.Command {
26
25
  (0, utils_1.log)(importConfig, `The log has been stored at '${node_path_1.default.join(importConfig.backupDir, 'logs', 'import')}'`, 'success');
27
26
  }
28
27
  catch (error) {
29
- (0, log_1.trace)(error, 'error', true);
30
28
  (0, utils_1.log)({ data: backupDir }, `Failed to import stack content - ${(0, utils_1.formatError)(error)}`, 'error');
31
29
  (0, utils_1.log)({ data: backupDir }, `The log has been stored at ${{ data: backupDir } ? node_path_1.default.join(backupDir || __dirname, 'logs', 'import') : node_path_1.default.join(__dirname, 'logs')}`, 'info');
32
30
  }
@@ -113,7 +111,6 @@ ImportCommand.flags = {
113
111
  'replace-existing': cli_utilities_1.flags.boolean({
114
112
  required: false,
115
113
  description: 'Replaces the existing module in the target stack.',
116
- dependsOn: ['module'],
117
114
  }),
118
115
  'skip-existing': cli_utilities_1.flags.boolean({
119
116
  required: false,
@@ -20,17 +20,8 @@ class ModuleImporter {
20
20
  }
21
21
  // Temporarily adding this api call to verify management token has read and write permissions
22
22
  // TODO: CS-40354 - CLI | import rewrite | Migrate HTTP call to SDK call once fix is ready from SDK side
23
- const httpClient = new cli_utilities_1.HttpClient({
24
- headers: { api_key: this.importConfig.apiKey, authorization: this.importConfig.management_token },
25
- });
26
- const { data } = await httpClient.post(`https://${this.importConfig.host}/v3/locales`, {
27
- locale: {
28
- name: 'English',
29
- code: 'en-us',
30
- },
31
- });
32
- if (data.error_code === 161) {
33
- throw new Error(data.error_message);
23
+ if (this.importConfig.management_token) {
24
+ await (0, cli_utilities_1.addLocale)(this.importConfig.apiKey, this.importConfig.management_token, this.importConfig.host);
34
25
  }
35
26
  if (!this.importConfig.master_locale) {
36
27
  let masterLocalResponse = await (0, utils_1.masterLocalDetails)(this.stackAPIClient);
@@ -26,6 +26,7 @@ export default class ImportAssets extends BaseClass {
26
26
  private assetsUidMap;
27
27
  private assetsUrlMap;
28
28
  private assetsFolderMap;
29
+ private rootFolder;
29
30
  constructor({ importConfig, stackAPIClient }: ModuleClassParams);
30
31
  /**
31
32
  * @method start
@@ -10,6 +10,7 @@ const isEmpty_1 = tslib_1.__importDefault(require("lodash/isEmpty"));
10
10
  const uniq_1 = tslib_1.__importDefault(require("lodash/uniq"));
11
11
  const node_fs_1 = require("node:fs");
12
12
  const includes_1 = tslib_1.__importDefault(require("lodash/includes"));
13
+ const uuid_1 = require("uuid");
13
14
  const node_path_1 = require("node:path");
14
15
  const cli_utilities_1 = require("@contentstack/cli-utilities");
15
16
  const config_1 = tslib_1.__importDefault(require("../../config"));
@@ -184,6 +185,10 @@ class ImportAssets extends base_class_1.default {
184
185
  if (asset.parent_uid) {
185
186
  asset.parent_uid = this.assetsFolderMap[asset.parent_uid];
186
187
  }
188
+ else if (this.importConfig.replaceExisting) {
189
+ // adds the root folder as parent for all assets in the root level
190
+ asset.parent_uid = this.assetsFolderMap[this.rootFolder.uid];
191
+ }
187
192
  apiOptions.apiData = asset;
188
193
  if (this.assetsUidMap[asset.uid] && this.assetConfig.importSameStructure) {
189
194
  apiOptions.entity = 'replace-assets';
@@ -249,19 +254,43 @@ class ImportAssets extends base_class_1.default {
249
254
  * @returns {Array<Record<string, any>>} Array<Record<string, any>>
250
255
  */
251
256
  constructFolderImportOrder(folders) {
252
- let parentUid = [];
257
+ let parentUIds = [];
253
258
  // NOTE: Read root folder
254
259
  const importOrder = (0, filter_1.default)(folders, { parent_uid: null }).map(({ uid, name, parent_uid, created_at }) => {
255
- parentUid.push(uid);
260
+ parentUIds.push(uid);
256
261
  return { uid, name, parent_uid, created_at };
257
262
  });
258
- while (!(0, isEmpty_1.default)(parentUid)) {
263
+ while (!(0, isEmpty_1.default)(parentUIds)) {
259
264
  // NOTE: Read nested folders every iteration until we find empty folders
260
- parentUid = (0, filter_1.default)(folders, ({ parent_uid }) => (0, includes_1.default)(parentUid, parent_uid)).map(({ uid, name, parent_uid, created_at }) => {
265
+ parentUIds = (0, filter_1.default)(folders, ({ parent_uid }) => (0, includes_1.default)(parentUIds, parent_uid)).map(({ uid, name, parent_uid, created_at }) => {
261
266
  importOrder.push({ uid, name, parent_uid, created_at });
262
267
  return uid;
263
268
  });
264
269
  }
270
+ if (this.importConfig.replaceExisting) {
271
+ // Note: adds a root folder to distinguish latest asset uploads
272
+ // Todo: This temporary approach should be updated with asset and folder overwrite strategy, which follows
273
+ // folder overwrite
274
+ // 1. Create folder trees, 2. Export all target stack folders, 3.Match the source to target folders and create a list of existing folders
275
+ // 4. Replace existing folders
276
+ // Asset overwrite
277
+ // 1. Search asset with title + filename + type
278
+ // 2. if there are multiple assets fetched with same query, then check the parent uid against mapper created while importing folders
279
+ // 3. Replace matched assets
280
+ this.rootFolder = {
281
+ uid: (0, uuid_1.v4)(),
282
+ name: `Import-${(0, utils_1.formatDate)()}`,
283
+ parent_uid: null,
284
+ created_at: null,
285
+ };
286
+ (0, filter_1.default)(importOrder, (folder, index) => {
287
+ if (!folder.parent_uid) {
288
+ importOrder.splice(index, 1, Object.assign(Object.assign({}, folder), { parent_uid: this.rootFolder.uid }));
289
+ }
290
+ });
291
+ // NOTE: Adds root folder
292
+ importOrder.unshift(this.rootFolder);
293
+ }
265
294
  return importOrder;
266
295
  }
267
296
  }
@@ -63,7 +63,7 @@ export default class EntriesImport extends BaseClass {
63
63
  cTUid: string;
64
64
  locale: string;
65
65
  }): Promise<void>;
66
- replaceEntriesHandler({ apiParams, element: entry, isLastRequest, }: {
66
+ replaceEntriesHandler({ apiParams, element: entry }: {
67
67
  apiParams: ApiOptions;
68
68
  element: Record<string, string>;
69
69
  isLastRequest: boolean;
@@ -39,6 +39,7 @@ class EntriesImport extends base_class_1.default {
39
39
  this.failedEntries = [];
40
40
  }
41
41
  async start() {
42
+ var _a;
42
43
  try {
43
44
  this.cTs = utils_1.fsUtil.readFile(path.join(this.cTsPath, 'schema.json'));
44
45
  if (!this.cTs || (0, lodash_1.isEmpty)(this.cTs)) {
@@ -58,7 +59,7 @@ class EntriesImport extends base_class_1.default {
58
59
  for (let entryRequestOption of entryRequestOptions) {
59
60
  await this.createEntries(entryRequestOption);
60
61
  }
61
- if (this.importConfig.replaceExisting && (0, lodash_1.indexOf)(this.importConfig.overwriteSupportedModules, 'entries') !== -1) {
62
+ if (this.importConfig.replaceExisting) {
62
63
  // Note: Instead of using entryRequestOptions, we can prepare request options for replace, to avoid unnecessary operations
63
64
  for (let entryRequestOption of entryRequestOptions) {
64
65
  await this.replaceEntries(entryRequestOption).catch((error) => {
@@ -68,7 +69,7 @@ class EntriesImport extends base_class_1.default {
68
69
  }
69
70
  await utils_1.fileHelper.writeLargeFile(path.join(this.entriesMapperPath, 'uid-mapping.json'), this.entriesUidMapper); // TBD: manages mapper in one file, should find an alternative
70
71
  utils_1.fsUtil.writeFile(path.join(this.entriesMapperPath, 'failed-entries.json'), this.failedEntries);
71
- if (this.autoCreatedEntries.length > 0) {
72
+ if (((_a = this.autoCreatedEntries) === null || _a === void 0 ? void 0 : _a.length) > 0) {
72
73
  (0, utils_1.log)(this.importConfig, 'Removing entries from master language which got created by default', 'info');
73
74
  await this.removeAutoCreatedEntries().catch((error) => {
74
75
  (0, utils_1.log)(this.importConfig, `Error while removing auto created entries in master locale ${(0, utils_1.formatError)(error)}`, 'error');
@@ -253,8 +254,7 @@ class EntriesImport extends base_class_1.default {
253
254
  //Note: write existing entries into files to handler later
254
255
  if (error.errorCode === 119) {
255
256
  if (((_a = error === null || error === void 0 ? void 0 : error.errors) === null || _a === void 0 ? void 0 : _a.title) || ((_b = error === null || error === void 0 ? void 0 : error.errors) === null || _b === void 0 ? void 0 : _b.uid)) {
256
- if (this.importConfig.replaceExisting &&
257
- (0, lodash_1.indexOf)(this.importConfig.overwriteSupportedModules, 'entries') !== -1) {
257
+ if (this.importConfig.replaceExisting) {
258
258
  entry.entryOldUid = uid;
259
259
  entry.sourceEntryFilePath = path.join(basePath, additionalInfo.entryFileName); // stores source file path temporarily
260
260
  existingEntriesFileHelper.writeIntoFile({ [uid]: entry }, { mapKeyVal: true });
@@ -410,7 +410,7 @@ class EntriesImport extends base_class_1.default {
410
410
  }
411
411
  }
412
412
  }
413
- async replaceEntriesHandler({ apiParams, element: entry, isLastRequest, }) {
413
+ async replaceEntriesHandler({ apiParams, element: entry }) {
414
414
  const { additionalInfo: { cTUid, locale } = {} } = apiParams;
415
415
  return new Promise(async (resolve, reject) => {
416
416
  const { items: [entryInStack] = [] } = (await this.stack
@@ -539,6 +539,7 @@ class EntriesImport extends base_class_1.default {
539
539
  if (this.jsonRteCTs.indexOf(cTUid) > -1) {
540
540
  // the entries stored in eSuccessFilePath, have the same uids as the entries from source data
541
541
  entry = (0, utils_1.restoreJsonRteEntryRefs)(entry, sourceEntry, contentType.schema, {
542
+ uidMapper: this.entriesUidMapper,
542
543
  mappedAssetUids: this.assetUidMapper,
543
544
  mappedAssetUrls: this.assetUrlMapper,
544
545
  });
@@ -619,6 +620,7 @@ class EntriesImport extends base_class_1.default {
619
620
  });
620
621
  }
621
622
  async updateFieldRules() {
623
+ var _a, _b, _c;
622
624
  let cTsWithFieldRules = utils_1.fsUtil.readFile(path.join(this.cTsPath + '/field_rules_uid.json'));
623
625
  if (!cTsWithFieldRules || (cTsWithFieldRules === null || cTsWithFieldRules === void 0 ? void 0 : cTsWithFieldRules.length) === 0) {
624
626
  return;
@@ -628,13 +630,13 @@ class EntriesImport extends base_class_1.default {
628
630
  const contentType = (0, lodash_1.find)(cTs, { uid: cTUid });
629
631
  if (contentType.field_rules) {
630
632
  const fieldDatatypeMap = {};
631
- for (let i = 0; i < contentType.schema.length; i++) {
633
+ for (let i = 0; i < ((_a = contentType.schema) === null || _a === void 0 ? void 0 : _a.length); i++) {
632
634
  const field = contentType.schema[i].uid;
633
635
  fieldDatatypeMap[field] = contentType.schema[i].data_type;
634
636
  }
635
- let fieldRuleLength = contentType.field_rules.length;
637
+ let fieldRuleLength = (_b = contentType.field_rules) === null || _b === void 0 ? void 0 : _b.length;
636
638
  for (let k = 0; k < fieldRuleLength; k++) {
637
- let fieldRuleConditionLength = contentType.field_rules[k].conditions.length;
639
+ let fieldRuleConditionLength = (_c = contentType.field_rules[k].conditions) === null || _c === void 0 ? void 0 : _c.length;
638
640
  for (let i = 0; i < fieldRuleConditionLength; i++) {
639
641
  if (fieldDatatypeMap[contentType.field_rules[k].conditions[i].operand_field] === 'reference') {
640
642
  let fieldRulesValue = contentType.field_rules[k].conditions[i].value;
@@ -724,13 +726,14 @@ class EntriesImport extends base_class_1.default {
724
726
  * @returns {ApiOptions} ApiOptions
725
727
  */
726
728
  serializePublishEntries(apiOptions) {
729
+ var _a;
727
730
  let { apiData: entry, additionalInfo } = apiOptions;
728
731
  const requestObject = {
729
732
  environments: [],
730
733
  locales: [],
731
734
  entryUid: this.entriesUidMapper[entry.uid],
732
735
  };
733
- if (entry.publish_details && entry.publish_details.length > 0) {
736
+ if (entry.publish_details && ((_a = entry.publish_details) === null || _a === void 0 ? void 0 : _a.length) > 0) {
734
737
  (0, lodash_1.forEach)(entry.publish_details, (pubObject) => {
735
738
  if (this.envs.hasOwnProperty(pubObject.environment) &&
736
739
  (0, lodash_1.indexOf)(requestObject.environments, this.envs[pubObject.environment].name) === -1) {
@@ -0,0 +1,11 @@
1
+ type EntryJsonRTEFieldDataType = {
2
+ uid?: string;
3
+ type?: string;
4
+ text?: string;
5
+ attrs?: {
6
+ 'entry-uid'?: string;
7
+ type?: string;
8
+ } & Record<string, any>;
9
+ children?: EntryJsonRTEFieldDataType[];
10
+ };
11
+ export { EntryJsonRTEFieldDataType };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -72,3 +72,4 @@ export interface TermsConfig {
72
72
  }
73
73
  export { default as DefaultConfig } from './default-config';
74
74
  export { default as ImportConfig } from './import-config';
75
+ export * from './entries';
@@ -1,2 +1,4 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ tslib_1.__exportStar(require("./entries"), exports);
@@ -18,3 +18,4 @@ export declare const executeTask: (tasks: unknown[], handler: (task: unknown) =>
18
18
  concurrency: number;
19
19
  }) => Promise<unknown[]>;
20
20
  export declare const validateBranch: (stackAPIClient: any, config: ImportConfig, branch: any) => Promise<unknown>;
21
+ export declare const formatDate: (date?: Date) => string;
@@ -6,7 +6,7 @@
6
6
  * MIT Licensed
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.validateBranch = exports.executeTask = exports.formatError = exports.getConfig = exports.field_rules_update = exports.masterLocalDetails = exports.sanitizeStack = exports.buildAppConfig = exports.validateConfig = exports.initialization = void 0;
9
+ exports.formatDate = exports.validateBranch = exports.executeTask = exports.formatError = exports.getConfig = exports.field_rules_update = exports.masterLocalDetails = exports.sanitizeStack = exports.buildAppConfig = exports.validateConfig = exports.initialization = void 0;
10
10
  const tslib_1 = require("tslib");
11
11
  const _ = tslib_1.__importStar(require("lodash"));
12
12
  const path = tslib_1.__importStar(require("path"));
@@ -231,3 +231,18 @@ const validateBranch = async (stackAPIClient, config, branch) => {
231
231
  });
232
232
  };
233
233
  exports.validateBranch = validateBranch;
234
+ const formatDate = (date = new Date()) => {
235
+ // Format the date manually
236
+ const formattedDate = `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date
237
+ .getDate()
238
+ .toString()
239
+ .padStart(2, '0')}T${date.getHours().toString().padStart(2, '0')}-${date
240
+ .getMinutes()
241
+ .toString()
242
+ .padStart(2, '0')}-${date.getSeconds().toString().padStart(2, '0')}-${date
243
+ .getMilliseconds()
244
+ .toString()
245
+ .padStart(3, '0')}Z`;
246
+ return formattedDate;
247
+ };
248
+ exports.formatDate = formatDate;
@@ -7,4 +7,4 @@ export declare const lookupEntries: (data: {
7
7
  }, mappedUids: Record<string, any>, uidMapperPath: string) => any;
8
8
  export declare const removeUidsFromJsonRteFields: (entry: Record<string, any>, ctSchema?: Record<string, any>[]) => Record<string, any>;
9
9
  export declare const removeEntryRefsFromJSONRTE: (entry: Record<string, any>, ctSchema?: Record<string, any>[]) => Record<string, any>;
10
- export declare const restoreJsonRteEntryRefs: (entry: Record<string, any>, sourceStackEntry: any, ctSchema: any, { mappedAssetUids, mappedAssetUrls }: any) => Record<string, any>;
10
+ export declare const restoreJsonRteEntryRefs: (entry: Record<string, any>, sourceStackEntry: any, ctSchema: any, { uidMapper, mappedAssetUids, mappedAssetUrls }: any) => Record<string, any>;
@@ -2,6 +2,7 @@
2
2
  /**
3
3
  * Entries lookup
4
4
  */
5
+ // FIXME refactor the complete file/code after discussed with the team
5
6
  Object.defineProperty(exports, "__esModule", { value: true });
6
7
  exports.restoreJsonRteEntryRefs = exports.removeEntryRefsFromJSONRTE = exports.removeUidsFromJsonRteFields = exports.lookupEntries = void 0;
7
8
  const tslib_1 = require("tslib");
@@ -18,7 +19,9 @@ const lookupEntries = function (data, mappedUids, uidMapperPath) {
18
19
  let isNewRefFields = false;
19
20
  let preserveStackVersion = config_1.default.preserveStackVersion;
20
21
  function gatherJsonRteEntryIds(jsonRteData) {
21
- jsonRteData.children.forEach((element) => {
22
+ var _a;
23
+ (_a = jsonRteData.children) === null || _a === void 0 ? void 0 : _a.forEach((element) => {
24
+ var _a, _b;
22
25
  if (element.type) {
23
26
  switch (element.type) {
24
27
  default: {
@@ -28,7 +31,7 @@ const lookupEntries = function (data, mappedUids, uidMapperPath) {
28
31
  break;
29
32
  }
30
33
  case 'reference': {
31
- if (Object.keys(element.attrs).length > 0 && element.attrs.type === 'entry') {
34
+ if (((_a = Object.keys(element.attrs)) === null || _a === void 0 ? void 0 : _a.length) > 0 && ((_b = element.attrs) === null || _b === void 0 ? void 0 : _b.type) === 'entry') {
32
35
  if (uids.indexOf(element.attrs['entry-uid']) === -1) {
33
36
  uids.push(element.attrs['entry-uid']);
34
37
  }
@@ -43,13 +46,14 @@ const lookupEntries = function (data, mappedUids, uidMapperPath) {
43
46
  });
44
47
  }
45
48
  const update = function (_parent, form_id, updateEntry) {
49
+ var _a, _b, _c;
46
50
  let _entry = updateEntry;
47
- let len = _parent.length;
51
+ let len = _parent === null || _parent === void 0 ? void 0 : _parent.length;
48
52
  for (let j = 0; j < len; j++) {
49
53
  if (_entry && _parent[j]) {
50
54
  if (j === len - 1 && _entry[_parent[j]]) {
51
55
  if (form_id !== '_assets') {
52
- if (_entry[_parent[j]].length) {
56
+ if ((_a = _entry[_parent[j]]) === null || _a === void 0 ? void 0 : _a.length) {
53
57
  _entry[_parent[j]].forEach((item, idx) => {
54
58
  if (typeof item.uid === 'string' && item._content_type_uid) {
55
59
  uids.push(item.uid);
@@ -69,12 +73,12 @@ const lookupEntries = function (data, mappedUids, uidMapperPath) {
69
73
  }
70
74
  else if (Array.isArray(_entry[_parent[j]])) {
71
75
  for (const element of _entry[_parent[j]]) {
72
- if (element.uid.length) {
76
+ if ((_b = element.uid) === null || _b === void 0 ? void 0 : _b.length) {
73
77
  uids.push(element.uid);
74
78
  }
75
79
  }
76
80
  }
77
- else if (_entry[_parent[j]].uid.length) {
81
+ else if ((_c = _entry[_parent[j]].uid) === null || _c === void 0 ? void 0 : _c.length) {
78
82
  uids.push(_entry[_parent[j]].uid);
79
83
  }
80
84
  }
@@ -82,7 +86,7 @@ const lookupEntries = function (data, mappedUids, uidMapperPath) {
82
86
  _entry = _entry[_parent[j]];
83
87
  let _keys = _.clone(_parent).splice(j + 1, len);
84
88
  if (Array.isArray(_entry)) {
85
- for (let i = 0, _i = _entry.length; i < _i; i++) {
89
+ for (let i = 0, _i = _entry === null || _entry === void 0 ? void 0 : _entry.length; i < _i; i++) {
86
90
  update(_keys, form_id, _entry[i]);
87
91
  }
88
92
  }
@@ -94,6 +98,7 @@ const lookupEntries = function (data, mappedUids, uidMapperPath) {
94
98
  }
95
99
  };
96
100
  const find = function (schema = [], _entry) {
101
+ var _a;
97
102
  for (let i = 0, _i = schema === null || schema === void 0 ? void 0 : schema.length; i < _i; i++) {
98
103
  switch (schema[i].data_type) {
99
104
  case 'reference':
@@ -118,7 +123,7 @@ const lookupEntries = function (data, mappedUids, uidMapperPath) {
118
123
  parent.pop();
119
124
  break;
120
125
  case 'blocks':
121
- for (let j = 0, _j = schema[i].blocks.length; j < _j; j++) {
126
+ for (let j = 0, _j = (_a = schema[i].blocks) === null || _a === void 0 ? void 0 : _a.length; j < _j; j++) {
122
127
  parent.push(schema[i].uid);
123
128
  parent.push(schema[i].blocks[j].uid);
124
129
  find(schema[i].blocks[j].schema, _entry);
@@ -135,12 +140,13 @@ const lookupEntries = function (data, mappedUids, uidMapperPath) {
135
140
  }
136
141
  };
137
142
  function findEntryIdsFromJsonRte(entry, ctSchema = []) {
143
+ var _a, _b, _c;
138
144
  for (const element of ctSchema) {
139
145
  switch (element.data_type) {
140
146
  case 'blocks': {
141
147
  if (entry[element.uid]) {
142
148
  if (element.multiple) {
143
- entry[element.uid].forEach((e) => {
149
+ (_a = entry[element.uid]) === null || _a === void 0 ? void 0 : _a.forEach((e) => {
144
150
  let key = Object.keys(e).pop();
145
151
  let subBlock = element.blocks.filter((e) => e.uid === key).pop();
146
152
  findEntryIdsFromJsonRte(e[key], subBlock.schema);
@@ -153,7 +159,7 @@ const lookupEntries = function (data, mappedUids, uidMapperPath) {
153
159
  case 'group': {
154
160
  if (entry[element.uid]) {
155
161
  if (element.multiple) {
156
- entry[element.uid].forEach((e) => {
162
+ (_b = entry[element.uid]) === null || _b === void 0 ? void 0 : _b.forEach((e) => {
157
163
  findEntryIdsFromJsonRte(e, element.schema);
158
164
  });
159
165
  }
@@ -166,7 +172,7 @@ const lookupEntries = function (data, mappedUids, uidMapperPath) {
166
172
  case 'json': {
167
173
  if (entry[element.uid] && element.field_metadata.rich_text_type) {
168
174
  if (element.multiple) {
169
- entry[element.uid].forEach((jsonRteData) => {
175
+ (_c = entry[element.uid]) === null || _c === void 0 ? void 0 : _c.forEach((jsonRteData) => {
170
176
  gatherJsonRteEntryIds(jsonRteData);
171
177
  });
172
178
  }
@@ -192,6 +198,9 @@ const lookupEntries = function (data, mappedUids, uidMapperPath) {
192
198
  let entry = JSON.stringify(data.entry);
193
199
  uids.forEach(function (uid) {
194
200
  if (mappedUids.hasOwnProperty(uid)) {
201
+ // NOTE g: matches the pattern multiple times
202
+ // NOTE i: makes the regex case insensitive
203
+ // NOTE m: enables multi-line mode. Where ^ and $ match the start and end of the entire string. Without this, multi-line strings match the beginning and end of each line.
195
204
  entry = entry.replace(new RegExp(uid, 'img'), mappedUids[uid]);
196
205
  mapped.push(uid);
197
206
  }
@@ -256,8 +265,9 @@ const removeUidsFromJsonRteFields = (entry, ctSchema = []) => {
256
265
  if (entry[element.uid]) {
257
266
  if (element.multiple) {
258
267
  entry[element.uid] = entry[element.uid].map((e) => {
268
+ var _a;
259
269
  let key = Object.keys(e).pop();
260
- let subBlock = element.blocks.filter((block) => block.uid === key).pop();
270
+ let subBlock = (_a = element.blocks) === null || _a === void 0 ? void 0 : _a.filter((block) => block.uid === key).pop();
261
271
  e[key] = (0, exports.removeUidsFromJsonRteFields)(e[key], subBlock.schema);
262
272
  return e;
263
273
  });
@@ -312,7 +322,7 @@ const removeUidsFromJsonRteFields = (entry, ctSchema = []) => {
312
322
  };
313
323
  exports.removeUidsFromJsonRteFields = removeUidsFromJsonRteFields;
314
324
  function removeUidsFromChildren(children) {
315
- if (children.length && children.length > 0) {
325
+ if ((children === null || children === void 0 ? void 0 : children.length) && children.length > 0) {
316
326
  return children.map((child) => {
317
327
  if (child.type && child.type.length > 0) {
318
328
  delete child.uid; // remove uid
@@ -340,14 +350,16 @@ function removeUidsFromChildren(children) {
340
350
  }
341
351
  }
342
352
  const removeEntryRefsFromJSONRTE = (entry, ctSchema = []) => {
353
+ var _a, _b;
343
354
  for (const element of ctSchema) {
344
355
  switch (element.data_type) {
345
356
  case 'blocks': {
346
357
  if (entry[element.uid]) {
347
358
  if (element.multiple) {
348
359
  entry[element.uid] = entry[element.uid].map((e) => {
360
+ var _a;
349
361
  let key = Object.keys(e).pop();
350
- let subBlock = element.blocks.filter((block) => block.uid === key).pop();
362
+ let subBlock = (_a = element.blocks) === null || _a === void 0 ? void 0 : _a.filter((block) => block.uid === key).pop();
351
363
  e[key] = (0, exports.removeEntryRefsFromJSONRTE)(e[key], subBlock.schema);
352
364
  return e;
353
365
  });
@@ -374,10 +386,12 @@ const removeEntryRefsFromJSONRTE = (entry, ctSchema = []) => {
374
386
  const structuredPTag = '{"type":"p","attrs":{},"children":[{"text":""}]}';
375
387
  if (entry[element.uid] && element.field_metadata.rich_text_type) {
376
388
  if (element.multiple) {
389
+ entry[element.uid] = entry[element.uid].map(removeReferenceInJsonRTE);
377
390
  entry[element.uid] = entry[element.uid].map((jsonRteData) => {
391
+ var _a;
378
392
  // repeated code from else block, will abstract later
379
- let entryReferences = jsonRteData.children.filter((e) => doEntryReferencesExist(e));
380
- if (entryReferences.length > 0) {
393
+ let entryReferences = (_a = jsonRteData.children) === null || _a === void 0 ? void 0 : _a.filter((e) => doEntryReferencesExist(e));
394
+ if ((entryReferences === null || entryReferences === void 0 ? void 0 : entryReferences.length) > 0) {
381
395
  jsonRteData.children = jsonRteData.children.filter((e) => !doEntryReferencesExist(e));
382
396
  if (jsonRteData.children.length === 0) {
383
397
  // empty children array are no longer acceptable by the API, a default structure must be there
@@ -391,10 +405,12 @@ const removeEntryRefsFromJSONRTE = (entry, ctSchema = []) => {
391
405
  });
392
406
  }
393
407
  else {
394
- let entryReferences = entry[element.uid].children.filter((e) => doEntryReferencesExist(e));
395
- if (entryReferences.length > 0) {
408
+ // NOTE Clean up all the reference
409
+ entry[element.uid] = removeReferenceInJsonRTE(entry[element.uid]);
410
+ let entryReferences = (_a = entry[element.uid].children) === null || _a === void 0 ? void 0 : _a.filter((e) => doEntryReferencesExist(e));
411
+ if ((entryReferences === null || entryReferences === void 0 ? void 0 : entryReferences.length) > 0) {
396
412
  entry[element.uid].children = entry[element.uid].children.filter((e) => !doEntryReferencesExist(e));
397
- if (entry[element.uid].children.length === 0) {
413
+ if (((_b = entry[element.uid].children) === null || _b === void 0 ? void 0 : _b.length) === 0) {
398
414
  entry[element.uid].children.push(JSON.parse(structuredPTag));
399
415
  }
400
416
  }
@@ -410,9 +426,11 @@ exports.removeEntryRefsFromJSONRTE = removeEntryRefsFromJSONRTE;
410
426
  function doEntryReferencesExist(element) {
411
427
  // checks if the children of p element contain any references
412
428
  // only checking one level deep, not recursive
413
- if (element.length) {
429
+ if (element === null || element === void 0 ? void 0 : element.length) {
414
430
  for (const item of element) {
415
- if ((item.type === 'p' || item.type === 'a' || item.type === 'span') && item.children && item.children.length > 0) {
431
+ if ((item.type === 'p' || item.type === 'a' || item.type === 'span') &&
432
+ item.children &&
433
+ item.children.length > 0) {
416
434
  return doEntryReferencesExist(item.children);
417
435
  }
418
436
  else if (isEntryRef(item)) {
@@ -424,28 +442,31 @@ function doEntryReferencesExist(element) {
424
442
  if (isEntryRef(element)) {
425
443
  return true;
426
444
  }
427
- if ((element.type === 'p' || element.type === 'a' || element.type === 'span') && element.children && element.children.length > 0) {
445
+ if ((element.type === 'p' || element.type === 'a' || element.type === 'span') &&
446
+ element.children &&
447
+ element.children.length > 0) {
428
448
  return doEntryReferencesExist(element.children);
429
449
  }
430
450
  }
431
451
  return false;
432
452
  }
433
453
  function isEntryRef(element) {
434
- return element.type === 'reference' && element.attrs.type === 'entry';
454
+ var _a;
455
+ return element.type === 'reference' && ((_a = element.attrs) === null || _a === void 0 ? void 0 : _a.type) === 'entry';
435
456
  }
436
- const restoreJsonRteEntryRefs = (entry, sourceStackEntry, ctSchema = [], { mappedAssetUids, mappedAssetUrls }) => {
437
- // let mappedAssetUids = fileHelper.readFileSync(this.mappedAssetUidPath) || {};
438
- // let mappedAssetUrls = fileHelper.readFileSync(this.mappedAssetUrlPath) || {};
457
+ const restoreJsonRteEntryRefs = (entry, sourceStackEntry, ctSchema = [], { uidMapper, mappedAssetUids, mappedAssetUrls }) => {
439
458
  for (const element of ctSchema) {
440
459
  switch (element.data_type) {
441
460
  case 'blocks': {
442
461
  if (entry[element.uid]) {
443
462
  if (element.multiple && Array.isArray(entry[element.uid])) {
444
463
  entry[element.uid] = entry[element.uid].map((e, eIndex) => {
464
+ var _a;
445
465
  let key = Object.keys(e).pop();
446
- let subBlock = element.blocks.filter((block) => block.uid === key).pop();
466
+ let subBlock = (_a = element.blocks) === null || _a === void 0 ? void 0 : _a.filter((block) => block.uid === key).pop();
447
467
  let sourceStackElement = sourceStackEntry[element.uid][eIndex][key];
448
468
  e[key] = (0, exports.restoreJsonRteEntryRefs)(e[key], sourceStackElement, subBlock.schema, {
469
+ uidMapper,
449
470
  mappedAssetUids,
450
471
  mappedAssetUrls,
451
472
  });
@@ -461,13 +482,18 @@ const restoreJsonRteEntryRefs = (entry, sourceStackEntry, ctSchema = [], { mappe
461
482
  if (element.multiple && Array.isArray(entry[element.uid])) {
462
483
  entry[element.uid] = entry[element.uid].map((e, eIndex) => {
463
484
  let sourceStackElement = sourceStackEntry[element.uid][eIndex];
464
- e = (0, exports.restoreJsonRteEntryRefs)(e, sourceStackElement, element.schema, { mappedAssetUids, mappedAssetUrls });
485
+ e = (0, exports.restoreJsonRteEntryRefs)(e, sourceStackElement, element.schema, {
486
+ uidMapper,
487
+ mappedAssetUids,
488
+ mappedAssetUrls,
489
+ });
465
490
  return e;
466
491
  });
467
492
  }
468
493
  else {
469
494
  let sourceStackElement = sourceStackEntry[element.uid];
470
495
  entry[element.uid] = (0, exports.restoreJsonRteEntryRefs)(entry[element.uid], sourceStackElement, element.schema, {
496
+ uidMapper,
471
497
  mappedAssetUids,
472
498
  mappedAssetUrls,
473
499
  });
@@ -478,55 +504,23 @@ const restoreJsonRteEntryRefs = (entry, sourceStackEntry, ctSchema = [], { mappe
478
504
  case 'json': {
479
505
  if (entry[element.uid] && element.field_metadata.rich_text_type) {
480
506
  if (element.multiple && Array.isArray(entry[element.uid])) {
481
- entry[element.uid] = entry[element.uid].map((field, index) => {
482
- // i am facing a Maximum call stack exceeded issue,
483
- // probably because of this loop operation
484
- let entryRefs = sourceStackEntry[element.uid][index].children
485
- .map((e, i) => {
486
- return { index: i, value: e };
487
- })
488
- .filter((e) => doEntryReferencesExist(e.value))
489
- .map((e) => {
490
- // commenting the line below resolved the maximum call stack exceeded issue
491
- // e.value = this.setDirtyTrue(e.value)
492
- setDirtyTrue(e.value);
493
- return e;
494
- })
495
- .map((e) => {
496
- // commenting the line below resolved the maximum call stack exceeded issue
497
- // e.value = this.resolveAssetRefsInEntryRefsForJsonRte(e, mappedAssetUids, mappedAssetUrls)
498
- resolveAssetRefsInEntryRefsForJsonRte(e.value, mappedAssetUids, mappedAssetUrls);
499
- return e;
507
+ entry[element.uid] = sourceStackEntry[element.uid].map((jsonRTE) => {
508
+ jsonRTE = restoreReferenceInJsonRTE(jsonRTE, uidMapper);
509
+ jsonRTE.children = jsonRTE.children.map((child) => {
510
+ child = setDirtyTrue(child);
511
+ child = resolveAssetRefsInEntryRefsForJsonRte(child, mappedAssetUids, mappedAssetUrls);
512
+ return child;
500
513
  });
501
- if (entryRefs.length > 0) {
502
- entryRefs.forEach((entryRef) => {
503
- field.children.splice(entryRef.index, 0, entryRef.value);
504
- });
505
- }
506
- return field;
514
+ return jsonRTE;
507
515
  });
508
516
  }
509
517
  else {
510
- let entryRefs = sourceStackEntry[element.uid].children
511
- .map((e, index) => {
512
- return { index: index, value: e };
513
- })
514
- .filter((e) => doEntryReferencesExist(e.value))
515
- .map((e) => {
516
- setDirtyTrue(e.value);
517
- return e;
518
- })
519
- .map((e) => {
520
- resolveAssetRefsInEntryRefsForJsonRte(e.value, mappedAssetUids, mappedAssetUrls);
521
- return e;
518
+ entry[element.uid] = restoreReferenceInJsonRTE(sourceStackEntry[element.uid], uidMapper);
519
+ entry[element.uid].children = entry[element.uid].children.map((child) => {
520
+ child = setDirtyTrue(child);
521
+ child = resolveAssetRefsInEntryRefsForJsonRte(child, mappedAssetUids, mappedAssetUrls);
522
+ return child;
522
523
  });
523
- if (entryRefs.length > 0) {
524
- entryRefs.forEach((entryRef) => {
525
- if (!_.isEmpty(entry[element.uid]) && entry[element.uid].children) {
526
- entry[element.uid].children.splice(entryRef.index, 0, entryRef.value);
527
- }
528
- });
529
- }
530
524
  }
531
525
  }
532
526
  break;
@@ -550,8 +544,9 @@ function setDirtyTrue(jsonRteChild) {
550
544
  return jsonRteChild;
551
545
  }
552
546
  function resolveAssetRefsInEntryRefsForJsonRte(jsonRteChild, mappedAssetUids, mappedAssetUrls) {
547
+ var _a;
553
548
  if (jsonRteChild.type) {
554
- if (jsonRteChild.attrs.type === 'asset') {
549
+ if (((_a = jsonRteChild.attrs) === null || _a === void 0 ? void 0 : _a.type) === 'asset') {
555
550
  let assetUrl;
556
551
  if (mappedAssetUids[jsonRteChild.attrs['asset-uid']]) {
557
552
  jsonRteChild.attrs['asset-uid'] = mappedAssetUids[jsonRteChild.attrs['asset-uid']];
@@ -577,3 +572,62 @@ function resolveAssetRefsInEntryRefsForJsonRte(jsonRteChild, mappedAssetUids, ma
577
572
  }
578
573
  return jsonRteChild;
579
574
  }
575
+ /**
576
+ * The function removes references from a JSON RTE (Rich Text Editor) object.
577
+ * @param {EntryJsonRTEFieldDataType} jsonRTE - The parameter `jsonRTE` is of type
578
+ * `EntryJsonRTEFieldDataType`. It represents a JSON object that contains rich text content. The
579
+ * function `removeReferenceInJsonRTE` takes this JSON object as input and removes any references
580
+ * present in the content. It recursively traverses the JSON
581
+ * @returns the modified `jsonRTE` object after removing any references in the JSON RTE.
582
+ */
583
+ function removeReferenceInJsonRTE(jsonRTE) {
584
+ var _a;
585
+ // NOTE Other possible reference logic will be added related to JSON RTE (Ex missing assets, extensions etc.,)
586
+ if ((jsonRTE === null || jsonRTE === void 0 ? void 0 : jsonRTE.children) && Array.isArray(jsonRTE.children)) {
587
+ jsonRTE.children = (_a = jsonRTE === null || jsonRTE === void 0 ? void 0 : jsonRTE.children) === null || _a === void 0 ? void 0 : _a.map((child) => {
588
+ const { children, attrs, type } = child;
589
+ if (type === 'reference' && (attrs === null || attrs === void 0 ? void 0 : attrs['entry-uid'])) {
590
+ child = {
591
+ type: 'p',
592
+ attrs: {},
593
+ children: [{ text: '' }],
594
+ };
595
+ }
596
+ if (!_.isEmpty(children)) {
597
+ return removeReferenceInJsonRTE(child);
598
+ }
599
+ return child;
600
+ });
601
+ }
602
+ return jsonRTE;
603
+ }
604
+ /**
605
+ * The function `restoreReferenceInJsonRTE` takes a JSON object `jsonRTE` and a mapping object
606
+ * `uidMapper`, and recursively replaces the `entry-uid` attribute values in any `reference` type
607
+ * elements with their corresponding values from the `uidMapper` object.
608
+ * @param {EntryJsonRTEFieldDataType} jsonRTE - The `jsonRTE` parameter is an object that represents a
609
+ * JSON structure. It contains a `children` property which is an array of objects. Each object
610
+ * represents a child element in the JSON structure and can have properties like `children`, `attrs`,
611
+ * and `type`.
612
+ * @param uidMapper - The `uidMapper` parameter is an object that maps entry UIDs to their
613
+ * corresponding restored UIDs. It is used to replace the `entry-uid` attribute in the JSON RTE with
614
+ * the restored UID.
615
+ * @returns the updated `jsonRTE` object with the restored references.
616
+ */
617
+ function restoreReferenceInJsonRTE(jsonRTE, uidMapper) {
618
+ var _a;
619
+ if ((jsonRTE === null || jsonRTE === void 0 ? void 0 : jsonRTE.children) && Array.isArray(jsonRTE.children)) {
620
+ jsonRTE.children = (_a = jsonRTE === null || jsonRTE === void 0 ? void 0 : jsonRTE.children) === null || _a === void 0 ? void 0 : _a.map((child, index) => {
621
+ const { children, attrs, type } = child;
622
+ if (type === 'reference' && (attrs === null || attrs === void 0 ? void 0 : attrs['entry-uid'])) {
623
+ jsonRTE.children[index] = child;
624
+ jsonRTE.children[index].attrs['entry-uid'] = uidMapper[child.attrs['entry-uid']];
625
+ }
626
+ if (!_.isEmpty(children)) {
627
+ return restoreReferenceInJsonRTE(child, uidMapper);
628
+ }
629
+ return child;
630
+ });
631
+ }
632
+ return jsonRTE;
633
+ }
@@ -77,9 +77,6 @@ const setupConfig = async (importCmdFlags) => {
77
77
  config.target_stack = config.apiKey;
78
78
  config.replaceExisting = importCmdFlags['replace-existing'];
79
79
  config.skipExisting = importCmdFlags['skip-existing'];
80
- if (config.replaceExisting && !(0, lodash_1.includes)(config.overwriteSupportedModules, config.moduleName)) {
81
- throw new Error(`Failed to overwrite ${config.moduleName} module! Currently, with the import command, you can overwrite the following modules: ${config.overwriteSupportedModules.join(',')}`);
82
- }
83
80
  return config;
84
81
  };
85
82
  exports.default = setupConfig;
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.11.1",
2
+ "version": "1.12.1",
3
3
  "commands": {
4
4
  "cm:stacks:import": {
5
5
  "id": "cm:stacks:import",
@@ -128,10 +128,7 @@
128
128
  "type": "boolean",
129
129
  "description": "Replaces the existing module in the target stack.",
130
130
  "required": false,
131
- "allowNo": false,
132
- "dependsOn": [
133
- "module"
134
- ]
131
+ "allowNo": false
135
132
  },
136
133
  "skip-existing": {
137
134
  "name": "skip-existing",
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@contentstack/cli-cm-import",
3
3
  "description": "Contentstack CLI plugin to import content into stack",
4
- "version": "1.11.1",
4
+ "version": "1.12.1",
5
5
  "author": "Contentstack",
6
6
  "bugs": "https://github.com/contentstack/cli/issues",
7
7
  "dependencies": {
8
8
  "@contentstack/cli-command": "~1.2.16",
9
- "@contentstack/cli-utilities": "~1.5.7",
9
+ "@contentstack/cli-utilities": "~1.5.8",
10
10
  "@contentstack/management": "~1.12.0",
11
11
  "@oclif/core": "^2.9.3",
12
12
  "axios": "^1.6.0",
@@ -21,6 +21,7 @@
21
21
  "mkdirp": "^1.0.4",
22
22
  "promise-limit": "^2.7.0",
23
23
  "tslib": "^2.4.1",
24
+ "uuid": "^9.0.0",
24
25
  "winston": "^3.7.2"
25
26
  },
26
27
  "devDependencies": {
@@ -34,6 +35,7 @@
34
35
  "@types/node": "^14.14.32",
35
36
  "@types/sinon": "^10.0.2",
36
37
  "@types/tar": "^4.0.3",
38
+ "@types/uuid": "^9.0.7",
37
39
  "@typescript-eslint/eslint-plugin": "^5.48.2",
38
40
  "chai": "^4.2.0",
39
41
  "eslint": "^8.18.0",
@@ -97,4 +99,4 @@
97
99
  }
98
100
  },
99
101
  "repository": "https://github.com/contentstack/cli"
100
- }
102
+ }