@nebutra/next-unicorn-skill 1.0.6 → 1.0.7

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/SKILL.md CHANGED
@@ -2,10 +2,12 @@
2
2
  name: analyze-and-recommend-third-party-optimizations
3
3
  description: >-
4
4
  Scan a codebase to identify hand-rolled implementations that should be replaced
5
- by third-party libraries, and identify missing capabilities the project should
6
- have. Produce structured migration plans with Context7-verified recommendations.
5
+ by third-party libraries, identify missing capabilities, and detect code
6
+ organization issues (directory structure, naming, circular deps, barrel bloat).
7
+ Produce structured migration plans with Context7-verified recommendations.
7
8
  Use when analyzing technical debt, auditing dependency health, reviewing
8
- hand-rolled code, planning library migrations, or assessing capability gaps.
9
+ hand-rolled code, planning library migrations, assessing capability gaps,
10
+ or auditing project structure and module organization.
9
11
  ---
10
12
 
11
13
  # Analyze and Recommend Third-Party Optimizations
@@ -13,10 +15,11 @@ description: >-
13
15
  ## Architecture
14
16
 
15
17
  ```
16
- Scanner (deterministic) → AI Agent (generative) → Pipeline (deterministic)
17
- Regex patterns detect 1. Recommend replacements Score, plan, audit,
18
- hand-rolled code 2. Identify capability gaps filter, serialize
19
- using knowledge + Context7
18
+ Scanner (deterministic) → AI Agent (generative) → Pipeline (deterministic)
19
+ 1. Regex: detect hand-rolled code 1. Recommend library replacements Score, plan, audit,
20
+ 2. FS: detect code org issues 2. Identify capability gaps filter, serialize
21
+ (god-dirs, circular deps, 3. Recommend org patterns + tooling
22
+ naming, barrel bloat) using knowledge + Context7
20
23
  ```
21
24
 
22
25
  **Design constraints**:
