code-sentinel-mcp 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.
@@ -0,0 +1,2 @@
1
+ import { Issue } from '../types.js';
2
+ export declare function analyzePlaceholders(code: string, filename: string): Issue[];
@@ -0,0 +1,216 @@
1
+ const placeholderPatterns = [
2
+ // TODO/FIXME comments
3
+ {
4
+ id: 'CS-PH001',
5
+ pattern: /\/\/\s*TODO(?::|\.|\s).*$/gim,
6
+ title: 'TODO Comment Found',
7
+ description: 'Incomplete work marker found in code.',
8
+ severity: 'low',
9
+ category: 'placeholder',
10
+ suggestion: 'Complete or remove the TODO before shipping.'
11
+ },
12
+ {
13
+ id: 'CS-PH002',
14
+ pattern: /\/\/\s*FIXME(?::|\.|\s).*$/gim,
15
+ title: 'FIXME Comment Found',
16
+ description: 'Known issue marker found - this should be fixed.',
17
+ severity: 'medium',
18
+ category: 'placeholder',
19
+ suggestion: 'Fix the issue or create a ticket to track it.'
20
+ },
21
+ {
22
+ id: 'CS-PH003',
23
+ pattern: /\/\/\s*HACK(?::|\.|\s).*$/gim,
24
+ title: 'HACK Comment Found',
25
+ description: 'Workaround marker found - technical debt.',
26
+ severity: 'medium',
27
+ category: 'placeholder',
28
+ suggestion: 'Document why the hack exists and plan to remove it.'
29
+ },
30
+ {
31
+ id: 'CS-PH004',
32
+ pattern: /\/\/\s*XXX(?::|\.|\s).*$/gim,
33
+ title: 'XXX Comment Found',
34
+ description: 'Attention marker found - requires review.',
35
+ severity: 'low',
36
+ category: 'placeholder',
37
+ suggestion: 'Address the flagged issue or remove the marker.'
38
+ },
39
+ // Lorem ipsum and dummy text
40
+ {
41
+ id: 'CS-PH010',
42
+ pattern: /lorem\s+ipsum/gi,
43
+ title: 'Lorem Ipsum Placeholder Text',
44
+ description: 'Placeholder text found - replace with real content.',
45
+ severity: 'medium',
46
+ category: 'placeholder',
47
+ suggestion: 'Replace with actual content before release.'
48
+ },
49
+ {
50
+ id: 'CS-PH011',
51
+ pattern: /['"`](?:foo|bar|baz|qux|test|dummy|sample|example|placeholder)['"`]/gi,
52
+ title: 'Common Placeholder Value',
53
+ description: 'Generic placeholder value detected.',
54
+ severity: 'low',
55
+ category: 'placeholder',
56
+ suggestion: 'Replace with meaningful values.'
57
+ },
58
+ // Test/dummy data
59
+ {
60
+ id: 'CS-PH020',
61
+ pattern: /['"`]test@(?:test|example|dummy|sample)\.[a-z]+['"`]/gi,
62
+ title: 'Test Email Address',
63
+ description: 'Placeholder email found - may not be intended for production.',
64
+ severity: 'medium',
65
+ category: 'placeholder',
66
+ suggestion: 'Remove or replace with proper configuration.'
67
+ },
68
+ {
69
+ id: 'CS-PH021',
70
+ pattern: /['"`](?:123|1234|12345|123456|password|admin|root|test)['"`]/gi,
71
+ title: 'Common Test Password/Value',
72
+ description: 'Potentially insecure placeholder password or test value.',
73
+ severity: 'high',
74
+ category: 'placeholder',
75
+ suggestion: 'Remove test credentials before deployment.'
76
+ },
77
+ {
78
+ id: 'CS-PH022',
79
+ pattern: /(?:localhost|127\.0\.0\.1):\d{4,5}/g,
80
+ title: 'Localhost URL in Code',
81
+ description: 'Hardcoded localhost URL may not work in production.',
82
+ severity: 'medium',
83
+ category: 'placeholder',
84
+ suggestion: 'Use environment variables for URLs.'
85
+ },
86
+ {
87
+ id: 'CS-PH023',
88
+ pattern: /['"`](?:xxx|yyy|zzz|aaa|bbb|ccc)['"`]/gi,
89
+ title: 'Placeholder String Pattern',
90
+ description: 'Obvious placeholder pattern detected.',
91
+ severity: 'low',
92
+ category: 'placeholder',
93
+ suggestion: 'Replace with actual values.'
94
+ },
95
+ // Fake/test phone numbers
96
+ {
97
+ id: 'CS-PH030',
98
+ pattern: /['"`](?:\+1)?[\s-]?555[\s-]?\d{3}[\s-]?\d{4}['"`]/g,
99
+ title: 'Test Phone Number (555)',
100
+ description: 'The 555 prefix is reserved for fictional use.',
101
+ severity: 'low',
102
+ category: 'placeholder',
103
+ suggestion: 'Use proper phone number handling or config.'
104
+ },
105
+ {
106
+ id: 'CS-PH031',
107
+ pattern: /['"`](?:000[-\s]?00[-\s]?0000|111[-\s]?11[-\s]?1111|123[-\s]?45[-\s]?6789)['"`]/g,
108
+ title: 'Obviously Fake ID Number',
109
+ description: 'Placeholder ID number pattern detected.',
110
+ severity: 'medium',
111
+ category: 'placeholder',
112
+ suggestion: 'Remove test data before production.'
113
+ },
114
+ // Incomplete implementations
115
+ {
116
+ id: 'CS-PH040',
117
+ pattern: /throw\s+new\s+Error\s*\(\s*['"`](?:not\s+implemented|todo|implement\s+me|coming\s+soon)['"`]\s*\)/gi,
118
+ title: 'Not Implemented Error',
119
+ description: 'Function explicitly marked as not implemented.',
120
+ severity: 'high',
121
+ category: 'placeholder',
122
+ suggestion: 'Implement the function or remove the dead code.'
123
+ },
124
+ {
125
+ id: 'CS-PH041',
126
+ pattern: /(?:return|=)\s*['"`](?:TBD|TBA|N\/A|pending|placeholder)['"`]/gi,
127
+ title: 'TBD/Placeholder Return Value',
128
+ description: 'Code returns a placeholder instead of real value.',
129
+ severity: 'medium',
130
+ category: 'placeholder',
131
+ suggestion: 'Implement actual logic or handle the case properly.'
132
+ },
133
+ // Debug/test code
134
+ {
135
+ id: 'CS-PH050',
136
+ pattern: /console\.log\s*\(\s*['"`](?:debug|test|here|working|checkpoint|\d+)['"`]\s*\)/gi,
137
+ title: 'Debug Console.log',
138
+ description: 'Debug logging statement left in code.',
139
+ severity: 'low',
140
+ category: 'placeholder',
141
+ suggestion: 'Remove debug statements or use a proper logger.'
142
+ },
143
+ {
144
+ id: 'CS-PH051',
145
+ pattern: /debugger\s*;/g,
146
+ title: 'Debugger Statement',
147
+ description: 'Debugger statement will pause execution in browser.',
148
+ severity: 'medium',
149
+ category: 'placeholder',
150
+ suggestion: 'Remove debugger statements before committing.'
151
+ },
152
+ {
153
+ id: 'CS-PH052',
154
+ pattern: /alert\s*\(\s*['"`](?:test|debug|here|working)['"`]\s*\)/gi,
155
+ title: 'Debug Alert',
156
+ description: 'Debug alert left in code.',
157
+ severity: 'medium',
158
+ category: 'placeholder',
159
+ suggestion: 'Remove debug alerts.'
160
+ },
161
+ // Commented out code blocks
162
+ {
163
+ id: 'CS-PH060',
164
+ pattern: /\/\/\s*(?:const|let|var|function|class|if|for|while|return)\s+\w+/g,
165
+ title: 'Commented Out Code',
166
+ description: 'Code appears to be commented out rather than deleted.',
167
+ severity: 'low',
168
+ category: 'placeholder',
169
+ suggestion: 'Remove dead code - use version control to recover if needed.'
170
+ },
171
+ // Hardcoded test IDs
172
+ {
173
+ id: 'CS-PH070',
174
+ pattern: /['"`](?:test-id|test_id|testid|fake-id|temp-id)['"`]/gi,
175
+ title: 'Test ID in Code',
176
+ description: 'Hardcoded test ID found.',
177
+ severity: 'medium',
178
+ category: 'placeholder',
179
+ suggestion: 'Use proper ID generation or configuration.'
180
+ }
181
+ ];
182
+ export function analyzePlaceholders(code, filename) {
183
+ const issues = [];
184
+ const lines = code.split('\n');
185
+ for (const patternDef of placeholderPatterns) {
186
+ patternDef.pattern.lastIndex = 0;
187
+ let match;
188
+ while ((match = patternDef.pattern.exec(code)) !== null) {
189
+ const beforeMatch = code.substring(0, match.index);
190
+ const lineNumber = beforeMatch.split('\n').length;
191
+ const lineContent = lines[lineNumber - 1] || '';
192
+ // Build verification with actual values substituted
193
+ let verification = patternDef.verification;
194
+ if (verification) {
195
+ verification = {
196
+ ...verification,
197
+ commands: verification.commands?.map(cmd => cmd.replace(/<filename>/g, filename))
198
+ };
199
+ }
200
+ issues.push({
201
+ id: patternDef.id,
202
+ category: patternDef.category,
203
+ severity: patternDef.severity,
204
+ title: patternDef.title,
205
+ description: patternDef.description,
206
+ line: lineNumber,
207
+ code: lineContent.trim(),
208
+ suggestion: patternDef.suggestion,
209
+ verification
210
+ });
211
+ if (!patternDef.pattern.global)
212
+ break;
213
+ }
214
+ }
215
+ return issues;
216
+ }
@@ -0,0 +1,2 @@
1
+ import { Issue } from '../types.js';
2
+ export declare function analyzeSecurityIssues(code: string, filename: string): Issue[];
@@ -0,0 +1,238 @@
1
+ const securityPatterns = [
2
+ // Hardcoded secrets
3
+ {
4
+ id: 'CS-SEC001',
5
+ pattern: /(?:api[_-]?key|apikey|secret|password|passwd|pwd|token|auth[_-]?token|access[_-]?token|private[_-]?key)\s*[:=]\s*['"`][^'"`]{8,}['"`]/gi,
6
+ title: 'Hardcoded Secret Detected',
7
+ description: 'Sensitive credentials appear to be hardcoded in the source code.',
8
+ severity: 'critical',
9
+ category: 'security',
10
+ suggestion: 'Move secrets to environment variables or a secure vault.',
11
+ verification: {
12
+ status: 'needs_verification',
13
+ assumption: 'The matched string appears to be a real secret, not a placeholder or test value',
14
+ commands: [
15
+ 'git log -p -S "<matched_value>" -- <filename>',
16
+ 'grep -r "<matched_value>" .env* config/'
17
+ ],
18
+ instruction: 'Verify this is a real secret, not a placeholder like "your-api-key-here" or test data',
19
+ confirmIf: 'Value looks like a real credential (high entropy, no placeholder words)',
20
+ falsePositiveIf: 'Value contains words like "example", "test", "placeholder", "your-", "xxx", or is clearly dummy data'
21
+ }
22
+ },
23
+ {
24
+ id: 'CS-SEC002',
25
+ pattern: /(?:ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9_]{36,}/g,
26
+ title: 'GitHub Token Detected',
27
+ description: 'A GitHub personal access token was found in the code.',
28
+ severity: 'critical',
29
+ category: 'security',
30
+ suggestion: 'Remove the token immediately and rotate it in GitHub settings.',
31
+ verification: {
32
+ status: 'needs_verification',
33
+ assumption: 'Token is real and may have been committed to git history',
34
+ commands: [
35
+ 'git log -p -S "<matched_value>" --all',
36
+ 'git ls-files <filename>'
37
+ ],
38
+ instruction: 'Check if token was ever committed. If in history, it must be rotated even if removed now',
39
+ confirmIf: 'Token pattern matches GitHub format (ghp_, gho_, etc.) and file is tracked',
40
+ falsePositiveIf: 'Token is in a test file with obviously fake data or documentation example'
41
+ }
42
+ },
43
+ {
44
+ id: 'CS-SEC003',
45
+ pattern: /sk-[A-Za-z0-9]{48,}/g,
46
+ title: 'OpenAI API Key Detected',
47
+ description: 'An OpenAI API key was found in the code.',
48
+ severity: 'critical',
49
+ category: 'security',
50
+ suggestion: 'Remove the key and rotate it in your OpenAI dashboard.',
51
+ verification: {
52
+ status: 'needs_verification',
53
+ assumption: 'Key is real and may have been committed to git history',
54
+ commands: [
55
+ 'git log -p -S "sk-" --all -- <filename>',
56
+ 'git ls-files <filename>'
57
+ ],
58
+ instruction: 'Check if key was ever committed. If in history, it must be rotated',
59
+ confirmIf: 'Key matches OpenAI format (sk- prefix, 48+ chars) and file is tracked',
60
+ falsePositiveIf: 'Key is in documentation as example or clearly marked as fake'
61
+ }
62
+ },
63
+ {
64
+ id: 'CS-SEC004',
65
+ pattern: /AKIA[0-9A-Z]{16}/g,
66
+ title: 'AWS Access Key Detected',
67
+ description: 'An AWS access key ID was found in the code.',
68
+ severity: 'critical',
69
+ category: 'security',
70
+ suggestion: 'Remove and rotate the AWS credentials immediately.',
71
+ verification: {
72
+ status: 'needs_verification',
73
+ assumption: 'Key is real and may have been committed to git history',
74
+ commands: [
75
+ 'git log -p -S "AKIA" --all -- <filename>',
76
+ 'git ls-files <filename>'
77
+ ],
78
+ instruction: 'Check if key was ever committed. AWS keys in git history are compromised',
79
+ confirmIf: 'Key matches AWS format (AKIA prefix, 16 chars) and file is tracked',
80
+ falsePositiveIf: 'Key is in documentation or test fixtures with fake data'
81
+ }
82
+ },
83
+ // SQL Injection
84
+ {
85
+ id: 'CS-SEC010',
86
+ pattern: /(?:execute|query|raw)\s*\(\s*['"`].*?\$\{.*?\}.*?['"`]\s*\)/gi,
87
+ title: 'Potential SQL Injection',
88
+ description: 'String interpolation in SQL query may allow injection attacks.',
89
+ severity: 'critical',
90
+ category: 'security',
91
+ suggestion: 'Use parameterized queries or prepared statements instead.'
92
+ },
93
+ {
94
+ id: 'CS-SEC011',
95
+ pattern: /(?:execute|query)\s*\(\s*['"`].*?\+.*?['"`]\s*\)/gi,
96
+ title: 'SQL Query String Concatenation',
97
+ description: 'Concatenating strings in SQL queries is vulnerable to injection.',
98
+ severity: 'high',
99
+ category: 'security',
100
+ suggestion: 'Use parameterized queries with placeholders.'
101
+ },
102
+ // XSS
103
+ {
104
+ id: 'CS-SEC020',
105
+ pattern: /innerHTML\s*=\s*(?!['"`]<)/g,
106
+ title: 'Potential XSS via innerHTML',
107
+ description: 'Setting innerHTML with dynamic content can lead to XSS.',
108
+ severity: 'high',
109
+ category: 'security',
110
+ suggestion: 'Use textContent or sanitize HTML before insertion.'
111
+ },
112
+ {
113
+ id: 'CS-SEC021',
114
+ pattern: /dangerouslySetInnerHTML/g,
115
+ title: 'React dangerouslySetInnerHTML Usage',
116
+ description: 'Using dangerouslySetInnerHTML can expose the app to XSS.',
117
+ severity: 'medium',
118
+ category: 'security',
119
+ suggestion: 'Ensure content is properly sanitized before rendering.'
120
+ },
121
+ // Insecure practices
122
+ {
123
+ id: 'CS-SEC030',
124
+ pattern: /eval\s*\(/g,
125
+ title: 'eval() Usage Detected',
126
+ description: 'eval() can execute arbitrary code and is a security risk.',
127
+ severity: 'high',
128
+ category: 'security',
129
+ suggestion: 'Avoid eval(). Use safer alternatives like JSON.parse().'
130
+ },
131
+ {
132
+ id: 'CS-SEC031',
133
+ pattern: /new\s+Function\s*\(/g,
134
+ title: 'Dynamic Function Constructor',
135
+ description: 'Creating functions from strings is similar to eval().',
136
+ severity: 'high',
137
+ category: 'security',
138
+ suggestion: 'Avoid dynamic function creation from user input.'
139
+ },
140
+ {
141
+ id: 'CS-SEC032',
142
+ pattern: /document\.write\s*\(/g,
143
+ title: 'document.write() Usage',
144
+ description: 'document.write() can overwrite the document and enable XSS.',
145
+ severity: 'medium',
146
+ category: 'security',
147
+ suggestion: 'Use DOM manipulation methods instead.'
148
+ },
149
+ // Crypto issues
150
+ {
151
+ id: 'CS-SEC040',
152
+ pattern: /(?:md5|sha1)\s*\(/gi,
153
+ title: 'Weak Hash Algorithm',
154
+ description: 'MD5 and SHA1 are cryptographically broken.',
155
+ severity: 'high',
156
+ category: 'security',
157
+ suggestion: 'Use SHA-256 or bcrypt for password hashing.'
158
+ },
159
+ {
160
+ id: 'CS-SEC041',
161
+ pattern: /Math\.random\s*\(\)/g,
162
+ title: 'Insecure Random for Security',
163
+ description: 'Math.random() is not cryptographically secure.',
164
+ severity: 'medium',
165
+ category: 'security',
166
+ suggestion: 'Use crypto.randomBytes() or crypto.getRandomValues().'
167
+ },
168
+ // Network
169
+ {
170
+ id: 'CS-SEC050',
171
+ pattern: /http:\/\/(?!localhost|127\.0\.0\.1)/g,
172
+ title: 'Insecure HTTP URL',
173
+ description: 'Using HTTP instead of HTTPS exposes data in transit.',
174
+ severity: 'medium',
175
+ category: 'security',
176
+ suggestion: 'Use HTTPS for all external URLs.'
177
+ },
178
+ {
179
+ id: 'CS-SEC051',
180
+ pattern: /rejectUnauthorized\s*:\s*false/g,
181
+ title: 'SSL Certificate Validation Disabled',
182
+ description: 'Disabling certificate validation enables MITM attacks.',
183
+ severity: 'critical',
184
+ category: 'security',
185
+ suggestion: 'Never disable SSL certificate validation in production.'
186
+ },
187
+ // CORS
188
+ {
189
+ id: 'CS-SEC060',
190
+ pattern: /Access-Control-Allow-Origin['":\s]+\*/g,
191
+ title: 'Wildcard CORS Origin',
192
+ description: 'Allowing all origins can expose the API to unauthorized access.',
193
+ severity: 'medium',
194
+ category: 'security',
195
+ suggestion: 'Specify allowed origins explicitly.'
196
+ }
197
+ ];
198
+ export function analyzeSecurityIssues(code, filename) {
199
+ const issues = [];
200
+ const lines = code.split('\n');
201
+ for (const patternDef of securityPatterns) {
202
+ // Reset regex state
203
+ patternDef.pattern.lastIndex = 0;
204
+ let match;
205
+ while ((match = patternDef.pattern.exec(code)) !== null) {
206
+ // Find line number
207
+ const beforeMatch = code.substring(0, match.index);
208
+ const lineNumber = beforeMatch.split('\n').length;
209
+ const lineContent = lines[lineNumber - 1] || '';
210
+ const matchedValue = match[0];
211
+ // Build verification with actual values substituted
212
+ let verification = patternDef.verification;
213
+ if (verification) {
214
+ verification = {
215
+ ...verification,
216
+ commands: verification.commands?.map(cmd => cmd
217
+ .replace(/<matched_value>/g, matchedValue.substring(0, 20) + '...')
218
+ .replace(/<filename>/g, filename))
219
+ };
220
+ }
221
+ issues.push({
222
+ id: patternDef.id,
223
+ category: patternDef.category,
224
+ severity: patternDef.severity,
225
+ title: patternDef.title,
226
+ description: patternDef.description,
227
+ line: lineNumber,
228
+ code: lineContent.trim(),
229
+ suggestion: patternDef.suggestion,
230
+ verification
231
+ });
232
+ // Prevent infinite loops for patterns without global flag
233
+ if (!patternDef.pattern.global)
234
+ break;
235
+ }
236
+ }
237
+ return issues;
238
+ }
@@ -0,0 +1,2 @@
1
+ import { Strength } from '../types.js';
2
+ export declare function analyzeStrengths(code: string, filename: string): Strength[];
@@ -0,0 +1,169 @@
1
+ const strengthPatterns = [
2
+ // TypeScript usage
3
+ {
4
+ id: 'CS-STR001',
5
+ pattern: /:\s*(?:string|number|boolean|void|never|unknown|null|undefined|\w+\[\]|Record<|Map<|Set<|Promise<)/g,
6
+ title: 'Strong Typing',
7
+ description: 'Explicit type annotations improve code safety and documentation.'
8
+ },
9
+ {
10
+ id: 'CS-STR002',
11
+ pattern: /interface\s+\w+\s*\{/g,
12
+ title: 'Interface Definitions',
13
+ description: 'Well-defined interfaces create clear contracts.'
14
+ },
15
+ {
16
+ id: 'CS-STR003',
17
+ pattern: /type\s+\w+\s*=\s*/g,
18
+ title: 'Type Aliases',
19
+ description: 'Type aliases improve code readability and reusability.'
20
+ },
21
+ // Error handling
22
+ {
23
+ id: 'CS-STR010',
24
+ pattern: /try\s*\{[\s\S]+?\}\s*catch\s*\([^)]+\)\s*\{[\s\S]+?\}/g,
25
+ title: 'Proper Try/Catch',
26
+ description: 'Structured error handling with meaningful catch blocks.'
27
+ },
28
+ {
29
+ id: 'CS-STR011',
30
+ pattern: /\.catch\s*\(\s*(?:error|err|e)\s*=>\s*\{[^}]+\}/g,
31
+ title: 'Promise Error Handling',
32
+ description: 'Promise chains have explicit error handling.'
33
+ },
34
+ {
35
+ id: 'CS-STR012',
36
+ pattern: /class\s+\w+Error\s+extends\s+Error/g,
37
+ title: 'Custom Error Classes',
38
+ description: 'Custom errors enable better error classification.'
39
+ },
40
+ // Documentation
41
+ {
42
+ id: 'CS-STR020',
43
+ pattern: /\/\*\*[\s\S]*?@(?:param|returns?|throws|example)[\s\S]*?\*\//g,
44
+ title: 'JSDoc Documentation',
45
+ description: 'Functions have proper JSDoc documentation.'
46
+ },
47
+ {
48
+ id: 'CS-STR021',
49
+ pattern: /\/\/\s+[A-Z][^.!?]*[.!?]\s*$/gm,
50
+ title: 'Meaningful Comments',
51
+ description: 'Code has explanatory comments in complete sentences.'
52
+ },
53
+ // Clean code patterns
54
+ {
55
+ id: 'CS-STR030',
56
+ pattern: /const\s+\w+\s*=/g,
57
+ title: 'Immutable Variables',
58
+ description: 'Using const by default prevents accidental reassignment.'
59
+ },
60
+ {
61
+ id: 'CS-STR031',
62
+ pattern: /(?:readonly|Object\.freeze|as\s+const)/g,
63
+ title: 'Immutability Patterns',
64
+ description: 'Code uses immutability patterns for data safety.'
65
+ },
66
+ {
67
+ id: 'CS-STR032',
68
+ pattern: /(?:private|protected|#\w+)/g,
69
+ title: 'Encapsulation',
70
+ description: 'Proper use of access modifiers for encapsulation.'
71
+ },
72
+ // Async patterns
73
+ {
74
+ id: 'CS-STR040',
75
+ pattern: /async\s+\w+\s*\([^)]*\)\s*(?::\s*Promise<[^>]+>)?/g,
76
+ title: 'Async/Await Usage',
77
+ description: 'Modern async/await syntax for readable asynchronous code.'
78
+ },
79
+ {
80
+ id: 'CS-STR041',
81
+ pattern: /Promise\.all\s*\(/g,
82
+ title: 'Parallel Promise Execution',
83
+ description: 'Using Promise.all for efficient parallel async operations.'
84
+ },
85
+ {
86
+ id: 'CS-STR042',
87
+ pattern: /Promise\.allSettled\s*\(/g,
88
+ title: 'Resilient Promise Handling',
89
+ description: 'Using allSettled handles both fulfilled and rejected promises.'
90
+ },
91
+ // Testing
92
+ {
93
+ id: 'CS-STR050',
94
+ pattern: /(?:describe|it|test|expect)\s*\(/g,
95
+ title: 'Test Coverage',
96
+ description: 'Code includes tests with standard testing patterns.'
97
+ },
98
+ {
99
+ id: 'CS-STR051',
100
+ pattern: /\.test\.|\.spec\.|__tests__/g,
101
+ title: 'Test Files Present',
102
+ description: 'Dedicated test files follow conventions.'
103
+ },
104
+ // Validation
105
+ {
106
+ id: 'CS-STR060',
107
+ pattern: /(?:z\.|yup\.|joi\.|validator\.)\w+/g,
108
+ title: 'Schema Validation',
109
+ description: 'Using validation libraries for input/data validation.'
110
+ },
111
+ {
112
+ id: 'CS-STR061',
113
+ pattern: /if\s*\(\s*!?\w+\s*(?:&&|\|\|)?\s*typeof\s+\w+/g,
114
+ title: 'Type Guards',
115
+ description: 'Runtime type checking before operations.'
116
+ },
117
+ // Modern JavaScript
118
+ {
119
+ id: 'CS-STR070',
120
+ pattern: /(?:\?\.|&&\s*\w+\?\.)/g,
121
+ title: 'Optional Chaining',
122
+ description: 'Using ?. for safe property access.'
123
+ },
124
+ {
125
+ id: 'CS-STR071',
126
+ pattern: /\?\?\s*(?![\[\{])/g,
127
+ title: 'Nullish Coalescing',
128
+ description: 'Using ?? for proper null/undefined handling.'
129
+ },
130
+ {
131
+ id: 'CS-STR072',
132
+ pattern: /\.\.\.\w+/g,
133
+ title: 'Spread Operator',
134
+ description: 'Using spread for immutable operations.'
135
+ },
136
+ // Environment handling
137
+ {
138
+ id: 'CS-STR080',
139
+ pattern: /process\.env\.\w+|import\.meta\.env\.\w+/g,
140
+ title: 'Environment Variables',
141
+ description: 'Configuration via environment variables.'
142
+ },
143
+ // Logging
144
+ {
145
+ id: 'CS-STR090',
146
+ pattern: /(?:logger|log)\.\w+\s*\(/g,
147
+ title: 'Structured Logging',
148
+ description: 'Using a logging library instead of console.log.'
149
+ }
150
+ ];
151
+ export function analyzeStrengths(code, filename) {
152
+ const strengths = [];
153
+ const foundPatterns = new Set();
154
+ for (const patternDef of strengthPatterns) {
155
+ patternDef.pattern.lastIndex = 0;
156
+ const matches = code.match(patternDef.pattern);
157
+ if (matches && matches.length > 0 && !foundPatterns.has(patternDef.id)) {
158
+ foundPatterns.add(patternDef.id);
159
+ // Only report each strength once, with example count
160
+ strengths.push({
161
+ id: patternDef.id,
162
+ title: patternDef.title,
163
+ description: patternDef.description,
164
+ examples: matches.slice(0, 3).map(m => m.trim())
165
+ });
166
+ }
167
+ }
168
+ return strengths;
169
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};