-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmodulesData.ts
More file actions
204 lines (181 loc) · 9.26 KB
/
modulesData.ts
File metadata and controls
204 lines (181 loc) · 9.26 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
import { join, resolve } from 'path';
import { existsSync, readFileSync, readdirSync } from 'fs';
import { FsUtility, sanitizePath, log } from '@contentstack/cli-utilities';
import { ConfigType, ContentTypeStruct, CtConstructorParam, ModuleConstructorParam } from '../types';
import { keys, values } from 'lodash';
export default class ModuleDataReader {
public config: ConfigType;
public folderPath: string;
public assets!: Record<string, any>;
public locales: any[] = [];
public gfSchema: ContentTypeStruct[];
public ctSchema: ContentTypeStruct[];
public environments: string[] = [];
public auditData: Record<string, unknown> = {};
protected schema: ContentTypeStruct[] = [];
constructor({ config, ctSchema, gfSchema }: ModuleConstructorParam & CtConstructorParam) {
this.config = config;
this.ctSchema = ctSchema;
this.gfSchema = gfSchema;
log.debug(`Initializing ModuleDataReader`, this.config.auditContext);
log.debug(`Content types count: ${ctSchema.length}`, this.config.auditContext);
log.debug(`Global fields count: ${gfSchema.length}`, this.config.auditContext);
this.folderPath = resolve(sanitizePath(config.basePath));
log.debug(`Folder path: ${this.folderPath}`, this.config.auditContext);
log.debug(`ModuleDataReader initialization completed`, this.config.auditContext);
}
async getModuleItemCount(moduleName: string): Promise<number> {
log.debug(`Getting item count for module: ${moduleName}`, this.config.auditContext);
let count = 0;
switch (moduleName) {
case 'content-types':
log.debug(`Counting content types`, this.config.auditContext);
count = this.ctSchema.length;
log.debug(`Content types count: ${count}`, this.config.auditContext);
break;
case 'global-fields':
log.debug(`Counting global fields`, this.config.auditContext);
count = this.gfSchema.length;
log.debug(`Global fields count: ${count}`, this.config.auditContext);
break;
case 'assets': {
log.debug(`Counting assets`, this.config.auditContext);
const spacesDir = join(this.folderPath, 'spaces');
if (existsSync(spacesDir)) {
log.debug(`Multi-space structure detected at: ${spacesDir}`, this.config.auditContext);
const spaceDirs = readdirSync(spacesDir, { withFileTypes: true }).filter(
(entry) => entry.isDirectory() && existsSync(join(spacesDir, entry.name, 'assets')),
);
for (const spaceDir of spaceDirs) {
const spaceAssetsPath = join(spacesDir, spaceDir.name, 'assets');
log.debug(`Counting assets in space: ${spaceDir.name} at ${spaceAssetsPath}`, this.config.auditContext);
const spaceCount = (await this.readEntryAssetsModule(spaceAssetsPath, 'assets')) || 0;
log.debug(`Space ${spaceDir.name} asset count: ${spaceCount}`, this.config.auditContext);
count += spaceCount;
}
} else {
const assetsPath = join(this.folderPath, 'assets');
log.debug(`Flat structure detected, assets path: ${assetsPath}`, this.config.auditContext);
count = (await this.readEntryAssetsModule(assetsPath, 'assets')) || 0;
}
log.debug(`Total assets count: ${count}`, this.config.auditContext);
break;
}
case 'entries':
log.debug(`Counting entries`, this.config.auditContext);
{
const localesFolderPath = resolve(this.config.basePath, this.config.moduleConfig.locales.dirName);
const localesPath = join(localesFolderPath, this.config.moduleConfig.locales.fileName);
const masterLocalesPath = join(localesFolderPath, 'master-locale.json');
log.debug(`Locales folder path: ${localesFolderPath}`, this.config.auditContext);
log.debug(`Locales path: ${localesPath}`, this.config.auditContext);
log.debug(`Master locales path: ${masterLocalesPath}`, this.config.auditContext);
log.debug(`Loading master locales`, this.config.auditContext);
this.locales = values(await this.readUsingFsModule(masterLocalesPath));
log.debug(
`Loaded ${this.locales.length} master locales: ${this.locales.map((locale) => locale.code).join(', ')}`,
this.config.auditContext,
);
if (existsSync(localesPath)) {
log.debug(`Loading additional locales from file`, this.config.auditContext);
this.locales.push(...values(JSON.parse(readFileSync(localesPath, 'utf8'))));
log.debug(
`Total locales after loading: ${this.locales.length} - ${this.locales
.map((locale) => locale.code)
.join(', ')}`,
this.config.auditContext,
);
} else {
log.debug(`Additional locales file not found`, this.config.auditContext);
}
log.debug(
`Processing ${this.locales.length} locales and ${this.ctSchema.length} content types`,
this.config.auditContext,
);
for (const { code } of this.locales) {
log.debug(`Processing locale: ${code}`, this.config.auditContext);
for (const ctSchema of this.ctSchema) {
log.debug(`Processing content type: ${ctSchema.uid}`, this.config.auditContext);
const basePath = join(this.folderPath, 'entries', ctSchema.uid, code);
log.debug(`Base path: ${basePath}`, this.config.auditContext);
const entryCount = (await this.readEntryAssetsModule(basePath, 'index')) || 0;
log.debug(`Found ${entryCount} entries for ${ctSchema.uid} in ${code}`, this.config.auditContext);
count = count + entryCount;
}
}
log.debug(`Total entries count: ${count}`, this.config.auditContext);
}
break;
case 'custom-roles':
case 'extensions':
case 'workflows':
case 'composable-studio': {
log.debug(`Counting ${moduleName}`, this.config.auditContext);
const modulePath = resolve(
this.folderPath,
sanitizePath(this.config.moduleConfig[moduleName].dirName),
sanitizePath(this.config.moduleConfig[moduleName].fileName),
);
log.debug(`Reading module: ${moduleName} from file: ${modulePath}`, this.config.auditContext);
const moduleData = await this.readUsingFsModule(modulePath);
// For composable-studio, it could be a single object or an array
if (moduleName === 'composable-studio') {
count = Array.isArray(moduleData) ? moduleData.length : Object.keys(moduleData).length > 0 ? 1 : 0;
} else {
count = keys(moduleData).length;
}
log.debug(`module:${moduleName} count: ${count}`, this.config.auditContext);
break;
}
}
log.debug(`Module ${moduleName} item count: ${count}`, this.config.auditContext);
return count;
}
async readUsingFsModule(path: string): Promise<Record<string, any>> {
log.debug(`Reading file: ${path}`, this.config.auditContext);
const data = existsSync(path) ? JSON.parse(readFileSync(path, 'utf-8')) : [];
log.debug(
`File ${existsSync(path) ? 'exists' : 'not found'}, data type: ${Array.isArray(data) ? 'array' : 'object'}`,
this.config.auditContext,
);
if (existsSync(path)) {
const dataSize = Array.isArray(data) ? data.length : Object.keys(data).length;
log.debug(`Loaded ${dataSize} items from file`, this.config.auditContext);
} else {
log.debug(`Returning empty array for non-existent file`, this.config.auditContext);
}
return data;
}
async readEntryAssetsModule(basePath: string, module: string): Promise<number> {
log.debug(`Reading entry/assets module: ${module}`, this.config.auditContext);
log.debug(`Base path: ${basePath}`, this.config.auditContext);
let fsUtility = new FsUtility({ basePath, indexFileName: `${module}.json` });
let indexer = fsUtility.indexFileContent;
log.debug(`Found ${Object.keys(indexer).length} index files`, this.config.auditContext);
let count = 0;
for (const _ in indexer) {
log.debug(`Reading chunk file`, this.config.auditContext);
const entries = (await fsUtility.readChunkFiles.next()) as Record<string, any>;
const chunkCount = Object.keys(entries).length;
log.debug(`Loaded ${chunkCount} items from chunk`, this.config.auditContext);
count = count + chunkCount;
}
log.debug(`Total ${module} count: ${count}`, this.config.auditContext);
return count;
}
async run(): Promise<Object> {
log.debug(`Starting ModuleDataReader run process`, this.config.auditContext);
log.debug(`Available modules: ${Object.keys(this.config.moduleConfig).join(', ')}`, this.config.auditContext);
await Promise.allSettled(
Object.keys(this.config.moduleConfig).map(async (module) => {
log.debug(`Processing module: ${module}`, this.config.auditContext);
const count = await this.getModuleItemCount(module);
this.auditData[module] = { Total: count };
log.debug(`Module ${module} processed with count: ${count}`, this.config.auditContext);
}),
);
log.debug(`ModuleDataReader run completed`, this.config.auditContext);
log.debug(`Audit data: ${JSON.stringify(this.auditData)}`, this.config.auditContext);
return this.auditData;
}
}