@contentstack/cli-audit 1.0.0 → 1.2.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.
@@ -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,36 +34,82 @@ 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
+ await this.fixPrerequisiteData();
35
38
  for (const { code } of this.locales) {
36
39
  for (const ctSchema of this.ctSchema) {
37
40
  const basePath = (0, path_1.join)(this.folderPath, ctSchema.uid, code);
38
41
  const fsUtility = new cli_utilities_1.FsUtility({ basePath, indexFileName: 'index.json' });
39
42
  const indexer = fsUtility.indexFileContent;
40
- for (const _ in indexer) {
43
+ for (const fileIndex in indexer) {
41
44
  const entries = (await fsUtility.readChunkFiles.next());
42
- for (const entryUid in entries) {
43
- let entry = entries[entryUid];
45
+ this.entries = entries;
46
+ for (const entryUid in this.entries) {
47
+ const entry = this.entries[entryUid];
44
48
  const { uid, title } = entry;
45
49
  this.currentUid = uid;
46
50
  this.currentTitle = title;
47
51
  this.missingRefs[this.currentUid] = [];
48
- await this.lookForReference([{ uid, name: title }], ctSchema, entry);
52
+ this.lookForReference([{ uid, name: title }], ctSchema, this.entries[entryUid]);
49
53
  this.log((0, messages_1.$t)(messages_1.auditMsg.SCAN_ENTRY_SUCCESS_MSG, {
50
54
  title,
51
55
  local: code,
52
56
  module: this.config.moduleConfig.entries.name,
53
57
  }), 'info');
54
58
  }
59
+ if (this.fix) {
60
+ await this.writeFixContent(`${basePath}/${indexer[fileIndex]}`, this.entries);
61
+ }
55
62
  }
56
63
  }
57
64
  }
58
65
  this.log('', 'info'); // Adding empty line
66
+ this.removeEmptyVal();
67
+ return this.missingRefs;
68
+ }
69
+ /**
70
+ * The function removes any properties from the `missingRefs` object that have an empty array value.
71
+ */
72
+ removeEmptyVal() {
59
73
  for (let propName in this.missingRefs) {
60
74
  if (!this.missingRefs[propName].length) {
61
75
  delete this.missingRefs[propName];
62
76
  }
63
77
  }
64
- return this.missingRefs;
78
+ }
79
+ /**
80
+ * The function `fixPrerequisiteData` fixes the prerequisite data by updating the `ctSchema` and
81
+ * `gfSchema` properties using the `ContentType` class.
82
+ */
83
+ async fixPrerequisiteData() {
84
+ this.ctSchema = (await new content_types_1.default({
85
+ fix: true,
86
+ log: () => { },
87
+ config: this.config,
88
+ moduleName: 'content-types',
89
+ ctSchema: this.ctSchema,
90
+ gfSchema: this.gfSchema,
91
+ }).run(true));
92
+ this.gfSchema = (await new content_types_1.default({
93
+ fix: true,
94
+ log: () => { },
95
+ config: this.config,
96
+ moduleName: 'entries',
97
+ ctSchema: this.ctSchema,
98
+ gfSchema: this.gfSchema,
99
+ }).run(true));
100
+ }
101
+ /**
102
+ * The function checks if it can write the fix content to a file and if so, it writes the content as
103
+ * JSON to the specified file path.
104
+ */
105
+ async writeFixContent(filePath, schema) {
106
+ let canWrite = true;
107
+ if (this.fix && !this.config.flags['copy-dir']) {
108
+ canWrite = this.config.flags.yes || (await core_1.ux.confirm(messages_1.commonMsg.FIX_CONFIRMATION));
109
+ }
110
+ if (canWrite) {
111
+ (0, fs_1.writeFileSync)(filePath, JSON.stringify(schema));
112
+ }
65
113
  }
66
114
  /**
67
115
  * The function `lookForReference` iterates over a given schema and validates different field types
@@ -75,30 +123,36 @@ class Entries {
75
123
  * EntryGroupFieldDataType} entry - The `entry` parameter is an object that represents the data of an
76
124
  * entry. It can have different types depending on the `schema` parameter.
77
125
  */
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) {
126
+ lookForReference(tree, field, entry) {
127
+ var _a;
128
+ if (this.fix) {
129
+ entry = this.runFixOnSchema(tree, field.schema, entry);
130
+ }
131
+ for (const child of (_a = field.schema) !== null && _a !== void 0 ? _a : []) {
132
+ const { uid } = child;
133
+ if (!(entry === null || entry === void 0 ? void 0 : entry[uid]))
134
+ return;
135
+ switch (child.data_type) {
82
136
  case 'reference':
83
- this.missingRefs[this.currentUid].push(...this.validateReferenceField([...tree, { uid: field.uid, name: field.display_name, field: uid }], field, entry[uid]));
137
+ this.missingRefs[this.currentUid].push(...this.validateReferenceField([...tree, { uid: child.uid, name: child.display_name, field: uid }], child, entry[uid]));
84
138
  break;
85
139
  case 'global_field':
86
- await this.validateGlobalField([...tree, { uid: field.uid, name: field.display_name, field: uid }], field, entry[uid]);
140
+ this.validateGlobalField([...tree, { uid: child.uid, name: child.display_name, field: uid }], child, entry[uid]);
87
141
  break;
88
142
  case 'json':
89
- if (field.field_metadata.extension) {
143
+ if (child.field_metadata.extension) {
90
144
  // NOTE Custom field type
91
145
  }
92
- else if (field.field_metadata.allow_json_rte) {
146
+ else if (child.field_metadata.allow_json_rte) {
93
147
  // NOTE JSON RTE field type
94
- await this.validateJsonRTEFields([...tree, { uid: field.uid, name: field.display_name, field: uid }], field, entry[uid]);
148
+ this.validateJsonRTEFields([...tree, { uid: child.uid, name: child.display_name, field: uid }], child, entry[uid]);
95
149
  }
96
150
  break;
97
151
  case 'blocks':
98
- await this.validateModularBlocksField([...tree, { uid: field.uid, name: field.display_name, field: uid }], field, entry[uid]);
152
+ this.validateModularBlocksField([...tree, { uid: child.uid, name: child.display_name, field: uid }], child, entry[uid]);
99
153
  break;
100
154
  case 'group':
101
- await this.validateGroupField([...tree, { uid: field.uid, name: field.display_name, field: uid }], field, entry[uid]);
155
+ this.validateGroupField([...tree, { uid: field.uid, name: child.display_name, field: uid }], child, entry[uid]);
102
156
  break;
103
157
  }
104
158
  }
@@ -131,9 +185,9 @@ class Entries {
131
185
  * @param {EntryGlobalFieldDataType} field - The `field` parameter is of type
132
186
  * `EntryGlobalFieldDataType`. It represents a single global field entry.
133
187
  */
134
- async validateGlobalField(tree, fieldStructure, field) {
188
+ validateGlobalField(tree, fieldStructure, field) {
135
189
  // NOTE Any GlobalField related logic can be added here
136
- await this.lookForReference(tree, fieldStructure, field);
190
+ this.lookForReference(tree, fieldStructure, field);
137
191
  }
138
192
  /**
139
193
  * The function `validateJsonRTEFields` is used to validate the JSON RTE fields by checking if the
@@ -147,32 +201,18 @@ class Entries {
147
201
  * `EntryJsonRTEFieldDataType`, which represents a JSON RTE field in an entry. It contains properties
148
202
  * such as `uid`, `attrs`, and `children`.
149
203
  */
150
- async validateJsonRTEFields(tree, fieldStructure, field) {
204
+ validateJsonRTEFields(tree, fieldStructure, field) {
151
205
  var _a;
206
+ // const missingRefIndex = []
152
207
  // 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
- }
208
+ for (const index in (_a = field === null || field === void 0 ? void 0 : field.children) !== null && _a !== void 0 ? _a : []) {
209
+ const child = field.children[index];
210
+ const { children } = child;
211
+ if (!this.fix) {
212
+ this.jsonRefCheck(tree, fieldStructure, child);
173
213
  }
174
214
  if (!(0, isEmpty_1.default)(children)) {
175
- await this.validateJsonRTEFields(tree, fieldStructure, child);
215
+ this.validateJsonRTEFields(tree, fieldStructure, field.children[index]);
176
216
  }
177
217
  }
178
218
  }
@@ -189,15 +229,18 @@ class Entries {
189
229
  * @param {EntryModularBlocksDataType[]} field - The `field` parameter is an array of objects of type
190
230
  * `EntryModularBlocksDataType`.
191
231
  */
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]);
232
+ validateModularBlocksField(tree, fieldStructure, field) {
233
+ if (!this.fix) {
234
+ for (const index in field) {
235
+ this.modularBlockRefCheck(tree, fieldStructure.blocks, field[index], +index);
236
+ }
237
+ }
238
+ for (const block of fieldStructure.blocks) {
239
+ const { uid, title } = block;
240
+ for (const eBlock of field) {
241
+ if (eBlock[uid]) {
242
+ this.lookForReference([...tree, { uid, name: title }], block, eBlock[uid]);
243
+ }
201
244
  }
202
245
  }
203
246
  }
@@ -210,9 +253,16 @@ class Entries {
210
253
  * @param {EntryGroupFieldDataType} field - The `field` parameter is of type
211
254
  * `EntryGroupFieldDataType` and represents a single group field entry.
212
255
  */
213
- async validateGroupField(tree, fieldStructure, field) {
256
+ validateGroupField(tree, fieldStructure, field) {
214
257
  // 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);
258
+ if (Array.isArray(field)) {
259
+ field.forEach((eGroup) => {
260
+ this.lookForReference([...tree, { uid: fieldStructure.uid, display_name: fieldStructure.display_name }], fieldStructure, eGroup);
261
+ });
262
+ }
263
+ else {
264
+ this.lookForReference(tree, fieldStructure, field);
265
+ }
216
266
  }
217
267
  /**
218
268
  * The function `validateReferenceValues` checks if the references in a given field exist in the
@@ -230,9 +280,12 @@ class Entries {
230
280
  * objects.
231
281
  */
232
282
  validateReferenceValues(tree, fieldStructure, field) {
283
+ if (this.fix)
284
+ return [];
233
285
  const missingRefs = [];
234
- const { data_type, display_name } = fieldStructure;
235
- for (const reference of field !== null && field !== void 0 ? field : []) {
286
+ const { uid: data_type, display_name } = fieldStructure;
287
+ for (const index in field !== null && field !== void 0 ? field : []) {
288
+ const reference = field[index];
236
289
  const { uid } = reference;
237
290
  // NOTE Can skip specific references keys (Ex, system defined keys can be skipped)
238
291
  // if (this.config.skipRefs.includes(reference)) continue;
@@ -258,6 +311,269 @@ class Entries {
258
311
  ]
259
312
  : [];
260
313
  }
314
+ /**
315
+ * The function `runFixOnSchema` takes in a tree, schema, and entry, and applies fixes to the entry
316
+ * based on the schema.
317
+ * @param {Record<string, unknown>[]} tree - An array of objects representing the tree structure of
318
+ * the schema. Each object has the following properties:
319
+ * @param {ContentTypeSchemaType[]} schema - The `schema` parameter is an array of objects
320
+ * representing the content type schema. Each object in the array contains information about a
321
+ * specific field in the schema, such as its unique identifier (`uid`) and data type (`data_type`).
322
+ * @param {EntryFieldType} entry - The `entry` parameter is of type `EntryFieldType`, which
323
+ * represents the data of an entry. It is an object that contains fields as key-value pairs, where
324
+ * the key is the field UID (unique identifier) and the value is the field data.
325
+ * @returns the updated `entry` object after applying fixes to the fields based on the provided
326
+ * `schema`.
327
+ */
328
+ runFixOnSchema(tree, schema, entry) {
329
+ // NOTE Global field Fix
330
+ schema.forEach((field) => {
331
+ const { uid, data_type } = field;
332
+ switch (data_type) {
333
+ case 'global_field':
334
+ entry[uid] = this.fixGlobalFieldReferences([...tree, { uid: field.uid, name: field.display_name, data_type: field.data_type }], field, entry[uid]);
335
+ break;
336
+ case 'json':
337
+ case 'reference':
338
+ if (data_type === 'json') {
339
+ if (field.field_metadata.extension) {
340
+ // NOTE Custom field type
341
+ break;
342
+ }
343
+ else if (field.field_metadata.allow_json_rte) {
344
+ this.fixJsonRteMissingReferences([...tree, { uid: field.uid, name: field.display_name, data_type: field.data_type }], field, entry[uid]);
345
+ break;
346
+ }
347
+ }
348
+ // NOTE Reference field
349
+ entry[uid] = this.fixMissingReferences([...tree, { uid: field.uid, name: field.display_name, data_type: field.data_type }], field, entry[uid]);
350
+ break;
351
+ case 'blocks':
352
+ entry[uid] = this.fixModularBlocksReferences([...tree, { uid: field.uid, name: field.display_name, data_type: field.data_type }], field.blocks, entry[uid]);
353
+ break;
354
+ case 'group':
355
+ entry[uid] = this.fixGroupField([...tree, { uid: field.uid, name: field.display_name, data_type: field.data_type }], field, entry[uid]);
356
+ break;
357
+ }
358
+ });
359
+ return entry;
360
+ }
361
+ /**
362
+ * The function `fixGlobalFieldReferences` adds a new entry to a tree data structure and runs a fix
363
+ * on the schema.
364
+ * @param {Record<string, unknown>[]} tree - An array of objects representing the tree structure.
365
+ * @param {GlobalFieldDataType} field - The `field` parameter is of type `GlobalFieldDataType` and
366
+ * represents a global field object. It contains properties such as `uid` and `display_name`.
367
+ * @param {EntryGlobalFieldDataType} entry - The `entry` parameter is of type
368
+ * `EntryGlobalFieldDataType` and represents the global field entry that needs to be fixed.
369
+ * @returns the result of calling the `runFixOnSchema` method with the updated `tree` array,
370
+ * `field.schema`, and `entry` as arguments.
371
+ */
372
+ fixGlobalFieldReferences(tree, field, entry) {
373
+ return this.runFixOnSchema([...tree, { uid: field.uid, display_name: field.display_name }], field.schema, entry);
374
+ }
375
+ /**
376
+ * The function `fixModularBlocksReferences` takes in a tree, a list of blocks, and an entry, and
377
+ * performs various operations to fix references within the entry.
378
+ * @param {Record<string, unknown>[]} tree - An array of objects representing the tree structure of
379
+ * the modular blocks.
380
+ * @param {ModularBlockType[]} blocks - An array of objects representing modular blocks. Each object
381
+ * has properties like `uid` (unique identifier) and `title` (display name).
382
+ * @param {EntryModularBlocksDataType[]} entry - An array of objects representing the modular blocks
383
+ * data in an entry. Each object in the array represents a modular block and contains its unique
384
+ * identifier (uid) and other properties.
385
+ * @returns the updated `entry` array after performing some modifications.
386
+ */
387
+ fixModularBlocksReferences(tree, blocks, entry) {
388
+ entry = entry
389
+ .map((block, index) => this.modularBlockRefCheck(tree, blocks, block, index))
390
+ .filter((val) => !(0, isEmpty_1.default)(val));
391
+ blocks.forEach((block) => {
392
+ entry = entry
393
+ .map((eBlock) => {
394
+ if (!(0, isEmpty_1.default)(block.schema)) {
395
+ if (eBlock[block.uid]) {
396
+ eBlock[block.uid] = this.runFixOnSchema([...tree, { uid: block.uid, display_name: block.title }], block.schema, eBlock[block.uid]);
397
+ }
398
+ }
399
+ return eBlock;
400
+ })
401
+ .filter((val) => !(0, isEmpty_1.default)(val));
402
+ });
403
+ return entry;
404
+ }
405
+ /**
406
+ * The function `fixGroupField` takes in a tree, a field, and an entry, and if the field has a
407
+ * schema, it runs a fix on the schema and returns the updated entry, otherwise it returns the
408
+ * original entry.
409
+ * @param {Record<string, unknown>[]} tree - An array of objects representing the tree structure.
410
+ * @param {GroupFieldDataType} field - The `field` parameter is of type `GroupFieldDataType` and
411
+ * represents a group field object. It contains properties such as `uid` (unique identifier) and
412
+ * `display_name` (name of the field).
413
+ * @param {EntryGroupFieldDataType} entry - The `entry` parameter is of type
414
+ * `EntryGroupFieldDataType`.
415
+ * @returns If the `field.schema` is not empty, the function will return the result of calling
416
+ * `this.runFixOnSchema` with the updated `tree`, `field.schema`, and `entry` as arguments.
417
+ * Otherwise, it will return the `entry` as is.
418
+ */
419
+ fixGroupField(tree, field, entry) {
420
+ if (!(0, isEmpty_1.default)(field.schema)) {
421
+ if (Array.isArray(entry)) {
422
+ entry = entry.map((eGroup) => {
423
+ return this.runFixOnSchema([...tree, { uid: field.uid, display_name: field.display_name }], field.schema, eGroup);
424
+ });
425
+ }
426
+ else {
427
+ entry = this.runFixOnSchema([...tree, { uid: field.uid, display_name: field.display_name }], field.schema, entry);
428
+ }
429
+ }
430
+ return entry;
431
+ }
432
+ /**
433
+ * The function fixes missing references in a JSON tree structure.
434
+ * @param {Record<string, unknown>[]} tree - An array of objects representing a tree structure. Each
435
+ * object in the array has a string key and an unknown value.
436
+ * @param {ReferenceFieldDataType | JsonRTEFieldDataType} field - The `field` parameter can be of
437
+ * type `ReferenceFieldDataType` or `JsonRTEFieldDataType`.
438
+ * @param {EntryJsonRTEFieldDataType} entry - The `entry` parameter is of type
439
+ * `EntryJsonRTEFieldDataType`, which represents an entry in a JSON Rich Text Editor (JsonRTE) field.
440
+ * @returns the updated `entry` object with fixed missing references in the `children` property.
441
+ */
442
+ fixJsonRteMissingReferences(tree, field, entry) {
443
+ if (Array.isArray(entry)) {
444
+ entry = entry.map((child, index) => {
445
+ 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);
446
+ });
447
+ }
448
+ else {
449
+ entry.children = entry.children
450
+ .map((child) => {
451
+ const refExist = this.jsonRefCheck(tree, field, child);
452
+ if (!refExist)
453
+ return null;
454
+ if ((0, isEmpty_1.default)(child.children)) {
455
+ child = this.fixJsonRteMissingReferences(tree, field, child);
456
+ }
457
+ return child;
458
+ })
459
+ .filter((val) => val);
460
+ }
461
+ return entry;
462
+ }
463
+ /**
464
+ * The `fixMissingReferences` function checks for missing references in an entry and adds them to a
465
+ * list if they are not found.
466
+ * @param {Record<string, unknown>[]} tree - An array of objects representing a tree structure. Each
467
+ * object in the array should have a "name" property and an optional "index" property.
468
+ * @param {ReferenceFieldDataType | JsonRTEFieldDataType} field - The `field` parameter is of type
469
+ * `ReferenceFieldDataType` or `JsonRTEFieldDataType`.
470
+ * @param {EntryReferenceFieldDataType[]} entry - The `entry` parameter is an array of objects that
471
+ * represent references to other entries. Each object in the array has the following properties:
472
+ * @returns the `entry` variable.
473
+ */
474
+ fixMissingReferences(tree, field, entry) {
475
+ const missingRefs = [];
476
+ entry = entry
477
+ .map((reference) => {
478
+ const { uid } = reference;
479
+ const refExist = (0, find_1.default)(this.entryMetaData, { uid });
480
+ if (!refExist) {
481
+ missingRefs.push(reference);
482
+ return null;
483
+ }
484
+ return reference;
485
+ })
486
+ .filter((val) => val);
487
+ if (!(0, isEmpty_1.default)(missingRefs)) {
488
+ this.missingRefs[this.currentUid].push({
489
+ tree,
490
+ fixStatus: 'Fixed',
491
+ uid: this.currentUid,
492
+ name: this.currentTitle,
493
+ data_type: field.data_type,
494
+ display_name: field.display_name,
495
+ treeStr: tree
496
+ .map(({ name, index }) => (index || index === 0 ? `[${+index}].${name}` : name))
497
+ .filter((val) => val)
498
+ .join(' ➜ '),
499
+ missingRefs,
500
+ });
501
+ }
502
+ return entry;
503
+ }
504
+ /**
505
+ * The function `modularBlockRefCheck` checks for invalid keys in an entry block and returns the
506
+ * updated entry block.
507
+ * @param {Record<string, unknown>[]} tree - An array of objects representing the tree structure of
508
+ * the blocks.
509
+ * @param {ModularBlockType[]} blocks - The `blocks` parameter is an array of `ModularBlockType`
510
+ * objects.
511
+ * @param {EntryModularBlocksDataType} entryBlock - The `entryBlock` parameter is an object that
512
+ * represents a modular block entry. It contains key-value pairs where the keys are the UIDs of the
513
+ * modular blocks and the values are the data associated with each modular block.
514
+ * @param {Number} index - The `index` parameter is a number that represents the index of the current
515
+ * block in the `tree` array.
516
+ * @returns the `entryBlock` object.
517
+ */
518
+ modularBlockRefCheck(tree, blocks, entryBlock, index) {
519
+ const validBlockUid = blocks.map((block) => block.uid);
520
+ const invalidKeys = Object.keys(entryBlock).filter((key) => !validBlockUid.includes(key));
521
+ invalidKeys.forEach((key) => {
522
+ if (this.fix) {
523
+ delete entryBlock[key];
524
+ }
525
+ this.missingRefs[this.currentUid].push({
526
+ uid: this.currentUid,
527
+ name: this.currentTitle,
528
+ data_type: key,
529
+ display_name: key,
530
+ fixStatus: this.fix ? 'Fixed' : undefined,
531
+ tree: [...tree, { index, uid: key, name: key }],
532
+ treeStr: [...tree, { index, uid: key, name: key }]
533
+ .map(({ name, index }) => (index || index === 0 ? `[${+index}].${name}` : name))
534
+ .filter((val) => val)
535
+ .join(' ➜ '),
536
+ missingRefs: [key],
537
+ });
538
+ });
539
+ return entryBlock;
540
+ }
541
+ /**
542
+ * The `jsonRefCheck` function checks if a reference exists in a JSON tree and adds missing
543
+ * references to a list if they are not found.
544
+ * @param {Record<string, unknown>[]} tree - An array of objects representing the tree structure.
545
+ * @param {JsonRTEFieldDataType} schema - The `schema` parameter is of type `JsonRTEFieldDataType`
546
+ * and represents the schema of a JSON field. It contains properties such as `uid`, `data_type`, and
547
+ * `display_name`.
548
+ * @param {EntryJsonRTEFieldDataType} child - The `child` parameter is an object that represents a
549
+ * child entry in a JSON tree. It has the following properties:
550
+ * @returns The function `jsonRefCheck` returns either `null` or `true`.
551
+ */
552
+ jsonRefCheck(tree, schema, child) {
553
+ const { uid: childrenUid } = child;
554
+ const { 'entry-uid': entryUid, 'content-type-uid': contentTypeUid } = child.attrs || {};
555
+ if (entryUid) {
556
+ const refExist = (0, find_1.default)(this.entryMetaData, { uid: entryUid });
557
+ if (!refExist) {
558
+ tree.push({ field: 'children' }, { field: childrenUid, uid: schema.uid });
559
+ this.missingRefs[this.currentUid].push({
560
+ tree,
561
+ uid: this.currentUid,
562
+ name: this.currentTitle,
563
+ data_type: schema.data_type,
564
+ display_name: schema.display_name,
565
+ fixStatus: this.fix ? 'Fixed' : undefined,
566
+ treeStr: tree
567
+ .map(({ name }) => name)
568
+ .filter((val) => val)
569
+ .join(' ➜ '),
570
+ missingRefs: [{ uid: entryUid, 'content-type-uid': contentTypeUid }],
571
+ });
572
+ return null;
573
+ }
574
+ }
575
+ return true;
576
+ }
261
577
  /**
262
578
  * The function prepares entry metadata by reading and processing files from different locales and
263
579
  * schemas.
@@ -267,8 +583,8 @@ class Entries {
267
583
  const localesFolderPath = (0, path_1.resolve)(this.config.basePath, this.config.moduleConfig.locales.dirName);
268
584
  const localesPath = (0, path_1.join)(localesFolderPath, this.config.moduleConfig.locales.fileName);
269
585
  const masterLocalesPath = (0, path_1.join)(localesFolderPath, 'master-locale.json');
270
- this.locales = (0, values_1.default)(JSON.parse((0, fs_1.readFileSync)(masterLocalesPath, 'utf-8')));
271
- this.locales.push(...(0, values_1.default)(JSON.parse((0, fs_1.readFileSync)(localesPath, 'utf-8'))));
586
+ this.locales = (0, values_1.default)(JSON.parse((0, fs_1.readFileSync)(masterLocalesPath, 'utf8')));
587
+ this.locales.push(...(0, values_1.default)(JSON.parse((0, fs_1.readFileSync)(localesPath, 'utf8'))));
272
588
  for (const { code } of this.locales) {
273
589
  for (const { uid } of this.ctSchema) {
274
590
  let basePath = (0, path_1.join)(this.folderPath, uid, code);
@@ -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, };