@contentstack/cli-audit 1.0.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/LICENSE +21 -0
- package/README.md +402 -0
- package/bin/dev +5 -0
- package/bin/dev.cmd +3 -0
- package/bin/run +5 -0
- package/bin/run.cmd +3 -0
- package/lib/base-command.d.ts +45 -0
- package/lib/base-command.js +88 -0
- package/lib/commands/cm/stacks/audit/fix.d.ts +8 -0
- package/lib/commands/cm/stacks/audit/fix.js +11 -0
- package/lib/commands/cm/stacks/audit/index.d.ts +62 -0
- package/lib/commands/cm/stacks/audit/index.js +242 -0
- package/lib/config/index.d.ts +28 -0
- package/lib/config/index.js +30 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +3 -0
- package/lib/messages/index.d.ts +33 -0
- package/lib/messages/index.js +46 -0
- package/lib/modules/content-types.d.ts +96 -0
- package/lib/modules/content-types.js +209 -0
- package/lib/modules/entries.d.ts +121 -0
- package/lib/modules/entries.js +288 -0
- package/lib/modules/global-fields.d.ts +27 -0
- package/lib/modules/global-fields.js +43 -0
- package/lib/modules/index.d.ts +4 -0
- package/lib/modules/index.js +10 -0
- package/lib/types/content-types.d.ts +69 -0
- package/lib/types/content-types.js +12 -0
- package/lib/types/entries.d.ts +46 -0
- package/lib/types/entries.js +2 -0
- package/lib/types/index.d.ts +3 -0
- package/lib/types/index.js +6 -0
- package/lib/types/utils.d.ts +18 -0
- package/lib/types/utils.js +2 -0
- package/lib/util/index.d.ts +1 -0
- package/lib/util/index.js +8 -0
- package/lib/util/log.d.ts +42 -0
- package/lib/util/log.js +153 -0
- package/oclif.manifest.json +134 -0
- package/package.json +85 -0
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const path_1 = require("path");
|
|
5
|
+
const find_1 = tslib_1.__importDefault(require("lodash/find"));
|
|
6
|
+
const fs_1 = require("fs");
|
|
7
|
+
const messages_1 = require("../messages");
|
|
8
|
+
/* The `ContentType` class is responsible for scanning content types, looking for references, and
|
|
9
|
+
generating a report in JSON and CSV formats. */
|
|
10
|
+
class ContentType {
|
|
11
|
+
constructor({ log, config, moduleName, ctSchema, gfSchema }) {
|
|
12
|
+
this.schema = [];
|
|
13
|
+
this.missingRefs = {};
|
|
14
|
+
this.moduleName = 'content-types';
|
|
15
|
+
this.log = log;
|
|
16
|
+
this.config = config;
|
|
17
|
+
this.ctSchema = ctSchema;
|
|
18
|
+
this.gfSchema = gfSchema;
|
|
19
|
+
this.moduleName = moduleName !== null && moduleName !== void 0 ? moduleName : 'content-types';
|
|
20
|
+
this.fileName = config.moduleConfig[this.moduleName].fileName;
|
|
21
|
+
this.folderPath = (0, path_1.resolve)(config.basePath, config.moduleConfig[this.moduleName].dirName);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The `run` function checks if a folder path exists, sets the schema based on the module name,
|
|
25
|
+
* iterates over the schema and looks for references, and returns a list of missing references.
|
|
26
|
+
* @returns the `missingRefs` object.
|
|
27
|
+
*/
|
|
28
|
+
async run() {
|
|
29
|
+
var _a;
|
|
30
|
+
if (!(0, fs_1.existsSync)(this.folderPath)) {
|
|
31
|
+
throw new Error((0, messages_1.$t)(messages_1.auditMsg.NOT_VALID_PATH, { path: this.folderPath }));
|
|
32
|
+
}
|
|
33
|
+
this.schema = this.moduleName === 'content-types' ? this.ctSchema : this.gfSchema;
|
|
34
|
+
for (const schema of (_a = this.schema) !== null && _a !== void 0 ? _a : []) {
|
|
35
|
+
this.currentUid = schema.uid;
|
|
36
|
+
this.currentTitle = schema.title;
|
|
37
|
+
this.missingRefs[this.currentUid] = [];
|
|
38
|
+
const { uid, title } = schema;
|
|
39
|
+
await this.lookForReference([{ uid, name: title }], schema);
|
|
40
|
+
this.log((0, messages_1.$t)(messages_1.auditMsg.SCAN_CT_SUCCESS_MSG, { title, module: this.config.moduleConfig[this.moduleName].name }), 'info');
|
|
41
|
+
}
|
|
42
|
+
for (let propName in this.missingRefs) {
|
|
43
|
+
if (!this.missingRefs[propName].length) {
|
|
44
|
+
delete this.missingRefs[propName];
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return this.missingRefs;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* The function `lookForReference` iterates through a given schema and performs validation checks
|
|
51
|
+
* based on the data type of each field.
|
|
52
|
+
* @param {Record<string, unknown>[]} tree - An array of objects representing the tree structure of
|
|
53
|
+
* the content type or field being validated. Each object in the array should have a "uid" property
|
|
54
|
+
* representing the unique identifier of the content type or field, and a "name" property
|
|
55
|
+
* representing the display name of the content type or field.
|
|
56
|
+
* @param {ContentTypeStruct | GlobalFieldDataType | ModularBlockType | GroupFieldDataType} - -
|
|
57
|
+
* `tree`: An array of objects representing the tree structure of the content type or field. Each
|
|
58
|
+
* object in the array should have a `uid` and `name` property.
|
|
59
|
+
*/
|
|
60
|
+
async lookForReference(tree, { schema }) {
|
|
61
|
+
for (const field of schema !== null && schema !== void 0 ? schema : []) {
|
|
62
|
+
switch (field.data_type) {
|
|
63
|
+
case 'reference':
|
|
64
|
+
this.missingRefs[this.currentUid].push(...this.validateReferenceField([...tree, { uid: field.uid, name: field.display_name }], field));
|
|
65
|
+
break;
|
|
66
|
+
case 'global_field':
|
|
67
|
+
await this.validateGlobalField([...tree, { uid: field.uid, name: field.display_name }], field);
|
|
68
|
+
break;
|
|
69
|
+
case 'json':
|
|
70
|
+
if (field.field_metadata.extension) {
|
|
71
|
+
// NOTE Custom field type
|
|
72
|
+
}
|
|
73
|
+
else if (field.field_metadata.allow_json_rte) {
|
|
74
|
+
// NOTE JSON RTE field type
|
|
75
|
+
this.missingRefs[this.currentUid].push(...this.validateJsonRTEFields([...tree, { uid: field.uid, name: field.display_name }], field));
|
|
76
|
+
}
|
|
77
|
+
break;
|
|
78
|
+
case 'blocks':
|
|
79
|
+
await this.validateModularBlocksField([...tree, { uid: field.uid, name: field.display_name }], field);
|
|
80
|
+
break;
|
|
81
|
+
case 'group':
|
|
82
|
+
await this.validateGroupField([...tree, { uid: field.uid, name: field.display_name }], field);
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* The function validates a reference field in a tree data structure.
|
|
89
|
+
* @param {Record<string, unknown>[]} tree - The "tree" parameter is an array of objects, where each
|
|
90
|
+
* object represents a node in a tree-like structure. Each object can have multiple properties, and
|
|
91
|
+
* the structure of the tree is defined by the relationships between these properties.
|
|
92
|
+
* @param {ReferenceFieldDataType} field - The `field` parameter is of type `ReferenceFieldDataType`.
|
|
93
|
+
* @returns an array of RefErrorReturnType.
|
|
94
|
+
*/
|
|
95
|
+
validateReferenceField(tree, field) {
|
|
96
|
+
return this.validateReferenceToValues(tree, field);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* The function "validateGlobalField" asynchronously validates a global field by looking for a
|
|
100
|
+
* reference in a tree data structure.
|
|
101
|
+
* @param {Record<string, unknown>[]} tree - The `tree` parameter is an array of objects. Each object
|
|
102
|
+
* represents a node in a tree structure. The tree structure can be represented as a hierarchical
|
|
103
|
+
* structure where each object can have child nodes.
|
|
104
|
+
* @param {GlobalFieldDataType} field - The `field` parameter is of type `GlobalFieldDataType`. It
|
|
105
|
+
* represents the field that needs to be validated.
|
|
106
|
+
*/
|
|
107
|
+
async validateGlobalField(tree, field) {
|
|
108
|
+
// NOTE Any GlobalField related logic can be added here
|
|
109
|
+
const missingRefs = [];
|
|
110
|
+
const { reference_to, display_name, data_type } = field;
|
|
111
|
+
if (!(0, find_1.default)(this.gfSchema, { uid: reference_to })) {
|
|
112
|
+
missingRefs.push(reference_to);
|
|
113
|
+
}
|
|
114
|
+
if (missingRefs.length) {
|
|
115
|
+
this.missingRefs[this.currentUid].push({
|
|
116
|
+
tree,
|
|
117
|
+
data_type,
|
|
118
|
+
missingRefs,
|
|
119
|
+
display_name,
|
|
120
|
+
ct_uid: this.currentUid,
|
|
121
|
+
name: this.currentTitle,
|
|
122
|
+
treeStr: tree.map(({ name }) => name).join(' ➜ '),
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
await this.lookForReference(tree, field);
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* The function validates the reference to values in a JSON RTE field.
|
|
129
|
+
* @param {Record<string, unknown>[]} tree - The "tree" parameter is an array of objects where each
|
|
130
|
+
* object represents a node in a tree-like structure. Each object can have multiple key-value pairs,
|
|
131
|
+
* where the key is a string and the value can be of any type.
|
|
132
|
+
* @param {JsonRTEFieldDataType} field - The `field` parameter is of type `JsonRTEFieldDataType`.
|
|
133
|
+
* @returns The function `validateJsonRTEFields` is returning an array of `RefErrorReturnType`
|
|
134
|
+
* objects.
|
|
135
|
+
*/
|
|
136
|
+
validateJsonRTEFields(tree, field) {
|
|
137
|
+
// NOTE Other possible reference logic will be added related to JSON RTE (Ex missing assets, extensions etc.,)
|
|
138
|
+
return this.validateReferenceToValues(tree, field);
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* The function validates the modular blocks field by traversing each module and looking for
|
|
142
|
+
* references.
|
|
143
|
+
* @param {Record<string, unknown>[]} tree - An array of objects representing the tree structure of
|
|
144
|
+
* the modular blocks. Each object in the array represents a node in the tree and contains properties
|
|
145
|
+
* like "uid" and "name".
|
|
146
|
+
* @param {ModularBlocksDataType} field - The `field` parameter is of type `ModularBlocksDataType`.
|
|
147
|
+
* It represents a modular blocks field and contains an array of blocks. Each block has properties
|
|
148
|
+
* like `uid` and `title`.
|
|
149
|
+
*/
|
|
150
|
+
async validateModularBlocksField(tree, field) {
|
|
151
|
+
const { blocks } = field;
|
|
152
|
+
// NOTE Traverse each and every module and look for reference
|
|
153
|
+
for (const block of blocks) {
|
|
154
|
+
const { uid, title } = block;
|
|
155
|
+
await this.lookForReference([...tree, { uid, name: title }], block);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* The function `validateGroupField` is an asynchronous function that validates a group field by
|
|
160
|
+
* looking for a reference in a tree data structure.
|
|
161
|
+
* @param {Record<string, unknown>[]} tree - The `tree` parameter is an array of objects that
|
|
162
|
+
* represents a tree structure. Each object in the array represents a node in the tree, and it
|
|
163
|
+
* contains key-value pairs where the keys are field names and the values are the corresponding field
|
|
164
|
+
* values.
|
|
165
|
+
* @param {GroupFieldDataType} field - The `field` parameter is of type `GroupFieldDataType`. It
|
|
166
|
+
* represents the group field that needs to be validated.
|
|
167
|
+
*/
|
|
168
|
+
async validateGroupField(tree, field) {
|
|
169
|
+
// NOTE Any Group Field related logic can be added here (Ex data serialization or picking any metadata for report etc.,)
|
|
170
|
+
await this.lookForReference(tree, field);
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* The function `validateReferenceToValues` checks if all the references specified in a field exist
|
|
174
|
+
* in a given tree of records and returns any missing references.
|
|
175
|
+
* @param {Record<string, unknown>[]} tree - An array of objects representing a tree structure. Each
|
|
176
|
+
* object in the array should have a "name" property.
|
|
177
|
+
* @param {ReferenceFieldDataType | JsonRTEFieldDataType} field - The `field` parameter is an object
|
|
178
|
+
* that represents a reference field in a content type. It has the following properties:
|
|
179
|
+
* @returns The function `validateReferenceToValues` returns an array of `RefErrorReturnType`
|
|
180
|
+
* objects.
|
|
181
|
+
*/
|
|
182
|
+
validateReferenceToValues(tree, field) {
|
|
183
|
+
const missingRefs = [];
|
|
184
|
+
const { reference_to, display_name, data_type } = field;
|
|
185
|
+
for (const reference of reference_to !== null && reference_to !== void 0 ? reference_to : []) {
|
|
186
|
+
// NOTE Can skip specific references keys (Ex, system defined keys can be skipped)
|
|
187
|
+
if (this.config.skipRefs.includes(reference))
|
|
188
|
+
continue;
|
|
189
|
+
const refExist = (0, find_1.default)(this.ctSchema, { uid: reference });
|
|
190
|
+
if (!refExist) {
|
|
191
|
+
missingRefs.push(reference);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return missingRefs.length
|
|
195
|
+
? [
|
|
196
|
+
{
|
|
197
|
+
tree,
|
|
198
|
+
data_type,
|
|
199
|
+
missingRefs,
|
|
200
|
+
display_name,
|
|
201
|
+
ct_uid: this.currentUid,
|
|
202
|
+
name: this.currentTitle,
|
|
203
|
+
treeStr: tree.map(({ name }) => name).join(' ➜ '),
|
|
204
|
+
},
|
|
205
|
+
]
|
|
206
|
+
: [];
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
exports.default = ContentType;
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { LogFn, Locale, ConfigType, EntryStruct, ModularBlockType, ContentTypeStruct, CtConstructorParam, GroupFieldDataType, GlobalFieldDataType, JsonRTEFieldDataType, ModularBlocksDataType, ModuleConstructorParam, ReferenceFieldDataType, EntryRefErrorReturnType, EntryGroupFieldDataType, EntryGlobalFieldDataType, EntryJsonRTEFieldDataType, EntryModularBlocksDataType, EntryReferenceFieldDataType } from '../types';
|
|
2
|
+
import auditConfig from '../config';
|
|
3
|
+
export default class Entries {
|
|
4
|
+
log: LogFn;
|
|
5
|
+
fileName: string;
|
|
6
|
+
locales: Locale[];
|
|
7
|
+
config: ConfigType;
|
|
8
|
+
folderPath: string;
|
|
9
|
+
currentUid: string;
|
|
10
|
+
currentTitle: string;
|
|
11
|
+
gfSchema: ContentTypeStruct[];
|
|
12
|
+
ctSchema: ContentTypeStruct[];
|
|
13
|
+
protected missingRefs: Record<string, any>;
|
|
14
|
+
entryMetaData: Record<string, any>[];
|
|
15
|
+
moduleName: keyof typeof auditConfig.moduleConfig;
|
|
16
|
+
constructor({ log, config, moduleName, ctSchema, gfSchema }: ModuleConstructorParam & CtConstructorParam);
|
|
17
|
+
/**
|
|
18
|
+
* The `run` function checks if a folder path exists, sets the schema based on the module name,
|
|
19
|
+
* iterates over the schema and looks for references, and returns a list of missing references.
|
|
20
|
+
* @returns the `missingRefs` object.
|
|
21
|
+
*/
|
|
22
|
+
run(): Promise<Record<string, any>>;
|
|
23
|
+
/**
|
|
24
|
+
* The function `lookForReference` iterates over a given schema and validates different field types
|
|
25
|
+
* such as reference, global field, JSON, modular blocks, and group fields.
|
|
26
|
+
* @param {Record<string, unknown>[]} tree - An array of objects representing the tree structure of
|
|
27
|
+
* the content type or field being validated. Each object in the array has the following properties:
|
|
28
|
+
* @param {ContentTypeStruct | GlobalFieldDataType | ModularBlockType | GroupFieldDataType} - -
|
|
29
|
+
* `tree`: An array of objects representing the tree structure of the content type or field being
|
|
30
|
+
* validated.
|
|
31
|
+
* @param {EntryStruct | EntryGlobalFieldDataType | EntryModularBlocksDataType |
|
|
32
|
+
* EntryGroupFieldDataType} entry - The `entry` parameter is an object that represents the data of an
|
|
33
|
+
* entry. It can have different types depending on the `schema` parameter.
|
|
34
|
+
*/
|
|
35
|
+
lookForReference(tree: Record<string, unknown>[], { schema }: ContentTypeStruct | GlobalFieldDataType | ModularBlockType | GroupFieldDataType, entry: EntryStruct | EntryGlobalFieldDataType | EntryModularBlocksDataType | EntryGroupFieldDataType): Promise<void>;
|
|
36
|
+
/**
|
|
37
|
+
* The function `validateReferenceField` validates the reference values of a given field in a tree
|
|
38
|
+
* structure.
|
|
39
|
+
* @param {Record<string, unknown>[]} tree - An array of objects representing a tree structure. Each
|
|
40
|
+
* object in the array should have a unique identifier field.
|
|
41
|
+
* @param {ReferenceFieldDataType} fieldStructure - The `fieldStructure` parameter is of type
|
|
42
|
+
* `ReferenceFieldDataType`. It represents the structure of the reference field that needs to be
|
|
43
|
+
* validated.
|
|
44
|
+
* @param {EntryReferenceFieldDataType[]} field - The `field` parameter is an array of
|
|
45
|
+
* `EntryReferenceFieldDataType` objects.
|
|
46
|
+
* @returns the result of calling the `validateReferenceValues` function with the provided arguments
|
|
47
|
+
* `tree`, `fieldStructure`, and `field`.
|
|
48
|
+
*/
|
|
49
|
+
validateReferenceField(tree: Record<string, unknown>[], fieldStructure: ReferenceFieldDataType, field: EntryReferenceFieldDataType[]): EntryRefErrorReturnType[];
|
|
50
|
+
/**
|
|
51
|
+
* The function "validateGlobalField" is an asynchronous function that takes in a tree,
|
|
52
|
+
* fieldStructure, and field as parameters and looks for references in the tree.
|
|
53
|
+
* @param {Record<string, unknown>[]} tree - The `tree` parameter is an array of objects. Each object
|
|
54
|
+
* represents a node in a tree structure. The tree structure can be represented as a hierarchical
|
|
55
|
+
* structure where each object can have child objects.
|
|
56
|
+
* @param {GlobalFieldDataType} fieldStructure - The `fieldStructure` parameter is of type
|
|
57
|
+
* `GlobalFieldDataType` and represents the structure of the global field. It defines the expected
|
|
58
|
+
* properties and their types for the global field.
|
|
59
|
+
* @param {EntryGlobalFieldDataType} field - The `field` parameter is of type
|
|
60
|
+
* `EntryGlobalFieldDataType`. It represents a single global field entry.
|
|
61
|
+
*/
|
|
62
|
+
validateGlobalField(tree: Record<string, unknown>[], fieldStructure: GlobalFieldDataType, field: EntryGlobalFieldDataType): Promise<void>;
|
|
63
|
+
/**
|
|
64
|
+
* The function `validateJsonRTEFields` is used to validate the JSON RTE fields by checking if the
|
|
65
|
+
* referenced entries exist and adding missing references to a tree structure.
|
|
66
|
+
* @param {Record<string, unknown>[]} tree - An array of objects representing the tree structure of
|
|
67
|
+
* the JSON RTE fields.
|
|
68
|
+
* @param {JsonRTEFieldDataType} fieldStructure - The `fieldStructure` parameter is of type
|
|
69
|
+
* `JsonRTEFieldDataType` and represents the structure of a JSON RTE field. It contains properties
|
|
70
|
+
* such as `uid`, `data_type`, and `display_name`.
|
|
71
|
+
* @param {EntryJsonRTEFieldDataType} field - The `field` parameter is of type
|
|
72
|
+
* `EntryJsonRTEFieldDataType`, which represents a JSON RTE field in an entry. It contains properties
|
|
73
|
+
* such as `uid`, `attrs`, and `children`.
|
|
74
|
+
*/
|
|
75
|
+
validateJsonRTEFields(tree: Record<string, unknown>[], fieldStructure: JsonRTEFieldDataType, field: EntryJsonRTEFieldDataType): Promise<void>;
|
|
76
|
+
/**
|
|
77
|
+
* The function validates the modular blocks field by traversing each module and looking for
|
|
78
|
+
* references.
|
|
79
|
+
* @param {Record<string, unknown>[]} tree - The `tree` parameter is an array of objects that
|
|
80
|
+
* represent the structure of the modular blocks field. Each object in the array represents a level
|
|
81
|
+
* in the tree structure, and it contains a `field` property that represents the unique identifier of
|
|
82
|
+
* the modular block at that level.
|
|
83
|
+
* @param {ModularBlocksDataType} fieldStructure - The `fieldStructure` parameter is of type
|
|
84
|
+
* `ModularBlocksDataType` and represents the structure of the modular blocks field. It contains
|
|
85
|
+
* information about the blocks and their properties.
|
|
86
|
+
* @param {EntryModularBlocksDataType[]} field - The `field` parameter is an array of objects of type
|
|
87
|
+
* `EntryModularBlocksDataType`.
|
|
88
|
+
*/
|
|
89
|
+
validateModularBlocksField(tree: Record<string, unknown>[], fieldStructure: ModularBlocksDataType, field: EntryModularBlocksDataType[]): Promise<void>;
|
|
90
|
+
/**
|
|
91
|
+
* The function validates a group field by looking for a reference in a tree structure.
|
|
92
|
+
* @param {Record<string, unknown>[]} tree - An array of objects representing the tree structure.
|
|
93
|
+
* @param {GroupFieldDataType} fieldStructure - The `fieldStructure` parameter is of type
|
|
94
|
+
* `GroupFieldDataType` and represents the structure of the group field. It contains information
|
|
95
|
+
* about the fields and their types within the group.
|
|
96
|
+
* @param {EntryGroupFieldDataType} field - The `field` parameter is of type
|
|
97
|
+
* `EntryGroupFieldDataType` and represents a single group field entry.
|
|
98
|
+
*/
|
|
99
|
+
validateGroupField(tree: Record<string, unknown>[], fieldStructure: GroupFieldDataType, field: EntryGroupFieldDataType): Promise<void>;
|
|
100
|
+
/**
|
|
101
|
+
* The function `validateReferenceValues` checks if the references in a given field exist in the
|
|
102
|
+
* provided tree and returns any missing references.
|
|
103
|
+
* @param {Record<string, unknown>[]} tree - An array of objects representing the tree structure of
|
|
104
|
+
* the data. Each object in the array represents a node in the tree.
|
|
105
|
+
* @param {ReferenceFieldDataType} fieldStructure - The `fieldStructure` parameter is of type
|
|
106
|
+
* `ReferenceFieldDataType` and represents the structure of a reference field. It contains properties
|
|
107
|
+
* such as `data_type` (the data type of the reference field) and `display_name` (the display name of
|
|
108
|
+
* the reference field).
|
|
109
|
+
* @param {EntryReferenceFieldDataType[]} field - The `field` parameter is an array of objects
|
|
110
|
+
* representing entry reference fields. Each object in the array has properties such as `uid` which
|
|
111
|
+
* represents the unique identifier of the referenced entry.
|
|
112
|
+
* @returns The function `validateReferenceValues` returns an array of `EntryRefErrorReturnType`
|
|
113
|
+
* objects.
|
|
114
|
+
*/
|
|
115
|
+
validateReferenceValues(tree: Record<string, unknown>[], fieldStructure: ReferenceFieldDataType, field: EntryReferenceFieldDataType[]): EntryRefErrorReturnType[];
|
|
116
|
+
/**
|
|
117
|
+
* The function prepares entry metadata by reading and processing files from different locales and
|
|
118
|
+
* schemas.
|
|
119
|
+
*/
|
|
120
|
+
prepareEntryMetaData(): Promise<void>;
|
|
121
|
+
}
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const find_1 = tslib_1.__importDefault(require("lodash/find"));
|
|
5
|
+
const values_1 = tslib_1.__importDefault(require("lodash/values"));
|
|
6
|
+
const isEmpty_1 = tslib_1.__importDefault(require("lodash/isEmpty"));
|
|
7
|
+
const path_1 = require("path");
|
|
8
|
+
const fs_1 = require("fs");
|
|
9
|
+
const cli_utilities_1 = require("@contentstack/cli-utilities");
|
|
10
|
+
const messages_1 = require("../messages");
|
|
11
|
+
class Entries {
|
|
12
|
+
constructor({ log, config, moduleName, ctSchema, gfSchema }) {
|
|
13
|
+
this.missingRefs = {};
|
|
14
|
+
this.entryMetaData = [];
|
|
15
|
+
this.moduleName = 'content-types';
|
|
16
|
+
this.log = log;
|
|
17
|
+
this.config = config;
|
|
18
|
+
this.ctSchema = ctSchema;
|
|
19
|
+
this.gfSchema = gfSchema;
|
|
20
|
+
this.fileName = config.moduleConfig[this.moduleName].fileName;
|
|
21
|
+
this.folderPath = (0, path_1.resolve)(config.basePath, config.moduleConfig.entries.dirName);
|
|
22
|
+
if (moduleName)
|
|
23
|
+
this.moduleName = moduleName;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The `run` function checks if a folder path exists, sets the schema based on the module name,
|
|
27
|
+
* iterates over the schema and looks for references, and returns a list of missing references.
|
|
28
|
+
* @returns the `missingRefs` object.
|
|
29
|
+
*/
|
|
30
|
+
async run() {
|
|
31
|
+
if (!(0, fs_1.existsSync)(this.folderPath)) {
|
|
32
|
+
throw new Error((0, messages_1.$t)(messages_1.auditMsg.NOT_VALID_PATH, { path: this.folderPath }));
|
|
33
|
+
}
|
|
34
|
+
await this.prepareEntryMetaData();
|
|
35
|
+
for (const { code } of this.locales) {
|
|
36
|
+
for (const ctSchema of this.ctSchema) {
|
|
37
|
+
const basePath = (0, path_1.join)(this.folderPath, ctSchema.uid, code);
|
|
38
|
+
const fsUtility = new cli_utilities_1.FsUtility({ basePath, indexFileName: 'index.json' });
|
|
39
|
+
const indexer = fsUtility.indexFileContent;
|
|
40
|
+
for (const _ in indexer) {
|
|
41
|
+
const entries = (await fsUtility.readChunkFiles.next());
|
|
42
|
+
for (const entryUid in entries) {
|
|
43
|
+
let entry = entries[entryUid];
|
|
44
|
+
const { uid, title } = entry;
|
|
45
|
+
this.currentUid = uid;
|
|
46
|
+
this.currentTitle = title;
|
|
47
|
+
this.missingRefs[this.currentUid] = [];
|
|
48
|
+
await this.lookForReference([{ uid, name: title }], ctSchema, entry);
|
|
49
|
+
this.log((0, messages_1.$t)(messages_1.auditMsg.SCAN_ENTRY_SUCCESS_MSG, {
|
|
50
|
+
title,
|
|
51
|
+
local: code,
|
|
52
|
+
module: this.config.moduleConfig.entries.name,
|
|
53
|
+
}), 'info');
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
this.log('', 'info'); // Adding empty line
|
|
59
|
+
for (let propName in this.missingRefs) {
|
|
60
|
+
if (!this.missingRefs[propName].length) {
|
|
61
|
+
delete this.missingRefs[propName];
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return this.missingRefs;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* The function `lookForReference` iterates over a given schema and validates different field types
|
|
68
|
+
* such as reference, global field, JSON, modular blocks, and group fields.
|
|
69
|
+
* @param {Record<string, unknown>[]} tree - An array of objects representing the tree structure of
|
|
70
|
+
* the content type or field being validated. Each object in the array has the following properties:
|
|
71
|
+
* @param {ContentTypeStruct | GlobalFieldDataType | ModularBlockType | GroupFieldDataType} - -
|
|
72
|
+
* `tree`: An array of objects representing the tree structure of the content type or field being
|
|
73
|
+
* validated.
|
|
74
|
+
* @param {EntryStruct | EntryGlobalFieldDataType | EntryModularBlocksDataType |
|
|
75
|
+
* EntryGroupFieldDataType} entry - The `entry` parameter is an object that represents the data of an
|
|
76
|
+
* entry. It can have different types depending on the `schema` parameter.
|
|
77
|
+
*/
|
|
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) {
|
|
82
|
+
case 'reference':
|
|
83
|
+
this.missingRefs[this.currentUid].push(...this.validateReferenceField([...tree, { uid: field.uid, name: field.display_name, field: uid }], field, entry[uid]));
|
|
84
|
+
break;
|
|
85
|
+
case 'global_field':
|
|
86
|
+
await this.validateGlobalField([...tree, { uid: field.uid, name: field.display_name, field: uid }], field, entry[uid]);
|
|
87
|
+
break;
|
|
88
|
+
case 'json':
|
|
89
|
+
if (field.field_metadata.extension) {
|
|
90
|
+
// NOTE Custom field type
|
|
91
|
+
}
|
|
92
|
+
else if (field.field_metadata.allow_json_rte) {
|
|
93
|
+
// NOTE JSON RTE field type
|
|
94
|
+
await this.validateJsonRTEFields([...tree, { uid: field.uid, name: field.display_name, field: uid }], field, entry[uid]);
|
|
95
|
+
}
|
|
96
|
+
break;
|
|
97
|
+
case 'blocks':
|
|
98
|
+
await this.validateModularBlocksField([...tree, { uid: field.uid, name: field.display_name, field: uid }], field, entry[uid]);
|
|
99
|
+
break;
|
|
100
|
+
case 'group':
|
|
101
|
+
await this.validateGroupField([...tree, { uid: field.uid, name: field.display_name, field: uid }], field, entry[uid]);
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* The function `validateReferenceField` validates the reference values of a given field in a tree
|
|
108
|
+
* structure.
|
|
109
|
+
* @param {Record<string, unknown>[]} tree - An array of objects representing a tree structure. Each
|
|
110
|
+
* object in the array should have a unique identifier field.
|
|
111
|
+
* @param {ReferenceFieldDataType} fieldStructure - The `fieldStructure` parameter is of type
|
|
112
|
+
* `ReferenceFieldDataType`. It represents the structure of the reference field that needs to be
|
|
113
|
+
* validated.
|
|
114
|
+
* @param {EntryReferenceFieldDataType[]} field - The `field` parameter is an array of
|
|
115
|
+
* `EntryReferenceFieldDataType` objects.
|
|
116
|
+
* @returns the result of calling the `validateReferenceValues` function with the provided arguments
|
|
117
|
+
* `tree`, `fieldStructure`, and `field`.
|
|
118
|
+
*/
|
|
119
|
+
validateReferenceField(tree, fieldStructure, field) {
|
|
120
|
+
return this.validateReferenceValues(tree, fieldStructure, field);
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* The function "validateGlobalField" is an asynchronous function that takes in a tree,
|
|
124
|
+
* fieldStructure, and field as parameters and looks for references in the tree.
|
|
125
|
+
* @param {Record<string, unknown>[]} tree - The `tree` parameter is an array of objects. Each object
|
|
126
|
+
* represents a node in a tree structure. The tree structure can be represented as a hierarchical
|
|
127
|
+
* structure where each object can have child objects.
|
|
128
|
+
* @param {GlobalFieldDataType} fieldStructure - The `fieldStructure` parameter is of type
|
|
129
|
+
* `GlobalFieldDataType` and represents the structure of the global field. It defines the expected
|
|
130
|
+
* properties and their types for the global field.
|
|
131
|
+
* @param {EntryGlobalFieldDataType} field - The `field` parameter is of type
|
|
132
|
+
* `EntryGlobalFieldDataType`. It represents a single global field entry.
|
|
133
|
+
*/
|
|
134
|
+
async validateGlobalField(tree, fieldStructure, field) {
|
|
135
|
+
// NOTE Any GlobalField related logic can be added here
|
|
136
|
+
await this.lookForReference(tree, fieldStructure, field);
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* The function `validateJsonRTEFields` is used to validate the JSON RTE fields by checking if the
|
|
140
|
+
* referenced entries exist and adding missing references to a tree structure.
|
|
141
|
+
* @param {Record<string, unknown>[]} tree - An array of objects representing the tree structure of
|
|
142
|
+
* the JSON RTE fields.
|
|
143
|
+
* @param {JsonRTEFieldDataType} fieldStructure - The `fieldStructure` parameter is of type
|
|
144
|
+
* `JsonRTEFieldDataType` and represents the structure of a JSON RTE field. It contains properties
|
|
145
|
+
* such as `uid`, `data_type`, and `display_name`.
|
|
146
|
+
* @param {EntryJsonRTEFieldDataType} field - The `field` parameter is of type
|
|
147
|
+
* `EntryJsonRTEFieldDataType`, which represents a JSON RTE field in an entry. It contains properties
|
|
148
|
+
* such as `uid`, `attrs`, and `children`.
|
|
149
|
+
*/
|
|
150
|
+
async validateJsonRTEFields(tree, fieldStructure, field) {
|
|
151
|
+
var _a;
|
|
152
|
+
// 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
|
+
}
|
|
173
|
+
}
|
|
174
|
+
if (!(0, isEmpty_1.default)(children)) {
|
|
175
|
+
await this.validateJsonRTEFields(tree, fieldStructure, child);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* The function validates the modular blocks field by traversing each module and looking for
|
|
181
|
+
* references.
|
|
182
|
+
* @param {Record<string, unknown>[]} tree - The `tree` parameter is an array of objects that
|
|
183
|
+
* represent the structure of the modular blocks field. Each object in the array represents a level
|
|
184
|
+
* in the tree structure, and it contains a `field` property that represents the unique identifier of
|
|
185
|
+
* the modular block at that level.
|
|
186
|
+
* @param {ModularBlocksDataType} fieldStructure - The `fieldStructure` parameter is of type
|
|
187
|
+
* `ModularBlocksDataType` and represents the structure of the modular blocks field. It contains
|
|
188
|
+
* information about the blocks and their properties.
|
|
189
|
+
* @param {EntryModularBlocksDataType[]} field - The `field` parameter is an array of objects of type
|
|
190
|
+
* `EntryModularBlocksDataType`.
|
|
191
|
+
*/
|
|
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]);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* The function validates a group field by looking for a reference in a tree structure.
|
|
206
|
+
* @param {Record<string, unknown>[]} tree - An array of objects representing the tree structure.
|
|
207
|
+
* @param {GroupFieldDataType} fieldStructure - The `fieldStructure` parameter is of type
|
|
208
|
+
* `GroupFieldDataType` and represents the structure of the group field. It contains information
|
|
209
|
+
* about the fields and their types within the group.
|
|
210
|
+
* @param {EntryGroupFieldDataType} field - The `field` parameter is of type
|
|
211
|
+
* `EntryGroupFieldDataType` and represents a single group field entry.
|
|
212
|
+
*/
|
|
213
|
+
async validateGroupField(tree, fieldStructure, field) {
|
|
214
|
+
// 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);
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* The function `validateReferenceValues` checks if the references in a given field exist in the
|
|
219
|
+
* provided tree and returns any missing references.
|
|
220
|
+
* @param {Record<string, unknown>[]} tree - An array of objects representing the tree structure of
|
|
221
|
+
* the data. Each object in the array represents a node in the tree.
|
|
222
|
+
* @param {ReferenceFieldDataType} fieldStructure - The `fieldStructure` parameter is of type
|
|
223
|
+
* `ReferenceFieldDataType` and represents the structure of a reference field. It contains properties
|
|
224
|
+
* such as `data_type` (the data type of the reference field) and `display_name` (the display name of
|
|
225
|
+
* the reference field).
|
|
226
|
+
* @param {EntryReferenceFieldDataType[]} field - The `field` parameter is an array of objects
|
|
227
|
+
* representing entry reference fields. Each object in the array has properties such as `uid` which
|
|
228
|
+
* represents the unique identifier of the referenced entry.
|
|
229
|
+
* @returns The function `validateReferenceValues` returns an array of `EntryRefErrorReturnType`
|
|
230
|
+
* objects.
|
|
231
|
+
*/
|
|
232
|
+
validateReferenceValues(tree, fieldStructure, field) {
|
|
233
|
+
const missingRefs = [];
|
|
234
|
+
const { data_type, display_name } = fieldStructure;
|
|
235
|
+
for (const reference of field !== null && field !== void 0 ? field : []) {
|
|
236
|
+
const { uid } = reference;
|
|
237
|
+
// NOTE Can skip specific references keys (Ex, system defined keys can be skipped)
|
|
238
|
+
// if (this.config.skipRefs.includes(reference)) continue;
|
|
239
|
+
const refExist = (0, find_1.default)(this.entryMetaData, { uid });
|
|
240
|
+
if (!refExist) {
|
|
241
|
+
missingRefs.push(reference);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
return missingRefs.length
|
|
245
|
+
? [
|
|
246
|
+
{
|
|
247
|
+
tree,
|
|
248
|
+
data_type,
|
|
249
|
+
missingRefs,
|
|
250
|
+
display_name,
|
|
251
|
+
uid: this.currentUid,
|
|
252
|
+
name: this.currentTitle,
|
|
253
|
+
treeStr: tree
|
|
254
|
+
.map(({ name }) => name)
|
|
255
|
+
.filter((val) => val)
|
|
256
|
+
.join(' ➜ '),
|
|
257
|
+
},
|
|
258
|
+
]
|
|
259
|
+
: [];
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* The function prepares entry metadata by reading and processing files from different locales and
|
|
263
|
+
* schemas.
|
|
264
|
+
*/
|
|
265
|
+
async prepareEntryMetaData() {
|
|
266
|
+
this.log(messages_1.auditMsg.PREPARING_ENTRY_METADATA, 'info');
|
|
267
|
+
const localesFolderPath = (0, path_1.resolve)(this.config.basePath, this.config.moduleConfig.locales.dirName);
|
|
268
|
+
const localesPath = (0, path_1.join)(localesFolderPath, this.config.moduleConfig.locales.fileName);
|
|
269
|
+
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'))));
|
|
272
|
+
for (const { code } of this.locales) {
|
|
273
|
+
for (const { uid } of this.ctSchema) {
|
|
274
|
+
let basePath = (0, path_1.join)(this.folderPath, uid, code);
|
|
275
|
+
let fsUtility = new cli_utilities_1.FsUtility({ basePath, indexFileName: 'index.json' });
|
|
276
|
+
let indexer = fsUtility.indexFileContent;
|
|
277
|
+
for (const _ in indexer) {
|
|
278
|
+
const entries = (await fsUtility.readChunkFiles.next());
|
|
279
|
+
for (const entryUid in entries) {
|
|
280
|
+
let { title } = entries[entryUid];
|
|
281
|
+
this.entryMetaData.push({ uid: entryUid, title });
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
exports.default = Entries;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import ContentType from './content-types';
|
|
2
|
+
import { GroupFieldDataType, ModularBlocksDataType } from '../types';
|
|
3
|
+
export default class GlobalField extends ContentType {
|
|
4
|
+
/**
|
|
5
|
+
* The above function is an asynchronous function that runs a validation and returns any missing
|
|
6
|
+
* references.
|
|
7
|
+
* @returns the value of the variable `missingRefs`.
|
|
8
|
+
*/
|
|
9
|
+
run(): Promise<Record<string, any>>;
|
|
10
|
+
/**
|
|
11
|
+
* The function validates a field containing modular blocks by traversing each block and checking for
|
|
12
|
+
* references in a given tree.
|
|
13
|
+
* @param {Record<string, unknown>[]} tree - The `tree` parameter is an array of objects that
|
|
14
|
+
* represents a tree structure. Each object in the array represents a node in the tree.
|
|
15
|
+
* @param {ModularBlocksDataType} field - The `field` parameter is of type `ModularBlocksDataType`.
|
|
16
|
+
*/
|
|
17
|
+
validateModularBlocksField(tree: Record<string, unknown>[], field: ModularBlocksDataType): Promise<void>;
|
|
18
|
+
/**
|
|
19
|
+
* The function "validateGroupField" performs group field validation by looking for a reference in a
|
|
20
|
+
* tree structure.
|
|
21
|
+
* @param {Record<string, unknown>[]} tree - The `tree` parameter is an array of objects representing
|
|
22
|
+
* a tree structure. Each object in the array represents a node in the tree and has properties like
|
|
23
|
+
* `uid` and `name`.
|
|
24
|
+
* @param {GroupFieldDataType} field - The `field` parameter is of type `GroupFieldDataType`.
|
|
25
|
+
*/
|
|
26
|
+
validateGroupField(tree: Record<string, unknown>[], field: GroupFieldDataType): Promise<void>;
|
|
27
|
+
}
|