@@ -34,11 +37,16 @@ Parse and validate `InputSchema` JSON via Zod. Read `src/schemas/input.schema.ts
34
37
  Run `scanCodebase(input)`. The scanner:
35
38
 
36
39
  1. Detect workspace roots for monorepo support
37
- 2. Match code against 20+ domain patterns (i18n, auth, state-management, etc.)
38
- 3. Record each detection with: file path, line range, pattern category, confidence score, domain
39
- 4. Return `ScanResult` with detections and workspace info
40
+ 2. Match code against 30+ domain patterns (i18n, auth, state-management, code-organization, etc.)
41
+ 3. Run structural analysis: design system layers (monorepo), code organization (all projects)
42
+ 4. Record each detection with: file path, line range, pattern category, confidence score, domain
43
+ 5. Return `ScanResult` with:
44
+ - `detections` — hand-rolled code patterns found
45
+ - `structuralFindings` — architectural + code organization issues
46
+ - `codeOrganizationStats` — project-wide metrics (file counts, naming conventions, circular dep count)
47
+ - `workspaces` — monorepo workspace info
40
48
 
41
- Detections contain no library suggestions — only what was detected and where.
49
+ Detections and findings contain no recommendations — only facts. The AI agent interprets them.
42
50
 
43
51
  ### Step 2.5: Gap Analysis (AI Agent)
44
52
 
@@ -60,6 +68,98 @@ Provide each gap as a `GapRecommendation`. Read `src/index.ts` for the interface
60
68
  - **No existing frontend**: Scaffold from reference repos. Read `references/design-system-sources.md` for curated sources and sparse-checkout workflow.
61
69
  - **Existing frontend without formal design system**: First extract the spec (audit → tokens → classify → document) via `references/design-system-extraction.md`, then implement the architecture via `references/design-system-sources.md`.
62
70
 
71
+ ### Step 2.7: Code Organization Analysis
72
+
73
+ #### Phase A — Deterministic: Collect facts (MUST use tools, DO NOT estimate)
74
+
75
+ You cannot infer file counts, naming conventions, or import cycles from knowledge. You MUST read the filesystem.
76
+
77
+ **If using the npm library** — `scanResult.structuralFindings` and `scanResult.codeOrganizationStats` already contain all findings. Skip to Phase B.
78
+
79
+ **If not using the npm library** — run these shell commands to collect facts:
80
+
81
+ ```bash
82
+ # 1. God directories: find directories with >15 source files
83
+ find src -type d -exec sh -c 'count=$(find "$1" -maxdepth 1 -type f \( -name "*.ts" -o -name "*.tsx" -o -name "*.js" -o -name "*.jsx" \) | wc -l); [ "$count" -gt 15 ] && echo "$1: $count files"' _ {} \;
84
+
85
+ # 2. Mixed naming: list filenames per directory for manual inspection
86
+ ls -1 src/components/ # check if kebab-case and camelCase are mixed
87
+
88
+ # 3. Deep nesting: find directories >5 levels deep from src/
89
+ find src -mindepth 6 -type d
90
+
91
+ # 4. Barrel bloat: count re-exports in index files
92
+ grep -c "export.*from" src/**/index.ts
93
+
94
+ # 5. Catch-all directories: count files in utils/helpers/shared
95
+ find src/utils src/helpers src/shared src/common src/lib -maxdepth 1 -type f 2>/dev/null | wc -l
96
+
97
+ # 6. Circular dependencies: use npx if madge is not installed
98
+ npx madge --circular --extensions ts,tsx src/
99
+
100
+ # 7. Deep relative imports: find ../../../ patterns
101
+ grep -rn "from ['\"]\.\.\/\.\.\/\.\.\/" src/ --include="*.ts" --include="*.tsx"
102
+ ```
103
+
104
+ Record each finding with: **directory/file path, count, type**. These are facts.
105
+
106
+ #### Phase B — Generative: Recommend solutions (use your knowledge + Context7)
107
+
108
+ For each finding from Phase A, apply the decision tree below. **Do NOT recommend tools without Context7 verification.**
109
+
110
+ | Finding type | You MUST do | You MUST NOT do |
111
+ |---|---|---|
112
+ | `god-directory` | Read the files in that dir, group by domain, recommend split. Reference: Next.js App Router colocation, Linear feature-packages. | Guess file count. Say "probably too many files." |
113
+ | `mixed-naming-convention` | Check project framework → pick ONE convention. Next.js pages=kebab, React components=PascalCase, utils=camelCase. | Recommend "both are fine." Must pick one. |
114
+ | `deep-nesting` | Recommend `@/` path aliases. Read `tsconfig.json` to check if paths already exist. Generate the config change. | Say "consider flattening" without generating the actual config. |
115
+ | `barrel-bloat` | Recommend direct imports or namespace imports. Context7 verify `knip` for dead export detection. | Ignore it. Barrel bloat causes tree-shaking failures. |
116
+ | `catch-all-directory` | Read the actual files, group by domain (date, string, validation, etc.), recommend specific directory structure. | Say "split by concern" without reading what's actually in the files. |
117
+ | `circular-dependency` | Read the files in the cycle, understand WHY they import each other, recommend dependency inversion or extract shared module. Context7 verify `eslint-plugin-import`. | Just say "remove circular deps." Must explain the refactoring. |
118
+ | `org-deep-relative-import` | Same as `deep-nesting` — recommend path aliases. | Skip it. |
119
+ | `org-barrel-reexport-wildcard` | Recommend named re-exports `export { X } from` instead of `export *`. Explain namespace pollution risk. | Ignore it. |
120
+ | `org-catch-all-utils-import` | Same as `catch-all-directory` — recommend domain-specific modules. | Skip it. |
121
+
122
+ #### Phase B examples
123
+
124
+ **Example 1 — god-directory finding**:
125
+ ```
126
+ Fact: src/components/ has 23 source files
127
+ ```
128
+ Read those 23 files. You find: Button, Card, Modal, Table, Form, Input, Select, Checkbox...
129
+
130
+ Recommend:
131
+ ```
132
+ src/components/
133
+ ├── ui/ ← primitives (Button, Input, Select, Checkbox)
134
+ ├── data/ ← data display (Table, Card, DataGrid)
135
+ ├── overlay/ ← overlays (Modal, Dialog, Drawer, Tooltip)
136
+ └── form/ ← form elements (Form, FormField, FormError)
137
+ ```
138
+ Reference: shadcn/ui organizes by interaction type. Radix UI uses similar grouping.
139
+
140
+ **Example 2 — circular-dependency finding**:
141
+ ```
142
+ Fact: src/auth/session.ts → src/db/user.ts → src/auth/session.ts
143
+ ```
144
+ Read both files. You find: `session.ts` imports `getUserById`, `user.ts` imports `getSession` for auth checks.
145
+
146
+ Recommend: Extract `src/auth/types.ts` with shared interfaces. Both files import from types instead of each other. Context7 verify `eslint-plugin-import/no-cycle`.
147
+
148
+ **Example 3 — mixed-naming finding**:
149
+ ```
150
+ Fact: src/utils/ has kebab-case (5 files) + camelCase (3 files)
151
+ ```
152
+ Check package.json → framework is Next.js → convention is kebab-case for files.
153
+
154
+ Recommend: Rename the 3 camelCase files. Context7 verify `eslint-plugin-unicorn/filename-case` for CI enforcement.
155
+
156
+ #### Skip rules
157
+
158
+ Skip a code organization finding if:
159
+ - Directory is in `tests/`, `__tests__/`, `__mocks__/`, `fixtures/`, `generated/`, `.storybook/`
160
+ - File is auto-generated (has `// @generated` or `/* eslint-disable */` at top)
161
+ - Directory has <3 files (too few to judge naming convention)
162
+
63
163
  ### Step 3: Recommend Solutions (AI Agent)
