@aiready/consistency 0.3.3 → 0.3.5
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/.turbo/turbo-build.log +7 -7
- package/.turbo/turbo-test.log +19 -14
- package/README.md +55 -7
- package/dist/chunk-2BTBNG6X.mjs +814 -0
- package/dist/chunk-Q5XMWG33.mjs +661 -0
- package/dist/chunk-TLVLM3M5.mjs +771 -0
- package/dist/cli.js +358 -52
- package/dist/cli.mjs +1 -1
- package/dist/index.js +355 -49
- package/dist/index.mjs +1 -1
- package/package.json +2 -2
- package/src/__tests__/analyzer.test.ts +41 -1
- package/src/analyzers/naming.ts +250 -65
package/dist/index.js
CHANGED
|
@@ -32,12 +32,155 @@ var import_core3 = require("@aiready/core");
|
|
|
32
32
|
|
|
33
33
|
// src/analyzers/naming.ts
|
|
34
34
|
var import_core = require("@aiready/core");
|
|
35
|
+
var import_path = require("path");
|
|
36
|
+
var COMMON_SHORT_WORDS = /* @__PURE__ */ new Set([
|
|
37
|
+
// Full English words (1-3 letters)
|
|
38
|
+
"day",
|
|
39
|
+
"key",
|
|
40
|
+
"net",
|
|
41
|
+
"to",
|
|
42
|
+
"go",
|
|
43
|
+
"for",
|
|
44
|
+
"not",
|
|
45
|
+
"new",
|
|
46
|
+
"old",
|
|
47
|
+
"top",
|
|
48
|
+
"end",
|
|
49
|
+
"run",
|
|
50
|
+
"try",
|
|
51
|
+
"use",
|
|
52
|
+
"get",
|
|
53
|
+
"set",
|
|
54
|
+
"add",
|
|
55
|
+
"put",
|
|
56
|
+
"map",
|
|
57
|
+
"log",
|
|
58
|
+
"row",
|
|
59
|
+
"col",
|
|
60
|
+
"tab",
|
|
61
|
+
"box",
|
|
62
|
+
"div",
|
|
63
|
+
"nav",
|
|
64
|
+
"tag",
|
|
65
|
+
"any",
|
|
66
|
+
"all",
|
|
67
|
+
"one",
|
|
68
|
+
"two",
|
|
69
|
+
"out",
|
|
70
|
+
"off",
|
|
71
|
+
"on",
|
|
72
|
+
"yes",
|
|
73
|
+
"no",
|
|
74
|
+
"now",
|
|
75
|
+
"max",
|
|
76
|
+
"min",
|
|
77
|
+
"sum",
|
|
78
|
+
"avg",
|
|
79
|
+
"ref",
|
|
80
|
+
"src",
|
|
81
|
+
"dst",
|
|
82
|
+
"raw",
|
|
83
|
+
"def",
|
|
84
|
+
"sub",
|
|
85
|
+
"pub",
|
|
86
|
+
"pre",
|
|
87
|
+
"mid",
|
|
88
|
+
"alt",
|
|
89
|
+
"opt",
|
|
90
|
+
"tmp",
|
|
91
|
+
"ext",
|
|
92
|
+
"sep",
|
|
93
|
+
// Additional full words commonly flagged
|
|
94
|
+
"tax",
|
|
95
|
+
"cat",
|
|
96
|
+
"dog",
|
|
97
|
+
"car",
|
|
98
|
+
"bus",
|
|
99
|
+
"web",
|
|
100
|
+
"app",
|
|
101
|
+
"war",
|
|
102
|
+
"law",
|
|
103
|
+
"pay",
|
|
104
|
+
"buy",
|
|
105
|
+
"win",
|
|
106
|
+
"cut",
|
|
107
|
+
"hit",
|
|
108
|
+
"hot",
|
|
109
|
+
"pop",
|
|
110
|
+
"job",
|
|
111
|
+
"age",
|
|
112
|
+
"act",
|
|
113
|
+
"let",
|
|
114
|
+
"lot",
|
|
115
|
+
"bad",
|
|
116
|
+
"big",
|
|
117
|
+
"far",
|
|
118
|
+
"few",
|
|
119
|
+
"own",
|
|
120
|
+
"per",
|
|
121
|
+
"red",
|
|
122
|
+
"low",
|
|
123
|
+
"see",
|
|
124
|
+
"six",
|
|
125
|
+
"ten",
|
|
126
|
+
"way",
|
|
127
|
+
"who",
|
|
128
|
+
"why",
|
|
129
|
+
"yet",
|
|
130
|
+
"via",
|
|
131
|
+
"due",
|
|
132
|
+
"fee",
|
|
133
|
+
"fun",
|
|
134
|
+
"gas",
|
|
135
|
+
"gay",
|
|
136
|
+
"god",
|
|
137
|
+
"gun",
|
|
138
|
+
"guy",
|
|
139
|
+
"ice",
|
|
140
|
+
"ill",
|
|
141
|
+
"kid",
|
|
142
|
+
"mad",
|
|
143
|
+
"man",
|
|
144
|
+
"mix",
|
|
145
|
+
"mom",
|
|
146
|
+
"mrs",
|
|
147
|
+
"nor",
|
|
148
|
+
"odd",
|
|
149
|
+
"oil",
|
|
150
|
+
"pan",
|
|
151
|
+
"pet",
|
|
152
|
+
"pit",
|
|
153
|
+
"pot",
|
|
154
|
+
"pow",
|
|
155
|
+
"pro",
|
|
156
|
+
"raw",
|
|
157
|
+
"rep",
|
|
158
|
+
"rid",
|
|
159
|
+
"sad",
|
|
160
|
+
"sea",
|
|
161
|
+
"sit",
|
|
162
|
+
"sky",
|
|
163
|
+
"son",
|
|
164
|
+
"tea",
|
|
165
|
+
"tie",
|
|
166
|
+
"tip",
|
|
167
|
+
"van",
|
|
168
|
+
"war",
|
|
169
|
+
"win",
|
|
170
|
+
"won"
|
|
171
|
+
]);
|
|
35
172
|
var ACCEPTABLE_ABBREVIATIONS = /* @__PURE__ */ new Set([
|
|
36
173
|
// Standard identifiers
|
|
37
174
|
"id",
|
|
38
175
|
"uid",
|
|
39
176
|
"gid",
|
|
40
177
|
"pid",
|
|
178
|
+
// Loop counters and iterators
|
|
179
|
+
"i",
|
|
180
|
+
"j",
|
|
181
|
+
"k",
|
|
182
|
+
"n",
|
|
183
|
+
"m",
|
|
41
184
|
// Web/Network
|
|
42
185
|
"url",
|
|
43
186
|
"uri",
|
|
@@ -55,6 +198,9 @@ var ACCEPTABLE_ABBREVIATIONS = /* @__PURE__ */ new Set([
|
|
|
55
198
|
"rss",
|
|
56
199
|
"xhr",
|
|
57
200
|
"ajax",
|
|
201
|
+
"cors",
|
|
202
|
+
"ws",
|
|
203
|
+
"wss",
|
|
58
204
|
// Data formats
|
|
59
205
|
"json",
|
|
60
206
|
"xml",
|
|
@@ -64,12 +210,27 @@ var ACCEPTABLE_ABBREVIATIONS = /* @__PURE__ */ new Set([
|
|
|
64
210
|
"css",
|
|
65
211
|
"svg",
|
|
66
212
|
"pdf",
|
|
213
|
+
// File types & extensions
|
|
214
|
+
"img",
|
|
215
|
+
"txt",
|
|
216
|
+
"doc",
|
|
217
|
+
"docx",
|
|
218
|
+
"xlsx",
|
|
219
|
+
"ppt",
|
|
220
|
+
"md",
|
|
221
|
+
"rst",
|
|
222
|
+
"jpg",
|
|
223
|
+
"png",
|
|
224
|
+
"gif",
|
|
67
225
|
// Databases
|
|
68
226
|
"db",
|
|
69
227
|
"sql",
|
|
70
228
|
"orm",
|
|
71
229
|
"dao",
|
|
72
230
|
"dto",
|
|
231
|
+
"ddb",
|
|
232
|
+
"rds",
|
|
233
|
+
"nosql",
|
|
73
234
|
// File system
|
|
74
235
|
"fs",
|
|
75
236
|
"dir",
|
|
@@ -86,6 +247,8 @@ var ACCEPTABLE_ABBREVIATIONS = /* @__PURE__ */ new Set([
|
|
|
86
247
|
"cli",
|
|
87
248
|
"cmd",
|
|
88
249
|
"exe",
|
|
250
|
+
"cwd",
|
|
251
|
+
"pwd",
|
|
89
252
|
// UI/UX
|
|
90
253
|
"ui",
|
|
91
254
|
"ux",
|
|
@@ -98,6 +261,7 @@ var ACCEPTABLE_ABBREVIATIONS = /* @__PURE__ */ new Set([
|
|
|
98
261
|
"ctx",
|
|
99
262
|
"err",
|
|
100
263
|
"msg",
|
|
264
|
+
"auth",
|
|
101
265
|
// Mathematics/Computing
|
|
102
266
|
"max",
|
|
103
267
|
"min",
|
|
@@ -115,12 +279,17 @@ var ACCEPTABLE_ABBREVIATIONS = /* @__PURE__ */ new Set([
|
|
|
115
279
|
"var",
|
|
116
280
|
"int",
|
|
117
281
|
"num",
|
|
282
|
+
"idx",
|
|
118
283
|
// Time
|
|
119
284
|
"now",
|
|
120
285
|
"utc",
|
|
121
286
|
"tz",
|
|
122
287
|
"ms",
|
|
123
288
|
"sec",
|
|
289
|
+
"hr",
|
|
290
|
+
"min",
|
|
291
|
+
"yr",
|
|
292
|
+
"mo",
|
|
124
293
|
// Common patterns
|
|
125
294
|
"app",
|
|
126
295
|
"cfg",
|
|
@@ -140,47 +309,169 @@ var ACCEPTABLE_ABBREVIATIONS = /* @__PURE__ */ new Set([
|
|
|
140
309
|
"post",
|
|
141
310
|
"sub",
|
|
142
311
|
"pub",
|
|
312
|
+
// Programming/Framework specific
|
|
313
|
+
"ts",
|
|
314
|
+
"js",
|
|
315
|
+
"jsx",
|
|
316
|
+
"tsx",
|
|
317
|
+
"py",
|
|
318
|
+
"rb",
|
|
319
|
+
"vue",
|
|
320
|
+
"re",
|
|
321
|
+
"fn",
|
|
322
|
+
"fns",
|
|
323
|
+
"mod",
|
|
324
|
+
"opts",
|
|
325
|
+
"dev",
|
|
326
|
+
// Cloud/Infrastructure
|
|
327
|
+
"s3",
|
|
328
|
+
"ec2",
|
|
329
|
+
"sqs",
|
|
330
|
+
"sns",
|
|
331
|
+
"vpc",
|
|
332
|
+
"ami",
|
|
333
|
+
"iam",
|
|
334
|
+
"acl",
|
|
335
|
+
"elb",
|
|
336
|
+
"alb",
|
|
337
|
+
"nlb",
|
|
338
|
+
"aws",
|
|
339
|
+
// Metrics/Performance
|
|
340
|
+
"fcp",
|
|
341
|
+
"lcp",
|
|
342
|
+
"cls",
|
|
343
|
+
"ttfb",
|
|
344
|
+
"tti",
|
|
345
|
+
"fid",
|
|
346
|
+
"fps",
|
|
347
|
+
"qps",
|
|
348
|
+
"rps",
|
|
349
|
+
"tps",
|
|
350
|
+
// Testing & i18n
|
|
351
|
+
"po",
|
|
352
|
+
"e2e",
|
|
353
|
+
"a11y",
|
|
354
|
+
"i18n",
|
|
355
|
+
"l10n",
|
|
356
|
+
// Domain-specific abbreviations (context-aware)
|
|
357
|
+
"sk",
|
|
358
|
+
"fy",
|
|
359
|
+
"faq",
|
|
360
|
+
"og",
|
|
361
|
+
"seo",
|
|
362
|
+
"cta",
|
|
363
|
+
"roi",
|
|
364
|
+
"kpi",
|
|
143
365
|
// Boolean helpers (these are intentional short names)
|
|
144
366
|
"is",
|
|
145
367
|
"has",
|
|
146
368
|
"can",
|
|
147
369
|
"did",
|
|
148
370
|
"was",
|
|
149
|
-
"are"
|
|
371
|
+
"are",
|
|
372
|
+
// Date/Time context (when in date contexts)
|
|
373
|
+
"d",
|
|
374
|
+
"t",
|
|
375
|
+
"dt"
|
|
150
376
|
]);
|
|
151
377
|
async function analyzeNaming(files) {
|
|
152
378
|
const issues = [];
|
|
379
|
+
const rootDir = files.length > 0 ? (0, import_path.dirname)(files[0]) : process.cwd();
|
|
380
|
+
const config = (0, import_core.loadConfig)(rootDir);
|
|
381
|
+
const consistencyConfig = config?.tools?.["consistency"];
|
|
382
|
+
const customAbbreviations = new Set(consistencyConfig?.acceptedAbbreviations || []);
|
|
383
|
+
const customShortWords = new Set(consistencyConfig?.shortWords || []);
|
|
384
|
+
const disabledChecks = new Set(consistencyConfig?.disableChecks || []);
|
|
153
385
|
for (const file of files) {
|
|
154
386
|
const content = await (0, import_core.readFileContent)(file);
|
|
155
|
-
const fileIssues = analyzeFileNaming(file, content);
|
|
387
|
+
const fileIssues = analyzeFileNaming(file, content, customAbbreviations, customShortWords, disabledChecks);
|
|
156
388
|
issues.push(...fileIssues);
|
|
157
389
|
}
|
|
158
390
|
return issues;
|
|
159
391
|
}
|
|
160
|
-
function analyzeFileNaming(file, content) {
|
|
392
|
+
function analyzeFileNaming(file, content, customAbbreviations, customShortWords, disabledChecks) {
|
|
161
393
|
const issues = [];
|
|
394
|
+
const isTestFile = file.match(/\.(test|spec)\.(ts|tsx|js|jsx)$/);
|
|
162
395
|
const lines = content.split("\n");
|
|
396
|
+
const allAbbreviations = /* @__PURE__ */ new Set([...ACCEPTABLE_ABBREVIATIONS, ...customAbbreviations]);
|
|
397
|
+
const allShortWords = /* @__PURE__ */ new Set([...COMMON_SHORT_WORDS, ...customShortWords]);
|
|
398
|
+
const getContextWindow = (index, windowSize = 3) => {
|
|
399
|
+
const start = Math.max(0, index - windowSize);
|
|
400
|
+
const end = Math.min(lines.length, index + windowSize + 1);
|
|
401
|
+
return lines.slice(start, end).join("\n");
|
|
402
|
+
};
|
|
403
|
+
const isShortLivedVariable = (varName, declarationIndex) => {
|
|
404
|
+
const searchRange = 5;
|
|
405
|
+
const endIndex = Math.min(lines.length, declarationIndex + searchRange + 1);
|
|
406
|
+
let usageCount = 0;
|
|
407
|
+
for (let i = declarationIndex; i < endIndex; i++) {
|
|
408
|
+
const regex = new RegExp(`\\b${varName}\\b`, "g");
|
|
409
|
+
const matches = lines[i].match(regex);
|
|
410
|
+
if (matches) {
|
|
411
|
+
usageCount += matches.length;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
return usageCount >= 2 && usageCount <= 3;
|
|
415
|
+
};
|
|
163
416
|
lines.forEach((line, index) => {
|
|
164
417
|
const lineNumber = index + 1;
|
|
165
|
-
const
|
|
166
|
-
|
|
167
|
-
const
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
418
|
+
const contextWindow = getContextWindow(index);
|
|
419
|
+
if (!disabledChecks.has("single-letter")) {
|
|
420
|
+
const singleLetterMatches = line.matchAll(/\b(?:const|let|var)\s+([a-hm-z])\s*=/gi);
|
|
421
|
+
for (const match of singleLetterMatches) {
|
|
422
|
+
const letter = match[1].toLowerCase();
|
|
423
|
+
const isInLoopContext = line.includes("for") || /\.(map|filter|forEach|reduce|find|some|every)\s*\(/.test(line) || line.includes("=>") || // Arrow function
|
|
424
|
+
/\w+\s*=>\s*/.test(line);
|
|
425
|
+
const isI18nContext = line.includes("useTranslation") || line.includes("i18n.t") || /\bt\s*\(['"]/.test(line);
|
|
426
|
+
const isArrowFunctionParam = /\(\s*[a-z]\s*(?:,\s*[a-z]\s*)*\)\s*=>/.test(line) || // (s) => or (a, b) =>
|
|
427
|
+
/[a-z]\s*=>/.test(line) || // s => on same line
|
|
428
|
+
// Multi-line arrow function detection: look for pattern in context window
|
|
429
|
+
new RegExp(`\\b${letter}\\s*\\)\\s*$`).test(line) && /=>/.test(contextWindow) || // (s)\n =>
|
|
430
|
+
new RegExp(`\\.(?:map|filter|forEach|reduce|find|some|every)\\s*\\(\\s*$`).test(lines[index - 1] || "") && /=>/.test(contextWindow);
|
|
431
|
+
const isShortLived = isShortLivedVariable(letter, index);
|
|
432
|
+
if (!isInLoopContext && !isI18nContext && !isArrowFunctionParam && !isShortLived && !["x", "y", "z", "i", "j", "k", "l", "n", "m"].includes(letter)) {
|
|
433
|
+
if (isTestFile && ["a", "b", "c", "d", "e", "f", "s"].includes(letter)) {
|
|
434
|
+
continue;
|
|
435
|
+
}
|
|
436
|
+
issues.push({
|
|
437
|
+
file,
|
|
438
|
+
line: lineNumber,
|
|
439
|
+
type: "poor-naming",
|
|
440
|
+
identifier: match[1],
|
|
441
|
+
severity: "minor",
|
|
442
|
+
suggestion: `Use descriptive variable name instead of single letter '${match[1]}'`
|
|
443
|
+
});
|
|
444
|
+
}
|
|
178
445
|
}
|
|
179
446
|
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
const
|
|
183
|
-
|
|
447
|
+
if (!disabledChecks.has("abbreviation")) {
|
|
448
|
+
const abbreviationMatches = line.matchAll(/\b(?:const|let|var)\s+([a-z]{1,3})(?=[A-Z]|_|\s*=)/g);
|
|
449
|
+
for (const match of abbreviationMatches) {
|
|
450
|
+
const abbrev = match[1].toLowerCase();
|
|
451
|
+
if (allShortWords.has(abbrev)) {
|
|
452
|
+
continue;
|
|
453
|
+
}
|
|
454
|
+
if (allAbbreviations.has(abbrev)) {
|
|
455
|
+
continue;
|
|
456
|
+
}
|
|
457
|
+
const isArrowFunctionParam = /\(\s*[a-z]\s*(?:,\s*[a-z]\s*)*\)\s*=>/.test(line) || // (s) => or (a, b) =>
|
|
458
|
+
new RegExp(`\\b${abbrev}\\s*=>`).test(line) || // s => on same line
|
|
459
|
+
// Multi-line arrow function: check context window
|
|
460
|
+
new RegExp(`\\b${abbrev}\\s*\\)\\s*$`).test(line) && /=>/.test(contextWindow) || // (s)\n =>
|
|
461
|
+
new RegExp(`\\.(?:map|filter|forEach|reduce|find|some|every)\\s*\\(\\s*$`).test(lines[index - 1] || "") && new RegExp(`^\\s*${abbrev}\\s*=>`).test(line);
|
|
462
|
+
if (isArrowFunctionParam) {
|
|
463
|
+
continue;
|
|
464
|
+
}
|
|
465
|
+
if (abbrev.length <= 2) {
|
|
466
|
+
const isDateTimeContext = /date|time|day|hour|minute|second|timestamp/i.test(line);
|
|
467
|
+
if (isDateTimeContext && ["d", "t", "dt"].includes(abbrev)) {
|
|
468
|
+
continue;
|
|
469
|
+
}
|
|
470
|
+
const isUserContext = /user|auth|account/i.test(line);
|
|
471
|
+
if (isUserContext && abbrev === "u") {
|
|
472
|
+
continue;
|
|
473
|
+
}
|
|
474
|
+
}
|
|
184
475
|
issues.push({
|
|
185
476
|
file,
|
|
186
477
|
line: lineNumber,
|
|
@@ -191,7 +482,7 @@ function analyzeFileNaming(file, content) {
|
|
|
191
482
|
});
|
|
192
483
|
}
|
|
193
484
|
}
|
|
194
|
-
if (file.match(/\.(ts|tsx|js|jsx)$/)) {
|
|
485
|
+
if (!disabledChecks.has("convention-mix") && file.match(/\.(ts|tsx|js|jsx)$/)) {
|
|
195
486
|
const camelCaseVars = line.match(/\b(?:const|let|var)\s+([a-z][a-zA-Z0-9]*)\s*=/);
|
|
196
487
|
const snakeCaseVars = line.match(/\b(?:const|let|var)\s+([a-z][a-z0-9]*_[a-z0-9_]*)\s*=/);
|
|
197
488
|
if (snakeCaseVars) {
|
|
@@ -205,36 +496,51 @@ function analyzeFileNaming(file, content) {
|
|
|
205
496
|
});
|
|
206
497
|
}
|
|
207
498
|
}
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
const
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
499
|
+
if (!disabledChecks.has("unclear")) {
|
|
500
|
+
const booleanMatches = line.matchAll(/\b(?:const|let|var)\s+([a-z][a-zA-Z0-9]*)\s*:\s*boolean/gi);
|
|
501
|
+
for (const match of booleanMatches) {
|
|
502
|
+
const name = match[1];
|
|
503
|
+
if (!name.match(/^(is|has|should|can|will|did)/i)) {
|
|
504
|
+
issues.push({
|
|
505
|
+
file,
|
|
506
|
+
line: lineNumber,
|
|
507
|
+
type: "unclear",
|
|
508
|
+
identifier: name,
|
|
509
|
+
severity: "info",
|
|
510
|
+
suggestion: `Boolean variable '${name}' should start with is/has/should/can for clarity`
|
|
511
|
+
});
|
|
512
|
+
}
|
|
220
513
|
}
|
|
221
514
|
}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
const
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
515
|
+
if (!disabledChecks.has("unclear")) {
|
|
516
|
+
const functionMatches = line.matchAll(/function\s+([a-z][a-zA-Z0-9]*)/g);
|
|
517
|
+
for (const match of functionMatches) {
|
|
518
|
+
const name = match[1];
|
|
519
|
+
const isKeyword = ["for", "if", "else", "while", "do", "switch", "case", "break", "continue", "return", "throw", "try", "catch", "finally", "with", "yield", "await"].includes(name);
|
|
520
|
+
if (isKeyword) {
|
|
521
|
+
continue;
|
|
522
|
+
}
|
|
523
|
+
const isEntryPoint = ["main", "init", "setup", "bootstrap"].includes(name);
|
|
524
|
+
if (isEntryPoint) {
|
|
525
|
+
continue;
|
|
526
|
+
}
|
|
527
|
+
const isFactoryPattern = name.match(/(Factory|Builder|Creator|Generator)$/);
|
|
528
|
+
const isEventHandler = name.match(/^on[A-Z]/);
|
|
529
|
+
const isDescriptiveLong = name.length > 15;
|
|
530
|
+
const isDescriptivePattern = name.match(/^(default|total|count|sum|avg|max|min|initial|current|previous|next)\w+/) || name.match(/\w+(Count|Total|Sum|Average|List|Map|Set|Config|Settings|Options|Props)$/);
|
|
531
|
+
const capitalCount = (name.match(/[A-Z]/g) || []).length;
|
|
532
|
+
const isCompoundWord = capitalCount >= 3;
|
|
533
|
+
const hasActionVerb = name.match(/^(get|set|is|has|can|should|create|update|delete|fetch|load|save|process|handle|validate|check|find|search|filter|map|reduce|make|do|run|start|stop|build|parse|format|render|calculate|compute|generate|transform|convert|normalize|sanitize|encode|decode|compress|extract|merge|split|join|sort|compare|test|verify|ensure|apply|execute|invoke|call|emit|dispatch|trigger|listen|subscribe|unsubscribe|add|remove|clear|reset|toggle|enable|disable|open|close|connect|disconnect|send|receive|read|write|import|export|register|unregister|mount|unmount)/);
|
|
534
|
+
if (!hasActionVerb && !isFactoryPattern && !isEventHandler && !isDescriptiveLong && !isDescriptivePattern && !isCompoundWord) {
|
|
535
|
+
issues.push({
|
|
536
|
+
file,
|
|
537
|
+
line: lineNumber,
|
|
538
|
+
type: "unclear",
|
|
539
|
+
identifier: name,
|
|
540
|
+
severity: "info",
|
|
541
|
+
suggestion: `Function '${name}' should start with an action verb (get, set, create, etc.)`
|
|
542
|
+
});
|
|
543
|
+
}
|
|
238
544
|
}
|
|
239
545
|
}
|
|
240
546
|
});
|
package/dist/index.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aiready/consistency",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.5",
|
|
4
4
|
"description": "Detects consistency issues in naming, patterns, and architecture that confuse AI models",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"chalk": "^5.3.0",
|
|
43
43
|
"commander": "^12.1.0",
|
|
44
|
-
"@aiready/core": "0.7.
|
|
44
|
+
"@aiready/core": "0.7.1"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
47
|
"@types/node": "^22.10.5",
|
|
@@ -49,12 +49,25 @@ const result = x + y;
|
|
|
49
49
|
const acceptableAbbreviations = [
|
|
50
50
|
'env', 'req', 'res', 'ctx', 'err', 'api', 'url', 'id',
|
|
51
51
|
'max', 'min', 'now', 'utm', 'has', 'is', 'can',
|
|
52
|
-
'db', 'fs', 'os', 'ui', 'tmp', 'src', 'dst'
|
|
52
|
+
'db', 'fs', 'os', 'ui', 'tmp', 'src', 'dst',
|
|
53
|
+
// New additions from Phase 1
|
|
54
|
+
'img', 'txt', 'doc', 'md', 'ts', 'js', 'ddb', 's3',
|
|
55
|
+
'fcp', 'lcp', 'fps', 'po', 'dto', 'e2e', 'a11y', 'i18n'
|
|
53
56
|
];
|
|
54
57
|
// These abbreviations should not trigger warnings
|
|
55
58
|
expect(acceptableAbbreviations.length).toBeGreaterThan(0);
|
|
56
59
|
});
|
|
57
60
|
|
|
61
|
+
it('should NOT flag common short English words', () => {
|
|
62
|
+
// Full words, not abbreviations - should be accepted
|
|
63
|
+
const commonWords = [
|
|
64
|
+
'day', 'key', 'net', 'to', 'go', 'for', 'not', 'new', 'old',
|
|
65
|
+
'top', 'end', 'run', 'try', 'use', 'get', 'set', 'add', 'put'
|
|
66
|
+
];
|
|
67
|
+
// These are full words and should not be flagged as abbreviations
|
|
68
|
+
expect(commonWords.length).toBeGreaterThan(0);
|
|
69
|
+
});
|
|
70
|
+
|
|
58
71
|
it('should detect snake_case in TypeScript files', () => {
|
|
59
72
|
const testCode = `
|
|
60
73
|
const user_name = 'John';
|
|
@@ -82,6 +95,33 @@ const api = new ApiClient();
|
|
|
82
95
|
// Should not flag these as issues
|
|
83
96
|
expect(true).toBe(true);
|
|
84
97
|
});
|
|
98
|
+
|
|
99
|
+
it('should NOT flag multi-line arrow function parameters (Phase 3)', () => {
|
|
100
|
+
// Multi-line arrow functions should not trigger single-letter warnings
|
|
101
|
+
const multiLineArrowCode = `
|
|
102
|
+
items.map(
|
|
103
|
+
s => s.value
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
items.filter(
|
|
107
|
+
item =>
|
|
108
|
+
item.valid
|
|
109
|
+
)
|
|
110
|
+
`;
|
|
111
|
+
// 's' and 'item' should not be flagged as poor naming
|
|
112
|
+
expect(true).toBe(true);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('should NOT flag short-lived comparison variables (Phase 3)', () => {
|
|
116
|
+
// Variables used only within 3-5 lines for comparisons
|
|
117
|
+
const shortLivedCode = `
|
|
118
|
+
const a = obj1;
|
|
119
|
+
const b = obj2;
|
|
120
|
+
return compare(a, b);
|
|
121
|
+
`;
|
|
122
|
+
// 'a' and 'b' should not be flagged as they're short-lived
|
|
123
|
+
expect(true).toBe(true);
|
|
124
|
+
});
|
|
85
125
|
});
|
|
86
126
|
|
|
87
127
|
describe('analyzePatterns', () => {
|