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.
Files changed (97) hide show
  1. package/.snifferrc.json +29 -0
  2. package/LICENSE +21 -0
  3. package/README.md +289 -0
  4. package/bin/react-sniff.js +3 -0
  5. package/dist/src/cli/arg-parser.d.ts +10 -0
  6. package/dist/src/cli/arg-parser.d.ts.map +1 -0
  7. package/dist/src/cli/arg-parser.js +81 -0
  8. package/dist/src/cli/arg-parser.js.map +1 -0
  9. package/dist/src/cli/config-loader.d.ts +11 -0
  10. package/dist/src/cli/config-loader.d.ts.map +1 -0
  11. package/dist/src/cli/config-loader.js +140 -0
  12. package/dist/src/cli/config-loader.js.map +1 -0
  13. package/dist/src/cli/help.d.ts +3 -0
  14. package/dist/src/cli/help.d.ts.map +1 -0
  15. package/dist/src/cli/help.js +59 -0
  16. package/dist/src/cli/help.js.map +1 -0
  17. package/dist/src/cli/index.d.ts +2 -0
  18. package/dist/src/cli/index.d.ts.map +1 -0
  19. package/dist/src/cli/index.js +107 -0
  20. package/dist/src/cli/index.js.map +1 -0
  21. package/dist/src/core/file-discoverer.d.ts +8 -0
  22. package/dist/src/core/file-discoverer.d.ts.map +1 -0
  23. package/dist/src/core/file-discoverer.js +151 -0
  24. package/dist/src/core/file-discoverer.js.map +1 -0
  25. package/dist/src/core/orchestrator.d.ts +13 -0
  26. package/dist/src/core/orchestrator.d.ts.map +1 -0
  27. package/dist/src/core/orchestrator.js +176 -0
  28. package/dist/src/core/orchestrator.js.map +1 -0
  29. package/dist/src/core/sniffer-ignore.d.ts +25 -0
  30. package/dist/src/core/sniffer-ignore.d.ts.map +1 -0
  31. package/dist/src/core/sniffer-ignore.js +91 -0
  32. package/dist/src/core/sniffer-ignore.js.map +1 -0
  33. package/dist/src/core/sniffer-registry.d.ts +8 -0
  34. package/dist/src/core/sniffer-registry.d.ts.map +1 -0
  35. package/dist/src/core/sniffer-registry.js +64 -0
  36. package/dist/src/core/sniffer-registry.js.map +1 -0
  37. package/dist/src/core/worker-pool.d.ts +27 -0
  38. package/dist/src/core/worker-pool.d.ts.map +1 -0
  39. package/dist/src/core/worker-pool.js +176 -0
  40. package/dist/src/core/worker-pool.js.map +1 -0
  41. package/dist/src/core/worker-runner.d.ts +2 -0
  42. package/dist/src/core/worker-runner.d.ts.map +1 -0
  43. package/dist/src/core/worker-runner.js +52 -0
  44. package/dist/src/core/worker-runner.js.map +1 -0
  45. package/dist/src/output/formatter.d.ts +3 -0
  46. package/dist/src/output/formatter.d.ts.map +1 -0
  47. package/dist/src/output/formatter.js +13 -0
  48. package/dist/src/output/formatter.js.map +1 -0
  49. package/dist/src/output/json-renderer.d.ts +3 -0
  50. package/dist/src/output/json-renderer.d.ts.map +1 -0
  51. package/dist/src/output/json-renderer.js +49 -0
  52. package/dist/src/output/json-renderer.js.map +1 -0
  53. package/dist/src/output/markdown-renderer.d.ts +3 -0
  54. package/dist/src/output/markdown-renderer.d.ts.map +1 -0
  55. package/dist/src/output/markdown-renderer.js +70 -0
  56. package/dist/src/output/markdown-renderer.js.map +1 -0
  57. package/dist/src/plugins/plugin-loader.d.ts +7 -0
  58. package/dist/src/plugins/plugin-loader.d.ts.map +1 -0
  59. package/dist/src/plugins/plugin-loader.js +47 -0
  60. package/dist/src/plugins/plugin-loader.js.map +1 -0
  61. package/dist/src/plugins/plugin-sandbox.d.ts +3 -0
  62. package/dist/src/plugins/plugin-sandbox.d.ts.map +1 -0
  63. package/dist/src/plugins/plugin-sandbox.js +105 -0
  64. package/dist/src/plugins/plugin-sandbox.js.map +1 -0
  65. package/dist/src/plugins/plugin-validator.d.ts +14 -0
  66. package/dist/src/plugins/plugin-validator.d.ts.map +1 -0
  67. package/dist/src/plugins/plugin-validator.js +92 -0
  68. package/dist/src/plugins/plugin-validator.js.map +1 -0
  69. package/dist/src/sniffers/god-hook-sniffer.d.ts +12 -0
  70. package/dist/src/sniffers/god-hook-sniffer.d.ts.map +1 -0
  71. package/dist/src/sniffers/god-hook-sniffer.js +109 -0
  72. package/dist/src/sniffers/god-hook-sniffer.js.map +1 -0
  73. package/dist/src/sniffers/prop-drilling-sniffer.d.ts +5 -0
  74. package/dist/src/sniffers/prop-drilling-sniffer.d.ts.map +1 -0
  75. package/dist/src/sniffers/prop-drilling-sniffer.js +145 -0
  76. package/dist/src/sniffers/prop-drilling-sniffer.js.map +1 -0
  77. package/dist/src/sniffers/prop-explosion-sniffer.d.ts +4 -0
  78. package/dist/src/sniffers/prop-explosion-sniffer.d.ts.map +1 -0
  79. package/dist/src/sniffers/prop-explosion-sniffer.js +134 -0
  80. package/dist/src/sniffers/prop-explosion-sniffer.js.map +1 -0
  81. package/dist/src/sniffers/sniffer-interface.d.ts +88 -0
  82. package/dist/src/sniffers/sniffer-interface.d.ts.map +1 -0
  83. package/dist/src/sniffers/sniffer-interface.js +18 -0
  84. package/dist/src/sniffers/sniffer-interface.js.map +1 -0
  85. package/dist/src/tui/interactive-viewer.d.ts +7 -0
  86. package/dist/src/tui/interactive-viewer.d.ts.map +1 -0
  87. package/dist/src/tui/interactive-viewer.js +453 -0
  88. package/dist/src/tui/interactive-viewer.js.map +1 -0
  89. package/dist/src/utils/logger.d.ts +11 -0
  90. package/dist/src/utils/logger.d.ts.map +1 -0
  91. package/dist/src/utils/logger.js +90 -0
  92. package/dist/src/utils/logger.js.map +1 -0
  93. package/dist/src/utils/regex-helpers.d.ts +53 -0
  94. package/dist/src/utils/regex-helpers.d.ts.map +1 -0
  95. package/dist/src/utils/regex-helpers.js +275 -0
  96. package/dist/src/utils/regex-helpers.js.map +1 -0
  97. package/package.json +40 -0
