@soulbatical/tetra-dev-toolkit 1.6.1 → 1.7.0

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.
@@ -0,0 +1,140 @@
1
+ /**
2
+ * Check: File Size / God File Detection
3
+ *
4
+ * Prevents "god files" — overly large source files that:
5
+ * - Are hard to review, test, and maintain
6
+ * - Indicate missing separation of concerns
7
+ * - Grow silently until they become unmovable
8
+ *
9
+ * Uses config.codeQuality.maxFileLines (default: 500).
10
+ * Scans backend + frontend source directories.
11
+ */
12
+
13
+ import { glob } from 'glob'
14
+ import { readFileSync } from 'fs'
15
+
16
+ export const meta = {
17
+ id: 'file-size',
18
+ name: 'File Size / God File Detection',
19
+ category: 'codeQuality',
20
+ severity: 'high',
21
+ description: 'Detects source files exceeding maxFileLines — god files that need splitting'
22
+ }
23
+
24
+ export async function run(config, projectRoot) {
25
+ const maxLines = config.codeQuality?.maxFileLines || 500
26
+
27
+ const results = {
28
+ passed: true,
29
+ findings: [],
30
+ summary: { total: 0, critical: 0, high: 0, medium: 0, low: 0 },
31
+ info: {
32
+ maxFileLines: maxLines,
33
+ filesScanned: 0,
34
+ violations: 0,
35
+ largest: null
36
+ }
37
+ }
38
+
39
+ // Scan all TypeScript/JavaScript source files
40
+ const patterns = [
41
+ 'backend/src/**/*.ts',
42
+ 'frontend/src/**/*.ts',
43
+ 'frontend/src/**/*.tsx',
44
+ 'backend-mcp/src/**/*.ts',
45
+ 'src/**/*.ts',
46
+ 'src/**/*.tsx',
47
+ 'bot/**/*.ts',
48
+ ]
49
+
50
+ let files = []
51
+ for (const pattern of patterns) {
52
+ const found = await glob(pattern, {
53
+ cwd: projectRoot,
54
+ ignore: [
55
+ ...(config.ignore || []),
56
+ 'node_modules/**',
57
+ '**/node_modules/**',
58
+ 'dist/**',
59
+ '**/dist/**',
60
+ 'build/**',
61
+ '**/build/**',
62
+ '**/*.test.*',
63
+ '**/*.spec.*',
64
+ '**/*.d.ts',
65
+ '**/*.js.map',
66
+ '**/generated/**',
67
+ ]
68
+ })
69
+ files.push(...found)
70
+ }
71
+
72
+ // Deduplicate
73
+ files = [...new Set(files)]
74
+
75
+ if (files.length === 0) {
76
+ results.skipped = true
77
+ results.skipReason = 'No source files found'
78
+ return results
79
+ }
80
+
81
+ let largestFile = null
82
+ let largestLines = 0
83
+
84
+ for (const file of files) {
85
+ const filePath = `${projectRoot}/${file}`
86
+ let content
87
+ try {
88
+ content = readFileSync(filePath, 'utf-8')
89
+ } catch {
90
+ continue
91
+ }
92
+
93
+ results.info.filesScanned++
94
+
95
+ const lineCount = content.split('\n').length
96
+
97
+ // Track largest file
98
+ if (lineCount > largestLines) {
99
+ largestLines = lineCount
100
+ largestFile = file
101
+ }
102
+
103
+ if (lineCount <= maxLines) continue
104
+
105
+ // Determine severity based on how far over the limit
106
+ const ratio = lineCount / maxLines
107
+ let severity
108
+ if (ratio >= 5) {
109
+ severity = 'critical' // 5x over limit (e.g. 2500+ lines with 500 limit)
110
+ } else if (ratio >= 3) {
111
+ severity = 'high' // 3x over limit (e.g. 1500+ lines)
112
+ } else if (ratio >= 2) {
113
+ severity = 'medium' // 2x over limit (e.g. 1000+ lines)
114
+ } else {
115
+ severity = 'low' // Just over limit
116
+ }
117
+
118
+ results.findings.push({
119
+ file,
120
+ line: 1,
121
+ type: 'GOD_FILE',
122
+ severity,
123
+ message: `${file} has ${lineCount} lines (max: ${maxLines}) — split into smaller modules`,
124
+ fix: `Break this file into focused modules of <${maxLines} lines each`
125
+ })
126
+
127
+ results.summary[severity]++
128
+ results.summary.total++
129
+ results.info.violations++
130
+ }
131
+
132
+ results.info.largest = largestFile ? { file: largestFile, lines: largestLines } : null
133
+
134
+ // Fail on critical or high findings
135
+ results.passed = results.findings.filter(f =>
136
+ f.severity === 'critical' || f.severity === 'high'
137
+ ).length === 0
138
+
139
+ return results
140
+ }
package/lib/runner.js CHANGED
@@ -15,6 +15,7 @@ import * as huskyHooks from './checks/stability/husky-hooks.js'
15
15
  import * as ciPipeline from './checks/stability/ci-pipeline.js'
16
16
  import * as npmAudit from './checks/stability/npm-audit.js'
17
17
  import * as apiResponseFormat from './checks/codeQuality/api-response-format.js'
18
+ import * as fileSize from './checks/codeQuality/file-size.js'
18
19
  import * as gitignoreValidation from './checks/security/gitignore-validation.js'
19
20
  import * as rlsPolicyAudit from './checks/supabase/rls-policy-audit.js'
20
21
  import * as rpcParamMismatch from './checks/supabase/rpc-param-mismatch.js'
@@ -36,7 +37,8 @@ const ALL_CHECKS = {
36
37
  npmAudit
37
38
  ],
38
39
  codeQuality: [
39
- apiResponseFormat
40
+ apiResponseFormat,
41
+ fileSize
40
42
  ],
41
43
  supabase: [
42
44
  rlsPolicyAudit,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@soulbatical/tetra-dev-toolkit",
3
- "version": "1.6.1",
3
+ "version": "1.7.0",
4
4
  "publishConfig": {
5
5
  "access": "restricted"
6
6
  },