-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathFileClassifier.java
More file actions
139 lines (122 loc) · 5.55 KB
/
Copy pathFileClassifier.java
File metadata and controls
139 lines (122 loc) · 5.55 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package io.github.randomcodespace.iq.analyzer;
import java.nio.file.Path;
import java.util.Set;
/**
* Classifies files into categories that determine how they are processed
* in the analysis pipeline.
* <p>
* SOURCE and CONFIG files get full detector treatment; TEST, BINARY,
* GENERATED, and TEXT files get inventory-only nodes (no detectors).
* MINIFIED is detected via a content heuristic after classification.
*/
public final class FileClassifier {
private FileClassifier() {}
public enum FileType {
SOURCE, // Code files with architecture keywords -> full detection
CONFIG, // YAML, JSON, TOML, INI, properties, Dockerfile, etc.
TEST, // Test files -> inventory only, no detectors
GENERATED, // .d.ts, .map, .lock, .generated.*, vendor/, generated/
MINIFIED, // Detected by isMinified() heuristic
TEXT, // Readable but no arch keywords -> inventory + snippet
BINARY // Images, fonts, compiled assets -> inventory only
}
// Test path patterns
private static final Set<String> TEST_DIRS = Set.of(
"test", "tests", "spec", "specs", "__tests__", "__mocks__",
"testing", "testdata", "fixtures", "test-resources", "testFixtures"
);
// Generated directory patterns
private static final Set<String> GENERATED_DIRS = Set.of(
"generated", "gen", "vendor", "third_party", "thirdparty"
);
// Binary extensions
private static final Set<String> BINARY_EXTENSIONS = Set.of(
"png", "jpg", "jpeg", "gif", "bmp", "ico", "svg", "webp",
"woff", "woff2", "ttf", "eot", "otf",
"pdf", "zip", "gz", "tar", "jar", "war", "ear",
"class", "pyc", "pyo", "so", "dll", "exe", "dylib",
"mp3", "mp4", "wav", "avi", "mov",
"sqlite", "db", "mdb"
);
/**
* Classify a file based on its path, filename, and language.
*
* @param relativePath path relative to repository root
* @param language language identifier from FileDiscovery (may be null)
* @return the file type classification
*/
public static FileType classify(Path relativePath, String language) {
String pathStr = relativePath.toString().replace('\\', '/');
String fileName = java.util.Objects.toString(relativePath.getFileName(), "");
String ext = getExtension(fileName);
// Binary check first
if (BINARY_EXTENSIONS.contains(ext.toLowerCase())) {
return FileType.BINARY;
}
// Generated check
if (isGenerated(pathStr, fileName, ext)) {
return FileType.GENERATED;
}
// Test check
if (isTestFile(pathStr, fileName, language)) {
return FileType.TEST;
}
// Config languages (YAML, JSON, TOML, etc.) are handled as CONFIG
if (isConfigLanguage(language)) {
return FileType.CONFIG;
}
// If it has a known programming language, it's source
if (language != null && !language.isEmpty()) {
return FileType.SOURCE;
}
// Unknown -> TEXT (will be inventory + snippet)
return FileType.TEXT;
}
static boolean isTestFile(String pathStr, String fileName, String language) {
// Check path components
for (String part : pathStr.split("/")) {
if (TEST_DIRS.contains(part)) return true;
}
// Check filename patterns by language
String lower = fileName.toLowerCase();
if (lower.endsWith("test.java") || lower.endsWith("tests.java") ||
lower.endsWith("spec.java") || lower.endsWith("it.java")) return true;
if (lower.endsWith("_test.go")) return true;
if (lower.startsWith("test_") && lower.endsWith(".py")) return true;
if (lower.endsWith("_test.py")) return true;
if (lower.endsWith(".test.ts") || lower.endsWith(".spec.ts") ||
lower.endsWith(".test.js") || lower.endsWith(".spec.js") ||
lower.endsWith(".test.tsx") || lower.endsWith(".spec.tsx") ||
lower.endsWith(".test.jsx") || lower.endsWith(".spec.jsx")) return true;
if (lower.endsWith("test.kt") || lower.endsWith("test.scala") ||
lower.endsWith("spec.scala")) return true;
if (lower.endsWith("_test.rs")) return true;
return false;
}
static boolean isGenerated(String pathStr, String fileName, String ext) {
for (String part : pathStr.split("/")) {
if (GENERATED_DIRS.contains(part)) return true;
}
if (fileName.endsWith(".d.ts") || fileName.endsWith(".js.map") ||
fileName.endsWith(".css.map")) return true;
if (fileName.endsWith(".generated.java") || fileName.endsWith(".generated.ts") ||
fileName.contains("_generated")) return true;
if ("lock".equals(ext) || fileName.equals("package-lock.json") ||
fileName.equals("yarn.lock") || fileName.equals("pnpm-lock.yaml") ||
fileName.equals("Cargo.lock") || fileName.equals("poetry.lock") ||
fileName.equals("Gemfile.lock") || fileName.equals("go.sum")) return true;
return false;
}
static boolean isConfigLanguage(String language) {
if (language == null) return false;
return switch (language) {
case "yaml", "json", "toml", "ini", "properties", "xml",
"dockerfile", "hcl", "bicep", "proto", "graphql" -> true;
default -> false;
};
}
static String getExtension(String fileName) {
int dot = fileName.lastIndexOf('.');
return dot >= 0 ? fileName.substring(dot + 1) : "";
}
}