@nebutra/next-unicorn-skill 1.0.3 → 1.0.4
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/SKILL.md +46 -132
- package/dist/analyzer/pattern-catalog.d.ts +5 -2
- package/dist/analyzer/pattern-catalog.d.ts.map +1 -1
- package/dist/analyzer/pattern-catalog.js +338 -234
- package/dist/analyzer/pattern-catalog.js.map +1 -1
- package/dist/analyzer/scanner.d.ts +4 -0
- package/dist/analyzer/scanner.d.ts.map +1 -1
- package/dist/analyzer/scanner.js +13 -1
- package/dist/analyzer/scanner.js.map +1 -1
- package/dist/analyzer/structure-analyzer.d.ts +40 -0
- package/dist/analyzer/structure-analyzer.d.ts.map +1 -0
- package/dist/analyzer/structure-analyzer.js +228 -0
- package/dist/analyzer/structure-analyzer.js.map +1 -0
- package/dist/auditor/ux-auditor.js +8 -8
- package/dist/auditor/ux-auditor.js.map +1 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +27 -4
- package/dist/index.js.map +1 -1
- package/dist/schemas/output.schema.d.ts +18 -0
- package/dist/schemas/output.schema.d.ts.map +1 -1
- package/dist/schemas/output.schema.js +3 -0
- package/dist/schemas/output.schema.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,41 +1,143 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Returns the full pattern catalog covering Vibe Coding domains.
|
|
3
|
-
*
|
|
3
|
+
*
|
|
4
|
+
* Domain assignment rules:
|
|
5
|
+
* - Each pattern goes in its MOST SPECIFIC domain (e.g., A/B test → ab-testing-experimentation, not growth-hacking)
|
|
6
|
+
* - Parent domains (growth-hacking, observability, ux-completeness) are used only when no specific child domain fits
|
|
7
|
+
* - Domains with no regex-detectable patterns are left for Gap Analysis (AI Agent)
|
|
4
8
|
*
|
|
5
9
|
* The catalog defines WHAT to detect, not WHAT to recommend.
|
|
6
|
-
* Library recommendations are generated dynamically by the AI agent.
|
|
7
10
|
*/
|
|
8
11
|
export function getPatternCatalog() {
|
|
9
12
|
return [
|
|
10
13
|
// -----------------------------------------------------------------------
|
|
11
|
-
//
|
|
14
|
+
// A. UX / Design
|
|
12
15
|
// -----------------------------------------------------------------------
|
|
16
|
+
// ux-completeness — General UX patterns (parent)
|
|
13
17
|
{
|
|
14
|
-
id: '
|
|
15
|
-
domain: '
|
|
16
|
-
description: 'Hand-rolled
|
|
17
|
-
filePatterns: ['**/*.
|
|
18
|
+
id: 'ux-manual-loading-states',
|
|
19
|
+
domain: 'empty-loading-error-states',
|
|
20
|
+
description: 'Hand-rolled loading state management without skeleton/spinner library',
|
|
21
|
+
filePatterns: ['**/*.tsx', '**/*.jsx'],
|
|
18
22
|
codePatterns: [
|
|
19
|
-
/
|
|
20
|
-
|
|
23
|
+
/isLoading\s*\?\s*.*(?:Loading|Spinner|\.\.\.)/i,
|
|
24
|
+
/useState\s*<\s*boolean\s*>\s*\(\s*(?:true|false)\s*\).*loading/i,
|
|
25
|
+
],
|
|
26
|
+
confidenceBase: 0.55,
|
|
27
|
+
},
|
|
28
|
+
// a11y-accessibility
|
|
29
|
+
{
|
|
30
|
+
id: 'a11y-manual-click-handler-div',
|
|
31
|
+
domain: 'a11y-accessibility',
|
|
32
|
+
description: 'Clickable div/span without keyboard accessibility',
|
|
33
|
+
filePatterns: ['**/*.tsx', '**/*.jsx'],
|
|
34
|
+
codePatterns: [
|
|
35
|
+
/<div\s[^>]*onClick\s*=\s*\{/,
|
|
36
|
+
/<span\s[^>]*onClick\s*=\s*\{/,
|
|
37
|
+
],
|
|
38
|
+
confidenceBase: 0.6,
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
id: 'a11y-manual-focus-management',
|
|
42
|
+
domain: 'a11y-accessibility',
|
|
43
|
+
description: 'Hand-rolled focus management and keyboard trap',
|
|
44
|
+
filePatterns: ['**/*.tsx', '**/*.jsx', '**/*.ts', '**/*.js'],
|
|
45
|
+
codePatterns: [
|
|
46
|
+
/\.focus\s*\(\s*\)[\s\S]{0,200}(?:tabIndex|keyCode|keyDown)/i,
|
|
47
|
+
/addEventListener\s*\(\s*['"`]keydown['"`][\s\S]{0,200}(?:Tab|Escape|27|9)\b/,
|
|
48
|
+
/document\s*\.\s*activeElement/,
|
|
49
|
+
],
|
|
50
|
+
confidenceBase: 0.55,
|
|
51
|
+
},
|
|
52
|
+
// forms-ux
|
|
53
|
+
{
|
|
54
|
+
id: 'forms-manual-state-tracking',
|
|
55
|
+
domain: 'forms-ux',
|
|
56
|
+
description: 'Multiple useState hooks for individual form fields',
|
|
57
|
+
filePatterns: ['**/*.tsx', '**/*.jsx'],
|
|
58
|
+
codePatterns: [
|
|
59
|
+
/const\s*\[\s*\w+,\s*set\w+\s*\]\s*=\s*useState\s*\(\s*['"`]{2}\s*\)[\s\S]{0,200}onChange/,
|
|
60
|
+
/e\s*\.\s*target\s*\.\s*value[\s\S]{0,50}set\w+\s*\(\s*e\s*\.\s*target\s*\.\s*value\s*\)/,
|
|
61
|
+
],
|
|
62
|
+
confidenceBase: 0.65,
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
id: 'forms-manual-submit-handler',
|
|
66
|
+
domain: 'forms-ux',
|
|
67
|
+
description: 'Hand-rolled form submission with manual preventDefault and state collection',
|
|
68
|
+
filePatterns: ['**/*.tsx', '**/*.jsx'],
|
|
69
|
+
codePatterns: [
|
|
70
|
+
/handleSubmit[\s\S]{0,100}preventDefault\s*\(\s*\)[\s\S]{0,200}fetch\s*\(/,
|
|
71
|
+
/onSubmit[\s\S]{0,100}e\s*\.\s*preventDefault[\s\S]{0,200}(?:setLoading|setError)/,
|
|
72
|
+
],
|
|
73
|
+
confidenceBase: 0.6,
|
|
74
|
+
},
|
|
75
|
+
// validation-feedback
|
|
76
|
+
{
|
|
77
|
+
id: 'validation-manual-form-errors',
|
|
78
|
+
domain: 'validation-feedback',
|
|
79
|
+
description: 'Hand-rolled form validation with manual error state tracking',
|
|
80
|
+
filePatterns: ['**/*.tsx', '**/*.jsx', '**/*.ts', '**/*.js'],
|
|
81
|
+
codePatterns: [
|
|
82
|
+
/setError\s*\(\s*['"`]/,
|
|
83
|
+
/errors\s*\[\s*['"`]\w+['"`]\s*\]/,
|
|
84
|
+
/validate\w*\s*=\s*\(\s*\)\s*=>/,
|
|
21
85
|
],
|
|
22
86
|
confidenceBase: 0.7,
|
|
23
87
|
},
|
|
88
|
+
// notifications-inapp
|
|
24
89
|
{
|
|
25
|
-
id: '
|
|
26
|
-
domain: '
|
|
27
|
-
description: '
|
|
90
|
+
id: 'notifications-manual-alert',
|
|
91
|
+
domain: 'notifications-inapp',
|
|
92
|
+
description: 'Using window.alert/confirm/prompt instead of a toast/notification library',
|
|
28
93
|
filePatterns: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'],
|
|
29
94
|
codePatterns: [
|
|
30
|
-
/
|
|
31
|
-
/
|
|
32
|
-
/
|
|
95
|
+
/window\s*\.\s*alert\s*\(/,
|
|
96
|
+
/window\s*\.\s*confirm\s*\(/,
|
|
97
|
+
/window\s*\.\s*prompt\s*\(/,
|
|
33
98
|
],
|
|
34
|
-
confidenceBase: 0.
|
|
99
|
+
confidenceBase: 0.75,
|
|
100
|
+
},
|
|
101
|
+
// design-system
|
|
102
|
+
{
|
|
103
|
+
id: 'design-hardcoded-colors',
|
|
104
|
+
domain: 'design-system',
|
|
105
|
+
description: 'Hardcoded hex/rgb colors in JSX/TSX instead of CSS variables or design tokens',
|
|
106
|
+
filePatterns: ['**/*.tsx', '**/*.jsx'],
|
|
107
|
+
codePatterns: [
|
|
108
|
+
/(?:color|background|border|fill|stroke)\s*[:=]\s*['"`]#[0-9a-fA-F]{3,8}['"`]/,
|
|
109
|
+
/(?:color|background|border)\s*[:=]\s*['"`]rgb\(/,
|
|
110
|
+
/className\s*=.*(?:bg|text|border)-\[#[0-9a-fA-F]{3,8}\]/,
|
|
111
|
+
],
|
|
112
|
+
confidenceBase: 0.6,
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
id: 'design-inline-styles',
|
|
116
|
+
domain: 'design-system',
|
|
117
|
+
description: 'Inline style objects in JSX instead of utility classes or design tokens',
|
|
118
|
+
filePatterns: ['**/*.tsx', '**/*.jsx'],
|
|
119
|
+
codePatterns: [
|
|
120
|
+
/style\s*=\s*\{\s*\{/,
|
|
121
|
+
/style\s*=\s*\{[^}]*(?:padding|margin|fontSize|color|width|height)\s*:/,
|
|
122
|
+
],
|
|
123
|
+
confidenceBase: 0.55,
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
id: 'design-no-cn-utility',
|
|
127
|
+
domain: 'design-system',
|
|
128
|
+
description: 'String concatenation for className instead of cn()/clsx/cva utility',
|
|
129
|
+
filePatterns: ['**/*.tsx', '**/*.jsx'],
|
|
130
|
+
codePatterns: [
|
|
131
|
+
/className\s*=\s*\{[^}]*`[^`]*\$\{/,
|
|
132
|
+
/className\s*=\s*\{[^}]*\+\s*['"`]/,
|
|
133
|
+
/className\s*=\s*\{.*\?\s*['"`][^'"]*['"`]\s*:\s*['"`]/,
|
|
134
|
+
],
|
|
135
|
+
confidenceBase: 0.6,
|
|
35
136
|
},
|
|
36
137
|
// -----------------------------------------------------------------------
|
|
37
|
-
// SEO
|
|
138
|
+
// B. SEO / i18n / Content
|
|
38
139
|
// -----------------------------------------------------------------------
|
|
140
|
+
// seo
|
|
39
141
|
{
|
|
40
142
|
id: 'seo-manual-meta-tags',
|
|
41
143
|
domain: 'seo',
|
|
@@ -60,90 +162,31 @@ export function getPatternCatalog() {
|
|
|
60
162
|
],
|
|
61
163
|
confidenceBase: 0.8,
|
|
62
164
|
},
|
|
63
|
-
//
|
|
64
|
-
// growth-hacking — A/B Testing, Analytics, Feature Flags
|
|
65
|
-
// -----------------------------------------------------------------------
|
|
165
|
+
// i18n
|
|
66
166
|
{
|
|
67
|
-
id: '
|
|
68
|
-
domain: '
|
|
69
|
-
description: 'Hand-rolled
|
|
167
|
+
id: 'i18n-manual-pluralization',
|
|
168
|
+
domain: 'i18n',
|
|
169
|
+
description: 'Hand-rolled pluralization logic (if/else or ternary on count)',
|
|
70
170
|
filePatterns: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'],
|
|
71
171
|
codePatterns: [
|
|
72
|
-
/
|
|
73
|
-
|
|
74
|
-
/experiment\s*[=:]\s*.*random/i,
|
|
172
|
+
/count\s*[=!]==?\s*1\s*\?\s*['"`].*['"`]\s*:\s*['"`].*['"`]/,
|
|
173
|
+
/\.length\s*[=!]==?\s*1\s*\?\s*['"`].*['"`]\s*:\s*['"`].*['"`]/,
|
|
75
174
|
],
|
|
76
175
|
confidenceBase: 0.7,
|
|
77
176
|
},
|
|
78
177
|
{
|
|
79
|
-
id: '
|
|
80
|
-
domain: '
|
|
81
|
-
description: '
|
|
178
|
+
id: 'i18n-manual-locale-detection',
|
|
179
|
+
domain: 'i18n',
|
|
180
|
+
description: 'Manual navigator.language or Accept-Language header parsing',
|
|
82
181
|
filePatterns: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'],
|
|
83
182
|
codePatterns: [
|
|
84
|
-
/
|
|
85
|
-
/
|
|
86
|
-
/
|
|
87
|
-
],
|
|
88
|
-
confidenceBase: 0.6,
|
|
89
|
-
},
|
|
90
|
-
// -----------------------------------------------------------------------
|
|
91
|
-
// ai-model-serving — Inference, Model Registry, Prompt Management
|
|
92
|
-
// -----------------------------------------------------------------------
|
|
93
|
-
{
|
|
94
|
-
id: 'ai-manual-prompt-template',
|
|
95
|
-
domain: 'ai-model-serving',
|
|
96
|
-
description: 'Hand-rolled prompt template string interpolation',
|
|
97
|
-
filePatterns: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx', '**/*.py'],
|
|
98
|
-
codePatterns: [
|
|
99
|
-
/`[^`]*\$\{.*\}[^`]*`\s*.*(?:prompt|system|user|assistant)/i,
|
|
100
|
-
/f['"].*\{.*\}.*['"].*(?:prompt|model|completion)/i,
|
|
101
|
-
/\.replace\s*\(\s*['"`]\{.*\}['"`]/,
|
|
183
|
+
/navigator\s*\.\s*language/,
|
|
184
|
+
/accept-language/i,
|
|
185
|
+
/toLocaleDateString\s*\(/,
|
|
102
186
|
],
|
|
103
187
|
confidenceBase: 0.65,
|
|
104
188
|
},
|
|
105
|
-
|
|
106
|
-
id: 'ai-manual-inference-http',
|
|
107
|
-
domain: 'ai-model-serving',
|
|
108
|
-
description: 'Hand-rolled HTTP calls to model inference endpoints',
|
|
109
|
-
filePatterns: ['**/*.ts', '**/*.js', '**/*.py'],
|
|
110
|
-
codePatterns: [
|
|
111
|
-
/fetch\s*\(\s*['"`].*(?:openai|anthropic|huggingface|inference)/i,
|
|
112
|
-
/axios\s*\.\s*post\s*\(\s*['"`].*(?:completions|chat|generate)/i,
|
|
113
|
-
/requests\s*\.\s*post\s*\(\s*['"`].*(?:v1\/|api\/)/i,
|
|
114
|
-
],
|
|
115
|
-
confidenceBase: 0.7,
|
|
116
|
-
},
|
|
117
|
-
// -----------------------------------------------------------------------
|
|
118
|
-
// agent-architecture — MCP Integration, Tool Orchestration, Context
|
|
119
|
-
// -----------------------------------------------------------------------
|
|
120
|
-
{
|
|
121
|
-
id: 'agent-manual-tool-dispatch',
|
|
122
|
-
domain: 'agent-architecture',
|
|
123
|
-
description: 'Hand-rolled tool dispatch with switch/case or if/else chains',
|
|
124
|
-
filePatterns: ['**/*.ts', '**/*.js', '**/*.py'],
|
|
125
|
-
codePatterns: [
|
|
126
|
-
/switch\s*\(\s*tool(?:Name|_name|Id)\s*\)/i,
|
|
127
|
-
/if\s*\(\s*tool(?:Name|_name)\s*===?\s*['"`]/i,
|
|
128
|
-
/tool_map\s*\[/i,
|
|
129
|
-
],
|
|
130
|
-
confidenceBase: 0.7,
|
|
131
|
-
},
|
|
132
|
-
{
|
|
133
|
-
id: 'agent-manual-context-window',
|
|
134
|
-
domain: 'agent-architecture',
|
|
135
|
-
description: 'Hand-rolled context window management (token counting, truncation)',
|
|
136
|
-
filePatterns: ['**/*.ts', '**/*.js', '**/*.py'],
|
|
137
|
-
codePatterns: [
|
|
138
|
-
/token[_s]?\s*(?:count|length|limit)/i,
|
|
139
|
-
/truncat(?:e|ion)\s*.*(?:context|message|prompt)/i,
|
|
140
|
-
/maxTokens?\s*[=:]/i,
|
|
141
|
-
],
|
|
142
|
-
confidenceBase: 0.6,
|
|
143
|
-
},
|
|
144
|
-
// -----------------------------------------------------------------------
|
|
145
|
-
// content-marketing — CMS, MDX Pipelines
|
|
146
|
-
// -----------------------------------------------------------------------
|
|
189
|
+
// content-marketing
|
|
147
190
|
{
|
|
148
191
|
id: 'content-manual-markdown-parsing',
|
|
149
192
|
domain: 'content-marketing',
|
|
@@ -169,114 +212,64 @@ export function getPatternCatalog() {
|
|
|
169
212
|
confidenceBase: 0.6,
|
|
170
213
|
},
|
|
171
214
|
// -----------------------------------------------------------------------
|
|
172
|
-
//
|
|
173
|
-
// -----------------------------------------------------------------------
|
|
174
|
-
{
|
|
175
|
-
id: 'ecommerce-manual-payment-integration',
|
|
176
|
-
domain: 'cross-border-ecommerce',
|
|
177
|
-
description: 'Hand-rolled payment gateway HTTP integration',
|
|
178
|
-
filePatterns: ['**/*.ts', '**/*.js', '**/*.py'],
|
|
179
|
-
codePatterns: [
|
|
180
|
-
/fetch\s*\(\s*['"`].*(?:stripe|paypal|checkout).*['"`]/i,
|
|
181
|
-
/payment[_-]?intent/i,
|
|
182
|
-
/charge\s*\.\s*create/i,
|
|
183
|
-
],
|
|
184
|
-
confidenceBase: 0.75,
|
|
185
|
-
},
|
|
186
|
-
{
|
|
187
|
-
id: 'ecommerce-manual-tax-calculation',
|
|
188
|
-
domain: 'cross-border-ecommerce',
|
|
189
|
-
description: 'Hand-rolled tax/VAT calculation logic',
|
|
190
|
-
filePatterns: ['**/*.ts', '**/*.js', '**/*.py'],
|
|
191
|
-
codePatterns: [
|
|
192
|
-
/tax[_-]?rate\s*[=:]\s*0?\.\d+/i,
|
|
193
|
-
/vat\s*[=:*]/i,
|
|
194
|
-
/calculateTax\s*\(/i,
|
|
195
|
-
],
|
|
196
|
-
confidenceBase: 0.65,
|
|
197
|
-
},
|
|
198
|
-
// -----------------------------------------------------------------------
|
|
199
|
-
// observability — Logging, Tracing, Metrics, Error Tracking
|
|
215
|
+
// C. Growth & Data
|
|
200
216
|
// -----------------------------------------------------------------------
|
|
217
|
+
// ab-testing-experimentation (was: growth-hacking)
|
|
201
218
|
{
|
|
202
|
-
id: '
|
|
203
|
-
domain: '
|
|
204
|
-
description: 'Hand-rolled
|
|
205
|
-
filePatterns: ['**/*.ts', '**/*.
|
|
219
|
+
id: 'ab-test-manual-random-split',
|
|
220
|
+
domain: 'ab-testing-experimentation',
|
|
221
|
+
description: 'Hand-rolled A/B testing with Math.random() or cookie-based splits',
|
|
222
|
+
filePatterns: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'],
|
|
206
223
|
codePatterns: [
|
|
207
|
-
/
|
|
224
|
+
/Math\s*\.\s*random\s*\(\s*\)\s*[<>]=?\s*0?\.\s*5/,
|
|
225
|
+
/variant\s*=\s*['"`][AB]['"`]/i,
|
|
226
|
+
/experiment\s*[=:]\s*.*random/i,
|
|
208
227
|
],
|
|
209
|
-
confidenceBase: 0.
|
|
228
|
+
confidenceBase: 0.7,
|
|
210
229
|
},
|
|
230
|
+
// analytics-tracking
|
|
211
231
|
{
|
|
212
|
-
id: '
|
|
213
|
-
domain: '
|
|
214
|
-
description: 'Hand-rolled
|
|
215
|
-
filePatterns: ['**/*.ts', '**/*.
|
|
232
|
+
id: 'analytics-manual-tracking',
|
|
233
|
+
domain: 'analytics-tracking',
|
|
234
|
+
description: 'Hand-rolled analytics/tracking calls instead of a product analytics SDK',
|
|
235
|
+
filePatterns: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'],
|
|
216
236
|
codePatterns: [
|
|
217
|
-
/
|
|
218
|
-
/
|
|
219
|
-
/
|
|
237
|
+
/window\s*\.\s*dataLayer\s*\.\s*push\s*\(/,
|
|
238
|
+
/gtag\s*\(\s*['"`]event['"`]/,
|
|
239
|
+
/fbq\s*\(\s*['"`]track['"`]/,
|
|
240
|
+
/navigator\s*\.\s*sendBeacon\s*\(/,
|
|
220
241
|
],
|
|
221
242
|
confidenceBase: 0.7,
|
|
222
243
|
},
|
|
223
244
|
// -----------------------------------------------------------------------
|
|
224
|
-
//
|
|
245
|
+
// D. App / Frontend Architecture
|
|
225
246
|
// -----------------------------------------------------------------------
|
|
247
|
+
// agent-architecture
|
|
226
248
|
{
|
|
227
|
-
id: '
|
|
228
|
-
domain: '
|
|
229
|
-
description: 'Hand-rolled
|
|
249
|
+
id: 'agent-manual-tool-dispatch',
|
|
250
|
+
domain: 'agent-architecture',
|
|
251
|
+
description: 'Hand-rolled tool dispatch with switch/case or if/else chains',
|
|
230
252
|
filePatterns: ['**/*.ts', '**/*.js', '**/*.py'],
|
|
231
253
|
codePatterns: [
|
|
232
|
-
/
|
|
233
|
-
/
|
|
234
|
-
/
|
|
235
|
-
/createHmac\s*\(/,
|
|
236
|
-
],
|
|
237
|
-
confidenceBase: 0.75,
|
|
238
|
-
},
|
|
239
|
-
{
|
|
240
|
-
id: 'auth-manual-rate-limiting',
|
|
241
|
-
domain: 'auth-security',
|
|
242
|
-
description: 'Hand-rolled rate limiting with in-memory counters or timestamps',
|
|
243
|
-
filePatterns: ['**/*.ts', '**/*.js'],
|
|
244
|
-
codePatterns: [
|
|
245
|
-
/requestCount\s*[+]=\s*1/i,
|
|
246
|
-
/rateLimi(?:t|ter)/i,
|
|
247
|
-
/new\s+Map\s*\(\s*\).*(?:timestamp|count|window)/i,
|
|
248
|
-
],
|
|
249
|
-
confidenceBase: 0.65,
|
|
250
|
-
},
|
|
251
|
-
// -----------------------------------------------------------------------
|
|
252
|
-
// ux-completeness — Forms, Loading States
|
|
253
|
-
// -----------------------------------------------------------------------
|
|
254
|
-
{
|
|
255
|
-
id: 'ux-manual-form-validation',
|
|
256
|
-
domain: 'ux-completeness',
|
|
257
|
-
description: 'Hand-rolled form validation with manual state tracking',
|
|
258
|
-
filePatterns: ['**/*.tsx', '**/*.jsx', '**/*.ts', '**/*.js'],
|
|
259
|
-
codePatterns: [
|
|
260
|
-
/setError\s*\(\s*['"`]/,
|
|
261
|
-
/errors\s*\[\s*['"`]\w+['"`]\s*\]/,
|
|
262
|
-
/validate\w*\s*=\s*\(\s*\)\s*=>/,
|
|
254
|
+
/switch\s*\(\s*tool(?:Name|_name|Id)\s*\)/i,
|
|
255
|
+
/if\s*\(\s*tool(?:Name|_name)\s*===?\s*['"`]/i,
|
|
256
|
+
/tool_map\s*\[/i,
|
|
263
257
|
],
|
|
264
258
|
confidenceBase: 0.7,
|
|
265
259
|
},
|
|
266
260
|
{
|
|
267
|
-
id: '
|
|
268
|
-
domain: '
|
|
269
|
-
description: 'Hand-rolled
|
|
270
|
-
filePatterns: ['**/*.
|
|
261
|
+
id: 'agent-manual-context-window',
|
|
262
|
+
domain: 'agent-architecture',
|
|
263
|
+
description: 'Hand-rolled context window management (token counting, truncation)',
|
|
264
|
+
filePatterns: ['**/*.ts', '**/*.js', '**/*.py'],
|
|
271
265
|
codePatterns: [
|
|
272
|
-
/
|
|
273
|
-
/
|
|
266
|
+
/token[_s]?\s*(?:count|length|limit)/i,
|
|
267
|
+
/truncat(?:e|ion)\s*.*(?:context|message|prompt)/i,
|
|
268
|
+
/maxTokens?\s*[=:]/i,
|
|
274
269
|
],
|
|
275
|
-
confidenceBase: 0.
|
|
270
|
+
confidenceBase: 0.6,
|
|
276
271
|
},
|
|
277
|
-
//
|
|
278
|
-
// state-management — Manual state chains, Redux boilerplate
|
|
279
|
-
// -----------------------------------------------------------------------
|
|
272
|
+
// state-management
|
|
280
273
|
{
|
|
281
274
|
id: 'state-manual-usestate-chain',
|
|
282
275
|
domain: 'state-management',
|
|
@@ -312,9 +305,7 @@ export function getPatternCatalog() {
|
|
|
312
305
|
],
|
|
313
306
|
confidenceBase: 0.75,
|
|
314
307
|
},
|
|
315
|
-
//
|
|
316
|
-
// data-fetching-caching — Manual fetch + useEffect patterns
|
|
317
|
-
// -----------------------------------------------------------------------
|
|
308
|
+
// data-fetching-caching
|
|
318
309
|
{
|
|
319
310
|
id: 'data-fetch-useeffect',
|
|
320
311
|
domain: 'data-fetching-caching',
|
|
@@ -351,34 +342,7 @@ export function getPatternCatalog() {
|
|
|
351
342
|
],
|
|
352
343
|
confidenceBase: 0.7,
|
|
353
344
|
},
|
|
354
|
-
//
|
|
355
|
-
// forms-ux — Manual form state and validation
|
|
356
|
-
// -----------------------------------------------------------------------
|
|
357
|
-
{
|
|
358
|
-
id: 'forms-manual-state-tracking',
|
|
359
|
-
domain: 'forms-ux',
|
|
360
|
-
description: 'Multiple useState hooks for individual form fields',
|
|
361
|
-
filePatterns: ['**/*.tsx', '**/*.jsx'],
|
|
362
|
-
codePatterns: [
|
|
363
|
-
/const\s*\[\s*\w+,\s*set\w+\s*\]\s*=\s*useState\s*\(\s*['"`]{2}\s*\)[\s\S]{0,200}onChange/,
|
|
364
|
-
/e\s*\.\s*target\s*\.\s*value[\s\S]{0,50}set\w+\s*\(\s*e\s*\.\s*target\s*\.\s*value\s*\)/,
|
|
365
|
-
],
|
|
366
|
-
confidenceBase: 0.65,
|
|
367
|
-
},
|
|
368
|
-
{
|
|
369
|
-
id: 'forms-manual-submit-handler',
|
|
370
|
-
domain: 'forms-ux',
|
|
371
|
-
description: 'Hand-rolled form submission with manual preventDefault and state collection',
|
|
372
|
-
filePatterns: ['**/*.tsx', '**/*.jsx'],
|
|
373
|
-
codePatterns: [
|
|
374
|
-
/handleSubmit[\s\S]{0,100}preventDefault\s*\(\s*\)[\s\S]{0,200}fetch\s*\(/,
|
|
375
|
-
/onSubmit[\s\S]{0,100}e\s*\.\s*preventDefault[\s\S]{0,200}(?:setLoading|setError)/,
|
|
376
|
-
],
|
|
377
|
-
confidenceBase: 0.6,
|
|
378
|
-
},
|
|
379
|
-
// -----------------------------------------------------------------------
|
|
380
|
-
// error-handling-resilience — Error boundaries, Result types
|
|
381
|
-
// -----------------------------------------------------------------------
|
|
345
|
+
// error-handling-resilience
|
|
382
346
|
{
|
|
383
347
|
id: 'error-manual-error-boundary',
|
|
384
348
|
domain: 'error-handling-resilience',
|
|
@@ -403,35 +367,20 @@ export function getPatternCatalog() {
|
|
|
403
367
|
],
|
|
404
368
|
confidenceBase: 0.65,
|
|
405
369
|
},
|
|
406
|
-
//
|
|
407
|
-
// a11y-accessibility — Missing ARIA, keyboard navigation
|
|
408
|
-
// -----------------------------------------------------------------------
|
|
409
|
-
{
|
|
410
|
-
id: 'a11y-manual-click-handler-div',
|
|
411
|
-
domain: 'a11y-accessibility',
|
|
412
|
-
description: 'Clickable div/span without keyboard accessibility',
|
|
413
|
-
filePatterns: ['**/*.tsx', '**/*.jsx'],
|
|
414
|
-
codePatterns: [
|
|
415
|
-
/<div\s[^>]*onClick\s*=\s*\{/,
|
|
416
|
-
/<span\s[^>]*onClick\s*=\s*\{/,
|
|
417
|
-
],
|
|
418
|
-
confidenceBase: 0.6,
|
|
419
|
-
},
|
|
370
|
+
// realtime-collaboration
|
|
420
371
|
{
|
|
421
|
-
id: '
|
|
422
|
-
domain: '
|
|
423
|
-
description: 'Hand-rolled
|
|
424
|
-
filePatterns: ['**/*.
|
|
372
|
+
id: 'realtime-manual-websocket',
|
|
373
|
+
domain: 'realtime-collaboration',
|
|
374
|
+
description: 'Hand-rolled WebSocket connection management',
|
|
375
|
+
filePatterns: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'],
|
|
425
376
|
codePatterns: [
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
377
|
+
/new\s+WebSocket\s*\(/,
|
|
378
|
+
/\.onmessage\s*=\s*/,
|
|
379
|
+
/\.send\s*\(\s*JSON\s*\.\s*stringify/,
|
|
429
380
|
],
|
|
430
|
-
confidenceBase: 0.
|
|
381
|
+
confidenceBase: 0.65,
|
|
431
382
|
},
|
|
432
|
-
//
|
|
433
|
-
// file-upload-media — Manual FileReader, drag-and-drop
|
|
434
|
-
// -----------------------------------------------------------------------
|
|
383
|
+
// file-upload-media
|
|
435
384
|
{
|
|
436
385
|
id: 'upload-manual-filereader',
|
|
437
386
|
domain: 'file-upload-media',
|
|
@@ -457,8 +406,9 @@ export function getPatternCatalog() {
|
|
|
457
406
|
confidenceBase: 0.65,
|
|
458
407
|
},
|
|
459
408
|
// -----------------------------------------------------------------------
|
|
460
|
-
//
|
|
409
|
+
// E. Backend / Platform
|
|
461
410
|
// -----------------------------------------------------------------------
|
|
411
|
+
// database-orm-migrations
|
|
462
412
|
{
|
|
463
413
|
id: 'db-manual-raw-sql',
|
|
464
414
|
domain: 'database-orm-migrations',
|
|
@@ -484,9 +434,90 @@ export function getPatternCatalog() {
|
|
|
484
434
|
],
|
|
485
435
|
confidenceBase: 0.65,
|
|
486
436
|
},
|
|
437
|
+
// caching-rate-limit
|
|
438
|
+
{
|
|
439
|
+
id: 'ratelimit-manual-counter',
|
|
440
|
+
domain: 'caching-rate-limit',
|
|
441
|
+
description: 'Hand-rolled rate limiting with in-memory counters or timestamps',
|
|
442
|
+
filePatterns: ['**/*.ts', '**/*.js'],
|
|
443
|
+
codePatterns: [
|
|
444
|
+
/requestCount\s*[+]=\s*1/i,
|
|
445
|
+
/rateLimi(?:t|ter)/i,
|
|
446
|
+
/new\s+Map\s*\(\s*\).*(?:timestamp|count|window)/i,
|
|
447
|
+
],
|
|
448
|
+
confidenceBase: 0.65,
|
|
449
|
+
},
|
|
450
|
+
// feature-flags-config (was: growth-hacking)
|
|
451
|
+
{
|
|
452
|
+
id: 'feature-flags-manual-env',
|
|
453
|
+
domain: 'feature-flags-config',
|
|
454
|
+
description: 'Hand-rolled feature flag checks via environment variables or config objects',
|
|
455
|
+
filePatterns: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'],
|
|
456
|
+
codePatterns: [
|
|
457
|
+
/process\s*\.\s*env\s*\.\s*FEATURE_/,
|
|
458
|
+
/featureFlags?\s*\[/,
|
|
459
|
+
/isFeatureEnabled\s*\(/,
|
|
460
|
+
],
|
|
461
|
+
confidenceBase: 0.6,
|
|
462
|
+
},
|
|
463
|
+
// -----------------------------------------------------------------------
|
|
464
|
+
// F. Security / Compliance
|
|
465
|
+
// -----------------------------------------------------------------------
|
|
466
|
+
// auth-security
|
|
467
|
+
{
|
|
468
|
+
id: 'auth-manual-jwt-handling',
|
|
469
|
+
domain: 'auth-security',
|
|
470
|
+
description: 'Hand-rolled JWT token creation/verification',
|
|
471
|
+
filePatterns: ['**/*.ts', '**/*.js', '**/*.py'],
|
|
472
|
+
codePatterns: [
|
|
473
|
+
/atob\s*\(\s*.*split\s*\(\s*['"`]\.['"`]\s*\)/,
|
|
474
|
+
/Buffer\s*\.\s*from\s*\(.*['"`]base64['"`]\s*\)/,
|
|
475
|
+
/jwt\s*\.\s*sign\s*\(/i,
|
|
476
|
+
/createHmac\s*\(/,
|
|
477
|
+
],
|
|
478
|
+
confidenceBase: 0.75,
|
|
479
|
+
},
|
|
480
|
+
// security-hardening
|
|
481
|
+
{
|
|
482
|
+
id: 'security-manual-headers',
|
|
483
|
+
domain: 'security-hardening',
|
|
484
|
+
description: 'Hand-rolled security headers instead of helmet/middleware',
|
|
485
|
+
filePatterns: ['**/*.ts', '**/*.js'],
|
|
486
|
+
codePatterns: [
|
|
487
|
+
/setHeader\s*\(\s*['"`]X-Frame-Options['"`]/i,
|
|
488
|
+
/setHeader\s*\(\s*['"`]X-Content-Type-Options['"`]/i,
|
|
489
|
+
/setHeader\s*\(\s*['"`]Content-Security-Policy['"`]/i,
|
|
490
|
+
],
|
|
491
|
+
confidenceBase: 0.7,
|
|
492
|
+
},
|
|
487
493
|
// -----------------------------------------------------------------------
|
|
488
|
-
//
|
|
494
|
+
// G. Observability / Ops
|
|
489
495
|
// -----------------------------------------------------------------------
|
|
496
|
+
// observability (parent — generic console.log)
|
|
497
|
+
{
|
|
498
|
+
id: 'observability-manual-logging',
|
|
499
|
+
domain: 'observability',
|
|
500
|
+
description: 'Hand-rolled logging with console.log/console.error in production code',
|
|
501
|
+
filePatterns: ['**/*.ts', '**/*.js', '**/*.tsx', '**/*.jsx'],
|
|
502
|
+
codePatterns: [
|
|
503
|
+
/console\s*\.\s*(?:log|error|warn|info)\s*\(/,
|
|
504
|
+
],
|
|
505
|
+
confidenceBase: 0.55,
|
|
506
|
+
},
|
|
507
|
+
// error-monitoring (was: observability)
|
|
508
|
+
{
|
|
509
|
+
id: 'error-monitoring-manual-tracking',
|
|
510
|
+
domain: 'error-monitoring',
|
|
511
|
+
description: 'Hand-rolled error tracking with try/catch and HTTP reporting',
|
|
512
|
+
filePatterns: ['**/*.ts', '**/*.js', '**/*.tsx', '**/*.jsx'],
|
|
513
|
+
codePatterns: [
|
|
514
|
+
/catch\s*\(\s*\w+\s*\)\s*\{[^}]*fetch\s*\(/,
|
|
515
|
+
/window\s*\.\s*onerror/,
|
|
516
|
+
/process\s*\.\s*on\s*\(\s*['"`]uncaughtException['"`]/,
|
|
517
|
+
],
|
|
518
|
+
confidenceBase: 0.7,
|
|
519
|
+
},
|
|
520
|
+
// logging-tracing-metrics
|
|
490
521
|
{
|
|
491
522
|
id: 'metrics-manual-timing',
|
|
492
523
|
domain: 'logging-tracing-metrics',
|
|
@@ -511,8 +542,9 @@ export function getPatternCatalog() {
|
|
|
511
542
|
confidenceBase: 0.7,
|
|
512
543
|
},
|
|
513
544
|
// -----------------------------------------------------------------------
|
|
514
|
-
//
|
|
545
|
+
// H. Delivery / Quality / DevEx
|
|
515
546
|
// -----------------------------------------------------------------------
|
|
547
|
+
// testing-strategy
|
|
516
548
|
{
|
|
517
549
|
id: 'test-manual-assertions',
|
|
518
550
|
domain: 'testing-strategy',
|
|
@@ -537,6 +569,78 @@ export function getPatternCatalog() {
|
|
|
537
569
|
],
|
|
538
570
|
confidenceBase: 0.5,
|
|
539
571
|
},
|
|
572
|
+
// -----------------------------------------------------------------------
|
|
573
|
+
// I. Performance
|
|
574
|
+
// -----------------------------------------------------------------------
|
|
575
|
+
// performance-web-vitals
|
|
576
|
+
{
|
|
577
|
+
id: 'perf-unoptimized-images',
|
|
578
|
+
domain: 'performance-web-vitals',
|
|
579
|
+
description: 'Using raw <img> tags instead of optimized image components',
|
|
580
|
+
filePatterns: ['**/*.tsx', '**/*.jsx'],
|
|
581
|
+
codePatterns: [
|
|
582
|
+
/<img\s[^>]*src\s*=\s*\{/,
|
|
583
|
+
/<img\s[^>]*src\s*=\s*['"`](?:https?:|\/)/,
|
|
584
|
+
],
|
|
585
|
+
confidenceBase: 0.5,
|
|
586
|
+
},
|
|
587
|
+
// -----------------------------------------------------------------------
|
|
588
|
+
// J. AI Engineering
|
|
589
|
+
// -----------------------------------------------------------------------
|
|
590
|
+
// ai-model-serving
|
|
591
|
+
{
|
|
592
|
+
id: 'ai-manual-prompt-template',
|
|
593
|
+
domain: 'ai-model-serving',
|
|
594
|
+
description: 'Hand-rolled prompt template string interpolation',
|
|
595
|
+
filePatterns: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx', '**/*.py'],
|
|
596
|
+
codePatterns: [
|
|
597
|
+
/`[^`]*\$\{.*\}[^`]*`\s*.*(?:prompt|system|user|assistant)/i,
|
|
598
|
+
/f['"].*\{.*\}.*['"].*(?:prompt|model|completion)/i,
|
|
599
|
+
/\.replace\s*\(\s*['"`]\{.*\}['"`]/,
|
|
600
|
+
],
|
|
601
|
+
confidenceBase: 0.65,
|
|
602
|
+
},
|
|
603
|
+
{
|
|
604
|
+
id: 'ai-manual-inference-http',
|
|
605
|
+
domain: 'ai-model-serving',
|
|
606
|
+
description: 'Hand-rolled HTTP calls to model inference endpoints',
|
|
607
|
+
filePatterns: ['**/*.ts', '**/*.js', '**/*.py'],
|
|
608
|
+
codePatterns: [
|
|
609
|
+
/fetch\s*\(\s*['"`].*(?:openai|anthropic|huggingface|inference)/i,
|
|
610
|
+
/axios\s*\.\s*post\s*\(\s*['"`].*(?:completions|chat|generate)/i,
|
|
611
|
+
/requests\s*\.\s*post\s*\(\s*['"`].*(?:v1\/|api\/)/i,
|
|
612
|
+
],
|
|
613
|
+
confidenceBase: 0.7,
|
|
614
|
+
},
|
|
615
|
+
// -----------------------------------------------------------------------
|
|
616
|
+
// K. Business domains
|
|
617
|
+
// -----------------------------------------------------------------------
|
|
618
|
+
// payments-billing (was: cross-border-ecommerce)
|
|
619
|
+
{
|
|
620
|
+
id: 'payments-manual-integration',
|
|
621
|
+
domain: 'payments-billing',
|
|
622
|
+
description: 'Hand-rolled payment gateway HTTP integration',
|
|
623
|
+
filePatterns: ['**/*.ts', '**/*.js', '**/*.py'],
|
|
624
|
+
codePatterns: [
|
|
625
|
+
/fetch\s*\(\s*['"`].*(?:stripe|paypal|checkout).*['"`]/i,
|
|
626
|
+
/payment[_-]?intent/i,
|
|
627
|
+
/charge\s*\.\s*create/i,
|
|
628
|
+
],
|
|
629
|
+
confidenceBase: 0.75,
|
|
630
|
+
},
|
|
631
|
+
// cross-border-ecommerce
|
|
632
|
+
{
|
|
633
|
+
id: 'ecommerce-manual-tax-calculation',
|
|
634
|
+
domain: 'cross-border-ecommerce',
|
|
635
|
+
description: 'Hand-rolled tax/VAT calculation logic',
|
|
636
|
+
filePatterns: ['**/*.ts', '**/*.js', '**/*.py'],
|
|
637
|
+
codePatterns: [
|
|
638
|
+
/tax[_-]?rate\s*[=:]\s*0?\.\d+/i,
|
|
639
|
+
/vat\s*[=:*]/i,
|
|
640
|
+
/calculateTax\s*\(/i,
|
|
641
|
+
],
|
|
642
|
+
confidenceBase: 0.65,
|
|
643
|
+
},
|
|
540
644
|
];
|
|
541
645
|
}
|
|
542
646
|
/**
|