@contentstack/cli-audit 1.5.4 → 1.6.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
@@ -19,7 +19,7 @@ $ npm install -g @contentstack/cli-audit
19
19
  $ csdx COMMAND
20
20
  running command...
21
21
  $ csdx (--version|-v)
22
- @contentstack/cli-audit/1.5.4 linux-x64 node-v18.20.2
22
+ @contentstack/cli-audit/1.6.0 linux-x64 node-v18.20.2
23
23
  $ csdx --help [COMMAND]
24
24
  USAGE
25
25
  $ csdx COMMAND
@@ -285,7 +285,7 @@ EXAMPLES
285
285
  $ csdx plugins
286
286
  ```
287
287
 
288
- _See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.0.11/src/commands/plugins/index.ts)_
288
+ _See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.0.19/src/commands/plugins/index.ts)_
289
289
 
290
290
  ## `csdx plugins:add PLUGIN`
291
291
 
@@ -359,7 +359,7 @@ EXAMPLES
359
359
  $ csdx plugins:inspect myplugin
360
360
  ```
361
361
 
362
- _See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.0.11/src/commands/plugins/inspect.ts)_
362
+ _See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.0.19/src/commands/plugins/inspect.ts)_
363
363
 
364
364
  ## `csdx plugins:install PLUGIN`
365
365
 
@@ -408,7 +408,7 @@ EXAMPLES
408
408
  $ csdx plugins:install someuser/someplugin
409
409
  ```
410
410
 
411
- _See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.0.11/src/commands/plugins/install.ts)_
411
+ _See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.0.19/src/commands/plugins/install.ts)_
412
412
 
413
413
  ## `csdx plugins:link PATH`
414
414
 
@@ -438,7 +438,7 @@ EXAMPLES
438
438
  $ csdx plugins:link myplugin
439
439
  ```
440
440
 
441
- _See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.0.11/src/commands/plugins/link.ts)_
441
+ _See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.0.19/src/commands/plugins/link.ts)_
442
442
 
443
443
  ## `csdx plugins:remove [PLUGIN]`
444
444
 
@@ -479,7 +479,7 @@ FLAGS
479
479
  --reinstall Reinstall all plugins after uninstalling.
480
480
  ```
481
481
 
482
- _See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.0.11/src/commands/plugins/reset.ts)_
482
+ _See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.0.19/src/commands/plugins/reset.ts)_
483
483
 
484
484
  ## `csdx plugins:uninstall [PLUGIN]`
485
485
 
@@ -507,7 +507,7 @@ EXAMPLES
507
507
  $ csdx plugins:uninstall myplugin
508
508
  ```
509
509
 
510
- _See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.0.11/src/commands/plugins/uninstall.ts)_
510
+ _See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.0.19/src/commands/plugins/uninstall.ts)_
511
511
 
512
512
  ## `csdx plugins:unlink [PLUGIN]`
513
513
 
@@ -551,5 +551,5 @@ DESCRIPTION
551
551
  Update installed plugins.