64
164
 
65
165
  For each scanner detection, recommend a **solution**. Consider:
@@ -94,6 +194,14 @@ The pipeline handles these automatically:
94
194
  - **Step 9**: Auto-update existing dependencies (`registryClient`)
95
195
  - **Step 10**: PR auto-creation via GitHub/GitLab (`platformClient` + `gitOps`)
96
196
 
197
+ ## MCP Integration
198
+
199
+ Prefer MCP tools when available; fall back to shell commands if not.
200
+
201
+ - **Context7 MCP** (required) — `resolve-library-id` + `query-docs` for library verification
202
+ - **GitHub MCP** (preferred for PRs) — structured PR create/update/query; fallback: `gh` CLI
203
+ - **Git MCP / GitKraken MCP** (preferred for scaffold) — structured repo browse/sparse-checkout; fallback: `git` CLI
204
+
97
205
  ## Output
98
206
 
99
207
  Single `OutputSchema` JSON containing:
@@ -0,0 +1,26 @@
1
+ import type { StructuralFinding } from './structure-analyzer.js';
2
+ export interface CodeOrganizationAnalysis {
3
+ findings: StructuralFinding[];
4
+ stats: {
5
+ totalSourceFiles: number;
6
+ maxDirectoryDepth: number;
7
+ /** Naming convention distribution: kebab → count, camelCase → count, etc. */
8
+ namingConventions: Record<string, number>;
9
+ circularDependencyCount: number;
10
+ };
11
+ }
12
+ /**
13
+ * Analyze project code organization for structural issues.
14
+ *
15
+ * Deterministic filesystem analysis that Claude cannot replicate:
16
+ * - Counts files per directory (god directories)
17
+ * - Reads filenames to check naming conventions
18
+ * - Measures directory nesting depth
19
+ * - Counts re-exports in barrel files
20
+ * - Builds import graph to detect circular dependencies
21
+ *
22
+ * Recommendations (which pattern to adopt, which tools to use)
23
+ * are the AI agent's responsibility.
24
+ */
25
+ export declare function analyzeCodeOrganization(repoPath: string): CodeOrganizationAnalysis;
26
+ //# sourceMappingURL=code-organization-analyzer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code-organization-analyzer.d.ts","sourceRoot":"","sources":["../../src/analyzer/code-organization-analyzer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAMjE,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAC9B,KAAK,EAAE;QACL,gBAAgB,EAAE,MAAM,CAAC;QACzB,iBAAiB,EAAE,MAAM,CAAC;QAC1B,6EAA6E;QAC7E,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC1C,uBAAuB,EAAE,MAAM,CAAC;KACjC,CAAC;CACH;AAuND;;;;;;;;;;;;GAYG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,wBAAwB,CAmMlF"}
@@ -0,0 +1,389 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ // ---------------------------------------------------------------------------
4
+ // Constants — thresholds for code organization heuristics
5
+ //
6
+ // These thresholds are informed by the directory structures of
7
+ // Vercel (Next.js), Stripe (API docs), Linear, Supabase, shadcn/ui, Dub,
8
+ // and other reference Silicon Valley products. They represent the point
9
+ // where hand-rolled organization becomes unmaintainable and tools
10
+ // (eslint-plugin-import, knip, Barrel-file analyzers) are justified.
11
+ //
12
+ // Claude cannot determine these values without filesystem access.
13
+ // ---------------------------------------------------------------------------
14
+ /** Max source files in a single directory before it becomes a "god directory" */
15
+ const GOD_DIRECTORY_THRESHOLD = 15;
16
+ /** Max directory nesting depth from project root (src/) */
17
+ const MAX_NESTING_DEPTH = 5;
18
+ /** Max re-export lines in a barrel file */
19
+ const BARREL_BLOAT_THRESHOLD = 10;
20
+ /** Max files in a catch-all directory (utils/, helpers/, shared/, common/, lib/) */
21
+ const CATCH_ALL_THRESHOLD = 10;
22
+ /** Source file extensions to consider */
23
+ const SOURCE_EXTS = new Set(['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs']);
24
+ /** Directories to skip during analysis */
25
+ const SKIP_DIRS = new Set([
26
+ 'node_modules', '.git', 'dist', 'build', '.next', '__pycache__',
27
+ '.venv', 'venv', 'target', 'vendor', '.turbo', 'coverage',
28
+ ]);
29
+ /** Catch-all directory names that should be split by domain */
30
+ const CATCH_ALL_NAMES = new Set(['utils', 'helpers', 'common', 'shared', 'lib']);
31
+ function detectNamingConvention(filename) {
32
+ // Strip extension and any leading dot
33
+ const name = filename.replace(/\.[^.]+$/, '').replace(/^\./, '');
34
+ if (!name || name === 'index')
35
+ return 'unknown';
36
+ if (/^[A-Z][A-Z0-9_]+$/.test(name))
37
+ return 'SCREAMING_SNAKE';
38
+ if (/^[A-Z][a-zA-Z0-9]*$/.test(name))
39
+ return 'PascalCase';
40
+ if (/^[a-z][a-zA-Z0-9]*$/.test(name))
41
+ return 'camelCase';
42
+ if (/^[a-z][a-z0-9]*(-[a-z0-9]+)+$/.test(name))
43
+ return 'kebab-case';
44
+ if (/^[a-z][a-z0-9]*(_[a-z0-9]+)+$/.test(name))
45
+ return 'snake_case';
46
+ // Mixed patterns
47
+ if (name.includes('-'))
48
+ return 'kebab-case';
49
+ if (name.includes('_'))
50
+ return 'snake_case';
51
+ if (/^[A-Z]/.test(name))
52
+ return 'PascalCase';
53
+ return 'camelCase';
54
+ }
55
+ function* walkDirEntries(dir, repoPath) {
56
+ let entries;
57
+ try {
58
+ entries = fs.readdirSync(dir, { withFileTypes: true });
59
+ }
60
+ catch {
61
+ return;
62
+ }
63
+ for (const entry of entries) {
64
+ const fullPath = path.join(dir, entry.name);
65
+ const relativePath = path.relative(repoPath, fullPath);
66
+ if (entry.isDirectory()) {
67
+ if (!SKIP_DIRS.has(entry.name)) {
68
+ yield { name: entry.name, fullPath, relativePath, isDirectory: true };
69
+ yield* walkDirEntries(fullPath, repoPath);
70
+ }
71
+ }
72
+ else if (entry.isFile()) {
73
+ yield { name: entry.name, fullPath, relativePath, isDirectory: false };
74
+ }
75
+ }
76
+ }
77
+ // ---------------------------------------------------------------------------
78
+ // Import graph for circular dependency detection
79
+ // ---------------------------------------------------------------------------
80
+ /** Regex patterns to extract import/require paths from source files */
81
+ const IMPORT_PATTERNS = [
82
+ /(?:import\s+(?:[\s\S]*?\s+from\s+)?['"`])(\.{1,2}\/[^'"`\n]+)['"`]/g,
83
+ /(?:import\s*\(\s*['"`])(\.{1,2}\/[^'"`\n]+)['"`]/g,
84
+ /require\s*\(\s*['"`](\.{1,2}\/[^'"`\n]+)['"`]\s*\)/g,
85
+ /export\s+(?:\*|{[^}]*})\s+from\s+['"`](\.{1,2}\/[^'"`\n]+)['"`]/g,
86
+ ];
87
+ function extractImports(filePath) {
88
+ let content;
89
+ try {
90
+ content = fs.readFileSync(filePath, 'utf-8');
91
+ }
92
+ catch {
93
+ return [];
94
+ }
95
+ if (content.length > 500_000)
96
+ return [];
97
+ const imports = [];
98
+ for (const pattern of IMPORT_PATTERNS) {
99
+ // Reset regex state
100
+ const regex = new RegExp(pattern.source, pattern.flags);
101
+ let match;
102
+ while ((match = regex.exec(content)) !== null) {
103
+ if (match[1])
104
+ imports.push(match[1]);
105
+ }
106
+ }
107
+ return imports;
108
+ }
109
+ function resolveImportPath(fromFile, importPath) {
110
+ const fromDir = path.dirname(fromFile);
111
+ let resolved = path.resolve(fromDir, importPath);
112
+ // Try extensions if no extension present
113
+ const ext = path.extname(resolved);
114
+ if (!ext || !SOURCE_EXTS.has(ext)) {
115
+ for (const tryExt of ['.ts', '.tsx', '.js', '.jsx']) {
116
+ if (fs.existsSync(resolved + tryExt))
117
+ return resolved + tryExt;
118
+ }
119
+ // Try index file
120
+ const indexPath = path.join(resolved, 'index');
121
+ for (const tryExt of ['.ts', '.tsx', '.js', '.jsx']) {
122
+ if (fs.existsSync(indexPath + tryExt))
123
+ return indexPath + tryExt;
124
+ }
125
+ return null;
126
+ }
127
+ return fs.existsSync(resolved) ? resolved : null;
128
+ }
129
+ /**
130
+ * Detect circular dependencies using DFS cycle detection.
131
+ * Returns arrays of file paths forming cycles.
132
+ */
133
+ function detectCircularDependencies(sourceFiles, repoPath) {
134
+ // Build adjacency list
135
+ const graph = new Map();
136
+ for (const file of sourceFiles) {
137
+ const imports = extractImports(file);
138
+ const resolved = [];
139
+ for (const imp of imports) {
140
+ const target = resolveImportPath(file, imp);
141
+ if (target && sourceFiles.includes(target)) {
142
+ resolved.push(target);
143
+ }
144
+ }
145
+ graph.set(file, resolved);
146
+ }
147
+ // DFS cycle detection
148
+ const cycles = [];
149
+ const visited = new Set();
150
+ const onStack = new Set();
151
+ const pathStack = [];
152
+ const seen = new Set(); // deduplicate cycles
153
+ function dfs(node) {
154
+ visited.add(node);
155
+ onStack.add(node);
156
+ pathStack.push(node);
157
+ const neighbors = graph.get(node) ?? [];
158
+ for (const neighbor of neighbors) {
159
+ if (!visited.has(neighbor)) {
160
+ dfs(neighbor);
161
+ }
162
+ else if (onStack.has(neighbor)) {
163
+ // Found a cycle — extract it
164
+ const cycleStart = pathStack.indexOf(neighbor);
165
+ if (cycleStart >= 0) {
166
+ const cycle = pathStack.slice(cycleStart).map((f) => path.relative(repoPath, f));
167
+ const key = [...cycle].sort().join('|');
168
+ if (!seen.has(key)) {
169
+ seen.add(key);
170
+ cycles.push(cycle);
171
+ }
172
+ }
173
+ }
174
+ }
175
+ pathStack.pop();
176
+ onStack.delete(node);
177
+ }
178
+ for (const file of sourceFiles) {
179
+ if (!visited.has(file)) {
180
+ dfs(file);
181
+ }
182
+ }
183
+ return cycles;
184
+ }
185
+ // ---------------------------------------------------------------------------
186
+ // analyzeCodeOrganization — main entry point
187
+ // ---------------------------------------------------------------------------
188
+ /**
189
+ * Analyze project code organization for structural issues.
190
+ *
191
+ * Deterministic filesystem analysis that Claude cannot replicate:
192
+ * - Counts files per directory (god directories)
193
+ * - Reads filenames to check naming conventions
194
+ * - Measures directory nesting depth
195
+ * - Counts re-exports in barrel files
196
+ * - Builds import graph to detect circular dependencies
197
+ *
198
+ * Recommendations (which pattern to adopt, which tools to use)
199
+ * are the AI agent's responsibility.
200
+ */
201
+ export function analyzeCodeOrganization(repoPath) {
202
+ const findings = [];
203
+ const allSourceFiles = [];
204
+ const namingConventions = {};
205
+ // --- Collect directory info ---
206
+ const dirFileCount = new Map();
207
+ let maxDepth = 0;
208
+ for (const entry of walkDirEntries(repoPath, repoPath)) {
209
+ if (entry.isDirectory) {
210
+ // Track nesting depth
211
+ const depth = entry.relativePath.split(path.sep).length;
212
+ if (depth > maxDepth)
213
+ maxDepth = depth;
214
+ }
215
+ else {
216
+ const ext = path.extname(entry.name);
217
+ if (!SOURCE_EXTS.has(ext))
218
+ continue;
219
+ allSourceFiles.push(entry.fullPath);
220
+ // Track naming convention
221
+ const convention = detectNamingConvention(entry.name);
222
+ if (convention !== 'unknown') {
223
+ namingConventions[convention] = (namingConventions[convention] ?? 0) + 1;
224
+ }
225
+ // Track files per directory
226
+ const dir = path.dirname(entry.relativePath);
227
+ const existing = dirFileCount.get(dir);
228
+ if (existing) {
229
+ existing.count++;
230
+ existing.files.push(entry.name);
231
+ }
232
+ else {
233
+ dirFileCount.set(dir, { count: 1, files: [entry.name] });
234
+ }
235
+ }
236
+ }
237
+ // --- Check 1: God directories ---
238
+ for (const [dir, info] of dirFileCount) {
239
+ if (info.count > GOD_DIRECTORY_THRESHOLD) {
240
+ findings.push({
241
+ type: 'god-directory',
242
+ domain: 'code-organization',
243
+ description: `Directory "${dir}" contains ${info.count} source files (threshold: ${GOD_DIRECTORY_THRESHOLD}). Split by feature or domain.`,
244
+ paths: [dir],
245
+ severity: info.count > GOD_DIRECTORY_THRESHOLD * 2 ? 'critical' : 'warning',
246
+ metadata: { fileCount: info.count, threshold: GOD_DIRECTORY_THRESHOLD },
247
+ });
248
+ }
249
+ }
250
+ // --- Check 2: Mixed naming conventions per directory ---
251
+ for (const [dir, info] of dirFileCount) {
252
+ if (info.files.length < 3)
253
+ continue; // need enough files to judge
254
+ const conventions = new Map();
255
+ for (const file of info.files) {
256
+ const conv = detectNamingConvention(file);
257
+ if (conv === 'unknown')
258
+ continue;
259
+ const list = conventions.get(conv) ?? [];
260
+ list.push(file);
261
+ conventions.set(conv, list);
262
+ }
263
+ // Filter out conventions with only 1 file (noise)
264
+ const significant = [...conventions.entries()].filter(([, files]) => files.length >= 2);
265
+ if (significant.length >= 2) {
266
+ const summary = significant
267
+ .map(([conv, files]) => `${conv} (${files.length} files)`)
268
+ .join(', ');
269
+ findings.push({
270
+ type: 'mixed-naming-convention',
271
+ domain: 'code-organization',
272
+ description: `Directory "${dir}" uses mixed naming conventions: ${summary}. Choose one convention and enforce it.`,
273
+ paths: [dir],
274
+ severity: 'warning',
275
+ metadata: {
276
+ conventions: Object.fromEntries(significant.map(([k, v]) => [k, v.length])),
277
+ },
278
+ });
279
+ }
280
+ }
281
+ // --- Check 3: Deep nesting ---
282
+ for (const entry of walkDirEntries(repoPath, repoPath)) {
283
+ if (!entry.isDirectory)
284
+ continue;
285
+ const parts = entry.relativePath.split(path.sep);
286
+ // Only measure from src/ or packages/ onwards
287
+ const srcIdx = parts.indexOf('src');
288
+ const depth = srcIdx >= 0 ? parts.length - srcIdx : parts.length;
289
+ if (depth > MAX_NESTING_DEPTH) {
290
+ findings.push({
291
+ type: 'deep-nesting',
292
+ domain: 'code-organization',
293
+ description: `Directory "${entry.relativePath}" is ${depth} levels deep (max: ${MAX_NESTING_DEPTH}). Consider flattening or using path aliases.`,
294
+ paths: [entry.relativePath],
295
+ severity: 'warning',
296
+ metadata: { depth, threshold: MAX_NESTING_DEPTH },
297
+ });
298
+ }
299
+ }
300
+ // --- Check 4: Barrel bloat (index files with many re-exports) ---
301
+ for (const file of allSourceFiles) {
302
+ const basename = path.basename(file, path.extname(file));
303
+ if (basename !== 'index')
304
+ continue;
305
+ let content;
306
+ try {
307
+ content = fs.readFileSync(file, 'utf-8');
308
+ }
309
+ catch {
310
+ continue;
311
+ }
312
+ const reexportCount = (content.match(/export\s+(?:\*|{[^}]*})\s+from\s+['"`]/g) ?? []).length;
313
+ if (reexportCount > BARREL_BLOAT_THRESHOLD) {
314
+ const relativePath = path.relative(repoPath, file);
315
+ findings.push({
316
+ type: 'barrel-bloat',
317
+ domain: 'code-organization',
318
+ description: `Barrel file "${relativePath}" has ${reexportCount} re-exports (threshold: ${BARREL_BLOAT_THRESHOLD}). Consider direct imports or code-splitting.`,
319
+ paths: [relativePath],
320
+ severity: reexportCount > BARREL_BLOAT_THRESHOLD * 2 ? 'critical' : 'warning',
321
+ metadata: { reexportCount, threshold: BARREL_BLOAT_THRESHOLD },
322
+ });
323
+ }
324
+ }
325
+ // --- Check 5: Catch-all directories ---
326
+ for (const [dir, info] of dirFileCount) {
327
+ const dirName = path.basename(dir);
328
+ if (!CATCH_ALL_NAMES.has(dirName))
329
+ continue;
330
+ if (info.count > CATCH_ALL_THRESHOLD) {
331
+ findings.push({
332
+ type: 'catch-all-directory',
333
+ domain: 'code-organization',
334
+ description: `Catch-all directory "${dir}" contains ${info.count} files (threshold: ${CATCH_ALL_THRESHOLD}). Split into domain-specific modules (e.g., utils/date, utils/string, utils/validation).`,
335
+ paths: [dir],
336
+ severity: info.count > CATCH_ALL_THRESHOLD * 2 ? 'critical' : 'warning',
337
+ metadata: { fileCount: info.count, threshold: CATCH_ALL_THRESHOLD },
338
+ });
339
+ }
340
+ }
341
+ // --- Check 6: Mixed export styles (default + multiple named in same file) ---
342
+ for (const file of allSourceFiles) {
343
+ const basename = path.basename(file, path.extname(file));
344
+ if (basename === 'index')
345
+ continue; // barrel files are expected to have many exports
346
+ let content;
347
+ try {
348
+ content = fs.readFileSync(file, 'utf-8');
349
+ }
350
+ catch {
351
+ continue;
352
+ }
353
+ const hasDefaultExport = /export\s+default\s/.test(content);
354
+ const namedExportCount = (content.match(/export\s+(?:function|class|const|let|var|enum|type|interface)\s+\w/g) ?? []).length;
355
+ if (hasDefaultExport && namedExportCount >= 3) {
356
+ const relativePath = path.relative(repoPath, file);
357
+ findings.push({
358
+ type: 'god-directory', // reuse closest type — file is a "god module"
359
+ domain: 'code-organization',
360
+ description: `File "${relativePath}" mixes a default export with ${namedExportCount} named exports. One module, one responsibility — split into separate files.`,
361
+ paths: [relativePath],
362
+ severity: 'info',
363
+ metadata: { hasDefaultExport, namedExportCount, issue: 'mixed-export-style' },
364
+ });
365
+ }
366
+ }
367
+ // --- Check 7: Circular dependencies ---
368
+ const cycles = detectCircularDependencies(allSourceFiles, repoPath);
369
+ for (const cycle of cycles) {
370
+ findings.push({
371
+ type: 'circular-dependency',
372
+ domain: 'code-organization',
373
+ description: `Circular dependency detected: ${cycle.join(' → ')} → ${cycle[0]}`,
374
+ paths: cycle,
375
+ severity: cycle.length > 3 ? 'critical' : 'warning',
376
+ metadata: { cycleLength: cycle.length },
377
+ });
378
+ }
379
+ return {
380
+ findings,
381
+ stats: {
382
+ totalSourceFiles: allSourceFiles.length,
383
+ maxDirectoryDepth: maxDepth,
384
+ namingConventions,
385
+ circularDependencyCount: cycles.length,
386
+ },
387
+ };
388
+ }
389
+ //# sourceMappingURL=code-organization-analyzer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code-organization-analyzer.js","sourceRoot":"","sources":["../../src/analyzer/code-organization-analyzer.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"pattern-catalog.d.ts","sourceRoot":"","sources":["../../src/analyzer/pattern-catalog.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAEnE;;;;;;;;;GASG;AACH,MAAM,WAAW,iBAAiB;IAChC,6EAA6E;IAC7E,EAAE,EAAE,MAAM,CAAC;IACX,qDAAqD;IACrD,MAAM,EAAE,gBAAgB,CAAC;IACzB,8DAA8D;IAC9D,WAAW,EAAE,MAAM,CAAC;IACpB,sCAAsC;IACtC,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,+CAA+C;IAC/C,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,mDAAmD;IACnD,cAAc,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,IAAI,iBAAiB,EAAE,CAkqBvD;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAExE"}
1
+ {"version":3,"file":"pattern-catalog.d.ts","sourceRoot":"","sources":["../../src/analyzer/pattern-catalog.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAEnE;;;;;;;;;GASG;AACH,MAAM,WAAW,iBAAiB;IAChC,6EAA6E;IAC7E,EAAE,EAAE,MAAM,CAAC;IACX,qDAAqD;IACrD,MAAM,EAAE,gBAAgB,CAAC;IACzB,8DAA8D;IAC9D,WAAW,EAAE,MAAM,CAAC;IACpB,sCAAsC;IACtC,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,+CAA+C;IAC/C,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,mDAAmD;IACnD,cAAc,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,IAAI,iBAAiB,EAAE,CAmsBvD;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAExE"}
@@ -544,6 +544,39 @@ export function getPatternCatalog() {
544
544
  // -----------------------------------------------------------------------
545
545
  // H. Delivery / Quality / DevEx
546
546
  // -----------------------------------------------------------------------
547
+ // code-organization
548
+ {
549
+ id: 'org-deep-relative-import',
550
+ domain: 'code-organization',
551
+ description: 'Deep relative import path (3+ parent traversals) indicating poor module structure',
552
+ filePatterns: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'],
553
+ codePatterns: [
554
+ /(?:import|from)\s+['"`]\.\.\/\.\.\/\.\.\//,
555
+ /require\s*\(\s*['"`]\.\.\/\.\.\/\.\.\//,
556
+ ],
557
+ confidenceBase: 0.75,
558
+ },
559
+ {
560
+ id: 'org-barrel-reexport-wildcard',
561
+ domain: 'code-organization',
562
+ description: 'Wildcard barrel re-export (export * from) — risks namespace pollution and circular deps',
563
+ filePatterns: ['**/index.ts', '**/index.tsx', '**/index.js', '**/index.jsx'],
564
+ codePatterns: [
565
+ /export\s+\*\s+from\s+['"`]/,
566
+ ],
567
+ confidenceBase: 0.65,
568
+ },
569
+ {
570
+ id: 'org-catch-all-utils-import',
571
+ domain: 'code-organization',
572
+ description: 'Import from catch-all utils/helpers/common directory — should be split by domain',
573
+ filePatterns: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'],
574
+ codePatterns: [
575
+ /(?:import|from)\s+['"`][.\/]*(?:utils|helpers|common|shared|lib)\/(?!index)/,
576
+ /require\s*\(\s*['"`][.\/]*(?:utils|helpers|common|shared|lib)\//,
577
+ ],
578
+ confidenceBase: 0.5,
579
+ },
547
580
  // testing-strategy
548
581
  {
549
582
  id: 'test-manual-assertions',