@rankcli/agent-runtime 0.0.8 → 0.0.11
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/README.md +90 -196
- package/dist/analyzer-GMURJADU.mjs +7 -0
- package/dist/chunk-2JADKV3Z.mjs +244 -0
- package/dist/chunk-3ZSCLNTW.mjs +557 -0
- package/dist/chunk-4E4MQOSP.mjs +374 -0
- package/dist/chunk-6BWS3CLP.mjs +16 -0
- package/dist/chunk-AK2IC22C.mjs +206 -0
- package/dist/chunk-K6VSXDD6.mjs +293 -0
- package/dist/chunk-M27NQCWW.mjs +303 -0
- package/dist/{chunk-YNZYHEYM.mjs → chunk-PJLNXOLN.mjs} +0 -14
- package/dist/chunk-VSQD74I7.mjs +474 -0
- package/dist/core-web-vitals-analyzer-TE6LQJMS.mjs +7 -0
- package/dist/geo-analyzer-D47LTMMA.mjs +25 -0
- package/dist/image-optimization-analyzer-XP4OQGRP.mjs +9 -0
- package/dist/index.d.mts +1523 -17
- package/dist/index.d.ts +1523 -17
- package/dist/index.js +9582 -2664
- package/dist/index.mjs +4812 -380
- package/dist/internal-linking-analyzer-MRMBV7NM.mjs +9 -0
- package/dist/mobile-seo-analyzer-67HNQ7IO.mjs +7 -0
- package/dist/security-headers-analyzer-3ZUQARS5.mjs +9 -0
- package/dist/structured-data-analyzer-2I4NQAUP.mjs +9 -0
- package/package.json +2 -2
- package/src/analyzers/core-web-vitals-analyzer.test.ts +236 -0
- package/src/analyzers/core-web-vitals-analyzer.ts +557 -0
- package/src/analyzers/geo-analyzer.test.ts +310 -0
- package/src/analyzers/geo-analyzer.ts +814 -0
- package/src/analyzers/image-optimization-analyzer.test.ts +145 -0
- package/src/analyzers/image-optimization-analyzer.ts +348 -0
- package/src/analyzers/index.ts +233 -0
- package/src/analyzers/internal-linking-analyzer.test.ts +141 -0
- package/src/analyzers/internal-linking-analyzer.ts +419 -0
- package/src/analyzers/mobile-seo-analyzer.test.ts +140 -0
- package/src/analyzers/mobile-seo-analyzer.ts +455 -0
- package/src/analyzers/security-headers-analyzer.test.ts +115 -0
- package/src/analyzers/security-headers-analyzer.ts +318 -0
- package/src/analyzers/structured-data-analyzer.test.ts +210 -0
- package/src/analyzers/structured-data-analyzer.ts +590 -0
- package/src/audit/engine.ts +3 -3
- package/src/audit/types.ts +3 -2
- package/src/fixer/framework-fixes.test.ts +489 -0
- package/src/fixer/framework-fixes.ts +3418 -0
- package/src/fixer/index.ts +1 -0
- package/src/fixer/schemas.ts +971 -0
- package/src/frameworks/detector.ts +642 -114
- package/src/frameworks/suggestion-engine.ts +38 -1
- package/src/index.ts +6 -0
- package/src/types.ts +15 -1
- package/dist/analyzer-2CSWIQGD.mjs +0 -6
|
@@ -3,11 +3,15 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Detects web frameworks from:
|
|
5
5
|
* 1. HTML signatures (data attributes, meta tags, scripts)
|
|
6
|
-
* 2. package.json
|
|
6
|
+
* 2. package.json / Gemfile / requirements.txt / composer.json / etc.
|
|
7
7
|
* 3. File structure patterns
|
|
8
|
+
* 4. HTTP response headers
|
|
9
|
+
*
|
|
10
|
+
* Supports 25+ frameworks across JavaScript, Ruby, Python, PHP, Java, C#, Go, and Elixir.
|
|
8
11
|
*/
|
|
9
12
|
|
|
10
13
|
export type Framework =
|
|
14
|
+
// JavaScript/TypeScript
|
|
11
15
|
| 'react'
|
|
12
16
|
| 'nextjs'
|
|
13
17
|
| 'vue'
|
|
@@ -18,193 +22,359 @@ export type Framework =
|
|
|
18
22
|
| 'astro'
|
|
19
23
|
| 'remix'
|
|
20
24
|
| 'gatsby'
|
|
25
|
+
| 'solidjs'
|
|
26
|
+
| 'qwik'
|
|
27
|
+
| 'fresh'
|
|
28
|
+
// Ruby
|
|
21
29
|
| 'rails'
|
|
22
|
-
|
|
30
|
+
// Python
|
|
23
31
|
| 'django'
|
|
32
|
+
| 'flask'
|
|
33
|
+
| 'fastapi'
|
|
34
|
+
// PHP
|
|
35
|
+
| 'laravel'
|
|
36
|
+
| 'symfony'
|
|
24
37
|
| 'wordpress'
|
|
38
|
+
// Java
|
|
39
|
+
| 'spring'
|
|
40
|
+
// C#
|
|
41
|
+
| 'aspnet'
|
|
42
|
+
// Go
|
|
43
|
+
| 'go'
|
|
44
|
+
// Elixir
|
|
45
|
+
| 'phoenix'
|
|
46
|
+
// Hypermedia
|
|
47
|
+
| 'htmx'
|
|
48
|
+
| 'hotwire'
|
|
49
|
+
// Static Site Generators
|
|
50
|
+
| 'hugo'
|
|
51
|
+
| 'jekyll'
|
|
52
|
+
| 'eleventy'
|
|
53
|
+
| 'pelican'
|
|
54
|
+
// Unknown
|
|
25
55
|
| 'unknown';
|
|
26
56
|
|
|
57
|
+
export type Language = 'javascript' | 'typescript' | 'ruby' | 'python' | 'php' | 'java' | 'csharp' | 'go' | 'elixir' | 'rust' | 'unknown';
|
|
58
|
+
|
|
27
59
|
export interface FrameworkInfo {
|
|
28
60
|
framework: Framework;
|
|
29
61
|
version?: string;
|
|
62
|
+
language: Language;
|
|
30
63
|
confidence: 'high' | 'medium' | 'low';
|
|
31
|
-
detected_from: 'html' | 'package.json' | 'files' | 'headers';
|
|
64
|
+
detected_from: 'html' | 'package.json' | 'files' | 'headers' | 'gemfile' | 'requirements' | 'composer' | 'pom' | 'csproj' | 'go.mod' | 'mix.exs';
|
|
32
65
|
meta_framework?: Framework; // e.g., Next.js for React
|
|
33
66
|
}
|
|
34
67
|
|
|
35
68
|
interface HtmlSignature {
|
|
36
69
|
framework: Framework;
|
|
70
|
+
language: Language;
|
|
37
71
|
patterns: RegExp[];
|
|
38
72
|
confidence: 'high' | 'medium' | 'low';
|
|
39
73
|
}
|
|
40
74
|
|
|
41
75
|
const HTML_SIGNATURES: HtmlSignature[] = [
|
|
76
|
+
// ============ JavaScript/TypeScript Frameworks ============
|
|
77
|
+
|
|
42
78
|
// Next.js
|
|
43
79
|
{
|
|
44
80
|
framework: 'nextjs',
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
/_next\//,
|
|
48
|
-
/data-nscript/,
|
|
49
|
-
/__NEXT_DATA__/,
|
|
50
|
-
/next\/script/,
|
|
51
|
-
],
|
|
81
|
+
language: 'typescript',
|
|
82
|
+
patterns: [/__next/, /_next\//, /data-nscript/, /__NEXT_DATA__/, /next\/script/],
|
|
52
83
|
confidence: 'high',
|
|
53
84
|
},
|
|
54
85
|
// Nuxt
|
|
55
86
|
{
|
|
56
87
|
framework: 'nuxt',
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
/_nuxt\//,
|
|
60
|
-
/data-n-head/,
|
|
61
|
-
/nuxt-link/,
|
|
62
|
-
/__NUXT__/,
|
|
63
|
-
],
|
|
88
|
+
language: 'typescript',
|
|
89
|
+
patterns: [/__nuxt/, /_nuxt\//, /data-n-head/, /nuxt-link/, /__NUXT__/],
|
|
64
90
|
confidence: 'high',
|
|
65
91
|
},
|
|
66
92
|
// Gatsby
|
|
67
93
|
{
|
|
68
94
|
framework: 'gatsby',
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
/gatsby-/,
|
|
72
|
-
/gatsby-image/,
|
|
73
|
-
/data-gatsby/,
|
|
74
|
-
],
|
|
95
|
+
language: 'javascript',
|
|
96
|
+
patterns: [/___gatsby/, /gatsby-/, /gatsby-image/, /data-gatsby/],
|
|
75
97
|
confidence: 'high',
|
|
76
98
|
},
|
|
77
99
|
// Astro
|
|
78
100
|
{
|
|
79
101
|
framework: 'astro',
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
/data-astro/,
|
|
83
|
-
/_astro\//,
|
|
84
|
-
],
|
|
102
|
+
language: 'typescript',
|
|
103
|
+
patterns: [/astro-/, /data-astro/, /_astro\//],
|
|
85
104
|
confidence: 'high',
|
|
86
105
|
},
|
|
87
106
|
// SvelteKit
|
|
88
107
|
{
|
|
89
108
|
framework: 'sveltekit',
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
/_app\/immutable/,
|
|
93
|
-
/svelte-kit/,
|
|
94
|
-
],
|
|
109
|
+
language: 'typescript',
|
|
110
|
+
patterns: [/__sveltekit/, /_app\/immutable/, /svelte-kit/],
|
|
95
111
|
confidence: 'high',
|
|
96
112
|
},
|
|
97
113
|
// Svelte (standalone)
|
|
98
114
|
{
|
|
99
115
|
framework: 'svelte',
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
/__svelte/,
|
|
103
|
-
],
|
|
116
|
+
language: 'javascript',
|
|
117
|
+
patterns: [/svelte-\w+/, /__svelte/],
|
|
104
118
|
confidence: 'medium',
|
|
105
119
|
},
|
|
106
120
|
// Remix
|
|
107
121
|
{
|
|
108
122
|
framework: 'remix',
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
123
|
+
language: 'typescript',
|
|
124
|
+
patterns: [/__remix/, /remix-/, /data-remix/],
|
|
125
|
+
confidence: 'high',
|
|
126
|
+
},
|
|
127
|
+
// Solid.js
|
|
128
|
+
{
|
|
129
|
+
framework: 'solidjs',
|
|
130
|
+
language: 'typescript',
|
|
131
|
+
patterns: [/solid-/, /data-solid/, /_solid/],
|
|
114
132
|
confidence: 'high',
|
|
115
133
|
},
|
|
116
|
-
//
|
|
134
|
+
// Qwik
|
|
135
|
+
{
|
|
136
|
+
framework: 'qwik',
|
|
137
|
+
language: 'typescript',
|
|
138
|
+
patterns: [/q:/, /qwik/, /q-/],
|
|
139
|
+
confidence: 'high',
|
|
140
|
+
},
|
|
141
|
+
// Fresh (Deno)
|
|
142
|
+
{
|
|
143
|
+
framework: 'fresh',
|
|
144
|
+
language: 'typescript',
|
|
145
|
+
patterns: [/fresh-/, /_frsh\//, /data-fresh/],
|
|
146
|
+
confidence: 'high',
|
|
147
|
+
},
|
|
148
|
+
// React (generic - lower priority)
|
|
117
149
|
{
|
|
118
150
|
framework: 'react',
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
/data-react-helmet/,
|
|
122
|
-
/_react/,
|
|
123
|
-
/react-app/,
|
|
124
|
-
],
|
|
151
|
+
language: 'javascript',
|
|
152
|
+
patterns: [/data-reactroot/, /data-react-helmet/, /_react/, /react-app/],
|
|
125
153
|
confidence: 'medium',
|
|
126
154
|
},
|
|
127
|
-
// Vue (generic - lower priority
|
|
155
|
+
// Vue (generic - lower priority)
|
|
128
156
|
{
|
|
129
157
|
framework: 'vue',
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
/v-cloak/,
|
|
133
|
-
/__vue/,
|
|
134
|
-
],
|
|
158
|
+
language: 'javascript',
|
|
159
|
+
patterns: [/data-v-[a-f0-9]+/, /v-cloak/, /__vue/],
|
|
135
160
|
confidence: 'medium',
|
|
136
161
|
},
|
|
137
162
|
// Angular
|
|
138
163
|
{
|
|
139
164
|
framework: 'angular',
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
/_ngcontent/,
|
|
143
|
-
/ng-\w+=/,
|
|
144
|
-
/\[ng/,
|
|
145
|
-
],
|
|
165
|
+
language: 'typescript',
|
|
166
|
+
patterns: [/ng-version/, /_ngcontent/, /ng-\w+=/, /\[ng/],
|
|
146
167
|
confidence: 'high',
|
|
147
168
|
},
|
|
169
|
+
|
|
170
|
+
// ============ Hypermedia Frameworks ============
|
|
171
|
+
|
|
172
|
+
// HTMX
|
|
173
|
+
{
|
|
174
|
+
framework: 'htmx',
|
|
175
|
+
language: 'unknown',
|
|
176
|
+
patterns: [/hx-get/, /hx-post/, /hx-trigger/, /hx-swap/, /htmx\.org/],
|
|
177
|
+
confidence: 'high',
|
|
178
|
+
},
|
|
179
|
+
// Hotwire/Turbo
|
|
180
|
+
{
|
|
181
|
+
framework: 'hotwire',
|
|
182
|
+
language: 'ruby',
|
|
183
|
+
patterns: [/turbo-frame/, /turbo-stream/, /data-turbo/, /stimulus/],
|
|
184
|
+
confidence: 'high',
|
|
185
|
+
},
|
|
186
|
+
|
|
187
|
+
// ============ PHP Frameworks ============
|
|
188
|
+
|
|
148
189
|
// WordPress
|
|
149
190
|
{
|
|
150
191
|
framework: 'wordpress',
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
/wp-includes/,
|
|
154
|
-
/wp-json/,
|
|
155
|
-
/wordpress/i,
|
|
156
|
-
],
|
|
192
|
+
language: 'php',
|
|
193
|
+
patterns: [/wp-content/, /wp-includes/, /wp-json/, /wordpress/i],
|
|
157
194
|
confidence: 'high',
|
|
158
195
|
},
|
|
159
196
|
// Laravel
|
|
160
197
|
{
|
|
161
198
|
framework: 'laravel',
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
/XSRF-TOKEN/,
|
|
165
|
-
/@csrf/,
|
|
166
|
-
],
|
|
199
|
+
language: 'php',
|
|
200
|
+
patterns: [/laravel_session/, /XSRF-TOKEN/, /@csrf/, /laravel/i],
|
|
167
201
|
confidence: 'medium',
|
|
168
202
|
},
|
|
203
|
+
// Symfony
|
|
204
|
+
{
|
|
205
|
+
framework: 'symfony',
|
|
206
|
+
language: 'php',
|
|
207
|
+
patterns: [/symfony/, /sf2/, /_sf_/, /profiler\.css/],
|
|
208
|
+
confidence: 'medium',
|
|
209
|
+
},
|
|
210
|
+
|
|
211
|
+
// ============ Ruby Frameworks ============
|
|
212
|
+
|
|
169
213
|
// Rails
|
|
170
214
|
{
|
|
171
215
|
framework: 'rails',
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
/turbolinks/,
|
|
175
|
-
/data-turbo/,
|
|
176
|
-
/rails-ujs/,
|
|
177
|
-
],
|
|
216
|
+
language: 'ruby',
|
|
217
|
+
patterns: [/csrf-token/, /turbolinks/, /data-turbo/, /rails-ujs/, /action-cable/],
|
|
178
218
|
confidence: 'medium',
|
|
179
219
|
},
|
|
220
|
+
|
|
221
|
+
// ============ Python Frameworks ============
|
|
222
|
+
|
|
180
223
|
// Django
|
|
181
224
|
{
|
|
182
225
|
framework: 'django',
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
226
|
+
language: 'python',
|
|
227
|
+
patterns: [/csrfmiddlewaretoken/, /django/, /__debug__\//],
|
|
228
|
+
confidence: 'medium',
|
|
229
|
+
},
|
|
230
|
+
// Flask
|
|
231
|
+
{
|
|
232
|
+
framework: 'flask',
|
|
233
|
+
language: 'python',
|
|
234
|
+
patterns: [/flask/, /werkzeug/i],
|
|
235
|
+
confidence: 'low',
|
|
236
|
+
},
|
|
237
|
+
// FastAPI
|
|
238
|
+
{
|
|
239
|
+
framework: 'fastapi',
|
|
240
|
+
language: 'python',
|
|
241
|
+
patterns: [/fastapi/, /openapi\.json/],
|
|
242
|
+
confidence: 'low',
|
|
243
|
+
},
|
|
244
|
+
|
|
245
|
+
// ============ Java Frameworks ============
|
|
246
|
+
|
|
247
|
+
// Spring Boot
|
|
248
|
+
{
|
|
249
|
+
framework: 'spring',
|
|
250
|
+
language: 'java',
|
|
251
|
+
patterns: [/spring/, /thymeleaf/, /th:/, /_csrf/],
|
|
252
|
+
confidence: 'medium',
|
|
253
|
+
},
|
|
254
|
+
|
|
255
|
+
// ============ C# Frameworks ============
|
|
256
|
+
|
|
257
|
+
// ASP.NET Core
|
|
258
|
+
{
|
|
259
|
+
framework: 'aspnet',
|
|
260
|
+
language: 'csharp',
|
|
261
|
+
patterns: [/aspnetcore/, /__RequestVerificationToken/, /blazor/, /_framework\/blazor/],
|
|
262
|
+
confidence: 'medium',
|
|
263
|
+
},
|
|
264
|
+
|
|
265
|
+
// ============ Elixir Frameworks ============
|
|
266
|
+
|
|
267
|
+
// Phoenix
|
|
268
|
+
{
|
|
269
|
+
framework: 'phoenix',
|
|
270
|
+
language: 'elixir',
|
|
271
|
+
patterns: [/phx-/, /phoenix/, /live-socket/, /data-phx/],
|
|
272
|
+
confidence: 'high',
|
|
273
|
+
},
|
|
274
|
+
|
|
275
|
+
// ============ Static Site Generators ============
|
|
276
|
+
|
|
277
|
+
// Hugo
|
|
278
|
+
{
|
|
279
|
+
framework: 'hugo',
|
|
280
|
+
language: 'go',
|
|
281
|
+
patterns: [/hugo/, /generator.*hugo/i],
|
|
282
|
+
confidence: 'medium',
|
|
283
|
+
},
|
|
284
|
+
// Jekyll
|
|
285
|
+
{
|
|
286
|
+
framework: 'jekyll',
|
|
287
|
+
language: 'ruby',
|
|
288
|
+
patterns: [/jekyll/, /generator.*jekyll/i],
|
|
289
|
+
confidence: 'medium',
|
|
290
|
+
},
|
|
291
|
+
// Eleventy
|
|
292
|
+
{
|
|
293
|
+
framework: 'eleventy',
|
|
294
|
+
language: 'javascript',
|
|
295
|
+
patterns: [/11ty/, /eleventy/, /generator.*eleventy/i],
|
|
296
|
+
confidence: 'medium',
|
|
297
|
+
},
|
|
298
|
+
// Pelican
|
|
299
|
+
{
|
|
300
|
+
framework: 'pelican',
|
|
301
|
+
language: 'python',
|
|
302
|
+
patterns: [/pelican/, /generator.*pelican/i],
|
|
187
303
|
confidence: 'medium',
|
|
188
304
|
},
|
|
189
305
|
];
|
|
190
306
|
|
|
191
307
|
interface PackageDependency {
|
|
192
308
|
framework: Framework;
|
|
309
|
+
language: Language;
|
|
193
310
|
packages: string[];
|
|
194
311
|
meta_framework?: Framework;
|
|
195
312
|
}
|
|
196
313
|
|
|
314
|
+
// NPM package.json dependencies
|
|
197
315
|
const PACKAGE_DEPENDENCIES: PackageDependency[] = [
|
|
198
|
-
|
|
199
|
-
{ framework: '
|
|
200
|
-
{ framework: '
|
|
201
|
-
{ framework: '
|
|
202
|
-
{ framework: '
|
|
203
|
-
{ framework: '
|
|
204
|
-
{ framework: '
|
|
205
|
-
{ framework: '
|
|
206
|
-
{ framework: '
|
|
207
|
-
{ framework: '
|
|
316
|
+
// Meta-frameworks (check first - more specific)
|
|
317
|
+
{ framework: 'nextjs', language: 'typescript', packages: ['next'], meta_framework: 'react' },
|
|
318
|
+
{ framework: 'gatsby', language: 'javascript', packages: ['gatsby'], meta_framework: 'react' },
|
|
319
|
+
{ framework: 'remix', language: 'typescript', packages: ['@remix-run/react', '@remix-run/node'], meta_framework: 'react' },
|
|
320
|
+
{ framework: 'nuxt', language: 'typescript', packages: ['nuxt', 'nuxt3'], meta_framework: 'vue' },
|
|
321
|
+
{ framework: 'sveltekit', language: 'typescript', packages: ['@sveltejs/kit'], meta_framework: 'svelte' },
|
|
322
|
+
{ framework: 'astro', language: 'typescript', packages: ['astro'] },
|
|
323
|
+
{ framework: 'solidjs', language: 'typescript', packages: ['solid-js', 'solid-start'] },
|
|
324
|
+
{ framework: 'qwik', language: 'typescript', packages: ['@builder.io/qwik'] },
|
|
325
|
+
{ framework: 'eleventy', language: 'javascript', packages: ['@11ty/eleventy'] },
|
|
326
|
+
|
|
327
|
+
// Base frameworks
|
|
328
|
+
{ framework: 'react', language: 'javascript', packages: ['react', 'react-dom'] },
|
|
329
|
+
{ framework: 'vue', language: 'javascript', packages: ['vue'] },
|
|
330
|
+
{ framework: 'angular', language: 'typescript', packages: ['@angular/core'] },
|
|
331
|
+
{ framework: 'svelte', language: 'javascript', packages: ['svelte'] },
|
|
332
|
+
|
|
333
|
+
// HTMX (can be used with any backend)
|
|
334
|
+
{ framework: 'htmx', language: 'unknown', packages: ['htmx.org'] },
|
|
335
|
+
];
|
|
336
|
+
|
|
337
|
+
// Ruby Gemfile dependencies
|
|
338
|
+
const GEMFILE_DEPENDENCIES: PackageDependency[] = [
|
|
339
|
+
{ framework: 'rails', language: 'ruby', packages: ['rails'] },
|
|
340
|
+
{ framework: 'hotwire', language: 'ruby', packages: ['turbo-rails', 'stimulus-rails'], meta_framework: 'rails' },
|
|
341
|
+
{ framework: 'jekyll', language: 'ruby', packages: ['jekyll'] },
|
|
342
|
+
];
|
|
343
|
+
|
|
344
|
+
// Python requirements.txt / pyproject.toml dependencies
|
|
345
|
+
const PYTHON_DEPENDENCIES: PackageDependency[] = [
|
|
346
|
+
{ framework: 'django', language: 'python', packages: ['django', 'Django'] },
|
|
347
|
+
{ framework: 'flask', language: 'python', packages: ['flask', 'Flask'] },
|
|
348
|
+
{ framework: 'fastapi', language: 'python', packages: ['fastapi', 'FastAPI'] },
|
|
349
|
+
{ framework: 'pelican', language: 'python', packages: ['pelican', 'Pelican'] },
|
|
350
|
+
];
|
|
351
|
+
|
|
352
|
+
// PHP composer.json dependencies
|
|
353
|
+
const COMPOSER_DEPENDENCIES: PackageDependency[] = [
|
|
354
|
+
{ framework: 'laravel', language: 'php', packages: ['laravel/framework'] },
|
|
355
|
+
{ framework: 'symfony', language: 'php', packages: ['symfony/framework-bundle', 'symfony/symfony'] },
|
|
356
|
+
{ framework: 'wordpress', language: 'php', packages: ['johnpbloch/wordpress-core'] },
|
|
357
|
+
];
|
|
358
|
+
|
|
359
|
+
// Java pom.xml / build.gradle dependencies
|
|
360
|
+
const JAVA_DEPENDENCIES: PackageDependency[] = [
|
|
361
|
+
{ framework: 'spring', language: 'java', packages: ['spring-boot-starter-web', 'org.springframework.boot'] },
|
|
362
|
+
];
|
|
363
|
+
|
|
364
|
+
// C# .csproj dependencies
|
|
365
|
+
const DOTNET_DEPENDENCIES: PackageDependency[] = [
|
|
366
|
+
{ framework: 'aspnet', language: 'csharp', packages: ['Microsoft.AspNetCore', 'Microsoft.NET.Sdk.Web'] },
|
|
367
|
+
];
|
|
368
|
+
|
|
369
|
+
// Go go.mod dependencies
|
|
370
|
+
const GO_DEPENDENCIES: PackageDependency[] = [
|
|
371
|
+
{ framework: 'hugo', language: 'go', packages: ['github.com/gohugoio/hugo'] },
|
|
372
|
+
{ framework: 'go', language: 'go', packages: ['github.com/gin-gonic/gin', 'github.com/labstack/echo', 'github.com/gofiber/fiber'] },
|
|
373
|
+
];
|
|
374
|
+
|
|
375
|
+
// Elixir mix.exs dependencies
|
|
376
|
+
const ELIXIR_DEPENDENCIES: PackageDependency[] = [
|
|
377
|
+
{ framework: 'phoenix', language: 'elixir', packages: [':phoenix', 'phoenix'] },
|
|
208
378
|
];
|
|
209
379
|
|
|
210
380
|
/**
|
|
@@ -216,6 +386,7 @@ export function detectFromHtml(html: string): FrameworkInfo | null {
|
|
|
216
386
|
if (pattern.test(html)) {
|
|
217
387
|
return {
|
|
218
388
|
framework: signature.framework,
|
|
389
|
+
language: signature.language,
|
|
219
390
|
confidence: signature.confidence,
|
|
220
391
|
detected_from: 'html',
|
|
221
392
|
};
|
|
@@ -226,7 +397,7 @@ export function detectFromHtml(html: string): FrameworkInfo | null {
|
|
|
226
397
|
}
|
|
227
398
|
|
|
228
399
|
/**
|
|
229
|
-
* Detect framework from package.json content
|
|
400
|
+
* Detect framework from package.json content (JavaScript/TypeScript)
|
|
230
401
|
*/
|
|
231
402
|
export function detectFromPackageJson(packageJson: {
|
|
232
403
|
dependencies?: Record<string, string>;
|
|
@@ -242,6 +413,7 @@ export function detectFromPackageJson(packageJson: {
|
|
|
242
413
|
if (allDeps[pkg]) {
|
|
243
414
|
return {
|
|
244
415
|
framework: dep.framework,
|
|
416
|
+
language: dep.language,
|
|
245
417
|
version: allDeps[pkg],
|
|
246
418
|
confidence: 'high',
|
|
247
419
|
detected_from: 'package.json',
|
|
@@ -254,29 +426,234 @@ export function detectFromPackageJson(packageJson: {
|
|
|
254
426
|
return null;
|
|
255
427
|
}
|
|
256
428
|
|
|
429
|
+
/**
|
|
430
|
+
* Detect framework from Gemfile content (Ruby)
|
|
431
|
+
*/
|
|
432
|
+
export function detectFromGemfile(gemfileContent: string): FrameworkInfo | null {
|
|
433
|
+
const gemPattern = /gem\s+['"]([^'"]+)['"]/g;
|
|
434
|
+
const gems: string[] = [];
|
|
435
|
+
let match;
|
|
436
|
+
|
|
437
|
+
while ((match = gemPattern.exec(gemfileContent)) !== null) {
|
|
438
|
+
gems.push(match[1]);
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
for (const dep of GEMFILE_DEPENDENCIES) {
|
|
442
|
+
for (const pkg of dep.packages) {
|
|
443
|
+
if (gems.includes(pkg)) {
|
|
444
|
+
return {
|
|
445
|
+
framework: dep.framework,
|
|
446
|
+
language: dep.language,
|
|
447
|
+
confidence: 'high',
|
|
448
|
+
detected_from: 'gemfile',
|
|
449
|
+
meta_framework: dep.meta_framework,
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
return null;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* Detect framework from requirements.txt or pyproject.toml (Python)
|
|
460
|
+
*/
|
|
461
|
+
export function detectFromPythonDeps(content: string): FrameworkInfo | null {
|
|
462
|
+
for (const dep of PYTHON_DEPENDENCIES) {
|
|
463
|
+
for (const pkg of dep.packages) {
|
|
464
|
+
// Match package name at start of line or after whitespace, ignoring version specs
|
|
465
|
+
const pattern = new RegExp(`(^|\\s)${pkg.toLowerCase()}[\\s=<>~!]`, 'im');
|
|
466
|
+
if (pattern.test(content.toLowerCase())) {
|
|
467
|
+
return {
|
|
468
|
+
framework: dep.framework,
|
|
469
|
+
language: dep.language,
|
|
470
|
+
confidence: 'high',
|
|
471
|
+
detected_from: 'requirements',
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
return null;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
/**
|
|
481
|
+
* Detect framework from composer.json (PHP)
|
|
482
|
+
*/
|
|
483
|
+
export function detectFromComposerJson(composerJson: {
|
|
484
|
+
require?: Record<string, string>;
|
|
485
|
+
'require-dev'?: Record<string, string>;
|
|
486
|
+
}): FrameworkInfo | null {
|
|
487
|
+
const allDeps = {
|
|
488
|
+
...composerJson.require,
|
|
489
|
+
...composerJson['require-dev'],
|
|
490
|
+
};
|
|
491
|
+
|
|
492
|
+
for (const dep of COMPOSER_DEPENDENCIES) {
|
|
493
|
+
for (const pkg of dep.packages) {
|
|
494
|
+
if (allDeps[pkg]) {
|
|
495
|
+
return {
|
|
496
|
+
framework: dep.framework,
|
|
497
|
+
language: dep.language,
|
|
498
|
+
version: allDeps[pkg],
|
|
499
|
+
confidence: 'high',
|
|
500
|
+
detected_from: 'composer',
|
|
501
|
+
};
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
return null;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* Detect framework from pom.xml content (Java/Maven)
|
|
511
|
+
*/
|
|
512
|
+
export function detectFromPomXml(pomContent: string): FrameworkInfo | null {
|
|
513
|
+
for (const dep of JAVA_DEPENDENCIES) {
|
|
514
|
+
for (const pkg of dep.packages) {
|
|
515
|
+
if (pomContent.includes(pkg)) {
|
|
516
|
+
return {
|
|
517
|
+
framework: dep.framework,
|
|
518
|
+
language: dep.language,
|
|
519
|
+
confidence: 'high',
|
|
520
|
+
detected_from: 'pom',
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
return null;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
/**
|
|
530
|
+
* Detect framework from .csproj content (C#/.NET)
|
|
531
|
+
*/
|
|
532
|
+
export function detectFromCsproj(csprojContent: string): FrameworkInfo | null {
|
|
533
|
+
for (const dep of DOTNET_DEPENDENCIES) {
|
|
534
|
+
for (const pkg of dep.packages) {
|
|
535
|
+
if (csprojContent.includes(pkg)) {
|
|
536
|
+
return {
|
|
537
|
+
framework: dep.framework,
|
|
538
|
+
language: dep.language,
|
|
539
|
+
confidence: 'high',
|
|
540
|
+
detected_from: 'csproj',
|
|
541
|
+
};
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
return null;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
/**
|
|
550
|
+
* Detect framework from go.mod content (Go)
|
|
551
|
+
*/
|
|
552
|
+
export function detectFromGoMod(goModContent: string): FrameworkInfo | null {
|
|
553
|
+
for (const dep of GO_DEPENDENCIES) {
|
|
554
|
+
for (const pkg of dep.packages) {
|
|
555
|
+
if (goModContent.includes(pkg)) {
|
|
556
|
+
return {
|
|
557
|
+
framework: dep.framework,
|
|
558
|
+
language: dep.language,
|
|
559
|
+
confidence: 'high',
|
|
560
|
+
detected_from: 'go.mod',
|
|
561
|
+
};
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
return null;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
/**
|
|
570
|
+
* Detect framework from mix.exs content (Elixir)
|
|
571
|
+
*/
|
|
572
|
+
export function detectFromMixExs(mixContent: string): FrameworkInfo | null {
|
|
573
|
+
for (const dep of ELIXIR_DEPENDENCIES) {
|
|
574
|
+
for (const pkg of dep.packages) {
|
|
575
|
+
if (mixContent.includes(pkg)) {
|
|
576
|
+
return {
|
|
577
|
+
framework: dep.framework,
|
|
578
|
+
language: dep.language,
|
|
579
|
+
confidence: 'high',
|
|
580
|
+
detected_from: 'mix.exs',
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
return null;
|
|
587
|
+
}
|
|
588
|
+
|
|
257
589
|
/**
|
|
258
590
|
* Detect framework from HTTP response headers
|
|
259
591
|
*/
|
|
260
592
|
export function detectFromHeaders(headers: Record<string, string>): FrameworkInfo | null {
|
|
261
593
|
const poweredBy = headers['x-powered-by']?.toLowerCase() || '';
|
|
262
594
|
const server = headers['server']?.toLowerCase() || '';
|
|
595
|
+
const generator = headers['x-generator']?.toLowerCase() || '';
|
|
263
596
|
|
|
597
|
+
// JavaScript/TypeScript
|
|
264
598
|
if (poweredBy.includes('next.js') || poweredBy.includes('next')) {
|
|
265
|
-
return { framework: 'nextjs', confidence: 'high', detected_from: 'headers' };
|
|
599
|
+
return { framework: 'nextjs', language: 'typescript', confidence: 'high', detected_from: 'headers' };
|
|
266
600
|
}
|
|
267
601
|
if (poweredBy.includes('nuxt')) {
|
|
268
|
-
return { framework: 'nuxt', confidence: 'high', detected_from: 'headers' };
|
|
602
|
+
return { framework: 'nuxt', language: 'typescript', confidence: 'high', detected_from: 'headers' };
|
|
603
|
+
}
|
|
604
|
+
if (poweredBy.includes('remix')) {
|
|
605
|
+
return { framework: 'remix', language: 'typescript', confidence: 'high', detected_from: 'headers' };
|
|
269
606
|
}
|
|
270
|
-
|
|
271
|
-
|
|
607
|
+
|
|
608
|
+
// Ruby
|
|
609
|
+
if (poweredBy.includes('phusion') || poweredBy.includes('passenger') || poweredBy.includes('puma') || poweredBy.includes('unicorn')) {
|
|
610
|
+
return { framework: 'rails', language: 'ruby', confidence: 'medium', detected_from: 'headers' };
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
// Python
|
|
614
|
+
if (poweredBy.includes('gunicorn') || poweredBy.includes('uvicorn') || poweredBy.includes('daphne')) {
|
|
615
|
+
// Python but unclear which framework - needs HTML detection
|
|
272
616
|
return null;
|
|
273
617
|
}
|
|
274
|
-
|
|
275
|
-
|
|
618
|
+
|
|
619
|
+
// PHP
|
|
620
|
+
if (poweredBy.includes('php')) {
|
|
621
|
+
// Could be WordPress, Laravel, or Symfony - needs HTML detection
|
|
276
622
|
return null;
|
|
277
623
|
}
|
|
278
|
-
|
|
279
|
-
|
|
624
|
+
|
|
625
|
+
// Java
|
|
626
|
+
if (server.includes('tomcat') || server.includes('jetty') || poweredBy.includes('spring')) {
|
|
627
|
+
return { framework: 'spring', language: 'java', confidence: 'medium', detected_from: 'headers' };
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
// .NET
|
|
631
|
+
if (poweredBy.includes('asp.net') || server.includes('kestrel')) {
|
|
632
|
+
return { framework: 'aspnet', language: 'csharp', confidence: 'high', detected_from: 'headers' };
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
// Elixir
|
|
636
|
+
if (poweredBy.includes('phoenix') || poweredBy.includes('cowboy')) {
|
|
637
|
+
return { framework: 'phoenix', language: 'elixir', confidence: 'medium', detected_from: 'headers' };
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
// Go
|
|
641
|
+
if (server.includes('gin') || server.includes('echo') || server.includes('fiber')) {
|
|
642
|
+
return { framework: 'go', language: 'go', confidence: 'medium', detected_from: 'headers' };
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
// Static site generators (from generator meta/header)
|
|
646
|
+
if (generator.includes('hugo')) {
|
|
647
|
+
return { framework: 'hugo', language: 'go', confidence: 'high', detected_from: 'headers' };
|
|
648
|
+
}
|
|
649
|
+
if (generator.includes('jekyll')) {
|
|
650
|
+
return { framework: 'jekyll', language: 'ruby', confidence: 'high', detected_from: 'headers' };
|
|
651
|
+
}
|
|
652
|
+
if (generator.includes('eleventy') || generator.includes('11ty')) {
|
|
653
|
+
return { framework: 'eleventy', language: 'javascript', confidence: 'high', detected_from: 'headers' };
|
|
654
|
+
}
|
|
655
|
+
if (generator.includes('pelican')) {
|
|
656
|
+
return { framework: 'pelican', language: 'python', confidence: 'high', detected_from: 'headers' };
|
|
280
657
|
}
|
|
281
658
|
|
|
282
659
|
return null;
|
|
@@ -288,15 +665,66 @@ export function detectFromHeaders(headers: Record<string, string>): FrameworkInf
|
|
|
288
665
|
export function detectFramework(options: {
|
|
289
666
|
html?: string;
|
|
290
667
|
packageJson?: { dependencies?: Record<string, string>; devDependencies?: Record<string, string> };
|
|
668
|
+
composerJson?: { require?: Record<string, string>; 'require-dev'?: Record<string, string> };
|
|
669
|
+
gemfileContent?: string;
|
|
670
|
+
requirementsContent?: string;
|
|
671
|
+
pomXmlContent?: string;
|
|
672
|
+
csprojContent?: string;
|
|
673
|
+
goModContent?: string;
|
|
674
|
+
mixExsContent?: string;
|
|
291
675
|
headers?: Record<string, string>;
|
|
292
676
|
files?: string[];
|
|
293
677
|
}): FrameworkInfo {
|
|
294
|
-
// Try
|
|
678
|
+
// Try dependency files first (most reliable)
|
|
679
|
+
|
|
680
|
+
// JavaScript/TypeScript
|
|
295
681
|
if (options.packageJson) {
|
|
296
682
|
const result = detectFromPackageJson(options.packageJson);
|
|
297
683
|
if (result) return result;
|
|
298
684
|
}
|
|
299
685
|
|
|
686
|
+
// Ruby
|
|
687
|
+
if (options.gemfileContent) {
|
|
688
|
+
const result = detectFromGemfile(options.gemfileContent);
|
|
689
|
+
if (result) return result;
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
// Python
|
|
693
|
+
if (options.requirementsContent) {
|
|
694
|
+
const result = detectFromPythonDeps(options.requirementsContent);
|
|
695
|
+
if (result) return result;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
// PHP
|
|
699
|
+
if (options.composerJson) {
|
|
700
|
+
const result = detectFromComposerJson(options.composerJson);
|
|
701
|
+
if (result) return result;
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
// Java
|
|
705
|
+
if (options.pomXmlContent) {
|
|
706
|
+
const result = detectFromPomXml(options.pomXmlContent);
|
|
707
|
+
if (result) return result;
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
// C#
|
|
711
|
+
if (options.csprojContent) {
|
|
712
|
+
const result = detectFromCsproj(options.csprojContent);
|
|
713
|
+
if (result) return result;
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
// Go
|
|
717
|
+
if (options.goModContent) {
|
|
718
|
+
const result = detectFromGoMod(options.goModContent);
|
|
719
|
+
if (result) return result;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
// Elixir
|
|
723
|
+
if (options.mixExsContent) {
|
|
724
|
+
const result = detectFromMixExs(options.mixExsContent);
|
|
725
|
+
if (result) return result;
|
|
726
|
+
}
|
|
727
|
+
|
|
300
728
|
// Try headers
|
|
301
729
|
if (options.headers) {
|
|
302
730
|
const result = detectFromHeaders(options.headers);
|
|
@@ -311,39 +739,83 @@ export function detectFramework(options: {
|
|
|
311
739
|
|
|
312
740
|
// Check file patterns
|
|
313
741
|
if (options.files) {
|
|
742
|
+
// JavaScript/TypeScript
|
|
314
743
|
if (options.files.some(f => f.includes('next.config'))) {
|
|
315
|
-
return { framework: 'nextjs', confidence: 'high', detected_from: 'files' };
|
|
744
|
+
return { framework: 'nextjs', language: 'typescript', confidence: 'high', detected_from: 'files' };
|
|
316
745
|
}
|
|
317
746
|
if (options.files.some(f => f.includes('nuxt.config'))) {
|
|
318
|
-
return { framework: 'nuxt', confidence: 'high', detected_from: 'files' };
|
|
747
|
+
return { framework: 'nuxt', language: 'typescript', confidence: 'high', detected_from: 'files' };
|
|
319
748
|
}
|
|
320
749
|
if (options.files.some(f => f.includes('astro.config'))) {
|
|
321
|
-
return { framework: 'astro', confidence: 'high', detected_from: 'files' };
|
|
750
|
+
return { framework: 'astro', language: 'typescript', confidence: 'high', detected_from: 'files' };
|
|
322
751
|
}
|
|
323
752
|
if (options.files.some(f => f.includes('svelte.config'))) {
|
|
324
|
-
return { framework: 'sveltekit', confidence: 'high', detected_from: 'files' };
|
|
753
|
+
return { framework: 'sveltekit', language: 'typescript', confidence: 'high', detected_from: 'files' };
|
|
325
754
|
}
|
|
326
755
|
if (options.files.some(f => f.includes('angular.json'))) {
|
|
327
|
-
return { framework: 'angular', confidence: 'high', detected_from: 'files' };
|
|
756
|
+
return { framework: 'angular', language: 'typescript', confidence: 'high', detected_from: 'files' };
|
|
328
757
|
}
|
|
329
758
|
if (options.files.some(f => f.includes('gatsby-config'))) {
|
|
330
|
-
return { framework: 'gatsby', confidence: 'high', detected_from: 'files' };
|
|
759
|
+
return { framework: 'gatsby', language: 'javascript', confidence: 'high', detected_from: 'files' };
|
|
760
|
+
}
|
|
761
|
+
if (options.files.some(f => f.includes('remix.config'))) {
|
|
762
|
+
return { framework: 'remix', language: 'typescript', confidence: 'high', detected_from: 'files' };
|
|
763
|
+
}
|
|
764
|
+
if (options.files.some(f => f.includes('.eleventy.js') || f.includes('eleventy.config'))) {
|
|
765
|
+
return { framework: 'eleventy', language: 'javascript', confidence: 'high', detected_from: 'files' };
|
|
331
766
|
}
|
|
767
|
+
|
|
768
|
+
// PHP
|
|
332
769
|
if (options.files.some(f => f === 'wp-config.php')) {
|
|
333
|
-
return { framework: 'wordpress', confidence: 'high', detected_from: 'files' };
|
|
770
|
+
return { framework: 'wordpress', language: 'php', confidence: 'high', detected_from: 'files' };
|
|
334
771
|
}
|
|
335
772
|
if (options.files.some(f => f === 'artisan')) {
|
|
336
|
-
return { framework: 'laravel', confidence: 'high', detected_from: 'files' };
|
|
773
|
+
return { framework: 'laravel', language: 'php', confidence: 'high', detected_from: 'files' };
|
|
337
774
|
}
|
|
775
|
+
if (options.files.some(f => f.includes('symfony.lock') || f.includes('config/bundles.php'))) {
|
|
776
|
+
return { framework: 'symfony', language: 'php', confidence: 'high', detected_from: 'files' };
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
// Python
|
|
338
780
|
if (options.files.some(f => f === 'manage.py')) {
|
|
339
|
-
return { framework: 'django', confidence: 'high', detected_from: 'files' };
|
|
781
|
+
return { framework: 'django', language: 'python', confidence: 'high', detected_from: 'files' };
|
|
782
|
+
}
|
|
783
|
+
if (options.files.some(f => f.includes('pelicanconf.py'))) {
|
|
784
|
+
return { framework: 'pelican', language: 'python', confidence: 'high', detected_from: 'files' };
|
|
340
785
|
}
|
|
786
|
+
|
|
787
|
+
// Ruby
|
|
341
788
|
if (options.files.some(f => f === 'Gemfile') && options.files.some(f => f.includes('config/routes.rb'))) {
|
|
342
|
-
return { framework: 'rails', confidence: 'high', detected_from: 'files' };
|
|
789
|
+
return { framework: 'rails', language: 'ruby', confidence: 'high', detected_from: 'files' };
|
|
790
|
+
}
|
|
791
|
+
if (options.files.some(f => f === '_config.yml') && options.files.some(f => f === 'Gemfile')) {
|
|
792
|
+
return { framework: 'jekyll', language: 'ruby', confidence: 'high', detected_from: 'files' };
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
// Go
|
|
796
|
+
if (options.files.some(f => f.includes('hugo.toml') || f.includes('hugo.yaml') || f.includes('config.toml'))) {
|
|
797
|
+
return { framework: 'hugo', language: 'go', confidence: 'high', detected_from: 'files' };
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
// Java
|
|
801
|
+
if (options.files.some(f => f.includes('pom.xml') || f.includes('build.gradle'))) {
|
|
802
|
+
if (options.files.some(f => f.includes('src/main/resources/application'))) {
|
|
803
|
+
return { framework: 'spring', language: 'java', confidence: 'high', detected_from: 'files' };
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
// C#
|
|
808
|
+
if (options.files.some(f => f.endsWith('.csproj'))) {
|
|
809
|
+
return { framework: 'aspnet', language: 'csharp', confidence: 'medium', detected_from: 'files' };
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
// Elixir
|
|
813
|
+
if (options.files.some(f => f === 'mix.exs') && options.files.some(f => f.includes('lib') && f.includes('_web'))) {
|
|
814
|
+
return { framework: 'phoenix', language: 'elixir', confidence: 'high', detected_from: 'files' };
|
|
343
815
|
}
|
|
344
816
|
}
|
|
345
817
|
|
|
346
|
-
return { framework: 'unknown', confidence: 'low', detected_from: 'html' };
|
|
818
|
+
return { framework: 'unknown', language: 'unknown', confidence: 'low', detected_from: 'html' };
|
|
347
819
|
}
|
|
348
820
|
|
|
349
821
|
/**
|
|
@@ -351,6 +823,7 @@ export function detectFramework(options: {
|
|
|
351
823
|
*/
|
|
352
824
|
export function getFrameworkDisplayName(framework: Framework): string {
|
|
353
825
|
const names: Record<Framework, string> = {
|
|
826
|
+
// JavaScript/TypeScript
|
|
354
827
|
react: 'React',
|
|
355
828
|
nextjs: 'Next.js',
|
|
356
829
|
vue: 'Vue.js',
|
|
@@ -361,11 +834,66 @@ export function getFrameworkDisplayName(framework: Framework): string {
|
|
|
361
834
|
astro: 'Astro',
|
|
362
835
|
remix: 'Remix',
|
|
363
836
|
gatsby: 'Gatsby',
|
|
837
|
+
solidjs: 'Solid.js',
|
|
838
|
+
qwik: 'Qwik',
|
|
839
|
+
fresh: 'Fresh (Deno)',
|
|
840
|
+
|
|
841
|
+
// Ruby
|
|
364
842
|
rails: 'Ruby on Rails',
|
|
365
|
-
|
|
843
|
+
|
|
844
|
+
// Python
|
|
366
845
|
django: 'Django',
|
|
846
|
+
flask: 'Flask',
|
|
847
|
+
fastapi: 'FastAPI',
|
|
848
|
+
|
|
849
|
+
// PHP
|
|
850
|
+
laravel: 'Laravel',
|
|
851
|
+
symfony: 'Symfony',
|
|
367
852
|
wordpress: 'WordPress',
|
|
853
|
+
|
|
854
|
+
// Java
|
|
855
|
+
spring: 'Spring Boot',
|
|
856
|
+
|
|
857
|
+
// C#
|
|
858
|
+
aspnet: 'ASP.NET Core',
|
|
859
|
+
|
|
860
|
+
// Go
|
|
861
|
+
go: 'Go (Gin/Echo/Fiber)',
|
|
862
|
+
|
|
863
|
+
// Elixir
|
|
864
|
+
phoenix: 'Phoenix',
|
|
865
|
+
|
|
866
|
+
// Hypermedia
|
|
867
|
+
htmx: 'HTMX',
|
|
868
|
+
hotwire: 'Hotwire/Turbo',
|
|
869
|
+
|
|
870
|
+
// Static Site Generators
|
|
871
|
+
hugo: 'Hugo',
|
|
872
|
+
jekyll: 'Jekyll',
|
|
873
|
+
eleventy: 'Eleventy (11ty)',
|
|
874
|
+
pelican: 'Pelican',
|
|
875
|
+
|
|
368
876
|
unknown: 'Unknown',
|
|
369
877
|
};
|
|
370
878
|
return names[framework];
|
|
371
879
|
}
|
|
880
|
+
|
|
881
|
+
/**
|
|
882
|
+
* Get language display name
|
|
883
|
+
*/
|
|
884
|
+
export function getLanguageDisplayName(language: Language): string {
|
|
885
|
+
const names: Record<Language, string> = {
|
|
886
|
+
javascript: 'JavaScript',
|
|
887
|
+
typescript: 'TypeScript',
|
|
888
|
+
ruby: 'Ruby',
|
|
889
|
+
python: 'Python',
|
|
890
|
+
php: 'PHP',
|
|
891
|
+
java: 'Java',
|
|
892
|
+
csharp: 'C#',
|
|
893
|
+
go: 'Go',
|
|
894
|
+
elixir: 'Elixir',
|
|
895
|
+
rust: 'Rust',
|
|
896
|
+
unknown: 'Unknown',
|
|
897
|
+
};
|
|
898
|
+
return names[language];
|
|
899
|
+
}
|