552
552
  ```
553
553
 
554
- _See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.0.11/src/commands/plugins/update.ts)_
554
+ _See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.0.19/src/commands/plugins/update.ts)_
555
555
  <!-- commandsstop -->
@@ -29,6 +29,8 @@ export declare abstract class AuditBaseCommand extends BaseCommand<typeof AuditB
29
29
  missingEntryRefs: Record<string, any> | undefined;
30
30
  missingCtRefsInExtensions: {} | undefined;
31
31
  missingCtRefsInWorkflow: {} | undefined;
32
+ missingSelectFeild: Record<string, any> | undefined;
33
+ missingMandatoryFields: Record<string, any> | undefined;
32
34
  }>;
33
35
  /**
34
36
  * The `promptQueue` function prompts the user to enter a data directory path if the `data-dir` flag
@@ -74,7 +76,7 @@ export declare abstract class AuditBaseCommand extends BaseCommand<typeof AuditB
74
76
  * reference name and the value represents additional information about the missing reference.
75
77
  * @returns The function `prepareReport` returns a Promise that resolves to `void`.
76
78
  */
77
- prepareReport(moduleName: keyof typeof config.moduleConfig, listOfMissingRefs: Record<string, any>): Promise<void>;
79
+ prepareReport(moduleName: keyof typeof config.moduleConfig | keyof typeof config.ReportTitleForEntries, listOfMissingRefs: Record<string, any>): Promise<void>;
78
80
  /**
79
81
  * The function `prepareCSV` takes a module name and a list of missing references, and generates a
80
82
  * CSV file with the specified columns and filtered rows.
@@ -85,5 +87,5 @@ export declare abstract class AuditBaseCommand extends BaseCommand<typeof AuditB
85
87
  * corresponding value is an array of objects that contain details about the missing reference.
86
88
  * @returns The function `prepareCSV` returns a Promise that resolves to `void`.
87
89
  */
88
- prepareCSV(moduleName: keyof typeof config.moduleConfig, listOfMissingRefs: Record<string, any>): Promise<void>;
90
+ prepareCSV(moduleName: keyof typeof config.moduleConfig | keyof typeof config.ReportTitleForEntries, listOfMissingRefs: Record<string, any>): Promise<void>;
89
91
  }
@@ -11,6 +11,7 @@ const path_1 = require("path");
11
11
  const cloneDeep_1 = tslib_1.__importDefault(require("lodash/cloneDeep"));
12
12
  const cli_utilities_1 = require("@contentstack/cli-utilities");
13
13
  const fs_1 = require("fs");
14
+ const config_1 = tslib_1.__importDefault(require("./config"));
14
15
  const log_1 = require("./util/log");
15
16
  const messages_1 = require("./messages");
16
17
  const base_command_1 = require("./base-command");
@@ -39,7 +40,7 @@ class AuditBaseCommand extends base_command_1.BaseCommand {
39
40
  await this.promptQueue();
40
41
  await this.createBackUp();
41
42
  this.sharedConfig.reportPath = (0, path_1.resolve)(this.flags['report-path'] || process.cwd(), 'audit-report');
42
- const { missingCtRefs, missingGfRefs, missingEntryRefs, missingCtRefsInExtensions, missingCtRefsInWorkflow } = await this.scanAndFix();
43
+ const { missingCtRefs, missingGfRefs, missingEntryRefs, missingCtRefsInExtensions, missingCtRefsInWorkflow, missingSelectFeild, missingMandatoryFields, } = await this.scanAndFix();
43
44
  this.showOutputOnScreen([
44
45
  { module: 'Content types', missingRefs: missingCtRefs },
45
46
  { module: 'Global Fields', missingRefs: missingGfRefs },
@@ -47,11 +48,16 @@ class AuditBaseCommand extends base_command_1.BaseCommand {
47
48
  ]);
48
49
  this.showOutputOnScreenWorkflowsAndExtension([{ module: 'Extensions', missingRefs: missingCtRefsInExtensions }]);
49
50
  this.showOutputOnScreenWorkflowsAndExtension([{ module: 'Workflows', missingRefs: missingCtRefsInWorkflow }]);
51
+ this.showOutputOnScreenWorkflowsAndExtension([{ module: 'Entries Select Field', missingRefs: missingSelectFeild }]);
52
+ this.showOutputOnScreenWorkflowsAndExtension([
53
+ { module: 'Entries Mandatory Field', missingRefs: missingMandatoryFields },
54
+ ]);
50
55
  if (!(0, isEmpty_1.default)(missingCtRefs) ||
51
56
  !(0, isEmpty_1.default)(missingGfRefs) ||
52
57
  !(0, isEmpty_1.default)(missingEntryRefs) ||
53
58
  !(0, isEmpty_1.default)(missingCtRefsInWorkflow) ||
54
- !(0, isEmpty_1.default)(missingCtRefsInExtensions)) {
59
+ !(0, isEmpty_1.default)(missingCtRefsInExtensions) ||
60
+ !(0, isEmpty_1.default)(missingSelectFeild)) {
55
61
  if (this.currentCommand === 'cm:stacks:audit') {
56
62
  this.log(this.$t(messages_1.auditMsg.FINAL_REPORT_PATH, { path: this.sharedConfig.reportPath }), 'warn');
57
63
  }
@@ -73,7 +79,8 @@ class AuditBaseCommand extends base_command_1.BaseCommand {
73
79
  !(0, isEmpty_1.default)(missingGfRefs) ||
74
80
  !(0, isEmpty_1.default)(missingEntryRefs) ||
75
81
  !(0, isEmpty_1.default)(missingCtRefsInWorkflow) ||
76
- !(0, isEmpty_1.default)(missingCtRefsInExtensions));
82
+ !(0, isEmpty_1.default)(missingCtRefsInExtensions) ||
83
+ !(0, isEmpty_1.default)(missingSelectFeild));
77
84
  }
78
85
  /**
79
86
  * The `scan` function performs an audit on different modules (content-types, global-fields, and
@@ -82,8 +89,9 @@ class AuditBaseCommand extends base_command_1.BaseCommand {
82
89
  * and `missingEntryRefs`.
83
90
  */
84
91
  async scanAndFix() {
92
+ var _a, _b, _c;
85
93
  let { ctSchema, gfSchema } = this.getCtAndGfSchema();
86
- let missingCtRefs, missingGfRefs, missingEntryRefs, missingCtRefsInExtensions, missingCtRefsInWorkflow;
94
+ let missingCtRefs, missingGfRefs, missingEntryRefs, missingCtRefsInExtensions, missingCtRefsInWorkflow, missingSelectFeild, missingEntry, missingMandatoryFields;
87
95
  for (const module of this.sharedConfig.flags.modules || this.sharedConfig.modules) {
88
96
  (0, log_1.print)([
89
97
  {
@@ -110,8 +118,13 @@ class AuditBaseCommand extends base_command_1.BaseCommand {
110
118
  await this.prepareReport(module, missingGfRefs);
111
119
  break;
112
120
  case 'entries':
113
- missingEntryRefs = await new modules_1.Entries((0, cloneDeep_1.default)(constructorParam)).run();
121
+ missingEntry = await new modules_1.Entries((0, cloneDeep_1.default)(constructorParam)).run();
122
+ missingEntryRefs = (_a = missingEntry.missingEntryRefs) !== null && _a !== void 0 ? _a : {};
123
+ missingSelectFeild = (_b = missingEntry.missingSelectFeild) !== null && _b !== void 0 ? _b : {};
124
+ missingMandatoryFields = (_c = missingEntry.missingMandatoryFields) !== null && _c !== void 0 ? _c : {};
114
125
  await this.prepareReport(module, missingEntryRefs);
126
+ await this.prepareReport(`Entries_Select_feild`, missingSelectFeild);
127
+ await this.prepareReport('Entries_Mandatory_feild', missingMandatoryFields);
115
128
  break;
116
129
  case 'workflows':
117
130
  missingCtRefsInWorkflow = await new modules_1.Workflows({
@@ -141,7 +154,15 @@ class AuditBaseCommand extends base_command_1.BaseCommand {
141
154
  },
142
155
  ]);
143
156
  }
144
- return { missingCtRefs, missingGfRefs, missingEntryRefs, missingCtRefsInExtensions, missingCtRefsInWorkflow };
157
+ return {
158
+ missingCtRefs,
159
+ missingGfRefs,
160
+ missingEntryRefs,
161
+ missingCtRefsInExtensions,
162
+ missingCtRefsInWorkflow,
163
+ missingSelectFeild,
164
+ missingMandatoryFields,
165
+ };
145
166
  }
146
167
  /**
147
168
  * The `promptQueue` function prompts the user to enter a data directory path if the `data-dir` flag
@@ -241,15 +262,16 @@ class AuditBaseCommand extends base_command_1.BaseCommand {
241
262
  return;
242
263
  }
243
264
  this.log(''); // Adding a new line
244
- for (const { module, missingRefs } of allMissingRefs) {
265
+ for (let { module, missingRefs } of allMissingRefs) {
245
266
  if ((0, isEmpty_1.default)(missingRefs)) {
246
267
  continue;
247
268
  }
248
269
  (0, log_1.print)([{ bold: true, color: 'cyan', message: ` ${module}` }]);
249
270
  const tableValues = Object.values(missingRefs).flat();
271
+ missingRefs = Object.values(missingRefs).flat();
250
272
  const tableKeys = Object.keys(missingRefs[0]);
251
273
  const arrayOfObjects = tableKeys.map((key) => {
252
- if (['title', 'name', 'uid', 'content_types', 'branches', 'fixStatus'].includes(key)) {
274
+ if (config_1.default.OutputTableKeys.includes(key)) {
253
275
  return {
254
276
  [key]: {
255
277
  minWidth: 7,
@@ -258,7 +280,10 @@ class AuditBaseCommand extends base_command_1.BaseCommand {
258
280
  if (key === 'fixStatus') {
259
281
  return chalk_1.default.green(typeof row[key] === 'object' ? JSON.stringify(row[key]) : row[key]);
260
282
  }
261
- else if (key === 'content_types' || key === 'branches') {
283
+ else if (key === 'content_types' ||
284
+ key === 'branches' ||
285
+ key === 'missingCTSelectFieldValues' ||
286
+ key === 'missingFieldUid') {
262
287
  return chalk_1.default.red(typeof row[key] === 'object' ? JSON.stringify(row[key]) : row[key]);
263
288
  }
264
289
  else {
@@ -39,5 +39,10 @@ declare const config: {
39
39
  entries: {
40
40
  systemKeys: string[];
41
41
  };
42
+ OutputTableKeys: string[];
43
+ ReportTitleForEntries: {
44
+ Entries_Select_feild: string;
45
+ Entries_Mandatory_feild: string;
46
+ };
42
47
  };
43
48
  export default config;
@@ -56,5 +56,27 @@ const config = {
56
56
  'publish_details',
57
57
  ],
58
58
  },
59
+ //These keys will be used output the modules with issues and fixes on console
60
+ OutputTableKeys: [
61
+ 'title',
62
+ 'name',
63
+ 'uid',
64
+ 'content_types',
65
+ 'branches',
66
+ 'fixStatus',
67
+ 'tree',
68
+ 'display_name',
69
+ 'display_type',
70
+ 'missingRefs',
71
+ 'treeStr',
72
+ 'missingCTSelectFieldValues',
73
+ 'min_instance',
74
+ 'missingFieldUid',
75
+ 'isPublished',
76
+ ],
77
+ ReportTitleForEntries: {
78
+ Entries_Select_feild: 'Entries_Select_feild',
79
+ Entries_Mandatory_feild: 'Entries_Mandatory_feild',
80
+ },
59
81
  };
60
82
  exports.default = config;
@@ -39,6 +39,8 @@ declare const auditFixMsg: {
39
39
  EMPTY_FIX_MSG: string;
40
40
  AUDIT_FIX_CMD_DESCRIPTION: string;
41
41
  WF_FIX_MSG: string;
42
+ ENTRY_MANDATORY_FIELD_FIX: string;
43
+ ENTRY_SELECT_FIELD_FIX: string;
42
44
  };
43
45
  declare const messages: typeof errors & typeof commonMsg & typeof auditMsg & typeof auditFixMsg & typeof tableColumnDescriptions;
44
46
  /**
@@ -49,6 +49,8 @@ const auditFixMsg = {
49
49
  EMPTY_FIX_MSG: 'Successfully removed the empty field/block found at {path} from the schema.',
50
50
  AUDIT_FIX_CMD_DESCRIPTION: 'Perform audits and fix possible errors in the exported Contentstack data.',
51
51
  WF_FIX_MSG: 'Successfully removed the workflow {uid} named {name}.',
52
+ ENTRY_MANDATORY_FIELD_FIX: `Removing the publish details from entry uid '{uid}' from locale '{locale}'`,
53
+ ENTRY_SELECT_FIELD_FIX: `Adding the value '{value}' in select field of uid '{uid}'`
52
54
  };
53
55
  exports.auditFixMsg = auditFixMsg;
54
56
  const messages = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, errors), commonMsg), auditMsg), auditFixMsg), tableColumnDescriptions);
@@ -1,5 +1,5 @@
1
1
  import auditConfig from '../config';
2
- import { LogFn, Locale, ConfigType, EntryStruct, EntryFieldType, ModularBlockType, ContentTypeStruct, CtConstructorParam, GroupFieldDataType, GlobalFieldDataType, JsonRTEFieldDataType, ContentTypeSchemaType, ModularBlocksDataType, ModuleConstructorParam, ReferenceFieldDataType, EntryRefErrorReturnType, EntryGroupFieldDataType, EntryGlobalFieldDataType, EntryJsonRTEFieldDataType, EntryModularBlocksDataType, EntryReferenceFieldDataType, ExtensionOrAppFieldDataType, EntryExtensionOrAppFieldDataType } from '../types';
2
+ import { LogFn, Locale, ConfigType, EntryStruct, EntryFieldType, ModularBlockType, ContentTypeStruct, CtConstructorParam, GroupFieldDataType, GlobalFieldDataType, JsonRTEFieldDataType, ContentTypeSchemaType, ModularBlocksDataType, ModuleConstructorParam, ReferenceFieldDataType, EntryRefErrorReturnType, EntryGroupFieldDataType, EntryGlobalFieldDataType, EntryJsonRTEFieldDataType, EntryModularBlocksDataType, EntryReferenceFieldDataType, ExtensionOrAppFieldDataType, EntryExtensionOrAppFieldDataType, SelectFeildStruct } from '../types';
3
3
  export default class Entries {
4
4
  log: LogFn;
5
5
  protected fix: boolean;
@@ -14,6 +14,8 @@ export default class Entries {
14
14
  ctSchema: ContentTypeStruct[];
15
15
  protected entries: Record<string, EntryStruct>;
16
16
  protected missingRefs: Record<string, any>;
17
+ protected missingSelectFeild: Record<string, any>;
18
+ protected missingMandatoryFields: Record<string, any>;
17
19
  entryMetaData: Record<string, any>[];
18
20
  moduleName: keyof typeof auditConfig.moduleConfig;
19
21
  isEntryWithoutTitleField: boolean;
@@ -23,7 +25,15 @@ export default class Entries {
23
25
  * iterates over the schema and looks for references, and returns a list of missing references.
24
26
  * @returns the `missingRefs` object.
25
27
  */
26
- run(): Promise<Record<string, any>>;
28
+ run(): Promise<{
29
+ missingEntryRefs?: undefined;
30
+ missingSelectFeild?: undefined;
31
+ missingMandatoryFields?: undefined;
32
+ } | {
33
+ missingEntryRefs: Record<string, any>;
34
+ missingSelectFeild: Record<string, any>;
35
+ missingMandatoryFields: Record<string, any>;
36
+ }>;
27
37
  /**
28
38
  * The function removes any properties from the `missingRefs` object that have an empty array value.
29
39
  */
@@ -169,6 +179,54 @@ export default class Entries {
169
179
  * `schema`.
170
180
  */
171
181
  runFixOnSchema(tree: Record<string, unknown>[], schema: ContentTypeSchemaType[], entry: EntryFieldType): EntryFieldType;
182
+ /**
183
+ * We check for the select field with condition in order of multiple -> Array
184
+ * We find the missing values i.e. the values present in entry but not in the options of the content-type
185
+ * @param tree : Contains all the tree where the select field is located used for getting the path to it
186
+ * @param fieldStructure it contains the Content-type structure of the field
187
+ * @param field It contains the value that is present in the entry it can be array or value of number | string
188
+ * @returns if there is missing field returns field and path
189
+ * Else empty array
190
+ */
191
+ validateSelectField(tree: Record<string, unknown>[], fieldStructure: SelectFeildStruct, field: any): {
192
+ uid: string;
193
+ name: string;
194
+ display_name: string;
195
+ display_type: string;
196
+ missingCTSelectFieldValues: any;
197
+ min_instance: string | number;
198
+ tree: Record<string, unknown>[];
199
+ treeStr: string;
200
+ }[];
201
+ /**
202
+ * This functions check which of the select values used in entry is/are not present in the Content-type
203
+ * Then removes those values from entry
204
+ * If the entry is empty then adds the first value of the options
205
+ * If the entry has multiple choices and min_instances then adds that number of instances
206
+ * @param {Record<string, unknown>}tree Contains the path where the select field can be found
207
+ * @param field : It contains the content-type structure of the select field
208
+ * @param entry : it contains the value in the entry of select field one of the options of the CT.
209
+ * @returns
210
+ */
211
+ fixSelectField(tree: Record<string, unknown>[], field: SelectFeildStruct, entry: any): any;
212
+ validateMandatoryFields(tree: Record<string, unknown>[], fieldStructure: any, entry: any): {
213
+ uid: string;
214
+ name: string;
215
+ display_name: any;
216
+ missingFieldUid: any;
217
+ tree: Record<string, unknown>[];
218
+ treeStr: string;
219
+ }[];
220
+ /**
221
+ *
222
+ * @param field It contains the value to be searched
223
+ * @param selectOptions It contains the options that were added in CT
224
+ * @returns An Array of entry containing only the values that were present in CT, An array of not present entries
225
+ */
226
+ findNotPresentSelectField(field: any, selectOptions: any): {
227
+ filteredFeild: any[];
228
+ notPresent: any[];
229
+ };
172
230
  /**
173
231
  * The function `fixGlobalFieldReferences` adds a new entry to a tree data structure and runs a fix
174
232
  * on the schema.
@@ -16,6 +16,8 @@ class Entries {
16
16
  constructor({ log, fix, config, moduleName, ctSchema, gfSchema }) {
17
17
  this.extensions = [];
18
18
  this.missingRefs = {};
19
+ this.missingSelectFeild = {};
20
+ this.missingMandatoryFields = {};
19
21
  this.entryMetaData = [];
20
22
  this.moduleName = 'entries';
21
23
  this.isEntryWithoutTitleField = false;
@@ -57,10 +59,34 @@ class Entries {
57
59
  if (!this.missingRefs[this.currentUid]) {
58
60
  this.missingRefs[this.currentUid] = [];
59
61
  }
62
+ if (!this.missingSelectFeild[this.currentUid]) {
63
+ this.missingSelectFeild[this.currentUid] = [];
64
+ }
65
+ if (!this.missingMandatoryFields[this.currentUid]) {
66
+ this.missingMandatoryFields[this.currentUid] = [];
67
+ }
60
68
  if (this.fix) {
61
69
  this.removeMissingKeysOnEntry(ctSchema.schema, this.entries[entryUid]);
62
70
  }
63
71
  this.lookForReference([{ locale: code, uid, name: title }], ctSchema, this.entries[entryUid]);
72
+ const fields = this.missingMandatoryFields[uid];
73
+ const isPublished = entry.publish_details.length > 0;
74
+ if ((this.fix && fields.length && isPublished) || (!this.fix && fields)) {
75
+ const fixStatus = this.fix ? 'Fixed' : '';
76
+ fields === null || fields === void 0 ? void 0 : fields.forEach((field) => {
77
+ field.isPublished = isPublished;
78
+ if (this.fix && isPublished) {
79
+ field.fixStatus = fixStatus;
80
+ }
81
+ });
82
+ if (this.fix && isPublished) {
83
+ this.log((0, messages_1.$t)(messages_1.auditFixMsg.ENTRY_MANDATORY_FIELD_FIX, { uid, locale: code }), 'error');
84
+ entry.publish_details = [];
85
+ }
86
+ }
87
+ else {
88
+ delete this.missingMandatoryFields[uid];
89
+ }
64
90
  const message = (0, messages_1.$t)(messages_1.auditMsg.SCAN_ENTRY_SUCCESS_MSG, {
65
91
  title,
66
92
  local: code,
@@ -77,7 +103,11 @@ class Entries {
77
103
  }
78
104
  // this.log('', 'info'); // Adding empty line
79
105
  this.removeEmptyVal();
80
- return this.missingRefs;
106
+ return {
107
+ missingEntryRefs: this.missingRefs,
108
+ missingSelectFeild: this.missingSelectFeild,
109
+ missingMandatoryFields: this.missingMandatoryFields,
110
+ };
81
111
  }
82
112
  /**
83
113
  * The function removes any properties from the `missingRefs` object that have an empty array value.
@@ -88,6 +118,16 @@ class Entries {
88
118
  delete this.missingRefs[propName];
89
119
  }
90
120
  }
121
+ for (let propName in this.missingSelectFeild) {
122
+ if (!this.missingSelectFeild[propName].length) {
123
+ delete this.missingSelectFeild[propName];
124
+ }
125
+ }
126
+ for (let propName in this.missingMandatoryFields) {
127
+ if (!this.missingMandatoryFields[propName].length) {
128
+ delete this.missingMandatoryFields[propName];
129
+ }
130
+ }
91
131
  }
92
132
  /**
93
133
  * The function `fixPrerequisiteData` fixes the prerequisite data by updating the `ctSchema` and
@@ -163,10 +203,12 @@ class Entries {
163
203
  if (this.fix) {
164
204
  entry = this.runFixOnSchema(tree, field.schema, entry);
165
205
  }
166
- for (const child of (_a = field.schema) !== null && _a !== void 0 ? _a : []) {
206
+ for (const child of (_a = field === null || field === void 0 ? void 0 : field.schema) !== null && _a !== void 0 ? _a : []) {
167
207
  const { uid } = child;
168
- if (!(entry === null || entry === void 0 ? void 0 : entry[uid]))
208
+ this.missingMandatoryFields[this.currentUid].push(...this.validateMandatoryFields([...tree, { uid: field.uid, name: child.display_name, field: uid }], child, entry));
209
+ if (!(entry === null || entry === void 0 ? void 0 : entry[uid]) && !child.hasOwnProperty('display_type')) {
169
210
  continue;
211
+ }
170
212
  switch (child.data_type) {
171
213
  case 'reference':
172
214
  this.missingRefs[this.currentUid].push(...this.validateReferenceField([...tree, { uid: child.uid, name: child.display_name, field: uid }], child, entry[uid]));
@@ -190,6 +232,12 @@ class Entries {
190
232
  case 'group':
191
233
  this.validateGroupField([...tree, { uid: field.uid, name: child.display_name, field: uid }], child, entry[uid]);
192
234
  break;
235
+ case 'text':
236
+ case 'number':
237
+ if (child.hasOwnProperty('display_type')) {
238
+ this.missingSelectFeild[this.currentUid].push(...this.validateSelectField([...tree, { uid: field.uid, name: child.display_name, field: uid }], child, entry[uid]));
239
+ }
240
+ break;
193
241
  }
194
242
  }
195
243
  }
@@ -453,10 +501,205 @@ class Entries {
453
501
  case 'group':
454
502
  entry[uid] = this.fixGroupField([...tree, { uid: field.uid, name: field.display_name, data_type: field.data_type }], field, entry[uid]);
455
503
  break;
504
+ case 'text':
505
+ case 'number':
506
+ if (field.hasOwnProperty('display_type')) {
507
+ entry[uid] = this.fixSelectField([...tree, { uid: field.uid, name: field.display_name, data_type: field.data_type }], field, entry[uid]);
508
+ }
509
+ break;
456
510
  }
457
511
  });
458
512
  return entry;
459
513
  }
514
+ /**
515
+ * We check for the select field with condition in order of multiple -> Array
516
+ * We find the missing values i.e. the values present in entry but not in the options of the content-type
517
+ * @param tree : Contains all the tree where the select field is located used for getting the path to it
518
+ * @param fieldStructure it contains the Content-type structure of the field
519
+ * @param field It contains the value that is present in the entry it can be array or value of number | string
520
+ * @returns if there is missing field returns field and path
521
+ * Else empty array
522
+ */
523
+ validateSelectField(tree, fieldStructure, field) {
524
+ const { display_name, enum: selectOptions, multiple, min_instance, display_type } = fieldStructure;
525
+ if (field === null || field === '' || (field === null || field === void 0 ? void 0 : field.length) === 0 || !field) {
526
+ let missingCTSelectFieldValues = 'Not Selected';
527
+ return [
528
+ {
529
+ uid: this.currentUid,
530
+ name: this.currentTitle,
531
+ display_name,
532
+ display_type,
533
+ missingCTSelectFieldValues,
534
+ min_instance: min_instance !== null && min_instance !== void 0 ? min_instance : 'NA',
535
+ tree,
536
+ treeStr: tree
537
+ .map(({ name }) => name)
538
+ .filter((val) => val)
539
+ .join(' ➜ '),
540
+ },
541
+ ];
542
+ }
543
+ let missingCTSelectFieldValues;
544
+ if (multiple) {
545
+ if (Array.isArray(field)) {
546
+ let obj = this.findNotPresentSelectField(field, selectOptions);
547
+ let { notPresent } = obj;
548
+ if (notPresent.length) {
549
+ missingCTSelectFieldValues = notPresent;
550
+ }
551
+ }
552
+ }
553
+ else if (!selectOptions.choices.some((choice) => choice.value === field)) {
554
+ missingCTSelectFieldValues = field;
555
+ }
556
+ if (display_type && missingCTSelectFieldValues) {
557
+ return [
558
+ {
559
+ uid: this.currentUid,
560
+ name: this.currentTitle,
561
+ display_name,
562
+ display_type,
563
+ missingCTSelectFieldValues,
564
+ min_instance: min_instance !== null && min_instance !== void 0 ? min_instance : 'NA',
565
+ tree,
566
+ treeStr: tree
567
+ .map(({ name }) => name)
568
+ .filter((val) => val)
569
+ .join(' ➜ '),
570
+ },
571
+ ];
572
+ }
573
+ else {
574
+ return [];
575
+ }
576
+ }
577
+ /**
578
+ * This functions check which of the select values used in entry is/are not present in the Content-type
579
+ * Then removes those values from entry
580
+ * If the entry is empty then adds the first value of the options
581
+ * If the entry has multiple choices and min_instances then adds that number of instances
582
+ * @param {Record<string, unknown>}tree Contains the path where the select field can be found
583
+ * @param field : It contains the content-type structure of the select field
584
+ * @param entry : it contains the value in the entry of select field one of the options of the CT.
585
+ * @returns
586
+ */
587
+ fixSelectField(tree, field, entry) {
588
+ const { enum: selectOptions, multiple, min_instance, display_type, display_name, uid } = field;
589
+ let missingCTSelectFieldValues;
590
+ let isMissingValuePresent = false;
591
+ if (multiple) {
592
+ let obj = this.findNotPresentSelectField(entry, selectOptions);
593
+ let { notPresent, filteredFeild } = obj;
594
+ entry = filteredFeild;
595
+ missingCTSelectFieldValues = notPresent;
596
+ if (missingCTSelectFieldValues.length) {
597
+ isMissingValuePresent = true;
598
+ }
599
+ if (min_instance && Array.isArray(entry)) {
600
+ const missingInstances = min_instance - entry.length;
601
+ if (missingInstances > 0) {
602
+ isMissingValuePresent = true;
603
+ const newValues = selectOptions.choices
604
+ .filter((choice) => !entry.includes(choice.value))
605
+ .slice(0, missingInstances)
606
+ .map((choice) => choice.value);
607
+ entry.push(...newValues);
608
+ this.log((0, messages_1.$t)(messages_1.auditFixMsg.ENTRY_SELECT_FIELD_FIX, { value: newValues.join(' '), uid }), 'error');
609
+ }
610
+ }
611
+ else {
612
+ if (entry.length === 0) {
613
+ isMissingValuePresent = true;
614
+ const defaultValue = selectOptions.choices.length > 0 ? selectOptions.choices[0].value : null;
615
+ entry.push(defaultValue);
616
+ this.log((0, messages_1.$t)(messages_1.auditFixMsg.ENTRY_SELECT_FIELD_FIX, { value: defaultValue, uid }), 'error');
617
+ }
618
+ }
619
+ }
620
+ else {
621
+ const isPresent = selectOptions.choices.some((choice) => choice.value === entry);
622
+ if (!isPresent) {
623
+ missingCTSelectFieldValues = entry;
624
+ isMissingValuePresent = true;
625
+ let defaultValue = selectOptions.choices.length > 0 ? selectOptions.choices[0].value : null;
626
+ entry = defaultValue;
627
+ this.log((0, messages_1.$t)(messages_1.auditFixMsg.ENTRY_SELECT_FIELD_FIX, { value: defaultValue, uid }), 'error');
628
+ }
629
+ }
630
+ if (display_type && isMissingValuePresent) {
631
+ this.missingSelectFeild[this.currentUid].push({
632
+ uid: this.currentUid,
633
+ name: this.currentTitle,
634
+ display_name,
635
+ display_type,
636
+ missingCTSelectFieldValues,
637
+ min_instance: min_instance !== null && min_instance !== void 0 ? min_instance : 'NA',
638
+ tree,
639
+ treeStr: tree
640
+ .map(({ name }) => name)
641
+ .filter((val) => val)
642
+ .join(' ➜ '),
643
+ fixStatus: 'Fixed',
644
+ });
645
+ }
646
+ return entry;
647
+ }
648
+ validateMandatoryFields(tree, fieldStructure, entry) {
649
+ const { display_name, multiple, data_type, mandatory, field_metadata, uid } = fieldStructure;
650
+ const isJsonRteEmpty = () => {
651
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
652
+ const jsonNode = multiple
653
+ ? (_f = (_e = (_d = (_c = (_b = (_a = entry[uid]) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.children) === null || _c === void 0 ? void 0 : _c[0]) === null || _d === void 0 ? void 0 : _d.children) === null || _e === void 0 ? void 0 : _e[0]) === null || _f === void 0 ? void 0 : _f.text
654
+ : (_l = (_k = (_j = (_h = (_g = entry[uid]) === null || _g === void 0 ? void 0 : _g.children) === null || _h === void 0 ? void 0 : _h[0]) === null || _j === void 0 ? void 0 : _j.children) === null || _k === void 0 ? void 0 : _k[0]) === null || _l === void 0 ? void 0 : _l.text;
655
+ return jsonNode === '';
656
+ };
657
+ const isEntryEmpty = () => {
658
+ var _a;
659
+ const fieldValue = multiple ? (_a = entry[uid]) === null || _a === void 0 ? void 0 : _a.length : entry[uid];
660
+ return fieldValue === '' || !fieldValue;
661
+ };
662
+ if (mandatory) {
663
+ if ((data_type === 'json' && field_metadata.allow_json_rte && isJsonRteEmpty()) ||
664
+ (!(data_type === 'json') && isEntryEmpty())) {
665
+ return [
666
+ {
667
+ uid: this.currentUid,
668
+ name: this.currentTitle,
669
+ display_name,
670
+ missingFieldUid: uid,
671
+ tree,
672
+ treeStr: tree
673
+ .filter(({ name }) => name)
674
+ .map(({ name }) => name)
675
+ .join(' ➜ '),
676
+ },
677
+ ];
678
+ }
679
+ }
680
+ return [];
681
+ }
682
+ /**
683
+ *
684
+ * @param field It contains the value to be searched
685
+ * @param selectOptions It contains the options that were added in CT
686
+ * @returns An Array of entry containing only the values that were present in CT, An array of not present entries
687
+ */
688
+ findNotPresentSelectField(field, selectOptions) {
689
+ let present = [];
690
+ let notPresent = [];
691
+ const choicesMap = new Map(selectOptions.choices.map((choice) => [choice.value, choice]));
692
+ for (const value of field) {
693
+ const choice = choicesMap.get(value);
694
+ if (choice) {
695
+ present.push(choice.value);
696
+ }
697
+ else {
698
+ notPresent.push(value);
699
+ }
700
+ }
701
+ return { filteredFeild: present, notPresent };
702
+ }
460
703
  /**
461
704
  * The function `fixGlobalFieldReferences` adds a new entry to a tree data structure and runs a fix
462
705
  * on the schema.
@@ -733,7 +976,11 @@ class Entries {
733
976
  const entries = (await fsUtility.readChunkFiles.next());
734
977
  for (const entryUid in entries) {
735
978
  let { title } = entries[entryUid];
736
- if (!title) {
979
+ if (entries[entryUid].hasOwnProperty('title') && !title) {
980
+ this.isEntryWithoutTitleField = true;
981
+ this.log(`The 'title' field in Entry with UID '${entryUid}' of Content Type '${uid}' in Locale '${code}' is empty.`, `error`);
982
+ }
983
+ else if (!title) {
737
984
  this.isEntryWithoutTitleField = true;
738
985
  this.log(`Entry with UID '${entryUid}' of Content Type '${uid}' in Locale '${code}' does not have a 'title' field.`, `error`);
739
986
  }
@@ -743,7 +990,7 @@ class Entries {
743
990
  }
744
991
  }
745
992
  if (this.isEntryWithoutTitleField) {
746
- throw Error(`Entries found with missing 'title' field! Please make the data corrections and re-run the audit.`);
993
+ // throw Error(`Entries found with missing 'title' field! Please make the data corrections and re-run the audit.`);
747
994
  }
748
995
  }
749
996
  }
@@ -1,12 +1,13 @@
1
1
  import config from '../config';
2
2
  import { AnyProperty } from './common';
3
3
  import { ConfigType, LogFn } from './utils';
4
- type ContentTypeSchemaType = ReferenceFieldDataType | GlobalFieldDataType | ExtensionOrAppFieldDataType | JsonRTEFieldDataType | GroupFieldDataType | ModularBlocksDataType;
4
+ type ContentTypeSchemaType = ReferenceFieldDataType | GlobalFieldDataType | ExtensionOrAppFieldDataType | JsonRTEFieldDataType | GroupFieldDataType | ModularBlocksDataType | SelectFeildStruct;
5
5
  type ContentTypeStruct = {
6
6
  uid: string;
7
7
  title: string;
8
8
  description: string;
9
9
  schema?: ContentTypeSchemaType[];
10
+ mandatory: boolean;
10
11
  };
11
12
  type ModuleConstructorParam = {
12
13
  log: LogFn;
@@ -26,6 +27,7 @@ type CommonDataTypeStruct = {
26
27
  ref_multiple: boolean;
27
28
  allow_json_rte: boolean;
28
29
  } & AnyProperty;
30
+ mandatory: boolean;
29
31
  };
30
32
  type RefErrorReturnType = {
31
33
  name: string;
@@ -66,23 +68,38 @@ type ModularBlockType = {
66
68
  uid: string;
67
69
  title: string;
68
70
  reference_to?: string;
69
- schema: (JsonRTEFieldDataType | ModularBlocksDataType | ReferenceFieldDataType | ExtensionOrAppFieldDataType | GroupFieldDataType)[];
71
+ schema: (JsonRTEFieldDataType | ModularBlocksDataType | ReferenceFieldDataType | ExtensionOrAppFieldDataType | GroupFieldDataType | SelectFeildStruct)[];
70
72
  };
71
73
  type ModularBlocksDataType = CommonDataTypeStruct & {
72
74
  blocks: ModularBlockType[];
73
75
  };
74
- type GroupFieldSchemaTypes = GroupFieldDataType | CommonDataTypeStruct | GlobalFieldDataType | ReferenceFieldDataType | ExtensionOrAppFieldDataType;
75
- type GlobalFieldSchemaTypes = ReferenceFieldDataType | GroupFieldDataType | ExtensionOrAppFieldDataType;
76
- type ModularBlocksSchemaTypes = ReferenceFieldDataType | JsonRTEFieldDataType;
76
+ type GroupFieldSchemaTypes = GroupFieldDataType | CommonDataTypeStruct | GlobalFieldDataType | ReferenceFieldDataType | ExtensionOrAppFieldDataType | SelectFeildStruct;
77
+ type GlobalFieldSchemaTypes = ReferenceFieldDataType | GroupFieldDataType | ExtensionOrAppFieldDataType | SelectFeildStruct;
78
+ type ModularBlocksSchemaTypes = ReferenceFieldDataType | JsonRTEFieldDataType | SelectFeildStruct;
79
+ type SelectFeildStruct = CommonDataTypeStruct & {
80
+ display_type: string;
81
+ enum: {
82
+ advanced: string;
83
+ choices: Record<string, unknown>[];
84
+ };
85
+ min_instance?: number;
86
+ max_instance?: number;
87
+ multiple: boolean;
88
+ };
77
89
  declare enum OutputColumn {
78
90
  Title = "name",
79
91
  'Field name' = "display_name",
80
92
  'Field type' = "data_type",
93
+ 'Display type' = "display_type",
81
94
  'Missing references' = "missingRefs",
82
95
  Path = "treeStr",
83
96
  title = "title",
84
97
  'uid' = "uid",
85
98
  'missingCts' = "content_types",
86
- 'Missing Branches' = "branches"
99
+ 'Missing Branches' = "branches",
100
+ 'MissingValues' = "missingCTSelectFieldValues",
101
+ 'Minimum Required Instaces' = "min_instance",
102
+ 'missingFieldUid' = "missingFieldUid",
103
+ 'isPublished' = "isPublished"
87
104
  }
88
- export { CtConstructorParam, ContentTypeStruct, ModuleConstructorParam, ReferenceFieldDataType, GlobalFieldDataType, ExtensionOrAppFieldDataType, JsonRTEFieldDataType, GroupFieldDataType, ModularBlocksDataType, RefErrorReturnType, ModularBlocksSchemaTypes, ModularBlockType, OutputColumn, ContentTypeSchemaType, GlobalFieldSchemaTypes, WorkflowExtensionsRefErrorReturnType, };
105
+ export { CtConstructorParam, ContentTypeStruct, ModuleConstructorParam, ReferenceFieldDataType, GlobalFieldDataType, ExtensionOrAppFieldDataType, JsonRTEFieldDataType, GroupFieldDataType, ModularBlocksDataType, RefErrorReturnType, ModularBlocksSchemaTypes, ModularBlockType, OutputColumn, ContentTypeSchemaType, GlobalFieldSchemaTypes, WorkflowExtensionsRefErrorReturnType, SelectFeildStruct, };
@@ -6,11 +6,16 @@ var OutputColumn;
6
6
  OutputColumn["Title"] = "name";
7
7
  OutputColumn["Field name"] = "display_name";
8
8
  OutputColumn["Field type"] = "data_type";
9
+ OutputColumn["Display type"] = "display_type";
9
10
  OutputColumn["Missing references"] = "missingRefs";
10
11
  OutputColumn["Path"] = "treeStr";
11
12
  OutputColumn["title"] = "title";
12
13
  OutputColumn["uid"] = "uid";
13
14
  OutputColumn["missingCts"] = "content_types";
14
15
  OutputColumn["Missing Branches"] = "branches";
16
+ OutputColumn["MissingValues"] = "missingCTSelectFieldValues";
17
+ OutputColumn["Minimum Required Instaces"] = "min_instance";
18
+ OutputColumn["missingFieldUid"] = "missingFieldUid";
19
+ OutputColumn["isPublished"] = "isPublished";
15
20
  })(OutputColumn || (OutputColumn = {}));
16
21
  exports.OutputColumn = OutputColumn;
@@ -8,6 +8,7 @@ type Locale = {
8
8
  type EntryStruct = {
9
9
  uid: string;
10
10
  title: string;
11
+ publish_details: [];
11
12
  } & {
12
13
  [key: string]: EntryReferenceFieldDataType[] | EntryGlobalFieldDataType | EntryJsonRTEFieldDataType | EntryGroupFieldDataType | EntryModularBlocksDataType[];
13
14
  };
@@ -35,6 +36,10 @@ type GroupFieldType = EntryReferenceFieldDataType[] | EntryGlobalFieldDataType |
35
36
  type EntryGroupFieldDataType = {
36
37
  [key: string]: GroupFieldType;
37
38
  };
39
+ type SelectValue = string | string[] | number | number;
40
+ type EntrySelectFeildDataType = {
41
+ [key: string]: SelectValue;
42
+ };
38
43
  type EntryModularBlockType = {
39
44
  [key: string]: EntryJsonRTEFieldDataType | EntryModularBlocksDataType | EntryReferenceFieldDataType[] | EntryGroupFieldDataType;
40
45
  };
@@ -51,5 +56,7 @@ type EntryRefErrorReturnType = {
51
56
  tree: Record<string, unknown>[];
52
57
  missingRefs: string[] | Record<string, unknown>[];
53
58
  };
54
- type EntryFieldType = EntryStruct | EntryGlobalFieldDataType | EntryModularBlocksDataType | EntryGroupFieldDataType | EntryExtensionOrAppFieldDataType;
55
- export { Locale, EntryStruct, EntryFieldType, EntryGlobalFieldDataType, EntryExtensionOrAppFieldDataType, EntryJsonRTEFieldDataType, EntryGroupFieldDataType, EntryModularBlocksDataType, EntryReferenceFieldDataType, EntryRefErrorReturnType, GroupFieldType, EntryModularBlockType, };
59
+ type EntryFieldType = EntryStruct | EntryGlobalFieldDataType | EntryModularBlocksDataType | EntryGroupFieldDataType | EntryExtensionOrAppFieldDataType | EntrySelectFeildDataType | {
60
+ [key: string]: any;
61
+ };
62
+ export { Locale, EntryStruct, EntryFieldType, EntryGlobalFieldDataType, EntryExtensionOrAppFieldDataType, EntryJsonRTEFieldDataType, EntryGroupFieldDataType, EntryModularBlocksDataType, EntryReferenceFieldDataType, EntryRefErrorReturnType, GroupFieldType, EntryModularBlockType, EntrySelectFeildDataType, SelectValue };
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.5.4",
2
+ "version": "1.6.0",
3
3
  "commands": {
4
4
  "cm:stacks:audit:fix": {
5
5
  "id": "cm:stacks:audit:fix",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentstack/cli-audit",
3
- "version": "1.5.4",
3
+ "version": "1.6.0",
4
4
  "description": "Contentstack audit plugin",
5
5
  "author": "Contentstack CLI",
6
6
  "homepage": "https://github.com/contentstack/cli",