@@ -0,0 +1,275 @@
1
+ "use strict";
2
+ /**
3
+ * Shared regex patterns and utility functions for React code parsing.
4
+ * All sniffers depend on these for consistent detection.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.USE_LAYOUT_EFFECT = exports.USE_REDUCER = exports.USE_CONTEXT = exports.USE_REF = exports.USE_MEMO = exports.USE_CALLBACK = exports.USE_EFFECT = exports.USE_STATE = exports.CUSTOM_HOOK_DECL = exports.JSX_SPREAD = exports.JSX_ATTRIBUTE = exports.JSX_OPENING_TAG = exports.DESTRUCTURED_PROPS = exports.FUNCTIONAL_COMPONENT_DECL = void 0;
8
+ exports.extractBracedBlock = extractBracedBlock;
9
+ exports.getLineNumber = getLineNumber;
10
+ exports.getColumnNumber = getColumnNumber;
11
+ exports.countMatches = countMatches;
12
+ exports.stripCommentsAndStrings = stripCommentsAndStrings;
13
+ exports.parseDestructuredProps = parseDestructuredProps;
14
+ exports.findOpeningBrace = findOpeningBrace;
15
+ // Matches functional component declarations (PascalCase)
16
+ // Group 1: function declaration, Group 2: memo/forwardRef, Group 3: const assignment
17
+ // Uses [^=\n]* (non-greedy removed, bounded by newline) to avoid catastrophic backtracking on TS annotations
18
+ exports.FUNCTIONAL_COMPONENT_DECL = /(?:function\s+([A-Z][a-zA-Z0-9]*)\s*\(|(?:const|let|var)\s+([A-Z][a-zA-Z0-9]*)\s*(?::[^=\n]*)?\s*=\s*(?:React\.)?(?:memo|forwardRef)\s*\(\s*(?:function\s*\w*\s*)?\(|(?:const|let|var)\s+([A-Z][a-zA-Z0-9]*)\s*(?::[^=\n]*)?\s*=\s*(?:function\s*\w*\s*)?\()/g;
19
+ // Matches destructured props in function parameters: ({ a, b, c })
20
+ // Use on the text starting from the opening ( of a component
21
+ exports.DESTRUCTURED_PROPS = /\(\s*\{([^}]*)\}/;
22
+ // Matches a JSX opening tag with PascalCase name
23
+ // Group 1: component name, Group 2: attributes text
24
+ // Uses [^>]* instead of [\s\S]*? to avoid catastrophic backtracking on large files
25
+ exports.JSX_OPENING_TAG = /<([A-Z][a-zA-Z0-9.]*)(\s[^>]*?)?\s*(?:\/>|>)/g;
26
+ // Matches an individual JSX attribute (not spread)
27
+ // Group 1: attribute name
28
+ exports.JSX_ATTRIBUTE = /(?:^|\s)([a-zA-Z][\w-]*)(?:\s*=\s*(?:\{[^}]*\}|"[^"]*"|'[^']*'|[^\s/>]*)|\s*(?=[/>\s]))/g;
29
+ // Matches JSX spread attribute: {...expr}
30
+ exports.JSX_SPREAD = /\{\s*\.\.\.(\w+)\s*\}/g;
31
+ // Matches custom hook declarations
32
+ // Group 1 (function decl) or Group 2 (const assignment): hook name
33
+ exports.CUSTOM_HOOK_DECL = /(?:function\s+(use[A-Z]\w*)\s*\(|(?:const|let|var)\s+(use[A-Z]\w*)\s*=)/g;
34
+ // Hook call patterns
35
+ exports.USE_STATE = /\buseState\s*(?:<[^>]*>)?\s*\(/g;
36
+ exports.USE_EFFECT = /\buseEffect\s*\(/g;
37
+ exports.USE_CALLBACK = /\buseCallback\s*\(/g;
38
+ exports.USE_MEMO = /\buseMemo\s*\(/g;
39
+ exports.USE_REF = /\buseRef\s*(?:<[^>]*>)?\s*\(/g;
40
+ exports.USE_CONTEXT = /\buseContext\s*\(/g;
41
+ exports.USE_REDUCER = /\buseReducer\s*\(/g;
42
+ exports.USE_LAYOUT_EFFECT = /\buseLayoutEffect\s*\(/g;
43
+ /**
44
+ * Extract a brace-balanced block starting from a given index.
45
+ * The character at `startIndex` should be '{'.
46
+ * Returns the substring including the braces, or null if unbalanced.
47
+ */
48
+ function extractBracedBlock(source, startIndex) {
49
+ if (source[startIndex] !== '{')
50
+ return null;
51
+ let depth = 0;
52
+ let inString = null;
53
+ let escaped = false;
54
+ let inLineComment = false;
55
+ let inBlockComment = false;
56
+ let inTemplateLiteral = false;
57
+ for (let i = startIndex; i < source.length; i++) {
58
+ const ch = source[i];
59
+ const next = source[i + 1];
60
+ if (escaped) {
61
+ escaped = false;
62
+ continue;
63
+ }
64
+ if (ch === '\\' && (inString || inTemplateLiteral)) {
65
+ escaped = true;
66
+ continue;
67
+ }
68
+ // Handle line comments
69
+ if (inLineComment) {
70
+ if (ch === '\n')
71
+ inLineComment = false;
72
+ continue;
73
+ }
74
+ // Handle block comments
75
+ if (inBlockComment) {
76
+ if (ch === '*' && next === '/') {
77
+ inBlockComment = false;
78
+ i++; // skip '/'
79
+ }
80
+ continue;
81
+ }
82
+ // Handle strings
83
+ if (inString) {
84
+ if (ch === inString)
85
+ inString = null;
86
+ continue;
87
+ }
88
+ // Handle template literals
89
+ if (inTemplateLiteral) {
90
+ if (ch === '`')
91
+ inTemplateLiteral = false;
92
+ // Template literal ${} expressions can contain braces,
93
+ // but for our purposes we skip the whole template literal
94
+ continue;
95
+ }
96
+ // Detect start of comments
97
+ if (ch === '/' && next === '/') {
98
+ inLineComment = true;
99
+ i++;
100
+ continue;
101
+ }
102
+ if (ch === '/' && next === '*') {
103
+ inBlockComment = true;
104
+ i++;
105
+ continue;
106
+ }
107
+ // Detect start of strings
108
+ if (ch === '"' || ch === "'") {
109
+ inString = ch;
110
+ continue;
111
+ }
112
+ if (ch === '`') {
113
+ inTemplateLiteral = true;
114
+ continue;
115
+ }
116
+ // Track braces
117
+ if (ch === '{')
118
+ depth++;
119
+ if (ch === '}') {
120
+ depth--;
121
+ if (depth === 0) {
122
+ return source.substring(startIndex, i + 1);
123
+ }
124
+ }
125
+ }
126
+ return null;
127
+ }
128
+ /**
129
+ * Get the 1-indexed line number for a character offset.
130
+ */
131
+ function getLineNumber(source, charIndex) {
132
+ let line = 1;
133
+ for (let i = 0; i < charIndex && i < source.length; i++) {
134
+ if (source[i] === '\n')
135
+ line++;
136
+ }
137
+ return line;
138
+ }
139
+ /**
140
+ * Get the 1-indexed column number for a character offset.
141
+ */
142
+ function getColumnNumber(source, charIndex) {
143
+ let col = 1;
144
+ for (let i = charIndex - 1; i >= 0; i--) {
145
+ if (source[i] === '\n')
146
+ break;
147
+ col++;
148
+ }
149
+ return col;
150
+ }
151
+ /**
152
+ * Count regex matches in a string.
153
+ */
154
+ function countMatches(source, regex) {
155
+ const global = new RegExp(regex.source, regex.flags.includes('g') ? regex.flags : regex.flags + 'g');
156
+ const matches = source.match(global);
157
+ return matches ? matches.length : 0;
158
+ }
159
+ /**
160
+ * Strip comments and string literals from source code.
161
+ * Useful for avoiding false positives from commented-out code.
162
+ */
163
+ function stripCommentsAndStrings(source) {
164
+ let result = '';
165
+ let i = 0;
166
+ while (i < source.length) {
167
+ const ch = source[i];
168
+ const next = source[i + 1];
169
+ // Line comment
170
+ if (ch === '/' && next === '/') {
171
+ while (i < source.length && source[i] !== '\n')
172
+ i++;
173
+ result += '\n'; // preserve line count
174
+ continue;
175
+ }
176
+ // Block comment
177
+ if (ch === '/' && next === '*') {
178
+ i += 2;
179
+ while (i < source.length && !(source[i] === '*' && source[i + 1] === '/')) {
180
+ if (source[i] === '\n')
181
+ result += '\n'; // preserve line count
182
+ i++;
183
+ }
184
+ i += 2; // skip */
185
+ continue;
186
+ }
187
+ // String literals
188
+ if (ch === '"' || ch === "'" || ch === '`') {
189
+ const quote = ch;
190
+ i++;
191
+ while (i < source.length) {
192
+ if (source[i] === '\\') {
193
+ i += 2;
194
+ continue;
195
+ }
196
+ if (source[i] === quote) {
197
+ i++;
198
+ break;
199
+ }
200
+ if (source[i] === '\n')
201
+ result += '\n'; // preserve line count
202
+ i++;
203
+ }
204
+ result += '""'; // placeholder to maintain structure
205
+ continue;
206
+ }
207
+ result += ch;
208
+ i++;
209
+ }
210
+ return result;
211
+ }
212
+ /**
213
+ * Parse destructured prop names from a destructuring pattern string.
214
+ * Input: " a, b = 'default', c, ...rest "
215
+ * Output: ["a", "b", "c"] (excludes rest params)
216
+ */
217
+ function parseDestructuredProps(propsString) {
218
+ const props = [];
219
+ let depth = 0;
220
+ // Split by commas, but respect nesting
221
+ let current = '';
222
+ for (const ch of propsString) {
223
+ if ((ch === '{' || ch === '[' || ch === '('))
224
+ depth++;
225
+ if ((ch === '}' || ch === ']' || ch === ')'))
226
+ depth--;
227
+ if (ch === ',' && depth === 0) {
228
+ const trimmed = current.trim();
229
+ if (trimmed)
230
+ props.push(trimmed);
231
+ current = '';
232
+ }
233
+ else {
234
+ current += ch;
235
+ }
236
+ }
237
+ const last = current.trim();
238
+ if (last)
239
+ props.push(last);
240
+ return props
241
+ .map(p => {
242
+ // Skip rest params
243
+ if (p.startsWith('...'))
244
+ return null;
245
+ // Handle rename: originalName: newName
246
+ const colonIndex = p.indexOf(':');
247
+ if (colonIndex !== -1) {
248
+ // Could be type annotation in TS or rename
249
+ const beforeColon = p.substring(0, colonIndex).trim();
250
+ return beforeColon;
251
+ }
252
+ // Handle default values: name = defaultValue
253
+ const eqIndex = p.indexOf('=');
254
+ if (eqIndex !== -1) {
255
+ return p.substring(0, eqIndex).trim();
256
+ }
257
+ return p.trim();
258
+ })
259
+ .filter((p) => p !== null && p.length > 0);
260
+ }
261
+ /**
262
+ * Find the opening brace index after a given position.
263
+ * Skips parentheses, arrow functions, type annotations, etc.
264
+ */
265
+ function findOpeningBrace(source, startIndex) {
266
+ for (let i = startIndex; i < source.length; i++) {
267
+ if (source[i] === '{')
268
+ return i;
269
+ // If we hit a semicolon or another function declaration, stop
270
+ if (source[i] === ';')
271
+ return -1;
272
+ }
273
+ return -1;
274
+ }
275
+ //# sourceMappingURL=regex-helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"regex-helpers.js","sourceRoot":"","sources":["../../../src/utils/regex-helpers.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "react-anti-pattern-sniffer",
3
+ "version": "0.1.0",
4
+ "description": "Zero-dependency CLI that detects React anti-patterns via regex-based heuristics",
5
+ "main": "dist/src/core/orchestrator.js",
6
+ "types": "dist/src/core/orchestrator.d.ts",
7
+ "bin": {
8
+ "react-sniff": "bin/react-sniff.js",
9
+ "ras": "bin/react-sniff.js"
10
+ },
11
+ "scripts": {
12
+ "build": "tsc",
13
+ "test": "tsc && node --test 'dist/test/unit/**/*.test.js' 'dist/test/integration/**/*.test.js'",
14
+ "test:unit": "tsc && node --test 'dist/test/unit/**/*.test.js'",
15
+ "test:integration": "tsc && node --test 'dist/test/integration/**/*.test.js'",
16
+ "sniff": "tsc && node bin/react-sniff.js"
17
+ },
18
+ "keywords": [
19
+ "react",
20
+ "anti-pattern",
21
+ "linter",
22
+ "code-quality",
23
+ "cli",
24
+ "code-smell",
25
+ "static-analysis"
26
+ ],
27
+ "engines": {
28
+ "node": ">=20.0.0"
29
+ },
30
+ "files": [
31
+ "bin/",
32
+ "dist/src/",
33
+ ".snifferrc.json"
34
+ ],
35
+ "license": "MIT",
36
+ "devDependencies": {
37
+ "@types/node": "^25.5.0",
38
+ "typescript": "^5.0.0"
39
+ }
40
+ }