@aiready/consistency 0.3.4 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +24 -0
- package/.turbo/turbo-test.log +81 -0
- package/PHASE4-RESULTS.md +122 -0
- package/README.md +55 -7
- package/dist/chunk-2BTBNG6X.mjs +814 -0
- package/dist/chunk-CZUJTDNH.mjs +848 -0
- package/dist/cli.js +168 -91
- package/dist/cli.mjs +1 -1
- package/dist/index.js +165 -88
- package/dist/index.mjs +1 -1
- package/package.json +12 -13
- package/src/__tests__/analyzer.test.ts +27 -0
- package/src/analyzers/naming.ts +226 -142
package/dist/index.js
CHANGED
|
@@ -32,6 +32,7 @@ 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");
|
|
35
36
|
var COMMON_SHORT_WORDS = /* @__PURE__ */ new Set([
|
|
36
37
|
// Full English words (1-3 letters)
|
|
37
38
|
"day",
|
|
@@ -89,6 +90,13 @@ var COMMON_SHORT_WORDS = /* @__PURE__ */ new Set([
|
|
|
89
90
|
"tmp",
|
|
90
91
|
"ext",
|
|
91
92
|
"sep",
|
|
93
|
+
// Prepositions and conjunctions
|
|
94
|
+
"and",
|
|
95
|
+
"from",
|
|
96
|
+
"how",
|
|
97
|
+
"pad",
|
|
98
|
+
"bar",
|
|
99
|
+
"non",
|
|
92
100
|
// Additional full words commonly flagged
|
|
93
101
|
"tax",
|
|
94
102
|
"cat",
|
|
@@ -335,6 +343,17 @@ var ACCEPTABLE_ABBREVIATIONS = /* @__PURE__ */ new Set([
|
|
|
335
343
|
"alb",
|
|
336
344
|
"nlb",
|
|
337
345
|
"aws",
|
|
346
|
+
"ses",
|
|
347
|
+
"gst",
|
|
348
|
+
"cdk",
|
|
349
|
+
"btn",
|
|
350
|
+
"buf",
|
|
351
|
+
"agg",
|
|
352
|
+
"ocr",
|
|
353
|
+
"ai",
|
|
354
|
+
"cf",
|
|
355
|
+
"cfn",
|
|
356
|
+
"ga",
|
|
338
357
|
// Metrics/Performance
|
|
339
358
|
"fcp",
|
|
340
359
|
"lcp",
|
|
@@ -346,12 +365,14 @@ var ACCEPTABLE_ABBREVIATIONS = /* @__PURE__ */ new Set([
|
|
|
346
365
|
"qps",
|
|
347
366
|
"rps",
|
|
348
367
|
"tps",
|
|
368
|
+
"wpm",
|
|
349
369
|
// Testing & i18n
|
|
350
370
|
"po",
|
|
351
371
|
"e2e",
|
|
352
372
|
"a11y",
|
|
353
373
|
"i18n",
|
|
354
374
|
"l10n",
|
|
375
|
+
"spy",
|
|
355
376
|
// Domain-specific abbreviations (context-aware)
|
|
356
377
|
"sk",
|
|
357
378
|
"fy",
|
|
@@ -361,6 +382,16 @@ var ACCEPTABLE_ABBREVIATIONS = /* @__PURE__ */ new Set([
|
|
|
361
382
|
"cta",
|
|
362
383
|
"roi",
|
|
363
384
|
"kpi",
|
|
385
|
+
"ttl",
|
|
386
|
+
"pct",
|
|
387
|
+
// Technical abbreviations
|
|
388
|
+
"mac",
|
|
389
|
+
"hex",
|
|
390
|
+
"esm",
|
|
391
|
+
"git",
|
|
392
|
+
"rec",
|
|
393
|
+
"loc",
|
|
394
|
+
"dup",
|
|
364
395
|
// Boolean helpers (these are intentional short names)
|
|
365
396
|
"is",
|
|
366
397
|
"has",
|
|
@@ -375,75 +406,113 @@ var ACCEPTABLE_ABBREVIATIONS = /* @__PURE__ */ new Set([
|
|
|
375
406
|
]);
|
|
376
407
|
async function analyzeNaming(files) {
|
|
377
408
|
const issues = [];
|
|
409
|
+
const rootDir = files.length > 0 ? (0, import_path.dirname)(files[0]) : process.cwd();
|
|
410
|
+
const config = (0, import_core.loadConfig)(rootDir);
|
|
411
|
+
const consistencyConfig = config?.tools?.["consistency"];
|
|
412
|
+
const customAbbreviations = new Set(consistencyConfig?.acceptedAbbreviations || []);
|
|
413
|
+
const customShortWords = new Set(consistencyConfig?.shortWords || []);
|
|
414
|
+
const disabledChecks = new Set(consistencyConfig?.disableChecks || []);
|
|
378
415
|
for (const file of files) {
|
|
379
416
|
const content = await (0, import_core.readFileContent)(file);
|
|
380
|
-
const fileIssues = analyzeFileNaming(file, content);
|
|
417
|
+
const fileIssues = analyzeFileNaming(file, content, customAbbreviations, customShortWords, disabledChecks);
|
|
381
418
|
issues.push(...fileIssues);
|
|
382
419
|
}
|
|
383
420
|
return issues;
|
|
384
421
|
}
|
|
385
|
-
function analyzeFileNaming(file, content) {
|
|
422
|
+
function analyzeFileNaming(file, content, customAbbreviations, customShortWords, disabledChecks) {
|
|
386
423
|
const issues = [];
|
|
387
424
|
const isTestFile = file.match(/\.(test|spec)\.(ts|tsx|js|jsx)$/);
|
|
388
425
|
const lines = content.split("\n");
|
|
426
|
+
const allAbbreviations = /* @__PURE__ */ new Set([...ACCEPTABLE_ABBREVIATIONS, ...customAbbreviations]);
|
|
427
|
+
const allShortWords = /* @__PURE__ */ new Set([...COMMON_SHORT_WORDS, ...customShortWords]);
|
|
428
|
+
const getContextWindow = (index, windowSize = 3) => {
|
|
429
|
+
const start = Math.max(0, index - windowSize);
|
|
430
|
+
const end = Math.min(lines.length, index + windowSize + 1);
|
|
431
|
+
return lines.slice(start, end).join("\n");
|
|
432
|
+
};
|
|
433
|
+
const isShortLivedVariable = (varName, declarationIndex) => {
|
|
434
|
+
const searchRange = 5;
|
|
435
|
+
const endIndex = Math.min(lines.length, declarationIndex + searchRange + 1);
|
|
436
|
+
let usageCount = 0;
|
|
437
|
+
for (let i = declarationIndex; i < endIndex; i++) {
|
|
438
|
+
const regex = new RegExp(`\\b${varName}\\b`, "g");
|
|
439
|
+
const matches = lines[i].match(regex);
|
|
440
|
+
if (matches) {
|
|
441
|
+
usageCount += matches.length;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
return usageCount >= 2 && usageCount <= 3;
|
|
445
|
+
};
|
|
389
446
|
lines.forEach((line, index) => {
|
|
390
447
|
const lineNumber = index + 1;
|
|
391
|
-
const
|
|
392
|
-
|
|
393
|
-
const
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
448
|
+
const contextWindow = getContextWindow(index);
|
|
449
|
+
if (!disabledChecks.has("single-letter")) {
|
|
450
|
+
const singleLetterMatches = line.matchAll(/\b(?:const|let|var)\s+([a-hm-z])\s*=/gi);
|
|
451
|
+
for (const match of singleLetterMatches) {
|
|
452
|
+
const letter = match[1].toLowerCase();
|
|
453
|
+
const isInLoopContext = line.includes("for") || /\.(map|filter|forEach|reduce|find|some|every)\s*\(/.test(line) || line.includes("=>") || // Arrow function
|
|
454
|
+
/\w+\s*=>\s*/.test(line);
|
|
455
|
+
const isI18nContext = line.includes("useTranslation") || line.includes("i18n.t") || /\bt\s*\(['"]/.test(line);
|
|
456
|
+
const isArrowFunctionParam = /\(\s*[a-z]\s*(?:,\s*[a-z]\s*)*\)\s*=>/.test(line) || // (s) => or (a, b) =>
|
|
457
|
+
/[a-z]\s*=>/.test(line) || // s => on same line
|
|
458
|
+
// Multi-line arrow function detection: look for pattern in context window
|
|
459
|
+
new RegExp(`\\b${letter}\\s*\\)\\s*$`).test(line) && /=>/.test(contextWindow) || // (s)\n =>
|
|
460
|
+
new RegExp(`\\.(?:map|filter|forEach|reduce|find|some|every)\\s*\\(\\s*$`).test(lines[index - 1] || "") && /=>/.test(contextWindow);
|
|
461
|
+
const isShortLived = isShortLivedVariable(letter, index);
|
|
462
|
+
if (!isInLoopContext && !isI18nContext && !isArrowFunctionParam && !isShortLived && !["x", "y", "z", "i", "j", "k", "l", "n", "m"].includes(letter)) {
|
|
463
|
+
if (isTestFile && ["a", "b", "c", "d", "e", "f", "s"].includes(letter)) {
|
|
464
|
+
continue;
|
|
465
|
+
}
|
|
466
|
+
issues.push({
|
|
467
|
+
file,
|
|
468
|
+
line: lineNumber,
|
|
469
|
+
type: "poor-naming",
|
|
470
|
+
identifier: match[1],
|
|
471
|
+
severity: "minor",
|
|
472
|
+
suggestion: `Use descriptive variable name instead of single letter '${match[1]}'`
|
|
473
|
+
});
|
|
402
474
|
}
|
|
403
|
-
issues.push({
|
|
404
|
-
file,
|
|
405
|
-
line: lineNumber,
|
|
406
|
-
type: "poor-naming",
|
|
407
|
-
identifier: match[1],
|
|
408
|
-
severity: "minor",
|
|
409
|
-
suggestion: `Use descriptive variable name instead of single letter '${match[1]}'`
|
|
410
|
-
});
|
|
411
475
|
}
|
|
412
476
|
}
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
const
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
}
|
|
419
|
-
if (ACCEPTABLE_ABBREVIATIONS.has(abbrev)) {
|
|
420
|
-
continue;
|
|
421
|
-
}
|
|
422
|
-
const isArrowFunctionParam = /\(\s*[a-z]\s*(?:,\s*[a-z]\s*)*\)\s*=>/.test(line) || // (s) => or (a, b) =>
|
|
423
|
-
new RegExp(`\\b${abbrev}\\s*=>`).test(line);
|
|
424
|
-
if (isArrowFunctionParam) {
|
|
425
|
-
continue;
|
|
426
|
-
}
|
|
427
|
-
if (abbrev.length <= 2) {
|
|
428
|
-
const isDateTimeContext = /date|time|day|hour|minute|second|timestamp/i.test(line);
|
|
429
|
-
if (isDateTimeContext && ["d", "t", "dt"].includes(abbrev)) {
|
|
477
|
+
if (!disabledChecks.has("abbreviation")) {
|
|
478
|
+
const abbreviationMatches = line.matchAll(/\b(?:const|let|var)\s+([a-z]{1,3})(?=[A-Z]|_|\s*=)/g);
|
|
479
|
+
for (const match of abbreviationMatches) {
|
|
480
|
+
const abbrev = match[1].toLowerCase();
|
|
481
|
+
if (allShortWords.has(abbrev)) {
|
|
430
482
|
continue;
|
|
431
483
|
}
|
|
432
|
-
|
|
433
|
-
if (isUserContext && abbrev === "u") {
|
|
484
|
+
if (allAbbreviations.has(abbrev)) {
|
|
434
485
|
continue;
|
|
435
486
|
}
|
|
487
|
+
const isArrowFunctionParam = /\(\s*[a-z]\s*(?:,\s*[a-z]\s*)*\)\s*=>/.test(line) || // (s) => or (a, b) =>
|
|
488
|
+
new RegExp(`\\b${abbrev}\\s*=>`).test(line) || // s => on same line
|
|
489
|
+
// Multi-line arrow function: check context window
|
|
490
|
+
new RegExp(`\\b${abbrev}\\s*\\)\\s*$`).test(line) && /=>/.test(contextWindow) || // (s)\n =>
|
|
491
|
+
new RegExp(`\\.(?:map|filter|forEach|reduce|find|some|every)\\s*\\(\\s*$`).test(lines[index - 1] || "") && new RegExp(`^\\s*${abbrev}\\s*=>`).test(line);
|
|
492
|
+
if (isArrowFunctionParam) {
|
|
493
|
+
continue;
|
|
494
|
+
}
|
|
495
|
+
if (abbrev.length <= 2) {
|
|
496
|
+
const isDateTimeContext = /date|time|day|hour|minute|second|timestamp/i.test(line);
|
|
497
|
+
if (isDateTimeContext && ["d", "t", "dt"].includes(abbrev)) {
|
|
498
|
+
continue;
|
|
499
|
+
}
|
|
500
|
+
const isUserContext = /user|auth|account/i.test(line);
|
|
501
|
+
if (isUserContext && abbrev === "u") {
|
|
502
|
+
continue;
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
issues.push({
|
|
506
|
+
file,
|
|
507
|
+
line: lineNumber,
|
|
508
|
+
type: "abbreviation",
|
|
509
|
+
identifier: match[1],
|
|
510
|
+
severity: "info",
|
|
511
|
+
suggestion: `Consider using full word instead of abbreviation '${match[1]}'`
|
|
512
|
+
});
|
|
436
513
|
}
|
|
437
|
-
issues.push({
|
|
438
|
-
file,
|
|
439
|
-
line: lineNumber,
|
|
440
|
-
type: "abbreviation",
|
|
441
|
-
identifier: match[1],
|
|
442
|
-
severity: "info",
|
|
443
|
-
suggestion: `Consider using full word instead of abbreviation '${match[1]}'`
|
|
444
|
-
});
|
|
445
514
|
}
|
|
446
|
-
if (file.match(/\.(ts|tsx|js|jsx)$/)) {
|
|
515
|
+
if (!disabledChecks.has("convention-mix") && file.match(/\.(ts|tsx|js|jsx)$/)) {
|
|
447
516
|
const camelCaseVars = line.match(/\b(?:const|let|var)\s+([a-z][a-zA-Z0-9]*)\s*=/);
|
|
448
517
|
const snakeCaseVars = line.match(/\b(?:const|let|var)\s+([a-z][a-z0-9]*_[a-z0-9_]*)\s*=/);
|
|
449
518
|
if (snakeCaseVars) {
|
|
@@ -457,47 +526,55 @@ function analyzeFileNaming(file, content) {
|
|
|
457
526
|
});
|
|
458
527
|
}
|
|
459
528
|
}
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
const
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
529
|
+
if (!disabledChecks.has("unclear")) {
|
|
530
|
+
const booleanMatches = line.matchAll(/\b(?:const|let|var)\s+([a-z][a-zA-Z0-9]*)\s*:\s*boolean/gi);
|
|
531
|
+
for (const match of booleanMatches) {
|
|
532
|
+
const name = match[1];
|
|
533
|
+
if (!name.match(/^(is|has|should|can|will|did)/i)) {
|
|
534
|
+
issues.push({
|
|
535
|
+
file,
|
|
536
|
+
line: lineNumber,
|
|
537
|
+
type: "unclear",
|
|
538
|
+
identifier: name,
|
|
539
|
+
severity: "info",
|
|
540
|
+
suggestion: `Boolean variable '${name}' should start with is/has/should/can for clarity`
|
|
541
|
+
});
|
|
542
|
+
}
|
|
472
543
|
}
|
|
473
544
|
}
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
const
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
545
|
+
if (!disabledChecks.has("unclear")) {
|
|
546
|
+
const functionMatches = line.matchAll(/function\s+([a-z][a-zA-Z0-9]*)/g);
|
|
547
|
+
for (const match of functionMatches) {
|
|
548
|
+
const name = match[1];
|
|
549
|
+
const isKeyword = ["for", "if", "else", "while", "do", "switch", "case", "break", "continue", "return", "throw", "try", "catch", "finally", "with", "yield", "await"].includes(name);
|
|
550
|
+
if (isKeyword) {
|
|
551
|
+
continue;
|
|
552
|
+
}
|
|
553
|
+
const isEntryPoint = ["main", "init", "setup", "bootstrap"].includes(name);
|
|
554
|
+
if (isEntryPoint) {
|
|
555
|
+
continue;
|
|
556
|
+
}
|
|
557
|
+
const isFactoryPattern = name.match(/(Factory|Builder|Creator|Generator|Provider|Adapter|Mock)$/);
|
|
558
|
+
const isEventHandler = name.match(/^on[A-Z]/);
|
|
559
|
+
const isDescriptiveLong = name.length > 15;
|
|
560
|
+
const isReactHook = name.match(/^use[A-Z]/);
|
|
561
|
+
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|Data|Info|Details|State|Status|Response|Result)$/);
|
|
562
|
+
const isHelperPattern = name.match(/^(to|from|with|without|for|as|into)\w+/) || // toMetadata, withLogger, forPath
|
|
563
|
+
name.match(/^\w+(To|From|With|Without|For|As|Into)\w*$/);
|
|
564
|
+
const isUtilityName = ["cn", "proxy", "sitemap", "robots", "gtag"].includes(name);
|
|
565
|
+
const capitalCount = (name.match(/[A-Z]/g) || []).length;
|
|
566
|
+
const isCompoundWord = capitalCount >= 3;
|
|
567
|
+
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|track|store|persist|upsert|derive|classify|combine|discover|activate|require|assert|expect|mask|escape|sign|put|list|complete|page|safe|mock|pick|pluralize|text)/);
|
|
568
|
+
if (!hasActionVerb && !isFactoryPattern && !isEventHandler && !isDescriptiveLong && !isDescriptivePattern && !isCompoundWord && !isHelperPattern && !isUtilityName && !isReactHook) {
|
|
569
|
+
issues.push({
|
|
570
|
+
file,
|
|
571
|
+
line: lineNumber,
|
|
572
|
+
type: "unclear",
|
|
573
|
+
identifier: name,
|
|
574
|
+
severity: "info",
|
|
575
|
+
suggestion: `Function '${name}' should start with an action verb (get, set, create, etc.)`
|
|
576
|
+
});
|
|
577
|
+
}
|
|
501
578
|
}
|
|
502
579
|
}
|
|
503
580
|
});
|
package/dist/index.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aiready/consistency",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
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",
|
|
@@ -15,15 +15,6 @@
|
|
|
15
15
|
"import": "./dist/index.mjs"
|
|
16
16
|
}
|
|
17
17
|
},
|
|
18
|
-
"scripts": {
|
|
19
|
-
"build": "tsup src/index.ts src/cli.ts --format cjs,esm --dts",
|
|
20
|
-
"dev": "tsup src/index.ts src/cli.ts --format cjs,esm --dts --watch",
|
|
21
|
-
"test": "vitest run",
|
|
22
|
-
"lint": "eslint src",
|
|
23
|
-
"clean": "rm -rf dist",
|
|
24
|
-
"prepublishOnly": "pnpm build",
|
|
25
|
-
"release": "pnpm build && pnpm publish --no-git-checks"
|
|
26
|
-
},
|
|
27
18
|
"keywords": [
|
|
28
19
|
"aiready",
|
|
29
20
|
"consistency",
|
|
@@ -48,9 +39,9 @@
|
|
|
48
39
|
},
|
|
49
40
|
"homepage": "https://github.com/caopengau/aiready-consistency",
|
|
50
41
|
"dependencies": {
|
|
51
|
-
"@aiready/core": "workspace:*",
|
|
52
42
|
"chalk": "^5.3.0",
|
|
53
|
-
"commander": "^12.1.0"
|
|
43
|
+
"commander": "^12.1.0",
|
|
44
|
+
"@aiready/core": "0.7.1"
|
|
54
45
|
},
|
|
55
46
|
"devDependencies": {
|
|
56
47
|
"@types/node": "^22.10.5",
|
|
@@ -60,5 +51,13 @@
|
|
|
60
51
|
},
|
|
61
52
|
"engines": {
|
|
62
53
|
"node": ">=18.0.0"
|
|
54
|
+
},
|
|
55
|
+
"scripts": {
|
|
56
|
+
"build": "tsup src/index.ts src/cli.ts --format cjs,esm --dts",
|
|
57
|
+
"dev": "tsup src/index.ts src/cli.ts --format cjs,esm --dts --watch",
|
|
58
|
+
"test": "vitest run",
|
|
59
|
+
"lint": "eslint src",
|
|
60
|
+
"clean": "rm -rf dist",
|
|
61
|
+
"release": "pnpm build && pnpm publish --no-git-checks"
|
|
63
62
|
}
|
|
64
|
-
}
|
|
63
|
+
}
|
|
@@ -95,6 +95,33 @@ const api = new ApiClient();
|
|
|
95
95
|
// Should not flag these as issues
|
|
96
96
|
expect(true).toBe(true);
|
|
97
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
|
+
});
|
|
98
125
|
});
|
|
99
126
|
|
|
100
127
|
describe('analyzePatterns', () => {
|