react-anti-pattern-sniffer 0.1.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.
- package/.snifferrc.json +29 -0
- package/LICENSE +21 -0
- package/README.md +289 -0
- package/bin/react-sniff.js +3 -0
- package/dist/src/cli/arg-parser.d.ts +10 -0
- package/dist/src/cli/arg-parser.d.ts.map +1 -0
- package/dist/src/cli/arg-parser.js +81 -0
- package/dist/src/cli/arg-parser.js.map +1 -0
- package/dist/src/cli/config-loader.d.ts +11 -0
- package/dist/src/cli/config-loader.d.ts.map +1 -0
- package/dist/src/cli/config-loader.js +140 -0
- package/dist/src/cli/config-loader.js.map +1 -0
- package/dist/src/cli/help.d.ts +3 -0
- package/dist/src/cli/help.d.ts.map +1 -0
- package/dist/src/cli/help.js +59 -0
- package/dist/src/cli/help.js.map +1 -0
- package/dist/src/cli/index.d.ts +2 -0
- package/dist/src/cli/index.d.ts.map +1 -0
- package/dist/src/cli/index.js +107 -0
- package/dist/src/cli/index.js.map +1 -0
- package/dist/src/core/file-discoverer.d.ts +8 -0
- package/dist/src/core/file-discoverer.d.ts.map +1 -0
- package/dist/src/core/file-discoverer.js +151 -0
- package/dist/src/core/file-discoverer.js.map +1 -0
- package/dist/src/core/orchestrator.d.ts +13 -0
- package/dist/src/core/orchestrator.d.ts.map +1 -0
- package/dist/src/core/orchestrator.js +176 -0
- package/dist/src/core/orchestrator.js.map +1 -0
- package/dist/src/core/sniffer-ignore.d.ts +25 -0
- package/dist/src/core/sniffer-ignore.d.ts.map +1 -0
- package/dist/src/core/sniffer-ignore.js +91 -0
- package/dist/src/core/sniffer-ignore.js.map +1 -0
- package/dist/src/core/sniffer-registry.d.ts +8 -0
- package/dist/src/core/sniffer-registry.d.ts.map +1 -0
- package/dist/src/core/sniffer-registry.js +64 -0
- package/dist/src/core/sniffer-registry.js.map +1 -0
- package/dist/src/core/worker-pool.d.ts +27 -0
- package/dist/src/core/worker-pool.d.ts.map +1 -0
- package/dist/src/core/worker-pool.js +176 -0
- package/dist/src/core/worker-pool.js.map +1 -0
- package/dist/src/core/worker-runner.d.ts +2 -0
- package/dist/src/core/worker-runner.d.ts.map +1 -0
- package/dist/src/core/worker-runner.js +52 -0
- package/dist/src/core/worker-runner.js.map +1 -0
- package/dist/src/output/formatter.d.ts +3 -0
- package/dist/src/output/formatter.d.ts.map +1 -0
- package/dist/src/output/formatter.js +13 -0
- package/dist/src/output/formatter.js.map +1 -0
- package/dist/src/output/json-renderer.d.ts +3 -0
- package/dist/src/output/json-renderer.d.ts.map +1 -0
- package/dist/src/output/json-renderer.js +49 -0
- package/dist/src/output/json-renderer.js.map +1 -0
- package/dist/src/output/markdown-renderer.d.ts +3 -0
- package/dist/src/output/markdown-renderer.d.ts.map +1 -0
- package/dist/src/output/markdown-renderer.js +70 -0
- package/dist/src/output/markdown-renderer.js.map +1 -0
- package/dist/src/plugins/plugin-loader.d.ts +7 -0
- package/dist/src/plugins/plugin-loader.d.ts.map +1 -0
- package/dist/src/plugins/plugin-loader.js +47 -0
- package/dist/src/plugins/plugin-loader.js.map +1 -0
- package/dist/src/plugins/plugin-sandbox.d.ts +3 -0
- package/dist/src/plugins/plugin-sandbox.d.ts.map +1 -0
- package/dist/src/plugins/plugin-sandbox.js +105 -0
- package/dist/src/plugins/plugin-sandbox.js.map +1 -0
- package/dist/src/plugins/plugin-validator.d.ts +14 -0
- package/dist/src/plugins/plugin-validator.d.ts.map +1 -0
- package/dist/src/plugins/plugin-validator.js +92 -0
- package/dist/src/plugins/plugin-validator.js.map +1 -0
- package/dist/src/sniffers/god-hook-sniffer.d.ts +12 -0
- package/dist/src/sniffers/god-hook-sniffer.d.ts.map +1 -0
- package/dist/src/sniffers/god-hook-sniffer.js +109 -0
- package/dist/src/sniffers/god-hook-sniffer.js.map +1 -0
- package/dist/src/sniffers/prop-drilling-sniffer.d.ts +5 -0
- package/dist/src/sniffers/prop-drilling-sniffer.d.ts.map +1 -0
- package/dist/src/sniffers/prop-drilling-sniffer.js +145 -0
- package/dist/src/sniffers/prop-drilling-sniffer.js.map +1 -0
- package/dist/src/sniffers/prop-explosion-sniffer.d.ts +4 -0
- package/dist/src/sniffers/prop-explosion-sniffer.d.ts.map +1 -0
- package/dist/src/sniffers/prop-explosion-sniffer.js +134 -0
- package/dist/src/sniffers/prop-explosion-sniffer.js.map +1 -0
- package/dist/src/sniffers/sniffer-interface.d.ts +88 -0
- package/dist/src/sniffers/sniffer-interface.d.ts.map +1 -0
- package/dist/src/sniffers/sniffer-interface.js +18 -0
- package/dist/src/sniffers/sniffer-interface.js.map +1 -0
- package/dist/src/tui/interactive-viewer.d.ts +7 -0
- package/dist/src/tui/interactive-viewer.d.ts.map +1 -0
- package/dist/src/tui/interactive-viewer.js +453 -0
- package/dist/src/tui/interactive-viewer.js.map +1 -0
- package/dist/src/utils/logger.d.ts +11 -0
- package/dist/src/utils/logger.d.ts.map +1 -0
- package/dist/src/utils/logger.js +90 -0
- package/dist/src/utils/logger.js.map +1 -0
- package/dist/src/utils/regex-helpers.d.ts +53 -0
- package/dist/src/utils/regex-helpers.d.ts.map +1 -0
- package/dist/src/utils/regex-helpers.js +275 -0
- package/dist/src/utils/regex-helpers.js.map +1 -0
- package/package.json +40 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"help.js","sourceRoot":"","sources":["../../../src/cli/help.ts"],"names":[],"mappings":";;AAGA,8BA0CC;AAED,oCAQC;AAvDD,qCAAuC;AACvC,yCAAiC;AAEjC,SAAgB,SAAS;IACvB,MAAM,IAAI,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsCd,CAAC,IAAI,EAAE,CAAC;IAEP,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AACpB,CAAC;AAED,SAAgB,YAAY;IAC1B,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,IAAA,gBAAI,EAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,CAAC,CAAC;QAClE,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAA,sBAAY,EAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;QACtD,OAAO,CAAC,GAAG,CAAC,+BAA+B,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;IAC5D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,GAAG,CAAC,8CAA8C,CAAC,CAAC;IAC9D,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cli/index.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const arg_parser_js_1 = require("./arg-parser.js");
|
|
4
|
+
const config_loader_js_1 = require("./config-loader.js");
|
|
5
|
+
const help_js_1 = require("./help.js");
|
|
6
|
+
const orchestrator_js_1 = require("../core/orchestrator.js");
|
|
7
|
+
const interactive_viewer_js_1 = require("../tui/interactive-viewer.js");
|
|
8
|
+
const formatter_js_1 = require("../output/formatter.js");
|
|
9
|
+
const logger_js_1 = require("../utils/logger.js");
|
|
10
|
+
const node_fs_1 = require("node:fs");
|
|
11
|
+
const node_path_1 = require("node:path");
|
|
12
|
+
const DEFAULT_BATCH_SIZE = 10;
|
|
13
|
+
/**
|
|
14
|
+
* Apply a batch limit to grouped results — keeps only the first N detections total.
|
|
15
|
+
*/
|
|
16
|
+
function applyBatchLimit(grouped, batchSize) {
|
|
17
|
+
const limited = new Map();
|
|
18
|
+
let remaining = batchSize;
|
|
19
|
+
for (const [filePath, results] of grouped) {
|
|
20
|
+
if (remaining <= 0)
|
|
21
|
+
break;
|
|
22
|
+
const limitedResults = [];
|
|
23
|
+
for (const result of results) {
|
|
24
|
+
if (remaining <= 0)
|
|
25
|
+
break;
|
|
26
|
+
if (result.detections.length <= remaining) {
|
|
27
|
+
limitedResults.push(result);
|
|
28
|
+
remaining -= result.detections.length;
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
limitedResults.push({
|
|
32
|
+
...result,
|
|
33
|
+
detections: result.detections.slice(0, remaining),
|
|
34
|
+
});
|
|
35
|
+
remaining = 0;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (limitedResults.length > 0) {
|
|
39
|
+
limited.set(filePath, limitedResults);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return limited;
|
|
43
|
+
}
|
|
44
|
+
async function main() {
|
|
45
|
+
const { flags, positionals } = (0, arg_parser_js_1.parseArgs)(process.argv.slice(2));
|
|
46
|
+
if (flags.help) {
|
|
47
|
+
(0, help_js_1.printHelp)();
|
|
48
|
+
process.exit(0);
|
|
49
|
+
}
|
|
50
|
+
if (flags.version) {
|
|
51
|
+
(0, help_js_1.printVersion)();
|
|
52
|
+
process.exit(0);
|
|
53
|
+
}
|
|
54
|
+
const isInteractive = flags.interactive === true;
|
|
55
|
+
const hasBatchFlag = flags.batch !== undefined;
|
|
56
|
+
if (flags.verbose) {
|
|
57
|
+
(0, logger_js_1.setLogLevel)('debug');
|
|
58
|
+
}
|
|
59
|
+
else if (flags.quiet || isInteractive) {
|
|
60
|
+
(0, logger_js_1.setLogLevel)(isInteractive ? 'warn' : 'silent');
|
|
61
|
+
}
|
|
62
|
+
// Parse batch size
|
|
63
|
+
let batchSize = DEFAULT_BATCH_SIZE;
|
|
64
|
+
if (typeof flags.batch === 'string') {
|
|
65
|
+
const n = parseInt(flags.batch, 10);
|
|
66
|
+
if (isNaN(n) || n < 1) {
|
|
67
|
+
console.error(`Invalid batch size "${flags.batch}". Must be a positive integer.`);
|
|
68
|
+
process.exit(2);
|
|
69
|
+
}
|
|
70
|
+
batchSize = n;
|
|
71
|
+
}
|
|
72
|
+
try {
|
|
73
|
+
const config = (0, config_loader_js_1.loadConfig)(flags);
|
|
74
|
+
const targetDir = typeof flags.dir === 'string'
|
|
75
|
+
? (0, node_path_1.resolve)(flags.dir)
|
|
76
|
+
: positionals[0]
|
|
77
|
+
? (0, node_path_1.resolve)(positionals[0])
|
|
78
|
+
: process.cwd();
|
|
79
|
+
const result = await (0, orchestrator_js_1.orchestrate)(config, targetDir);
|
|
80
|
+
if (isInteractive) {
|
|
81
|
+
await (0, interactive_viewer_js_1.interactiveViewer)(result.grouped, result.issueCount, result.fileCount, targetDir, batchSize);
|
|
82
|
+
process.exit(result.issueCount > 0 ? 1 : 0);
|
|
83
|
+
}
|
|
84
|
+
// Apply batch limit if -b flag is used (even in non-interactive mode)
|
|
85
|
+
let outputStr;
|
|
86
|
+
if (hasBatchFlag) {
|
|
87
|
+
const limited = applyBatchLimit(result.grouped, batchSize);
|
|
88
|
+
outputStr = (0, formatter_js_1.formatOutput)(limited, config);
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
outputStr = result.output;
|
|
92
|
+
}
|
|
93
|
+
if (config.outputPath) {
|
|
94
|
+
(0, node_fs_1.writeFileSync)(config.outputPath, outputStr, 'utf8');
|
|
95
|
+
}
|
|
96
|
+
else if (!flags.quiet) {
|
|
97
|
+
process.stdout.write(outputStr);
|
|
98
|
+
}
|
|
99
|
+
process.exit(result.issueCount > 0 ? 1 : 0);
|
|
100
|
+
}
|
|
101
|
+
catch (err) {
|
|
102
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
103
|
+
process.exit(2);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
main();
|
|
107
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cli/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Discover files matching include patterns, excluding those matching exclude patterns.
|
|
3
|
+
* Uses an iterative directory walk to avoid stack overflow on large codebases.
|
|
4
|
+
* Skips excluded directories early during traversal for performance.
|
|
5
|
+
* Returns sorted array of absolute file paths.
|
|
6
|
+
*/
|
|
7
|
+
export declare function discoverFiles(include: string[], exclude: string[], basePath: string): string[];
|
|
8
|
+
//# sourceMappingURL=file-discoverer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-discoverer.d.ts","sourceRoot":"","sources":["../../../src/core/file-discoverer.ts"],"names":[],"mappings":"AA6FA;;;;;GAKG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EAAE,EACjB,OAAO,EAAE,MAAM,EAAE,EACjB,QAAQ,EAAE,MAAM,GACf,MAAM,EAAE,CAqDV"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.discoverFiles = discoverFiles;
|
|
4
|
+
const node_fs_1 = require("node:fs");
|
|
5
|
+
const node_path_1 = require("node:path");
|
|
6
|
+
/**
|
|
7
|
+
* Minimal glob pattern matcher.
|
|
8
|
+
* Supports: ** (any path), * (any name segment), {a,b} (alternatives)
|
|
9
|
+
*/
|
|
10
|
+
function matchesGlob(filePath, pattern) {
|
|
11
|
+
// Expand {a,b} alternatives
|
|
12
|
+
const braceMatch = pattern.match(/\{([^}]+)\}/);
|
|
13
|
+
if (braceMatch) {
|
|
14
|
+
const alternatives = braceMatch[1].split(',');
|
|
15
|
+
return alternatives.some(alt => {
|
|
16
|
+
const expanded = pattern.replace(braceMatch[0], alt.trim());
|
|
17
|
+
return matchesGlob(filePath, expanded);
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
// Convert glob to regex
|
|
21
|
+
let regexStr = '^';
|
|
22
|
+
let i = 0;
|
|
23
|
+
while (i < pattern.length) {
|
|
24
|
+
const ch = pattern[i];
|
|
25
|
+
if (ch === '*' && pattern[i + 1] === '*') {
|
|
26
|
+
// ** matches any path
|
|
27
|
+
if (pattern[i + 2] === '/') {
|
|
28
|
+
regexStr += '(?:.+/)?';
|
|
29
|
+
i += 3;
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
regexStr += '.*';
|
|
33
|
+
i += 2;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
else if (ch === '*') {
|
|
37
|
+
// * matches any non-separator chars
|
|
38
|
+
regexStr += '[^/]*';
|
|
39
|
+
i++;
|
|
40
|
+
}
|
|
41
|
+
else if (ch === '?') {
|
|
42
|
+
regexStr += '[^/]';
|
|
43
|
+
i++;
|
|
44
|
+
}
|
|
45
|
+
else if (ch === '.') {
|
|
46
|
+
regexStr += '\\.';
|
|
47
|
+
i++;
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
regexStr += ch;
|
|
51
|
+
i++;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
regexStr += '$';
|
|
55
|
+
return new RegExp(regexStr).test(filePath);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Check if a file path matches any of the given glob patterns.
|
|
59
|
+
*/
|
|
60
|
+
function matchesAny(filePath, patterns) {
|
|
61
|
+
return patterns.some(p => matchesGlob(filePath, p));
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Build a set of simple directory names to skip during traversal.
|
|
65
|
+
* Extracts plain names (no globs, no slashes) from exclude patterns.
|
|
66
|
+
*/
|
|
67
|
+
function buildExcludedDirs(exclude) {
|
|
68
|
+
const dirs = new Set();
|
|
69
|
+
for (const pattern of exclude) {
|
|
70
|
+
if (!pattern.includes('*') && !pattern.includes('/') && !pattern.includes('?')) {
|
|
71
|
+
dirs.add(pattern);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return dirs;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Check if a relative path matches any exclude pattern.
|
|
78
|
+
*/
|
|
79
|
+
function isExcluded(normalized, exclude, excludedDirs) {
|
|
80
|
+
// Check simple directory name exclusion
|
|
81
|
+
const segments = normalized.split('/');
|
|
82
|
+
for (const segment of segments) {
|
|
83
|
+
if (excludedDirs.has(segment))
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
// Check glob-based exclusion
|
|
87
|
+
for (const pattern of exclude) {
|
|
88
|
+
if (pattern.includes('*') || pattern.includes('/') || pattern.includes('?')) {
|
|
89
|
+
if (matchesGlob(normalized, pattern))
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Discover files matching include patterns, excluding those matching exclude patterns.
|
|
97
|
+
* Uses an iterative directory walk to avoid stack overflow on large codebases.
|
|
98
|
+
* Skips excluded directories early during traversal for performance.
|
|
99
|
+
* Returns sorted array of absolute file paths.
|
|
100
|
+
*/
|
|
101
|
+
function discoverFiles(include, exclude, basePath) {
|
|
102
|
+
const results = [];
|
|
103
|
+
const excludedDirs = buildExcludedDirs(exclude);
|
|
104
|
+
// Iterative BFS directory walk
|
|
105
|
+
const queue = [basePath];
|
|
106
|
+
while (queue.length > 0) {
|
|
107
|
+
const dir = queue.shift();
|
|
108
|
+
let entries;
|
|
109
|
+
try {
|
|
110
|
+
entries = (0, node_fs_1.readdirSync)(dir);
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
for (const entry of entries) {
|
|
116
|
+
// Skip hidden directories/files (., .git, etc.)
|
|
117
|
+
if (entry.startsWith('.'))
|
|
118
|
+
continue;
|
|
119
|
+
// Early skip: if this directory name is in the simple exclude set, skip entirely
|
|
120
|
+
if (excludedDirs.has(entry))
|
|
121
|
+
continue;
|
|
122
|
+
const fullPath = (0, node_path_1.join)(dir, entry);
|
|
123
|
+
let stat;
|
|
124
|
+
try {
|
|
125
|
+
stat = (0, node_fs_1.statSync)(fullPath);
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
if (stat.isDirectory()) {
|
|
131
|
+
// Check if this directory path matches any glob exclude pattern
|
|
132
|
+
const relDir = (0, node_path_1.relative)(basePath, fullPath).replace(/\\/g, '/');
|
|
133
|
+
if (!isExcluded(relDir, exclude, excludedDirs)) {
|
|
134
|
+
queue.push(fullPath);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
else if (stat.isFile()) {
|
|
138
|
+
const relPath = (0, node_path_1.relative)(basePath, fullPath).replace(/\\/g, '/');
|
|
139
|
+
// Check exclude patterns
|
|
140
|
+
if (isExcluded(relPath, exclude, excludedDirs))
|
|
141
|
+
continue;
|
|
142
|
+
// Check include patterns
|
|
143
|
+
if (matchesAny(relPath, include)) {
|
|
144
|
+
results.push(fullPath);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return results.sort();
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=file-discoverer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-discoverer.js","sourceRoot":"","sources":["../../../src/core/file-discoverer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { SnifferConfig, SnifferResult } from '../sniffers/sniffer-interface.js';
|
|
2
|
+
export interface OrchestrateResult {
|
|
3
|
+
output: string;
|
|
4
|
+
issueCount: number;
|
|
5
|
+
fileCount: number;
|
|
6
|
+
grouped: Map<string, SnifferResult[]>;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Main orchestration pipeline.
|
|
10
|
+
* Discovers files, loads sniffers, dispatches to workers, collects results, formats output.
|
|
11
|
+
*/
|
|
12
|
+
export declare function orchestrate(config: SnifferConfig, targetDir: string): Promise<OrchestrateResult>;
|
|
13
|
+
//# sourceMappingURL=orchestrator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../../../src/core/orchestrator.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAA4B,MAAM,kCAAkC,CAAC;AAQ/G,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,EAAE,CAAC,CAAC;CACvC;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAAC,MAAM,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAuLtG"}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.orchestrate = orchestrate;
|
|
4
|
+
const node_fs_1 = require("node:fs");
|
|
5
|
+
const node_path_1 = require("node:path");
|
|
6
|
+
const file_discoverer_js_1 = require("./file-discoverer.js");
|
|
7
|
+
const sniffer_registry_js_1 = require("./sniffer-registry.js");
|
|
8
|
+
const worker_pool_js_1 = require("./worker-pool.js");
|
|
9
|
+
const formatter_js_1 = require("../output/formatter.js");
|
|
10
|
+
const logger_js_1 = require("../utils/logger.js");
|
|
11
|
+
const sniffer_ignore_js_1 = require("./sniffer-ignore.js");
|
|
12
|
+
/**
|
|
13
|
+
* Main orchestration pipeline.
|
|
14
|
+
* Discovers files, loads sniffers, dispatches to workers, collects results, formats output.
|
|
15
|
+
*/
|
|
16
|
+
async function orchestrate(config, targetDir) {
|
|
17
|
+
const startTime = Date.now();
|
|
18
|
+
// 1. Discover target files
|
|
19
|
+
(0, logger_js_1.step)(`Scanning ${(0, node_path_1.relative)(process.cwd(), targetDir) || '.'} for React files...`);
|
|
20
|
+
const files = (0, file_discoverer_js_1.discoverFiles)(config.include, config.exclude, targetDir);
|
|
21
|
+
if (files.length === 0) {
|
|
22
|
+
(0, logger_js_1.warn)('No matching files found.');
|
|
23
|
+
const emptyResults = new Map();
|
|
24
|
+
return { output: (0, formatter_js_1.formatOutput)(emptyResults, config), issueCount: 0, fileCount: 0, grouped: emptyResults };
|
|
25
|
+
}
|
|
26
|
+
(0, logger_js_1.success)(`Found ${files.length} file${files.length === 1 ? '' : 's'} to analyze`);
|
|
27
|
+
// 2. Build sniffer registry
|
|
28
|
+
(0, logger_js_1.step)('Loading sniffers...');
|
|
29
|
+
const registry = new sniffer_registry_js_1.SnifferRegistry();
|
|
30
|
+
registry.registerBuiltIn();
|
|
31
|
+
// Register plugins
|
|
32
|
+
for (const pluginEntry of config.plugins) {
|
|
33
|
+
(0, logger_js_1.info)(` Loading plugin: ${pluginEntry.path}`);
|
|
34
|
+
registry.registerPlugin(pluginEntry, targetDir);
|
|
35
|
+
}
|
|
36
|
+
// 3. Get enabled sniffers
|
|
37
|
+
const enabledSniffers = registry.getEnabledSniffers(config.sniffers);
|
|
38
|
+
if (enabledSniffers.length === 0) {
|
|
39
|
+
(0, logger_js_1.warn)('No sniffers enabled.');
|
|
40
|
+
const emptyResults = new Map();
|
|
41
|
+
return { output: (0, formatter_js_1.formatOutput)(emptyResults, config), issueCount: 0, fileCount: files.length, grouped: emptyResults };
|
|
42
|
+
}
|
|
43
|
+
(0, logger_js_1.success)(`${enabledSniffers.length} sniffer${enabledSniffers.length === 1 ? '' : 's'} active: ${enabledSniffers.map(s => s.name).join(', ')}`);
|
|
44
|
+
// 4. Run sniffers
|
|
45
|
+
const allResults = [];
|
|
46
|
+
const mode = config.parallel && files.length > 1 ? 'parallel' : 'sequential';
|
|
47
|
+
const totalTasks = files.length * enabledSniffers.length;
|
|
48
|
+
let completedTasks = 0;
|
|
49
|
+
(0, logger_js_1.step)(`Running analysis (${mode}, ${totalTasks} tasks across ${files.length} files)...`);
|
|
50
|
+
if (mode === 'parallel') {
|
|
51
|
+
// Parallel mode via worker pool
|
|
52
|
+
const workerScript = (0, node_path_1.join)(__dirname, 'worker-runner.js');
|
|
53
|
+
const pool = new worker_pool_js_1.WorkerPool(workerScript, config.maxWorkers);
|
|
54
|
+
(0, logger_js_1.debug)(`Worker pool started with ${config.maxWorkers} workers`);
|
|
55
|
+
try {
|
|
56
|
+
const tasks = [];
|
|
57
|
+
for (const filePath of files) {
|
|
58
|
+
const fileContent = (0, node_fs_1.readFileSync)(filePath, 'utf8');
|
|
59
|
+
for (const sniffer of enabledSniffers) {
|
|
60
|
+
const task = pool
|
|
61
|
+
.runTask(sniffer.snifferPath, fileContent, filePath, sniffer.config, config.timeoutMs)
|
|
62
|
+
.then(msg => {
|
|
63
|
+
allResults.push(msg.result);
|
|
64
|
+
completedTasks++;
|
|
65
|
+
(0, logger_js_1.fileProgress)(completedTasks, totalTasks, (0, node_path_1.relative)(targetDir, filePath));
|
|
66
|
+
})
|
|
67
|
+
.catch(err => {
|
|
68
|
+
allResults.push({
|
|
69
|
+
snifferName: sniffer.name,
|
|
70
|
+
filePath,
|
|
71
|
+
detections: [],
|
|
72
|
+
durationMs: 0,
|
|
73
|
+
error: err instanceof Error ? err.message : String(err),
|
|
74
|
+
});
|
|
75
|
+
completedTasks++;
|
|
76
|
+
});
|
|
77
|
+
tasks.push(task);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
await Promise.allSettled(tasks);
|
|
81
|
+
}
|
|
82
|
+
finally {
|
|
83
|
+
await pool.destroy();
|
|
84
|
+
(0, logger_js_1.debug)('Worker pool destroyed');
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
// Sequential mode — run in main thread
|
|
89
|
+
for (let fi = 0; fi < files.length; fi++) {
|
|
90
|
+
const filePath = files[fi];
|
|
91
|
+
const fileContent = (0, node_fs_1.readFileSync)(filePath, 'utf8');
|
|
92
|
+
for (const sniffer of enabledSniffers) {
|
|
93
|
+
const startTimeTask = Date.now();
|
|
94
|
+
try {
|
|
95
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
96
|
+
const raw = require(sniffer.snifferPath);
|
|
97
|
+
const snifferModule = raw.default ?? raw;
|
|
98
|
+
const detections = snifferModule.detect(fileContent, filePath, sniffer.config);
|
|
99
|
+
allResults.push({
|
|
100
|
+
snifferName: sniffer.name,
|
|
101
|
+
filePath,
|
|
102
|
+
detections: Array.isArray(detections) ? detections : [],
|
|
103
|
+
durationMs: Date.now() - startTimeTask,
|
|
104
|
+
error: null,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
catch (err) {
|
|
108
|
+
allResults.push({
|
|
109
|
+
snifferName: sniffer.name,
|
|
110
|
+
filePath,
|
|
111
|
+
detections: [],
|
|
112
|
+
durationMs: Date.now() - startTimeTask,
|
|
113
|
+
error: err instanceof Error ? err.message : String(err),
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
completedTasks++;
|
|
117
|
+
(0, logger_js_1.fileProgress)(completedTasks, totalTasks, (0, node_path_1.relative)(targetDir, filePath));
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
// 5. Apply .snifferignore
|
|
122
|
+
const ignoreEntries = (0, sniffer_ignore_js_1.loadSnifferIgnore)(targetDir);
|
|
123
|
+
const filteredResults = ignoreEntries.length > 0
|
|
124
|
+
? (0, sniffer_ignore_js_1.applySnifferIgnore)(allResults, ignoreEntries, targetDir)
|
|
125
|
+
: allResults;
|
|
126
|
+
if (ignoreEntries.length > 0) {
|
|
127
|
+
const beforeCount = allResults.reduce((s, r) => s + r.detections.length, 0);
|
|
128
|
+
const afterCount = filteredResults.reduce((s, r) => s + r.detections.length, 0);
|
|
129
|
+
const ignored = beforeCount - afterCount;
|
|
130
|
+
if (ignored > 0) {
|
|
131
|
+
(0, logger_js_1.debug)(`Filtered ${ignored} detection(s) via .snifferignore`);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
// 6. Group results by file path
|
|
135
|
+
const grouped = new Map();
|
|
136
|
+
for (const result of filteredResults) {
|
|
137
|
+
const existing = grouped.get(result.filePath) || [];
|
|
138
|
+
existing.push(result);
|
|
139
|
+
grouped.set(result.filePath, existing);
|
|
140
|
+
}
|
|
141
|
+
// Log any errors
|
|
142
|
+
let errorCount = 0;
|
|
143
|
+
for (const result of filteredResults) {
|
|
144
|
+
if (result.error) {
|
|
145
|
+
errorCount++;
|
|
146
|
+
(0, logger_js_1.warn)(`Sniffer "${result.snifferName}" failed on "${(0, node_path_1.relative)(targetDir, result.filePath)}": ${result.error}`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
// 6. Count total issues
|
|
150
|
+
let issueCount = 0;
|
|
151
|
+
for (const result of filteredResults) {
|
|
152
|
+
issueCount += result.detections.length;
|
|
153
|
+
}
|
|
154
|
+
const elapsed = Date.now() - startTime;
|
|
155
|
+
const filesPerSec = Math.round(files.length / (elapsed / 1000));
|
|
156
|
+
if (issueCount > 0) {
|
|
157
|
+
(0, logger_js_1.step)(`Found ${issueCount} issue${issueCount === 1 ? '' : 's'} in ${elapsed}ms (${filesPerSec} files/sec)`);
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
(0, logger_js_1.success)(`No issues found! Scanned ${files.length} files in ${elapsed}ms (${filesPerSec} files/sec)`);
|
|
161
|
+
}
|
|
162
|
+
if (errorCount > 0) {
|
|
163
|
+
(0, logger_js_1.warn)(`${errorCount} sniffer error${errorCount === 1 ? '' : 's'} occurred (see above)`);
|
|
164
|
+
}
|
|
165
|
+
// 7. Format and return output
|
|
166
|
+
(0, logger_js_1.step)('Generating report...');
|
|
167
|
+
const output = (0, formatter_js_1.formatOutput)(grouped, config);
|
|
168
|
+
(0, logger_js_1.success)('Done!');
|
|
169
|
+
return {
|
|
170
|
+
output,
|
|
171
|
+
issueCount,
|
|
172
|
+
fileCount: files.length,
|
|
173
|
+
grouped,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
//# sourceMappingURL=orchestrator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orchestrator.js","sourceRoot":"","sources":["../../../src/core/orchestrator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { SnifferResult } from '../sniffers/sniffer-interface.js';
|
|
2
|
+
interface IgnoreEntry {
|
|
3
|
+
filePath: string;
|
|
4
|
+
componentName: string | null;
|
|
5
|
+
snifferName: string | null;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Parse a .snifferignore file.
|
|
9
|
+
* Format per line:
|
|
10
|
+
* path/to/file.tsx:ComponentName # sniffer-name
|
|
11
|
+
* path/to/file.tsx # sniffer-name
|
|
12
|
+
* path/to/file.tsx
|
|
13
|
+
* Lines starting with # are comments. Empty lines are skipped.
|
|
14
|
+
*/
|
|
15
|
+
export declare function parseSnifferIgnore(content: string): IgnoreEntry[];
|
|
16
|
+
/**
|
|
17
|
+
* Load .snifferignore from the target directory. Returns empty array if not found.
|
|
18
|
+
*/
|
|
19
|
+
export declare function loadSnifferIgnore(targetDir: string): IgnoreEntry[];
|
|
20
|
+
/**
|
|
21
|
+
* Filter out ignored detections from results.
|
|
22
|
+
*/
|
|
23
|
+
export declare function applySnifferIgnore(results: SnifferResult[], ignoreEntries: IgnoreEntry[], targetDir: string): SnifferResult[];
|
|
24
|
+
export {};
|
|
25
|
+
//# sourceMappingURL=sniffer-ignore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sniffer-ignore.d.ts","sourceRoot":"","sources":["../../../src/core/sniffer-ignore.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AAEtE,UAAU,WAAW;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,EAAE,CAiCjE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,WAAW,EAAE,CAUlE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,aAAa,EAAE,EACxB,aAAa,EAAE,WAAW,EAAE,EAC5B,SAAS,EAAE,MAAM,GAChB,aAAa,EAAE,CA8BjB"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseSnifferIgnore = parseSnifferIgnore;
|
|
4
|
+
exports.loadSnifferIgnore = loadSnifferIgnore;
|
|
5
|
+
exports.applySnifferIgnore = applySnifferIgnore;
|
|
6
|
+
const node_fs_1 = require("node:fs");
|
|
7
|
+
const node_path_1 = require("node:path");
|
|
8
|
+
/**
|
|
9
|
+
* Parse a .snifferignore file.
|
|
10
|
+
* Format per line:
|
|
11
|
+
* path/to/file.tsx:ComponentName # sniffer-name
|
|
12
|
+
* path/to/file.tsx # sniffer-name
|
|
13
|
+
* path/to/file.tsx
|
|
14
|
+
* Lines starting with # are comments. Empty lines are skipped.
|
|
15
|
+
*/
|
|
16
|
+
function parseSnifferIgnore(content) {
|
|
17
|
+
const entries = [];
|
|
18
|
+
for (const rawLine of content.split('\n')) {
|
|
19
|
+
const line = rawLine.trim();
|
|
20
|
+
if (!line || line.startsWith('#'))
|
|
21
|
+
continue;
|
|
22
|
+
// Split off inline comment
|
|
23
|
+
let main = line;
|
|
24
|
+
let snifferName = null;
|
|
25
|
+
const commentIdx = line.indexOf(' #');
|
|
26
|
+
if (commentIdx !== -1) {
|
|
27
|
+
main = line.substring(0, commentIdx).trim();
|
|
28
|
+
snifferName = line.substring(commentIdx + 3).trim() || null;
|
|
29
|
+
}
|
|
30
|
+
// Split file:component
|
|
31
|
+
const colonIdx = main.indexOf(':');
|
|
32
|
+
let filePath;
|
|
33
|
+
let componentName = null;
|
|
34
|
+
if (colonIdx !== -1) {
|
|
35
|
+
filePath = main.substring(0, colonIdx);
|
|
36
|
+
componentName = main.substring(colonIdx + 1) || null;
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
filePath = main;
|
|
40
|
+
}
|
|
41
|
+
entries.push({ filePath, componentName, snifferName });
|
|
42
|
+
}
|
|
43
|
+
return entries;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Load .snifferignore from the target directory. Returns empty array if not found.
|
|
47
|
+
*/
|
|
48
|
+
function loadSnifferIgnore(targetDir) {
|
|
49
|
+
const ignorePath = (0, node_path_1.join)(targetDir, '.snifferignore');
|
|
50
|
+
if (!(0, node_fs_1.existsSync)(ignorePath))
|
|
51
|
+
return [];
|
|
52
|
+
try {
|
|
53
|
+
const content = (0, node_fs_1.readFileSync)(ignorePath, 'utf8');
|
|
54
|
+
return parseSnifferIgnore(content);
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return [];
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Filter out ignored detections from results.
|
|
62
|
+
*/
|
|
63
|
+
function applySnifferIgnore(results, ignoreEntries, targetDir) {
|
|
64
|
+
if (ignoreEntries.length === 0)
|
|
65
|
+
return results;
|
|
66
|
+
return results.map(result => {
|
|
67
|
+
const filteredDetections = result.detections.filter(det => {
|
|
68
|
+
const relPath = (0, node_path_1.relative)(targetDir, det.filePath);
|
|
69
|
+
for (const entry of ignoreEntries) {
|
|
70
|
+
// Check file path match
|
|
71
|
+
if (relPath !== entry.filePath && det.filePath !== entry.filePath)
|
|
72
|
+
continue;
|
|
73
|
+
// Check sniffer name match (null = all sniffers)
|
|
74
|
+
if (entry.snifferName && entry.snifferName !== det.snifferName)
|
|
75
|
+
continue;
|
|
76
|
+
// Check component name match (null = entire file)
|
|
77
|
+
if (entry.componentName) {
|
|
78
|
+
const detComp = det.details?.componentName
|
|
79
|
+
|| det.details?.hookName;
|
|
80
|
+
if (detComp !== entry.componentName)
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
// Matched an ignore entry — filter out
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
return true;
|
|
87
|
+
});
|
|
88
|
+
return { ...result, detections: filteredDetections };
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=sniffer-ignore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sniffer-ignore.js","sourceRoot":"","sources":["../../../src/core/sniffer-ignore.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { SnifferEntry, PluginEntry } from '../sniffers/sniffer-interface.js';
|
|
2
|
+
export declare class SnifferRegistry {
|
|
3
|
+
private sniffers;
|
|
4
|
+
registerBuiltIn(): void;
|
|
5
|
+
registerPlugin(pluginEntry: PluginEntry, basePath: string): void;
|
|
6
|
+
getEnabledSniffers(snifferConfig: Record<string, Record<string, unknown>>): SnifferEntry[];
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=sniffer-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sniffer-registry.d.ts","sourceRoot":"","sources":["../../../src/core/sniffer-registry.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAiB,MAAM,kCAAkC,CAAC;AAUjG,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAoC;IAEpD,eAAe,IAAI,IAAI;IAiBvB,cAAc,CAAC,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAmBhE,kBAAkB,CAChB,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GACrD,YAAY,EAAE;CA0BlB"}
|