@contentstack/cli-audit 1.0.0 → 1.2.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.
@@ -2,25 +2,27 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const tslib_1 = require("tslib");
4
4
  const find_1 = tslib_1.__importDefault(require("lodash/find"));
5
+ const core_1 = require("@oclif/core");
5
6
  const values_1 = tslib_1.__importDefault(require("lodash/values"));
6
7
  const isEmpty_1 = tslib_1.__importDefault(require("lodash/isEmpty"));
7
8
  const path_1 = require("path");
8
- const fs_1 = require("fs");
9
9
  const cli_utilities_1 = require("@contentstack/cli-utilities");
10
+ const fs_1 = require("fs");
11
+ const content_types_1 = tslib_1.__importDefault(require("./content-types"));
10
12
  const messages_1 = require("../messages");
11
13
  class Entries {
12
- constructor({ log, config, moduleName, ctSchema, gfSchema }) {
14
+ constructor({ log, fix, config, moduleName, ctSchema, gfSchema }) {
13
15
  this.missingRefs = {};
14
16
  this.entryMetaData = [];
15
- this.moduleName = 'content-types';
17
+ this.moduleName = 'entries';
16
18
  this.log = log;
17
19
  this.config = config;
20
+ this.fix = fix !== null && fix !== void 0 ? fix : false;
18
21
  this.ctSchema = ctSchema;
19
22
  this.gfSchema = gfSchema;
23
+ this.moduleName = moduleName !== null && moduleName !== void 0 ? moduleName : 'entries';
20
24
  this.fileName = config.moduleConfig[this.moduleName].fileName;
21
25
  this.folderPath = (0, path_1.resolve)(config.basePath, config.moduleConfig.entries.dirName);
22
- if (moduleName)
23
- this.moduleName = moduleName;
24
26
  }
25
27
  /**
26
28
  * The `run` function checks if a folder path exists, sets the schema based on the module name,
@@ -32,26 +34,46 @@ class Entries {
32
34
  throw new Error((0, messages_1.$t)(messages_1.auditMsg.NOT_VALID_PATH, { path: this.folderPath }));
33
35
  }
34
36
  await this.prepareEntryMetaData();
37
+ this.ctSchema = (await new content_types_1.default({
38
+ fix: true,
39
+ log: () => { },
40
+ config: this.config,
41
+ moduleName: 'content-types',
42
+ ctSchema: this.ctSchema,
43
+ gfSchema: this.gfSchema,
44
+ }).run(true));
45
+ this.gfSchema = (await new content_types_1.default({
46
+ fix: true,
47
+ log: () => { },
48
+ config: this.config,
49
+ moduleName: 'entries',
50
+ ctSchema: this.ctSchema,
51
+ gfSchema: this.gfSchema,
52
+ }).run(true));
35
53
  for (const { code } of this.locales) {
36
54
  for (const ctSchema of this.ctSchema) {
37
55
  const basePath = (0, path_1.join)(this.folderPath, ctSchema.uid, code);
38
56
  const fsUtility = new cli_utilities_1.FsUtility({ basePath, indexFileName: 'index.json' });
39
57
  const indexer = fsUtility.indexFileContent;
40
- for (const _ in indexer) {
58
+ for (const fileIndex in indexer) {
41
59
  const entries = (await fsUtility.readChunkFiles.next());
42
- for (const entryUid in entries) {
43
- let entry = entries[entryUid];
60
+ this.entries = entries;
61
+ for (const entryUid in this.entries) {
62
+ const entry = this.entries[entryUid];
44
63
  const { uid, title } = entry;
45
64
  this.currentUid = uid;
46
65
  this.currentTitle = title;
47
66
  this.missingRefs[this.currentUid] = [];
48
- await this.lookForReference([{ uid, name: title }], ctSchema, entry);
67
+ this.lookForReference([{ uid, name: title }], ctSchema, this.entries[entryUid]);
49
68
  this.log((0, messages_1.$t)(messages_1.auditMsg.SCAN_ENTRY_SUCCESS_MSG, {
50
69
  title,
51
70
  local: code,
52
71
  module: this.config.moduleConfig.entries.name,
53
72
  }), 'info');
54
73
  }
74
+ if (this.fix) {
75
+ await this.writeFixContent(`${basePath}/${indexer[fileIndex]}`, this.entries);
76
+ }
55
77
  }
56
78
  }
57
79
  }
@@ -63,6 +85,19 @@ class Entries {
63
85
  }
64
86
  return this.missingRefs;
65
87
  }
88
+ /**
89
+ * The function checks if it can write the fix content to a file and if so, it writes the content as
90
+ * JSON to the specified file path.
91
+ */
92
+ async writeFixContent(filePath, schema) {
93
+ let canWrite = true;
94
+ if (this.fix && !this.config.flags['copy-dir']) {
95
+ canWrite = this.config.flags.yes || (await core_1.ux.confirm(messages_1.commonMsg.FIX_CONFIRMATION));
96
+ }
97
+ if (canWrite) {
98
+ (0, fs_1.writeFileSync)(filePath, JSON.stringify(schema));
99
+ }
100
+ }
66
101
  /**
67
102
  * The function `lookForReference` iterates over a given schema and validates different field types
68
103
  * such as reference, global field, JSON, modular blocks, and group fields.
@@ -75,30 +110,36 @@ class Entries {
75
110
  * EntryGroupFieldDataType} entry - The `entry` parameter is an object that represents the data of an
76
111
  * entry. It can have different types depending on the `schema` parameter.
77
112
  */
78
- async lookForReference(tree, { schema }, entry) {
79
- for (const field of schema !== null && schema !== void 0 ? schema : []) {
80
- const { uid } = field;
81
- switch (field.data_type) {
113
+ lookForReference(tree, field, entry) {
114
+ var _a;
115
+ if (this.fix) {
116
+ entry = this.runFixOnSchema(tree, field.schema, entry);
117
+ }
118
+ for (const child of (_a = field.schema) !== null && _a !== void 0 ? _a : []) {
119
+ const { uid } = child;
120
+ if (!(entry === null || entry === void 0 ? void 0 : entry[uid]))
121
+ return;
122
+ switch (child.data_type) {
82
123
  case 'reference':
83
- this.missingRefs[this.currentUid].push(...this.validateReferenceField([...tree, { uid: field.uid, name: field.display_name, field: uid }], field, entry[uid]));
124
+ this.missingRefs[this.currentUid].push(...this.validateReferenceField([...tree, { uid: child.uid, name: child.display_name, field: uid }], child, entry[uid]));
84
125
  break;
85
126
  case 'global_field':
86
- await this.validateGlobalField([...tree, { uid: field.uid, name: field.display_name, field: uid }], field, entry[uid]);
127
+ this.validateGlobalField([...tree, { uid: child.uid, name: child.display_name, field: uid }], child, entry[uid]);
87
128
  break;
88
129
  case 'json':
89
- if (field.field_metadata.extension) {
130
+ if (child.field_metadata.extension) {
90
131
  // NOTE Custom field type
91
132
  }
92
- else if (field.field_metadata.allow_json_rte) {
133
+ else if (child.field_metadata.allow_json_rte) {
93
134
  // NOTE JSON RTE field type
94
- await this.validateJsonRTEFields([...tree, { uid: field.uid, name: field.display_name, field: uid }], field, entry[uid]);
135
+ this.validateJsonRTEFields([...tree, { uid: child.uid, name: child.display_name, field: uid }], child, entry[uid]);
95
136
  }
96
137
  break;
97
138
  case 'blocks':
98
- await this.validateModularBlocksField([...tree, { uid: field.uid, name: field.display_name, field: uid }], field, entry[uid]);
139
+ this.validateModularBlocksField([...tree, { uid: child.uid, name: child.display_name, field: uid }], child, entry[uid]);
99
140
  break;
100
141
  case 'group':
101
- await this.validateGroupField([...tree, { uid: field.uid, name: field.display_name, field: uid }], field, entry[uid]);
142
+ this.validateGroupField([...tree, { uid: field.uid, name: child.display_name, field: uid }], child, entry[uid]);
102
143
  break;
103
144
  }
104
145
  }
@@ -131,9 +172,9 @@ class Entries {
131
172
  * @param {EntryGlobalFieldDataType} field - The `field` parameter is of type
132
173
  * `EntryGlobalFieldDataType`. It represents a single global field entry.
133
174
  */
134
- async validateGlobalField(tree, fieldStructure, field) {
175
+ validateGlobalField(tree, fieldStructure, field) {
135
176
  // NOTE Any GlobalField related logic can be added here
136
- await this.lookForReference(tree, fieldStructure, field);
177
+ this.lookForReference(tree, fieldStructure, field);
137
178
  }
138
179
  /**
139
180
  * The function `validateJsonRTEFields` is used to validate the JSON RTE fields by checking if the
@@ -147,32 +188,18 @@ class Entries {
147
188
  * `EntryJsonRTEFieldDataType`, which represents a JSON RTE field in an entry. It contains properties
148
189
  * such as `uid`, `attrs`, and `children`.
149
190
  */
150
- async validateJsonRTEFields(tree, fieldStructure, field) {
191
+ validateJsonRTEFields(tree, fieldStructure, field) {
151
192
  var _a;
193
+ // const missingRefIndex = []
152
194
  // NOTE Other possible reference logic will be added related to JSON RTE (Ex missing assets, extensions etc.,)
153
- for (const child of (_a = field === null || field === void 0 ? void 0 : field.children) !== null && _a !== void 0 ? _a : []) {
154
- const { uid: childrenUid, attrs, children } = child;
155
- const { 'entry-uid': entryUid, 'content-type-uid': contentTypeUid } = attrs || {};
156
- if (entryUid) {
157
- const refExist = (0, find_1.default)(this.entryMetaData, { uid: entryUid });
158
- if (!refExist) {
159
- tree.push({ field: 'children' }, { field: childrenUid, uid: fieldStructure.uid });
160
- this.missingRefs[this.currentUid].push({
161
- tree,
162
- uid: this.currentUid,
163
- name: this.currentTitle,
164
- data_type: fieldStructure.data_type,
165
- display_name: fieldStructure.display_name,
166
- treeStr: tree
167
- .map(({ name }) => name)
168
- .filter((val) => val)
169
- .join(' ➜ '),
170
- missingRefs: [{ uid: entryUid, 'content-type-uid': contentTypeUid }],
171
- });
172
- }
195
+ for (const index in (_a = field === null || field === void 0 ? void 0 : field.children) !== null && _a !== void 0 ? _a : []) {
196
+ const child = field.children[index];
197
+ const { children } = child;
198
+ if (!this.fix) {
199
+ this.jsonRefCheck(tree, fieldStructure, child);
173
200
  }
174
201
  if (!(0, isEmpty_1.default)(children)) {
175
- await this.validateJsonRTEFields(tree, fieldStructure, child);
202
+ this.validateJsonRTEFields(tree, fieldStructure, field.children[index]);
176
203
  }
177
204
  }
178
205
  }
@@ -189,15 +216,18 @@ class Entries {
189
216
  * @param {EntryModularBlocksDataType[]} field - The `field` parameter is an array of objects of type
190
217
  * `EntryModularBlocksDataType`.
191
218
  */
192
- async validateModularBlocksField(tree, fieldStructure, field) {
193
- const { blocks } = fieldStructure;
194
- // NOTE Traverse each and every module and look for reference
195
- for (let index = 0; index < blocks.length; index++) {
196
- const ctBlock = blocks[index];
197
- const entryBlock = field[index];
198
- const { uid } = ctBlock;
199
- if (entryBlock === null || entryBlock === void 0 ? void 0 : entryBlock[uid]) {
200
- await this.lookForReference([...tree, { field: uid }], ctBlock, entryBlock[uid]);
219
+ validateModularBlocksField(tree, fieldStructure, field) {
220
+ if (!this.fix) {
221
+ for (const index in field) {
222
+ this.modularBlockRefCheck(tree, fieldStructure.blocks, field[index], +index);
223
+ }
224
+ }
225
+ for (const block of fieldStructure.blocks) {
226
+ const { uid, title } = block;
227
+ for (const eBlock of field) {
228
+ if (eBlock[uid]) {
229
+ this.lookForReference([...tree, { uid, name: title }], block, eBlock[uid]);
230
+ }
201
231
  }
202
232
  }
203
233
  }
@@ -210,9 +240,16 @@ class Entries {
210
240
  * @param {EntryGroupFieldDataType} field - The `field` parameter is of type
211
241
  * `EntryGroupFieldDataType` and represents a single group field entry.
212
242
  */
213
- async validateGroupField(tree, fieldStructure, field) {
243
+ validateGroupField(tree, fieldStructure, field) {
214
244
  // NOTE Any Group Field related logic can be added here (Ex data serialization or picking any metadata for report etc.,)
215
- await this.lookForReference(tree, fieldStructure, field);
245
+ if (Array.isArray(field)) {
246
+ field.forEach((eGroup) => {
247
+ this.lookForReference([...tree, { uid: fieldStructure.uid, display_name: fieldStructure.display_name }], fieldStructure, eGroup);
248
+ });
249
+ }
250
+ else {
251
+ this.lookForReference(tree, fieldStructure, field);
252
+ }
216
253
  }
217
254
  /**
218
255
  * The function `validateReferenceValues` checks if the references in a given field exist in the
@@ -230,9 +267,12 @@ class Entries {
230
267
  * objects.
231
268
  */
232
269
  validateReferenceValues(tree, fieldStructure, field) {
270
+ if (this.fix)
271
+ return [];
233
272
  const missingRefs = [];
234
- const { data_type, display_name } = fieldStructure;
235
- for (const reference of field !== null && field !== void 0 ? field : []) {
273
+ const { uid: data_type, display_name } = fieldStructure;
274
+ for (const index in field !== null && field !== void 0 ? field : []) {
275
+ const reference = field[index];
236
276
  const { uid } = reference;
237
277
  // NOTE Can skip specific references keys (Ex, system defined keys can be skipped)
238
278
  // if (this.config.skipRefs.includes(reference)) continue;
@@ -258,6 +298,268 @@ class Entries {
258
298
  ]
259
299
  : [];
260
300
  }
301
+ /**
302
+ * The function `runFixOnSchema` takes in a tree, schema, and entry, and applies fixes to the entry
303
+ * based on the schema.
304
+ * @param {Record<string, unknown>[]} tree - An array of objects representing the tree structure of
305
+ * the schema. Each object has the following properties:
306
+ * @param {ContentTypeSchemaType[]} schema - The `schema` parameter is an array of objects
307
+ * representing the content type schema. Each object in the array contains information about a
308
+ * specific field in the schema, such as its unique identifier (`uid`) and data type (`data_type`).
309
+ * @param {EntryFieldType} entry - The `entry` parameter is of type `EntryFieldType`, which
310
+ * represents the data of an entry. It is an object that contains fields as key-value pairs, where
311
+ * the key is the field UID (unique identifier) and the value is the field data.
312
+ * @returns the updated `entry` object after applying fixes to the fields based on the provided
313
+ * `schema`.
314
+ */
315
+ runFixOnSchema(tree, schema, entry) {
316
+ // NOTE Global field Fix
317
+ schema.forEach((field) => {
318
+ const { uid, data_type } = field;
319
+ switch (data_type) {
320
+ case 'global_field':
321
+ entry[uid] = this.fixGlobalFieldReferences([...tree, { uid: field.uid, name: field.display_name, data_type: field.data_type }], field, entry[uid]);
322
+ break;
323
+ case 'json':
324
+ case 'reference':
325
+ if (data_type === 'json') {
326
+ if (field.field_metadata.extension) {
327
+ // NOTE Custom field type
328
+ return field;
329
+ }
330
+ else if (field.field_metadata.allow_json_rte) {
331
+ return this.fixJsonRteMissingReferences([...tree, { uid: field.uid, name: field.display_name, data_type: field.data_type }], field, entry[uid]);
332
+ }
333
+ }
334
+ // NOTE Reference field
335
+ entry[uid] = this.fixMissingReferences([...tree, { uid: field.uid, name: field.display_name, data_type: field.data_type }], field, entry[uid]);
336
+ break;
337
+ case 'blocks':
338
+ entry[uid] = this.fixModularBlocksReferences([...tree, { uid: field.uid, name: field.display_name, data_type: field.data_type }], field.blocks, entry[uid]);
339
+ break;
340
+ case 'group':
341
+ entry[uid] = this.fixGroupField([...tree, { uid: field.uid, name: field.display_name, data_type: field.data_type }], field, entry[uid]);
342
+ break;
343
+ }
344
+ });
345
+ return entry;
346
+ }
347
+ /**
348
+ * The function `fixGlobalFieldReferences` adds a new entry to a tree data structure and runs a fix
349
+ * on the schema.
350
+ * @param {Record<string, unknown>[]} tree - An array of objects representing the tree structure.
351
+ * @param {GlobalFieldDataType} field - The `field` parameter is of type `GlobalFieldDataType` and
352
+ * represents a global field object. It contains properties such as `uid` and `display_name`.
353
+ * @param {EntryGlobalFieldDataType} entry - The `entry` parameter is of type
354
+ * `EntryGlobalFieldDataType` and represents the global field entry that needs to be fixed.
355
+ * @returns the result of calling the `runFixOnSchema` method with the updated `tree` array,
356
+ * `field.schema`, and `entry` as arguments.
357
+ */
358
+ fixGlobalFieldReferences(tree, field, entry) {
359
+ return this.runFixOnSchema([...tree, { uid: field.uid, display_name: field.display_name }], field.schema, entry);
360
+ }
361
+ /**
362
+ * The function `fixModularBlocksReferences` takes in a tree, a list of blocks, and an entry, and
363
+ * performs various operations to fix references within the entry.
364
+ * @param {Record<string, unknown>[]} tree - An array of objects representing the tree structure of
365
+ * the modular blocks.
366
+ * @param {ModularBlockType[]} blocks - An array of objects representing modular blocks. Each object
367
+ * has properties like `uid` (unique identifier) and `title` (display name).
368
+ * @param {EntryModularBlocksDataType[]} entry - An array of objects representing the modular blocks
369
+ * data in an entry. Each object in the array represents a modular block and contains its unique
370
+ * identifier (uid) and other properties.
371
+ * @returns the updated `entry` array after performing some modifications.
372
+ */
373
+ fixModularBlocksReferences(tree, blocks, entry) {
374
+ entry = entry
375
+ .map((block, index) => this.modularBlockRefCheck(tree, blocks, block, index))
376
+ .filter((val) => !(0, isEmpty_1.default)(val));
377
+ blocks.forEach((block) => {
378
+ entry = entry
379
+ .map((eBlock) => {
380
+ if (!(0, isEmpty_1.default)(block.schema)) {
381
+ if (eBlock[block.uid]) {
382
+ eBlock[block.uid] = this.runFixOnSchema([...tree, { uid: block.uid, display_name: block.title }], block.schema, eBlock[block.uid]);
383
+ }
384
+ }
385
+ return eBlock;
386
+ })
387
+ .filter((val) => !(0, isEmpty_1.default)(val));
388
+ });
389
+ return entry;
390
+ }
391
+ /**
392
+ * The function `fixGroupField` takes in a tree, a field, and an entry, and if the field has a
393
+ * schema, it runs a fix on the schema and returns the updated entry, otherwise it returns the
394
+ * original entry.
395
+ * @param {Record<string, unknown>[]} tree - An array of objects representing the tree structure.
396
+ * @param {GroupFieldDataType} field - The `field` parameter is of type `GroupFieldDataType` and
397
+ * represents a group field object. It contains properties such as `uid` (unique identifier) and
398
+ * `display_name` (name of the field).
399
+ * @param {EntryGroupFieldDataType} entry - The `entry` parameter is of type
400
+ * `EntryGroupFieldDataType`.
401
+ * @returns If the `field.schema` is not empty, the function will return the result of calling
402
+ * `this.runFixOnSchema` with the updated `tree`, `field.schema`, and `entry` as arguments.
403
+ * Otherwise, it will return the `entry` as is.
404
+ */
405
+ fixGroupField(tree, field, entry) {
406
+ if (!(0, isEmpty_1.default)(field.schema)) {
407
+ if (Array.isArray(entry)) {
408
+ entry = entry.map((eGroup) => {
409
+ return this.runFixOnSchema([...tree, { uid: field.uid, display_name: field.display_name }], field.schema, eGroup);
410
+ });
411
+ }
412
+ else {
413
+ entry = this.runFixOnSchema([...tree, { uid: field.uid, display_name: field.display_name }], field.schema, entry);
414
+ }
415
+ }
416
+ return entry;
417
+ }
418
+ /**
419
+ * The function fixes missing references in a JSON tree structure.
420
+ * @param {Record<string, unknown>[]} tree - An array of objects representing a tree structure. Each
421
+ * object in the array has a string key and an unknown value.
422
+ * @param {ReferenceFieldDataType | JsonRTEFieldDataType} field - The `field` parameter can be of
423
+ * type `ReferenceFieldDataType` or `JsonRTEFieldDataType`.
424
+ * @param {EntryJsonRTEFieldDataType} entry - The `entry` parameter is of type
425
+ * `EntryJsonRTEFieldDataType`, which represents an entry in a JSON Rich Text Editor (JsonRTE) field.
426
+ * @returns the updated `entry` object with fixed missing references in the `children` property.
427
+ */
428
+ fixJsonRteMissingReferences(tree, field, entry) {
429
+ if (Array.isArray(entry)) {
430
+ entry = entry.map((child, index) => {
431
+ return this.fixJsonRteMissingReferences([...tree, { index, type: child === null || child === void 0 ? void 0 : child.type, uid: child === null || child === void 0 ? void 0 : child.uid }], field, child);
432
+ });
433
+ }
434
+ else {
435
+ entry.children = entry.children
436
+ .map((child) => {
437
+ const refExist = this.jsonRefCheck(tree, field, child);
438
+ if (!refExist)
439
+ return null;
440
+ if ((0, isEmpty_1.default)(child.children)) {
441
+ child = this.fixJsonRteMissingReferences(tree, field, child);
442
+ }
443
+ return child;
444
+ })
445
+ .filter((val) => val);
446
+ }
447
+ return entry;
448
+ }
449
+ /**
450
+ * The `fixMissingReferences` function checks for missing references in an entry and adds them to a
451
+ * list if they are not found.
452
+ * @param {Record<string, unknown>[]} tree - An array of objects representing a tree structure. Each
453
+ * object in the array should have a "name" property and an optional "index" property.
454
+ * @param {ReferenceFieldDataType | JsonRTEFieldDataType} field - The `field` parameter is of type
455
+ * `ReferenceFieldDataType` or `JsonRTEFieldDataType`.
456
+ * @param {EntryReferenceFieldDataType[]} entry - The `entry` parameter is an array of objects that
457
+ * represent references to other entries. Each object in the array has the following properties:
458
+ * @returns the `entry` variable.
459
+ */
460
+ fixMissingReferences(tree, field, entry) {
461
+ const missingRefs = [];
462
+ entry = entry
463
+ .map((reference) => {
464
+ const { uid } = reference;
465
+ const refExist = (0, find_1.default)(this.entryMetaData, { uid });
466
+ if (!refExist) {
467
+ missingRefs.push(reference);
468
+ return null;
469
+ }
470
+ return reference;
471
+ })
472
+ .filter((val) => val);
473
+ if (!(0, isEmpty_1.default)(missingRefs)) {
474
+ this.missingRefs[this.currentUid].push({
475
+ tree,
476
+ fixStatus: 'Fixed',
477
+ uid: this.currentUid,
478
+ name: this.currentTitle,
479
+ data_type: field.data_type,
480
+ display_name: field.display_name,
481
+ treeStr: tree
482
+ .map(({ name, index }) => (index || index === 0 ? `[${index}].${name}` : name))
483
+ .filter((val) => val)
484
+ .join(' ➜ '),
485
+ missingRefs,
486
+ });
487
+ }
488
+ return entry;
489
+ }
490
+ /**
491
+ * The function `modularBlockRefCheck` checks for invalid keys in an entry block and returns the
492
+ * updated entry block.
493
+ * @param {Record<string, unknown>[]} tree - An array of objects representing the tree structure of
494
+ * the blocks.
495
+ * @param {ModularBlockType[]} blocks - The `blocks` parameter is an array of `ModularBlockType`
496
+ * objects.
497
+ * @param {EntryModularBlocksDataType} entryBlock - The `entryBlock` parameter is an object that
498
+ * represents a modular block entry. It contains key-value pairs where the keys are the UIDs of the
499
+ * modular blocks and the values are the data associated with each modular block.
500
+ * @param {Number} index - The `index` parameter is a number that represents the index of the current
501
+ * block in the `tree` array.
502
+ * @returns the `entryBlock` object.
503
+ */
504
+ modularBlockRefCheck(tree, blocks, entryBlock, index) {
505
+ const validBlockUid = blocks.map((block) => block.uid);
506
+ const invalidKeys = Object.keys(entryBlock).filter((key) => !validBlockUid.includes(key));
507
+ invalidKeys.forEach((key) => {
508
+ if (this.fix) {
509
+ delete entryBlock[key];
510
+ }
511
+ this.missingRefs[this.currentUid].push({
512
+ uid: this.currentUid,
513
+ name: this.currentTitle,
514
+ data_type: key,
515
+ display_name: key,
516
+ fixStatus: this.fix ? 'Fixed' : undefined,
517
+ tree: [...tree, { index, uid: key, name: key }],
518
+ treeStr: [...tree, { index, uid: key, name: key }]
519
+ .map(({ name, index }) => (index || index === 0 ? `[${index}].${name}` : name))
520
+ .filter((val) => val)
521
+ .join(' ➜ '),
522
+ missingRefs: [key],
523
+ });
524
+ });
525
+ return entryBlock;
526
+ }
527
+ /**
528
+ * The `jsonRefCheck` function checks if a reference exists in a JSON tree and adds missing
529
+ * references to a list if they are not found.
530
+ * @param {Record<string, unknown>[]} tree - An array of objects representing the tree structure.
531
+ * @param {JsonRTEFieldDataType} schema - The `schema` parameter is of type `JsonRTEFieldDataType`
532
+ * and represents the schema of a JSON field. It contains properties such as `uid`, `data_type`, and
533
+ * `display_name`.
534
+ * @param {EntryJsonRTEFieldDataType} child - The `child` parameter is an object that represents a
535
+ * child entry in a JSON tree. It has the following properties:
536
+ * @returns The function `jsonRefCheck` returns either `null` or `true`.
537
+ */
538
+ jsonRefCheck(tree, schema, child) {
539
+ const { uid: childrenUid } = child;
540
+ const { 'entry-uid': entryUid, 'content-type-uid': contentTypeUid } = child.attrs || {};
541
+ if (entryUid) {
542
+ const refExist = (0, find_1.default)(this.entryMetaData, { uid: entryUid });
543
+ if (!refExist) {
544
+ tree.push({ field: 'children' }, { field: childrenUid, uid: schema.uid });
545
+ this.missingRefs[this.currentUid].push({
546
+ tree,
547
+ uid: this.currentUid,
548
+ name: this.currentTitle,
549
+ data_type: schema.data_type,
550
+ display_name: schema.display_name,
551
+ fixStatus: this.fix ? 'Fixed' : undefined,
552
+ treeStr: tree
553
+ .map(({ name }) => name)
554
+ .filter((val) => val)
555
+ .join(' ➜ '),
556
+ missingRefs: [{ uid: entryUid, 'content-type-uid': contentTypeUid }],
557
+ });
558
+ return null;
559
+ }
560
+ }
561
+ return true;
562
+ }
261
563
  /**
262
564
  * The function prepares entry metadata by reading and processing files from different locales and
263
565
  * schemas.
@@ -1,13 +1,15 @@
1
1
  import config from '../config';
2
2
  import { ConfigType, LogFn } from './utils';
3
+ type ContentTypeSchemaType = ReferenceFieldDataType | GlobalFieldDataType | CustomFieldDataType | JsonRTEFieldDataType | GroupFieldDataType | ModularBlocksDataType;
3
4
  type ContentTypeStruct = {
4
5
  uid: string;
5
6
  title: string;
6
7
  description: string;
7
- schema?: (ReferenceFieldDataType | GlobalFieldDataType | CustomFieldDataType | JsonRTEFieldDataType | GroupFieldDataType | ModularBlocksDataType)[];
8
+ schema?: ContentTypeSchemaType[];
8
9
  };
9
10
  type ModuleConstructorParam = {
10
11
  log: LogFn;
12
+ fix?: boolean;
11
13
  config: ConfigType;
12
14
  moduleName?: keyof typeof config.moduleConfig;
13
15
  };
@@ -30,6 +32,7 @@ type RefErrorReturnType = {
30
32
  ct_uid: string;
31
33
  treeStr: string;
32
34
  data_type: string;
35
+ fixStatus?: string;
33
36
  missingRefs: string[];
34
37
  display_name: string;
35
38
  tree: Record<string, unknown>[];
@@ -38,10 +41,13 @@ type ReferenceFieldDataType = CommonDataTypeStruct & {
38
41
  reference_to: string[];
39
42
  };
40
43
  type GlobalFieldDataType = CommonDataTypeStruct & {
41
- reference_to: string;
44
+ reference_to?: string;
42
45
  schema: GlobalFieldSchemaTypes[];
43
46
  };
44
- type CustomFieldDataType = CommonDataTypeStruct & {};
47
+ type CustomFieldDataType = CommonDataTypeStruct & {
48
+ reference_to: string[];
49
+ extension_uid: string;
50
+ };
45
51
  type JsonRTEFieldDataType = CommonDataTypeStruct & {
46
52
  reference_to: string[];
47
53
  };
@@ -51,6 +57,7 @@ type GroupFieldDataType = CommonDataTypeStruct & {
51
57
  type ModularBlockType = {
52
58
  uid: string;
53
59
  title: string;
60
+ reference_to?: string;
54
61
  schema: (JsonRTEFieldDataType | ModularBlocksDataType | ReferenceFieldDataType | CustomFieldDataType | GroupFieldDataType)[];
55
62
  };
56
63
  type ModularBlocksDataType = CommonDataTypeStruct & {
@@ -66,4 +73,4 @@ declare enum OutputColumn {
66
73
  'Missing references' = "missingRefs",
67
74
  Path = "treeStr"
68
75
  }
69
- export { CtConstructorParam, ContentTypeStruct, ModuleConstructorParam, ReferenceFieldDataType, GlobalFieldDataType, CustomFieldDataType, JsonRTEFieldDataType, GroupFieldDataType, ModularBlocksDataType, RefErrorReturnType, ModularBlocksSchemaTypes, ModularBlockType, OutputColumn, };
76
+ export { CtConstructorParam, ContentTypeStruct, ModuleConstructorParam, ReferenceFieldDataType, GlobalFieldDataType, CustomFieldDataType, JsonRTEFieldDataType, GroupFieldDataType, ModularBlocksDataType, RefErrorReturnType, ModularBlocksSchemaTypes, ModularBlockType, OutputColumn, ContentTypeSchemaType, };
@@ -25,8 +25,9 @@ type EntryJsonRTEFieldDataType = {
25
25
  attrs: Record<string, any>;
26
26
  children: EntryJsonRTEFieldDataType[];
27
27
  };
28
+ type GroupFieldType = EntryReferenceFieldDataType[] | EntryGlobalFieldDataType | EntryJsonRTEFieldDataType;
28
29
  type EntryGroupFieldDataType = {
29
- [key: string]: EntryReferenceFieldDataType[] | EntryGlobalFieldDataType | EntryJsonRTEFieldDataType;
30
+ [key: string]: GroupFieldType;
30
31
  };
31
32
  type EntryModularBlockType = {
32
33
  [key: string]: EntryJsonRTEFieldDataType | EntryModularBlocksDataType | EntryReferenceFieldDataType[] | EntryGroupFieldDataType;
@@ -39,8 +40,10 @@ type EntryRefErrorReturnType = {
39
40
  uid: string;
40
41
  treeStr: string;
41
42
  data_type: string;
42
- missingRefs: string[] | Record<string, unknown>[];
43
+ fixStatus?: string;
43
44
  display_name: string;
44
45
  tree: Record<string, unknown>[];
46
+ missingRefs: string[] | Record<string, unknown>[];
45
47
  };
46
- export { Locale, EntryStruct, EntryGlobalFieldDataType, EntryCustomFieldDataType, EntryJsonRTEFieldDataType, EntryGroupFieldDataType, EntryModularBlocksDataType, EntryReferenceFieldDataType, EntryRefErrorReturnType, };
48
+ type EntryFieldType = EntryStruct | EntryGlobalFieldDataType | EntryModularBlocksDataType | EntryGroupFieldDataType;
49
+ export { Locale, EntryStruct, EntryFieldType, EntryGlobalFieldDataType, EntryCustomFieldDataType, EntryJsonRTEFieldDataType, EntryGroupFieldDataType, EntryModularBlocksDataType, EntryReferenceFieldDataType, EntryRefErrorReturnType, GroupFieldType, EntryModularBlockType, };