@zohodesk/codestandard-validator 1.1.4 → 1.2.4-exp-2
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/bin/cliCI.js +0 -0
- package/build/ai/config.example.json +10 -0
- package/build/ai/ollama-service.js +403 -0
- package/build/ai/prompts/CODE_REVIEW_PROMPT.md +72 -0
- package/build/ai/prompts/PROMPT1.MD +70 -0
- package/build/ai/prompts/PROMPT2.md +159 -0
- package/build/ai/prompts/PROMPT3.md +64 -0
- package/build/ai/prompts/PROMPT4.md +64 -0
- package/build/ai/provider-factory.js +19 -0
- package/build/ai/providers/OllamaProvider.js +106 -0
- package/build/ai/render.js +157 -0
- package/build/ai/run-review.js +50 -0
- package/build/chunk/chunk_Restriction.js +202 -0
- package/build/hooks/Precommit/pre-commit-default.js +158 -140
- package/build/hooks/hook.js +6 -5
- package/build/lib/postinstall.js +6 -10
- package/build/mutation/branchDiff.js +178 -0
- package/build/mutation/fileResolver.js +170 -0
- package/build/mutation/index.js +16 -0
- package/build/mutation/mutatePattern.json +3 -0
- package/build/mutation/mutationCli.js +111 -0
- package/build/mutation/mutationRunner.js +208 -0
- package/build/mutation/reportGenerator.js +72 -0
- package/build/mutation/strykerWrapper.js +180 -0
- package/build/utils/FileAndFolderOperations/filterFiles.js +8 -6
- package/build/utils/FileAndFolderOperations/removeFolder.js +2 -2
- package/build/utils/General/Config.js +25 -0
- package/build/utils/General/SonarQubeUtil.js +1 -1
- package/jest.config.js +1 -1
- package/package.json +4 -1
- package/samples/sample-branch-mode.js +34 -0
- package/samples/sample-cli-entry.js +34 -0
- package/samples/sample-components.js +63 -0
- package/samples/sample-directory-mode.js +30 -0
- package/samples/sample-runner-direct.js +32 -0
- package/samples/sample-with-api.js +44 -0
package/bin/cliCI.js
CHANGED
|
File without changes
|
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const {
|
|
6
|
+
createProvider
|
|
7
|
+
} = require('./provider-factory');
|
|
8
|
+
const {
|
|
9
|
+
printMarkdown,
|
|
10
|
+
formatReviewResult,
|
|
11
|
+
renderMarkdown
|
|
12
|
+
} = require('./render');
|
|
13
|
+
function sanitizeStreamText(text) {
|
|
14
|
+
if (!text) return '';
|
|
15
|
+
return String(text).replace(/<think>[\s\S]*?<\/think>/gi, '').replace(/<\s*think[^>]*>/gi, '').replace(/<\/\s*think\s*>/gi, '').replace(/[^\S\r\n]+/g, ' ') // collapse excessive spaces
|
|
16
|
+
.replace(/\s*\n+\s*/g, '\n') // normalize newlines
|
|
17
|
+
.trim();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Ollama API Configuration Schema
|
|
22
|
+
* Ref: https://github.com/ollama/ollama/blob/main/docs/api.md#generate-a-completion
|
|
23
|
+
*/
|
|
24
|
+
const API_CONFIG_SCHEMA = {
|
|
25
|
+
baseUrl: {
|
|
26
|
+
type: 'string',
|
|
27
|
+
default: 'http://localhost:11434',
|
|
28
|
+
required: true
|
|
29
|
+
},
|
|
30
|
+
model: {
|
|
31
|
+
type: 'string',
|
|
32
|
+
default: 'codellama',
|
|
33
|
+
required: true
|
|
34
|
+
},
|
|
35
|
+
endpoint: {
|
|
36
|
+
type: 'string',
|
|
37
|
+
default: '/api/generate',
|
|
38
|
+
required: true
|
|
39
|
+
},
|
|
40
|
+
temperature: {
|
|
41
|
+
type: 'number',
|
|
42
|
+
default: 0.3,
|
|
43
|
+
min: 0,
|
|
44
|
+
max: 1
|
|
45
|
+
},
|
|
46
|
+
maxTokens: {
|
|
47
|
+
type: 'number',
|
|
48
|
+
default: 4096,
|
|
49
|
+
min: 256,
|
|
50
|
+
max: 16384
|
|
51
|
+
},
|
|
52
|
+
timeoutMs: {
|
|
53
|
+
type: 'number',
|
|
54
|
+
default: 120000
|
|
55
|
+
},
|
|
56
|
+
stream: {
|
|
57
|
+
type: 'boolean',
|
|
58
|
+
default: true
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Reads all .md files from a folder, sorted alphabetically, and concatenates their content.
|
|
64
|
+
* @param {string} promptFolder - Absolute or relative path to the prompts folder
|
|
65
|
+
* @returns {string} Combined prompt text
|
|
66
|
+
*/
|
|
67
|
+
function loadPromptsFromFolder(promptFolder) {
|
|
68
|
+
const resolvedPath = path.resolve(promptFolder);
|
|
69
|
+
if (!fs.existsSync(resolvedPath)) {
|
|
70
|
+
throw new Error(`Prompt folder not found: "${resolvedPath}"`);
|
|
71
|
+
}
|
|
72
|
+
const stat = fs.statSync(resolvedPath);
|
|
73
|
+
if (!stat.isDirectory()) {
|
|
74
|
+
throw new Error(`Prompt path is not a directory: "${resolvedPath}"`);
|
|
75
|
+
}
|
|
76
|
+
const mdFiles = fs.readdirSync(resolvedPath).filter(file => path.extname(file).toLowerCase() === '.md').sort();
|
|
77
|
+
if (mdFiles.length === 0) {
|
|
78
|
+
throw new Error(`No .md prompt files found in: "${resolvedPath}"`);
|
|
79
|
+
}
|
|
80
|
+
const combined = mdFiles.map(file => {
|
|
81
|
+
const filePath = path.join(resolvedPath, file);
|
|
82
|
+
const content = fs.readFileSync(filePath, 'utf-8').trim();
|
|
83
|
+
return `<!-- prompt: ${file} -->\n${content}`;
|
|
84
|
+
});
|
|
85
|
+
return combined.join('\n\n');
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Reads a single file and returns its content with metadata.
|
|
90
|
+
* @param {string} filePath
|
|
91
|
+
* @returns {{ filePath: string, fileName: string, content: string, extension: string }}
|
|
92
|
+
*/
|
|
93
|
+
function readFileForReview(filePath) {
|
|
94
|
+
const resolvedPath = path.resolve(filePath);
|
|
95
|
+
if (!fs.existsSync(resolvedPath)) {
|
|
96
|
+
throw new Error(`File not found: "${resolvedPath}"`);
|
|
97
|
+
}
|
|
98
|
+
const stat = fs.statSync(resolvedPath);
|
|
99
|
+
if (!stat.isFile()) {
|
|
100
|
+
throw new Error(`Path is not a file: "${resolvedPath}"`);
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
filePath: resolvedPath,
|
|
104
|
+
fileName: path.basename(resolvedPath),
|
|
105
|
+
content: fs.readFileSync(resolvedPath, 'utf-8'),
|
|
106
|
+
extension: path.extname(resolvedPath).slice(1)
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Reads all files from a folder (non-recursive) for review.
|
|
112
|
+
* @param {string} folderPath
|
|
113
|
+
* @param {string[]} [extensions] - Optional filter, e.g. ['.js', '.ts']
|
|
114
|
+
* @returns {Array<{ filePath: string, fileName: string, content: string, extension: string }>}
|
|
115
|
+
*/
|
|
116
|
+
function readFilesFromFolder(folderPath, extensions = []) {
|
|
117
|
+
const resolvedPath = path.resolve(folderPath);
|
|
118
|
+
if (!fs.existsSync(resolvedPath)) {
|
|
119
|
+
throw new Error(`Folder not found: "${resolvedPath}"`);
|
|
120
|
+
}
|
|
121
|
+
const stat = fs.statSync(resolvedPath);
|
|
122
|
+
if (!stat.isDirectory()) {
|
|
123
|
+
throw new Error(`Path is not a directory: "${resolvedPath}"`);
|
|
124
|
+
}
|
|
125
|
+
const entries = fs.readdirSync(resolvedPath);
|
|
126
|
+
return entries.filter(entry => {
|
|
127
|
+
const fullPath = path.join(resolvedPath, entry);
|
|
128
|
+
if (!fs.statSync(fullPath).isFile()) return false;
|
|
129
|
+
if (extensions.length === 0) return true;
|
|
130
|
+
return extensions.includes(path.extname(entry).toLowerCase());
|
|
131
|
+
}).map(entry => readFileForReview(path.join(resolvedPath, entry)));
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Validates and merges user config with schema defaults.
|
|
136
|
+
* @param {Object} userConfig
|
|
137
|
+
* @returns {Object} validated config
|
|
138
|
+
*/
|
|
139
|
+
function buildConfig(userConfig = {}) {
|
|
140
|
+
const config = {};
|
|
141
|
+
|
|
142
|
+
// Pass through provider field for factory
|
|
143
|
+
if (userConfig.provider) {
|
|
144
|
+
config.provider = userConfig.provider;
|
|
145
|
+
}
|
|
146
|
+
for (const [key, schema] of Object.entries(API_CONFIG_SCHEMA)) {
|
|
147
|
+
const value = userConfig[key];
|
|
148
|
+
if (value === undefined || value === null) {
|
|
149
|
+
if (schema.required && schema.default === undefined) {
|
|
150
|
+
throw new Error(`Missing required config: "${key}"`);
|
|
151
|
+
}
|
|
152
|
+
config[key] = schema.default;
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
if (typeof value !== schema.type) {
|
|
156
|
+
throw new TypeError(`Config "${key}" must be of type ${schema.type}, got ${typeof value}`);
|
|
157
|
+
}
|
|
158
|
+
if (schema.min !== undefined && value < schema.min) {
|
|
159
|
+
throw new RangeError(`Config "${key}" must be >= ${schema.min}`);
|
|
160
|
+
}
|
|
161
|
+
if (schema.max !== undefined && value > schema.max) {
|
|
162
|
+
throw new RangeError(`Config "${key}" must be <= ${schema.max}`);
|
|
163
|
+
}
|
|
164
|
+
config[key] = value;
|
|
165
|
+
}
|
|
166
|
+
return config;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Builds the full review prompt with injected code.
|
|
171
|
+
* Uses custom prompt from folder if provided, otherwise falls back to default.
|
|
172
|
+
* @param {string} code - The source code to inject
|
|
173
|
+
* @param {string} [promptFolder] - Optional path to folder containing .md prompt files
|
|
174
|
+
* @returns {string}
|
|
175
|
+
*/
|
|
176
|
+
function buildPrompt(code, promptFolder) {
|
|
177
|
+
if (!code || typeof code !== 'string') {
|
|
178
|
+
throw new Error('Code input must be a non-empty string');
|
|
179
|
+
}
|
|
180
|
+
let basePrompt;
|
|
181
|
+
if (promptFolder) {
|
|
182
|
+
basePrompt = loadPromptsFromFolder(promptFolder);
|
|
183
|
+
if (!basePrompt.includes('{{CODE}}')) {
|
|
184
|
+
basePrompt += `\n\n## Code to Review\n\`\`\`\n{{CODE}}\n\`\`\``;
|
|
185
|
+
}
|
|
186
|
+
} else {
|
|
187
|
+
basePrompt = DEFAULT_REVIEW_PROMPT + `\n\n## Code to Review\n\`\`\`\n{{CODE}}\n\`\`\``;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Force JSON-only output instruction at the end to reduce drift
|
|
191
|
+
basePrompt += `
|
|
192
|
+
|
|
193
|
+
CRITICAL: Output ONLY a single valid JSON object. No markdown, tables, or extra text. If streaming, emit NDJSON lines containing only JSON fragments or the final JSON object. Do not include <think> or hidden content.`;
|
|
194
|
+
return basePrompt.replace('{{CODE}}', code.trim());
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Parses JSON from Ollama response text, handling markdown fences.
|
|
199
|
+
* @param {string} text
|
|
200
|
+
* @param {Object} options
|
|
201
|
+
* @returns {Object}
|
|
202
|
+
*/
|
|
203
|
+
function parseReviewResponse(text, {
|
|
204
|
+
fileName
|
|
205
|
+
}) {
|
|
206
|
+
let cleaned = text.trim();
|
|
207
|
+
|
|
208
|
+
//Strip <think>...</think> blocks (deepseek-r1 reasoning)
|
|
209
|
+
cleaned = cleaned.replace(/<think>[\s\S]*?<\/think>/gi, '').trim();
|
|
210
|
+
|
|
211
|
+
// Strip markdown code fences and extract JSON
|
|
212
|
+
const jsonFenceMatch = cleaned.match(/```(?:json)?\s*([\s\S]*?)```/);
|
|
213
|
+
if (jsonFenceMatch) {
|
|
214
|
+
cleaned = jsonFenceMatch[1].trim();
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Try to find a JSON object anywhere in the text
|
|
218
|
+
if (!cleaned.startsWith('{')) {
|
|
219
|
+
const jsonObjectMatch = cleaned.match(/(\{[\s\S]*\})/);
|
|
220
|
+
if (jsonObjectMatch) {
|
|
221
|
+
cleaned = jsonObjectMatch[1].trim();
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
try {
|
|
225
|
+
const parsed = JSON.parse(cleaned);
|
|
226
|
+
parsed.fileName = fileName;
|
|
227
|
+
return parsed;
|
|
228
|
+
} catch {
|
|
229
|
+
return {
|
|
230
|
+
fileName,
|
|
231
|
+
overallScore: null,
|
|
232
|
+
categories: null,
|
|
233
|
+
criticalIssues: [],
|
|
234
|
+
suggestions: [],
|
|
235
|
+
summary: cleaned,
|
|
236
|
+
rawResponse: true
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Fetches a code review from the configured AI provider.
|
|
243
|
+
*
|
|
244
|
+
* @param {string} code - Source code to review
|
|
245
|
+
* @param {Object} [options]
|
|
246
|
+
* @param {Object} [options.config] - API config overrides
|
|
247
|
+
* @param {string} [options.promptFolder] - Path to folder with .md prompt files
|
|
248
|
+
* @param {string} [options.fileName] - Original file name for context
|
|
249
|
+
* @param {Function} [options.onToken] - Callback for streaming tokens
|
|
250
|
+
* @returns {Promise<Object>} Structured review result
|
|
251
|
+
*/
|
|
252
|
+
async function fetchCodeReview(code, options = {}) {
|
|
253
|
+
const {
|
|
254
|
+
config: userConfig = {},
|
|
255
|
+
promptFolder,
|
|
256
|
+
fileName,
|
|
257
|
+
onToken
|
|
258
|
+
} = options;
|
|
259
|
+
const config = buildConfig(userConfig);
|
|
260
|
+
const codeWithContext = fileName ? `// File: ${fileName}\n${code}` : code;
|
|
261
|
+
const prompt = buildPrompt(codeWithContext, promptFolder);
|
|
262
|
+
const provider = createProvider(config);
|
|
263
|
+
const {
|
|
264
|
+
text
|
|
265
|
+
} = await provider.generate({
|
|
266
|
+
prompt,
|
|
267
|
+
fileName,
|
|
268
|
+
onToken: chunk => {
|
|
269
|
+
// Forward raw token directly — let the caller decide how to handle it
|
|
270
|
+
if (chunk && typeof onToken === 'function') onToken(chunk);
|
|
271
|
+
}
|
|
272
|
+
});
|
|
273
|
+
const cleanText = sanitizeStreamText(text);
|
|
274
|
+
return parseReviewResponse(cleanText, {
|
|
275
|
+
fileName
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Reviews a single file by path.
|
|
281
|
+
* @param {string} filePath - Path to the file to review
|
|
282
|
+
* @param {Object} [options]
|
|
283
|
+
* @param {Object} [options.config] - API config overrides
|
|
284
|
+
* @param {string} [options.promptFolder] - Path to folder with .md prompt files
|
|
285
|
+
* @param {Function} [options.onToken] - Callback for streaming tokens
|
|
286
|
+
* @returns {Promise<Object>}
|
|
287
|
+
*/
|
|
288
|
+
async function reviewFile(filePath, options = {}) {
|
|
289
|
+
const file = readFileForReview(filePath);
|
|
290
|
+
return fetchCodeReview(file.content, {
|
|
291
|
+
...options,
|
|
292
|
+
fileName: file.fileName
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Reviews multiple files by their paths.
|
|
298
|
+
* @param {string[]} filePaths - Array of file paths to review
|
|
299
|
+
* @param {Object} [options]
|
|
300
|
+
* @param {Object} [options.config] - API config overrides
|
|
301
|
+
* @param {string} [options.promptFolder] - Path to folder with .md prompt files
|
|
302
|
+
* @param {number} [options.concurrency=1] - Number of concurrent reviews
|
|
303
|
+
* @param {boolean} [options.streamToConsole] - Whether to stream tokens to stdout
|
|
304
|
+
* @param {Function} [options.onResult] - Callback per completed review
|
|
305
|
+
* @returns {Promise<Object[]>} Array of review results
|
|
306
|
+
*/
|
|
307
|
+
async function reviewFiles(filePaths, options = {}) {
|
|
308
|
+
const {
|
|
309
|
+
concurrency = 1,
|
|
310
|
+
onResult,
|
|
311
|
+
streamToConsole,
|
|
312
|
+
...reviewOptions
|
|
313
|
+
} = options;
|
|
314
|
+
const results = [];
|
|
315
|
+
for (let i = 0; i < filePaths.length; i += concurrency) {
|
|
316
|
+
const batch = filePaths.slice(i, i + concurrency);
|
|
317
|
+
const promises = batch.map(fp => reviewFile(fp, {
|
|
318
|
+
...reviewOptions,
|
|
319
|
+
onToken: token => {
|
|
320
|
+
if (!streamToConsole) return;
|
|
321
|
+
if (!token) return;
|
|
322
|
+
// Write raw token directly to stdout during streaming
|
|
323
|
+
process.stdout.write(token);
|
|
324
|
+
}
|
|
325
|
+
}).then(value => {
|
|
326
|
+
// Print newline after stream ends for this file
|
|
327
|
+
if (streamToConsole) process.stdout.write('\n');
|
|
328
|
+
return {
|
|
329
|
+
status: 'fulfilled',
|
|
330
|
+
value,
|
|
331
|
+
filePath: fp
|
|
332
|
+
};
|
|
333
|
+
}).catch(error => {
|
|
334
|
+
if (streamToConsole) process.stdout.write('\n');
|
|
335
|
+
return {
|
|
336
|
+
status: 'rejected',
|
|
337
|
+
reason: error,
|
|
338
|
+
filePath: fp
|
|
339
|
+
};
|
|
340
|
+
}));
|
|
341
|
+
for (const p of promises) {
|
|
342
|
+
p.then(r => {
|
|
343
|
+
let out;
|
|
344
|
+
if (r.status === 'fulfilled') {
|
|
345
|
+
out = typeof r.value === 'string' ? {
|
|
346
|
+
message: sanitizeStreamText(r.value)
|
|
347
|
+
} : r.value;
|
|
348
|
+
results.push(out);
|
|
349
|
+
} else {
|
|
350
|
+
var _r$reason;
|
|
351
|
+
const fp = r.filePath;
|
|
352
|
+
out = {
|
|
353
|
+
success: false,
|
|
354
|
+
fileName: path.basename(fp),
|
|
355
|
+
filePath: fp,
|
|
356
|
+
error: ((_r$reason = r.reason) === null || _r$reason === void 0 ? void 0 : _r$reason.message) || r.reason || 'Unknown error'
|
|
357
|
+
};
|
|
358
|
+
results.push(out);
|
|
359
|
+
}
|
|
360
|
+
if (typeof onResult === 'function') {
|
|
361
|
+
try {
|
|
362
|
+
onResult(out);
|
|
363
|
+
} catch {}
|
|
364
|
+
}
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
await Promise.allSettled(promises);
|
|
368
|
+
}
|
|
369
|
+
return results;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Reviews all files in a folder.
|
|
374
|
+
* @param {string} folderPath - Path to folder containing files to review
|
|
375
|
+
* @param {Object} [options]
|
|
376
|
+
* @param {Object} [options.config] - API config overrides
|
|
377
|
+
* @param {string} [options.promptFolder] - Path to folder with .md prompt files
|
|
378
|
+
* @param {string[]} [options.extensions] - File extensions to include, e.g. ['.js', '.ts']
|
|
379
|
+
* @param {number} [options.concurrency=1] - Number of concurrent reviews
|
|
380
|
+
* @returns {Promise<Object[]>}
|
|
381
|
+
*/
|
|
382
|
+
async function reviewFolder(folderPath, options = {}) {
|
|
383
|
+
const {
|
|
384
|
+
extensions = [],
|
|
385
|
+
...rest
|
|
386
|
+
} = options;
|
|
387
|
+
const files = readFilesFromFolder(folderPath, extensions);
|
|
388
|
+
const filePaths = files.map(f => f.filePath);
|
|
389
|
+
return reviewFiles(filePaths, rest);
|
|
390
|
+
}
|
|
391
|
+
module.exports = {
|
|
392
|
+
API_CONFIG_SCHEMA,
|
|
393
|
+
loadPromptsFromFolder,
|
|
394
|
+
readFileForReview,
|
|
395
|
+
readFilesFromFolder,
|
|
396
|
+
buildConfig,
|
|
397
|
+
buildPrompt,
|
|
398
|
+
parseReviewResponse,
|
|
399
|
+
fetchCodeReview,
|
|
400
|
+
reviewFile,
|
|
401
|
+
reviewFiles,
|
|
402
|
+
reviewFolder
|
|
403
|
+
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
You are an expert code reviewer. Analyze the provided code against the following 50-point checklist.
|
|
2
|
+
Score each applicable category (1-10) and provide specific feedback.
|
|
3
|
+
|
|
4
|
+
**CRITICAL INSTRUCTION: Your entire response MUST be a single valid JSON object. No explanation, no commentary, no markdown outside the JSON. Do not wrap in code fences. Output ONLY the JSON object.**
|
|
5
|
+
|
|
6
|
+
## Review Categories
|
|
7
|
+
|
|
8
|
+
### 1. Code Quality (10 points)
|
|
9
|
+
1. Readability and clarity
|
|
10
|
+
2. Consistent naming conventions
|
|
11
|
+
3. Proper use of comments and documentation
|
|
12
|
+
4. Code simplicity (no unnecessary complexity)
|
|
13
|
+
5. DRY principle adherence
|
|
14
|
+
6. Single Responsibility Principle
|
|
15
|
+
7. Proper abstraction levels
|
|
16
|
+
8. Clean function/method signatures
|
|
17
|
+
9. Appropriate use of constants vs magic numbers
|
|
18
|
+
10. Code formatting and indentation
|
|
19
|
+
|
|
20
|
+
### 2. Error Handling (10 points)
|
|
21
|
+
11. Proper try-catch usage
|
|
22
|
+
12. Meaningful error messages
|
|
23
|
+
13. Graceful degradation
|
|
24
|
+
14. Input validation
|
|
25
|
+
15. Null/undefined safety
|
|
26
|
+
16. Boundary condition handling
|
|
27
|
+
17. Async error handling
|
|
28
|
+
18. Error propagation strategy
|
|
29
|
+
19. Logging of errors
|
|
30
|
+
20. User-facing error responses
|
|
31
|
+
|
|
32
|
+
### 3. Performance (10 points)
|
|
33
|
+
21. Algorithm efficiency (time complexity)
|
|
34
|
+
22. Memory usage optimization
|
|
35
|
+
23. Avoiding unnecessary computations
|
|
36
|
+
24. Efficient data structures
|
|
37
|
+
25. Lazy loading / deferred execution
|
|
38
|
+
26. Caching strategy
|
|
39
|
+
27. Loop optimization
|
|
40
|
+
28. Avoiding memory leaks
|
|
41
|
+
29. Database/API call optimization
|
|
42
|
+
30. Bundle size / import efficiency
|
|
43
|
+
|
|
44
|
+
### 4. Security (10 points)
|
|
45
|
+
31. Input sanitization
|
|
46
|
+
32. SQL/NoSQL injection prevention
|
|
47
|
+
33. XSS prevention
|
|
48
|
+
34. Authentication/authorization checks
|
|
49
|
+
35. Sensitive data exposure
|
|
50
|
+
36. Dependency vulnerability awareness
|
|
51
|
+
37. CSRF protection
|
|
52
|
+
38. Secure communication (HTTPS, encryption)
|
|
53
|
+
39. Proper secret management
|
|
54
|
+
40. Rate limiting / abuse prevention
|
|
55
|
+
|
|
56
|
+
### 5. Maintainability (10 points)
|
|
57
|
+
41. Modularity and reusability
|
|
58
|
+
42. Testability
|
|
59
|
+
43. Configuration externalization
|
|
60
|
+
44. Dependency management
|
|
61
|
+
45. Version compatibility
|
|
62
|
+
46. Backward compatibility
|
|
63
|
+
47. Documentation completeness
|
|
64
|
+
48. Changelog / migration notes
|
|
65
|
+
49. Linting / formatting rules followed
|
|
66
|
+
50. CI/CD readiness
|
|
67
|
+
|
|
68
|
+
## Required Output
|
|
69
|
+
|
|
70
|
+
Respond with ONLY this JSON structure (no other text before or after):
|
|
71
|
+
{"overallScore":<number 0-50>,"categories":{"codeQuality":{"score":<0-10>,"issues":[<string>,…]},"errorHandling":{"score":<0-10>,"issues":[<string>,…]},"performance":{"score":<0-10>,"issues":[<string>,…]},"security":{"score":<0-10>,"issues":[<string>,…]},"maintainability":{"score":<0-10>,"issues":[<string>,…]}},"criticalIssues":[<string>,…],"suggestions":[<string>,…],"summary":"<brief overall summary>"}
|
|
72
|
+
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
## Components & CSS Files Review Checklist
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
## Folder Structure Validation
|
|
5
|
+
All UAT-related files must be placed under the `{appName}/uat` directory.
|
|
6
|
+
|
|
7
|
+
The structure must follow:
|
|
8
|
+
- `{ComponentName}.css` – File names ends with
|
|
9
|
+
- it should closet to compponet file
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
### 1. Prop Types Definition
|
|
13
|
+
Props must be defined with types in `{ComponentName}.propTypes.js`.
|
|
14
|
+
Prop names must be raw, common HTML-based names and not application-specific.
|
|
15
|
+
|
|
16
|
+
### 2. Component Structure
|
|
17
|
+
`{ComponentName}.propTypes.js` must be imported into `{ComponentName}.js`.
|
|
18
|
+
Component name must start with a capital letter and must be a functional component (no class components).
|
|
19
|
+
|
|
20
|
+
### 3. Component Purity
|
|
21
|
+
No Redux, state, or application logic is allowed in `{ComponentName}.js`.
|
|
22
|
+
Hook or functional logic must be moved to `{ComponentName}.behaviour.js` or `{ComponentName}.hook.js` and imported.
|
|
23
|
+
|
|
24
|
+
### 4. Code Cleanliness
|
|
25
|
+
No duplicate lines, unused variables, unused methods, unused imports, or commented code.
|
|
26
|
+
Keep the component clean and minimal.
|
|
27
|
+
|
|
28
|
+
### 5. Linting & Hooks Validation
|
|
29
|
+
Code must pass linter checks.
|
|
30
|
+
React hooks must follow proper usage rules and performance best practices.
|
|
31
|
+
|
|
32
|
+
### 6. CSS Imports
|
|
33
|
+
CSS files must be imported as `styles` from `./{ComponentName}.css` in `{ComponentName}.js`
|
|
34
|
+
Other naming conventions are allowed if consistently used.
|
|
35
|
+
|
|
36
|
+
### 7. CSS Standards & Naming
|
|
37
|
+
CSS must follow BEM naming conventions and be compatible with CSS Modules.
|
|
38
|
+
Class names must be HTML/component-based and not application-specific.
|
|
39
|
+
|
|
40
|
+
### 8. CSS Variables & Layout Rules
|
|
41
|
+
All colors, fonts, widths, heights, and spacing must use variables only.
|
|
42
|
+
Width and height definitions must include appropriate min and max values.
|
|
43
|
+
|
|
44
|
+
### 9. CSS Selector Rules
|
|
45
|
+
Do not use units with zero values (`0` instead of `0px` or `0rem`).
|
|
46
|
+
Limit selector nesting depth to the allowed maximum.
|
|
47
|
+
Do not use ID selectors—use class selectors only.
|
|
48
|
+
Do not use TAG selectors—use class selectors only. if required the file line must have proper comment.
|
|
49
|
+
|
|
50
|
+
### 10. CSS Quality Rules
|
|
51
|
+
Avoid adjoining class selectors and prefer reusable single classes.
|
|
52
|
+
Avoid duplicate CSS properties, empty blocks, empty values, unknown or misspelled properties.
|
|
53
|
+
Do not use `!important`; if required, add a same-line comment explaining why.
|
|
54
|
+
|
|
55
|
+
### 11. CSS Content Rules
|
|
56
|
+
Always use double quotes for the `content` property.
|
|
57
|
+
Only valid and supported CSS properties are allowed.
|
|
58
|
+
|
|
59
|
+
### 12. HTML & Accessibility
|
|
60
|
+
HTML must follow accessibility (a11y) standards.
|
|
61
|
+
Avoid duplicate attributes and follow semantic HTML.
|
|
62
|
+
Reuse existing Haas or common components instead of rewriting code.
|
|
63
|
+
|
|
64
|
+
### 13. Events & Text Handling
|
|
65
|
+
Event bindings must not create new inline functions.
|
|
66
|
+
No hard-coded English text is allowed; all text must be passed via props.
|
|
67
|
+
|
|
68
|
+
### 14. Documentation
|
|
69
|
+
A `{ComponentName}.docs.js` file must be added and used for documentation.
|
|
70
|
+
Component usage and behavior must be clearly documented.
|