entkapp 5.5.0 → 5.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/README.md +1 -1
  2. package/bin/cli.js +2 -2
  3. package/bin/cli.mjs +175 -0
  4. package/index.cjs +18 -0
  5. package/index.mjs +51 -0
  6. package/package.json +7 -6
  7. package/src/EngineContext.mjs +428 -0
  8. package/src/Initializer.mjs +82 -0
  9. package/src/analyzers/CodeSmellAnalyzer.mjs +106 -0
  10. package/src/analyzers/OxcAnalyzer.mjs +11 -0
  11. package/src/api/HeadlessAPI.js +31 -16
  12. package/src/api/HeadlessAPI.mjs +369 -0
  13. package/src/api/PluginSDK.mjs +135 -0
  14. package/src/ast/ASTAnalyzer.js +17 -3
  15. package/src/ast/ASTAnalyzer.mjs +742 -0
  16. package/src/ast/AdvancedAnalysis.mjs +586 -0
  17. package/src/ast/BarrelParser.mjs +230 -0
  18. package/src/ast/DeadCodeDetector.js +7 -5
  19. package/src/ast/DeadCodeDetector.mjs +92 -0
  20. package/src/ast/MagicDetector.mjs +203 -0
  21. package/src/ast/OxcAnalyzer.mjs +188 -0
  22. package/src/ast/SecretScanner.mjs +374 -0
  23. package/src/healing/GitSandbox.mjs +82 -0
  24. package/src/healing/SelfHealer.mjs +48 -0
  25. package/src/index.js +37 -1
  26. package/src/index.mjs +1180 -0
  27. package/src/performance/GraphCache.mjs +108 -0
  28. package/src/performance/SupplyChainGuard.mjs +92 -0
  29. package/src/performance/WorkerPool.mjs +132 -0
  30. package/src/performance/WorkerTaskRunner.mjs +144 -0
  31. package/src/plugins/BasePlugin.mjs +240 -0
  32. package/src/plugins/PluginRegistry.mjs +203 -0
  33. package/src/plugins/ecosystems/BackendServices.mjs +197 -0
  34. package/src/plugins/ecosystems/GenericPlugins.mjs +142 -0
  35. package/src/plugins/ecosystems/ModernFrameworks.mjs +162 -0
  36. package/src/plugins/ecosystems/MorePlugins.mjs +562 -0
  37. package/src/plugins/ecosystems/NewPlugins.mjs +526 -0
  38. package/src/plugins/ecosystems/NextJsPlugin.mjs +45 -0
  39. package/src/plugins/ecosystems/PluginLoader.mjs +193 -0
  40. package/src/plugins/ecosystems/TypeScriptPlugin.mjs +56 -0
  41. package/src/plugins/ecosystems/UltimateBundle.mjs +1182 -0
  42. package/src/refractor/ImpactAnalyzer.mjs +92 -0
  43. package/src/refractor/SourceRewriter.mjs +86 -0
  44. package/src/refractor/TransactionManager.mjs +5 -0
  45. package/src/refractor/TypeIntegrity.mjs +4 -0
  46. package/src/resolution/BuildOrchestrator.mjs +46 -0
  47. package/src/resolution/CircularDetector.mjs +91 -0
  48. package/src/resolution/ConfigGenerator.mjs +83 -0
  49. package/src/resolution/ConfigLoader.mjs +94 -0
  50. package/src/resolution/DepencyResolver.mjs +66 -0
  51. package/src/resolution/DependencyFixer.mjs +88 -0
  52. package/src/resolution/DependencyProfiler.mjs +286 -0
  53. package/src/resolution/EntryPointDetector.mjs +134 -0
  54. package/src/resolution/FrameworkConfigParser.mjs +119 -0
  55. package/src/resolution/GraphAnalyzer.mjs +80 -0
  56. package/src/resolution/MigrationAnalyzer.mjs +60 -0
  57. package/src/resolution/PathMapper.mjs +82 -0
  58. package/src/resolution/TSConfigLoader.mjs +162 -0
  59. package/src/resolution/WorkSpaceGraph.mjs +183 -0
  60. package/src/resolution/WorkspaceDiagnostic.mjs +139 -0
  61. package/test.js +76 -0
  62. package/wrangler.toml +6 -0
@@ -0,0 +1,526 @@
1
+ /**
2
+ * ============================================================================
3
+ * New Ecosystem Plugins for entkapp v5.0.0
4
+ * ============================================================================
5
+ * State management, routing, animation, validation, i18n, monitoring, and more.
6
+ * All plugins implement getRequiredPackages() for dependency detection.
7
+ */
8
+ import path from 'path';
9
+ import fs from 'fs/promises';
10
+ import { BasePlugin } from '../BasePlugin.mjs';
11
+
12
+ // ─── STATE MANAGEMENT ────────────────────────────────────────────────────────
13
+
14
+ export class ReduxPlugin extends BasePlugin {
15
+ get name() { return 'redux'; }
16
+ getConfigFiles() { return ['package.json']; }
17
+ getRequiredPackages() { return [{ name: '@reduxjs/toolkit', dev: false }, { name: 'react-redux', dev: false }]; }
18
+ async isActive(baseDir) {
19
+ try {
20
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
21
+ return !!(pkgJson.dependencies?.['@reduxjs/toolkit'] || pkgJson.dependencies?.redux || pkgJson.devDependencies?.['@reduxjs/toolkit']);
22
+ } catch { return false; }
23
+ }
24
+ async analyze(node) {
25
+ if (node.rawCode?.includes('createSlice(') || node.rawCode?.includes('configureStore(')) node.isEntry = true;
26
+ }
27
+ }
28
+
29
+ export class ZustandPlugin extends BasePlugin {
30
+ get name() { return 'zustand'; }
31
+ getConfigFiles() { return ['package.json']; }
32
+ getRequiredPackages() { return [{ name: 'zustand', dev: false }]; }
33
+ async isActive(baseDir) {
34
+ try {
35
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
36
+ return !!(pkgJson.dependencies?.zustand || pkgJson.devDependencies?.zustand);
37
+ } catch { return false; }
38
+ }
39
+ async analyze(node) {
40
+ if (node.rawCode?.includes('create(') && node.rawCode?.includes('set =>')) node.isEntry = true;
41
+ }
42
+ }
43
+
44
+ export class JotaiPlugin extends BasePlugin {
45
+ get name() { return 'jotai'; }
46
+ getConfigFiles() { return ['package.json']; }
47
+ getRequiredPackages() { return [{ name: 'jotai', dev: false }]; }
48
+ async isActive(baseDir) {
49
+ try {
50
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
51
+ return !!(pkgJson.dependencies?.jotai || pkgJson.devDependencies?.jotai);
52
+ } catch { return false; }
53
+ }
54
+ async analyze(node) {
55
+ if (node.rawCode?.includes('atom(')) node.isEntry = true;
56
+ }
57
+ }
58
+
59
+ export class RecoilPlugin extends BasePlugin {
60
+ get name() { return 'recoil'; }
61
+ getConfigFiles() { return ['package.json']; }
62
+ getRequiredPackages() { return [{ name: 'recoil', dev: false }]; }
63
+ async isActive(baseDir) {
64
+ try {
65
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
66
+ return !!(pkgJson.dependencies?.recoil || pkgJson.devDependencies?.recoil);
67
+ } catch { return false; }
68
+ }
69
+ }
70
+
71
+ export class MobXPlugin extends BasePlugin {
72
+ get name() { return 'mobx'; }
73
+ getConfigFiles() { return ['package.json']; }
74
+ getRequiredPackages() { return [{ name: 'mobx', dev: false }, { name: 'mobx-react-lite', dev: false, optional: true }]; }
75
+ async isActive(baseDir) {
76
+ try {
77
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
78
+ return !!(pkgJson.dependencies?.mobx || pkgJson.devDependencies?.mobx);
79
+ } catch { return false; }
80
+ }
81
+ }
82
+
83
+ export class PiniaPlugin extends BasePlugin {
84
+ get name() { return 'pinia'; }
85
+ getConfigFiles() { return ['package.json']; }
86
+ getRequiredPackages() { return [{ name: 'pinia', dev: false }]; }
87
+ async isActive(baseDir) {
88
+ try {
89
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
90
+ return !!(pkgJson.dependencies?.pinia || pkgJson.devDependencies?.pinia);
91
+ } catch { return false; }
92
+ }
93
+ }
94
+
95
+ export class TanStackQueryPlugin extends BasePlugin {
96
+ get name() { return 'tanstack-query'; }
97
+ getConfigFiles() { return ['package.json']; }
98
+ getRequiredPackages() { return [{ name: '@tanstack/react-query', dev: false }]; }
99
+ async isActive(baseDir) {
100
+ try {
101
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
102
+ const allDeps = { ...(pkgJson.dependencies || {}), ...(pkgJson.devDependencies || {}) };
103
+ return Object.keys(allDeps).some(k => k.startsWith('@tanstack/') && k.includes('query'));
104
+ } catch { return false; }
105
+ }
106
+ }
107
+
108
+ // ─── ROUTING ─────────────────────────────────────────────────────────────────
109
+
110
+ export class ReactRouterPlugin extends BasePlugin {
111
+ get name() { return 'react-router'; }
112
+ getConfigFiles() { return ['package.json']; }
113
+ getRequiredPackages() { return [{ name: 'react-router-dom', dev: false }]; }
114
+ async isActive(baseDir) {
115
+ try {
116
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
117
+ return !!(pkgJson.dependencies?.['react-router-dom'] || pkgJson.dependencies?.['react-router'] ||
118
+ pkgJson.devDependencies?.['react-router-dom']);
119
+ } catch { return false; }
120
+ }
121
+ getRequiredSystemContracts() { return ['default', 'Route', 'Routes', 'Link', 'useNavigate', 'useParams', 'useLocation']; }
122
+ }
123
+
124
+ export class TanStackRouterPlugin extends BasePlugin {
125
+ get name() { return 'tanstack-router'; }
126
+ getConfigFiles() { return ['package.json']; }
127
+ getRequiredPackages() { return [{ name: '@tanstack/react-router', dev: false }]; }
128
+ async isActive(baseDir) {
129
+ try {
130
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
131
+ const allDeps = { ...(pkgJson.dependencies || {}), ...(pkgJson.devDependencies || {}) };
132
+ return Object.keys(allDeps).some(k => k.startsWith('@tanstack/') && k.includes('router'));
133
+ } catch { return false; }
134
+ }
135
+ }
136
+
137
+ export class VueRouterPlugin extends BasePlugin {
138
+ get name() { return 'vue-router'; }
139
+ getConfigFiles() { return ['package.json']; }
140
+ getRequiredPackages() { return [{ name: 'vue-router', dev: false }]; }
141
+ async isActive(baseDir) {
142
+ try {
143
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
144
+ return !!(pkgJson.dependencies?.['vue-router'] || pkgJson.devDependencies?.['vue-router']);
145
+ } catch { return false; }
146
+ }
147
+ }
148
+
149
+ // ─── UI COMPONENTS ───────────────────────────────────────────────────────────
150
+
151
+ export class AntdPlugin extends BasePlugin {
152
+ get name() { return 'antd'; }
153
+ getConfigFiles() { return ['package.json']; }
154
+ getRequiredPackages() { return [{ name: 'antd', dev: false }]; }
155
+ async isActive(baseDir) {
156
+ try {
157
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
158
+ return !!(pkgJson.dependencies?.antd || pkgJson.devDependencies?.antd);
159
+ } catch { return false; }
160
+ }
161
+ async analyze(node) {
162
+ if (node.rawCode?.includes('from "antd"') || node.rawCode?.includes("from 'antd'")) node.isEntry = true;
163
+ }
164
+ }
165
+
166
+ export class MuiPlugin extends BasePlugin {
167
+ get name() { return 'mui'; }
168
+ getConfigFiles() { return ['package.json']; }
169
+ getRequiredPackages() { return [{ name: '@mui/material', dev: false }, { name: '@emotion/react', dev: false }, { name: '@emotion/styled', dev: false }]; }
170
+ async isActive(baseDir) {
171
+ try {
172
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
173
+ return !!(pkgJson.dependencies?.['@mui/material'] || pkgJson.devDependencies?.['@mui/material']);
174
+ } catch { return false; }
175
+ }
176
+ async analyze(node) {
177
+ if (node.rawCode?.includes('@mui/material')) node.isEntry = true;
178
+ }
179
+ }
180
+
181
+ export class ShadcnPlugin extends BasePlugin {
182
+ get name() { return 'shadcn'; }
183
+ getConfigFiles() { return ['components.json']; }
184
+ getRequiredPackages() { return [{ name: 'class-variance-authority', dev: false }, { name: 'clsx', dev: false }]; }
185
+ async isActive(baseDir) {
186
+ try { await fs.access(path.join(baseDir, 'components.json')); return true; } catch { return false; }
187
+ }
188
+ }
189
+
190
+ export class RadixUIPlugin extends BasePlugin {
191
+ get name() { return 'radix-ui'; }
192
+ getConfigFiles() { return ['package.json']; }
193
+ async isActive(baseDir) {
194
+ try {
195
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
196
+ const allDeps = { ...(pkgJson.dependencies || {}), ...(pkgJson.devDependencies || {}) };
197
+ return Object.keys(allDeps).some(k => k.startsWith('@radix-ui/'));
198
+ } catch { return false; }
199
+ }
200
+ }
201
+
202
+ export class ChakraUIPlugin extends BasePlugin {
203
+ get name() { return 'chakra-ui'; }
204
+ getConfigFiles() { return ['package.json']; }
205
+ getRequiredPackages() { return [{ name: '@chakra-ui/react', dev: false }]; }
206
+ async isActive(baseDir) {
207
+ try {
208
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
209
+ return !!(pkgJson.dependencies?.['@chakra-ui/react'] || pkgJson.devDependencies?.['@chakra-ui/react']);
210
+ } catch { return false; }
211
+ }
212
+ }
213
+
214
+ // ─── ANIMATION ───────────────────────────────────────────────────────────────
215
+
216
+ export class FramerMotionPlugin extends BasePlugin {
217
+ get name() { return 'framer-motion'; }
218
+ getConfigFiles() { return ['package.json']; }
219
+ getRequiredPackages() { return [{ name: 'framer-motion', dev: false }]; }
220
+ async isActive(baseDir) {
221
+ try {
222
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
223
+ return !!(pkgJson.dependencies?.['framer-motion'] || pkgJson.devDependencies?.['framer-motion']);
224
+ } catch { return false; }
225
+ }
226
+ }
227
+
228
+ export class GSAPPlugin extends BasePlugin {
229
+ get name() { return 'gsap'; }
230
+ getConfigFiles() { return ['package.json']; }
231
+ getRequiredPackages() { return [{ name: 'gsap', dev: false }]; }
232
+ async isActive(baseDir) {
233
+ try {
234
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
235
+ return !!(pkgJson.dependencies?.gsap || pkgJson.devDependencies?.gsap);
236
+ } catch { return false; }
237
+ }
238
+ }
239
+
240
+ // ─── VALIDATION ──────────────────────────────────────────────────────────────
241
+
242
+ export class ZodPlugin extends BasePlugin {
243
+ get name() { return 'zod'; }
244
+ getConfigFiles() { return ['package.json']; }
245
+ getRequiredPackages() { return [{ name: 'zod', dev: false }]; }
246
+ async isActive(baseDir) {
247
+ try {
248
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
249
+ return !!(pkgJson.dependencies?.zod || pkgJson.devDependencies?.zod);
250
+ } catch { return false; }
251
+ }
252
+ }
253
+
254
+ export class YupPlugin extends BasePlugin {
255
+ get name() { return 'yup'; }
256
+ getConfigFiles() { return ['package.json']; }
257
+ getRequiredPackages() { return [{ name: 'yup', dev: false }]; }
258
+ async isActive(baseDir) {
259
+ try {
260
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
261
+ return !!(pkgJson.dependencies?.yup || pkgJson.devDependencies?.yup);
262
+ } catch { return false; }
263
+ }
264
+ }
265
+
266
+ export class ValibotPlugin extends BasePlugin {
267
+ get name() { return 'valibot'; }
268
+ getConfigFiles() { return ['package.json']; }
269
+ getRequiredPackages() { return [{ name: 'valibot', dev: false }]; }
270
+ async isActive(baseDir) {
271
+ try {
272
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
273
+ return !!(pkgJson.dependencies?.valibot || pkgJson.devDependencies?.valibot);
274
+ } catch { return false; }
275
+ }
276
+ }
277
+
278
+ // ─── INTERNATIONALISATION ────────────────────────────────────────────────────
279
+
280
+ export class I18nextPlugin extends BasePlugin {
281
+ get name() { return 'i18next'; }
282
+ getConfigFiles() { return ['i18next.config.mjs', 'i18next.config.ts', 'next-i18next.config.mjs']; }
283
+ getRequiredPackages() { return [{ name: 'i18next', dev: false }, { name: 'react-i18next', dev: false, optional: true }]; }
284
+ async isActive(baseDir) {
285
+ for (const f of this.getConfigFiles()) {
286
+ try { await fs.access(path.join(baseDir, f)); return true; } catch {}
287
+ }
288
+ try {
289
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
290
+ return !!(pkgJson.dependencies?.i18next || pkgJson.devDependencies?.i18next);
291
+ } catch { return false; }
292
+ }
293
+ }
294
+
295
+ export class VueI18nPlugin extends BasePlugin {
296
+ get name() { return 'vue-i18n'; }
297
+ getConfigFiles() { return ['package.json']; }
298
+ getRequiredPackages() { return [{ name: 'vue-i18n', dev: false }]; }
299
+ async isActive(baseDir) {
300
+ try {
301
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
302
+ return !!(pkgJson.dependencies?.['vue-i18n'] || pkgJson.devDependencies?.['vue-i18n']);
303
+ } catch { return false; }
304
+ }
305
+ }
306
+
307
+ // ─── MONITORING / OBSERVABILITY ──────────────────────────────────────────────
308
+
309
+ export class SentryPlugin extends BasePlugin {
310
+ get name() { return 'sentry'; }
311
+ getConfigFiles() { return ['sentry.client.config.ts', 'sentry.server.config.ts', 'sentry.edge.config.ts', 'sentry.config.mjs', 'sentry.config.ts']; }
312
+ getRequiredPackages() { return [{ name: '@sentry/nextjs', dev: false, optional: true }, { name: '@sentry/react', dev: false, optional: true }, { name: '@sentry/node', dev: false, optional: true }]; }
313
+ async isActive(baseDir) {
314
+ for (const f of this.getConfigFiles()) {
315
+ try { await fs.access(path.join(baseDir, f)); return true; } catch {}
316
+ }
317
+ try {
318
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
319
+ const allDeps = { ...(pkgJson.dependencies || {}), ...(pkgJson.devDependencies || {}) };
320
+ return Object.keys(allDeps).some(k => k.startsWith('@sentry/'));
321
+ } catch { return false; }
322
+ }
323
+ }
324
+
325
+ export class OpenTelemetryPlugin extends BasePlugin {
326
+ get name() { return 'opentelemetry'; }
327
+ getConfigFiles() { return ['package.json']; }
328
+ getRequiredPackages() { return [{ name: '@opentelemetry/api', dev: false }]; }
329
+ async isActive(baseDir) {
330
+ try {
331
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
332
+ const allDeps = { ...(pkgJson.dependencies || {}), ...(pkgJson.devDependencies || {}) };
333
+ return Object.keys(allDeps).some(k => k.startsWith('@opentelemetry/'));
334
+ } catch { return false; }
335
+ }
336
+ }
337
+
338
+ // ─── BACKEND FRAMEWORKS ──────────────────────────────────────────────────────
339
+
340
+ export class ExpressPlugin extends BasePlugin {
341
+ get name() { return 'express'; }
342
+ getConfigFiles() { return ['package.json']; }
343
+ getRequiredPackages() { return [{ name: 'express', dev: false }]; }
344
+ getRoutePatterns() { return [/\/routes\//, /\/controllers\//]; }
345
+ async isActive(baseDir) {
346
+ try {
347
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
348
+ return !!(pkgJson.dependencies?.express || pkgJson.devDependencies?.express);
349
+ } catch { return false; }
350
+ }
351
+ async analyze(node) {
352
+ if (node.rawCode?.includes('express()') || node.rawCode?.includes('express.Router()')) node.isEntry = true;
353
+ if (node.params?.length === 4) node.isEntry = true;
354
+ }
355
+ }
356
+
357
+ export class FastifyPlugin extends BasePlugin {
358
+ get name() { return 'fastify'; }
359
+ getConfigFiles() { return ['package.json']; }
360
+ getRequiredPackages() { return [{ name: 'fastify', dev: false }]; }
361
+ async isActive(baseDir) {
362
+ try {
363
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
364
+ return !!(pkgJson.dependencies?.fastify || pkgJson.devDependencies?.fastify);
365
+ } catch { return false; }
366
+ }
367
+ async analyze(node) {
368
+ if (node.rawCode?.includes('Fastify(') || node.rawCode?.includes('.register(')) node.isEntry = true;
369
+ }
370
+ }
371
+
372
+ export class NestJsPlugin extends BasePlugin {
373
+ get name() { return 'nestjs'; }
374
+ getConfigFiles() { return ['nest-cli.json', 'package.json']; }
375
+ getRequiredPackages() { return [{ name: '@nestjs/core', dev: false }, { name: '@nestjs/common', dev: false }]; }
376
+ async isActive(baseDir) {
377
+ try { await fs.access(path.join(baseDir, 'nest-cli.json')); return true; } catch {}
378
+ try {
379
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
380
+ return !!(pkgJson.dependencies?.['@nestjs/core'] || pkgJson.devDependencies?.['@nestjs/core']);
381
+ } catch { return false; }
382
+ }
383
+ async analyze(node) {
384
+ if (node.rawCode?.includes('@Module') || node.rawCode?.includes('@Controller') || node.rawCode?.includes('@Injectable'))
385
+ node.isEntry = true;
386
+ }
387
+ }
388
+
389
+ export class HonoPlugin extends BasePlugin {
390
+ get name() { return 'hono'; }
391
+ getConfigFiles() { return ['package.json']; }
392
+ getRequiredPackages() { return [{ name: 'hono', dev: false }]; }
393
+ async isActive(baseDir) {
394
+ try {
395
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
396
+ return !!(pkgJson.dependencies?.hono || pkgJson.devDependencies?.hono);
397
+ } catch { return false; }
398
+ }
399
+ async analyze(node) {
400
+ if (node.rawCode?.includes('new Hono()')) node.isEntry = true;
401
+ }
402
+ }
403
+
404
+ export class KoaPlugin extends BasePlugin {
405
+ get name() { return 'koa'; }
406
+ getConfigFiles() { return ['package.json']; }
407
+ getRequiredPackages() { return [{ name: 'koa', dev: false }]; }
408
+ async isActive(baseDir) {
409
+ try {
410
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
411
+ return !!(pkgJson.dependencies?.koa || pkgJson.devDependencies?.koa);
412
+ } catch { return false; }
413
+ }
414
+ async analyze(node) {
415
+ if (node.rawCode?.includes('new Koa()')) node.isEntry = true;
416
+ }
417
+ }
418
+
419
+ export class ElysiaPlugin extends BasePlugin {
420
+ get name() { return 'elysia'; }
421
+ getConfigFiles() { return ['package.json']; }
422
+ getRequiredPackages() { return [{ name: 'elysia', dev: false }]; }
423
+ async isActive(baseDir) {
424
+ try {
425
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
426
+ return !!(pkgJson.dependencies?.elysia || pkgJson.devDependencies?.elysia);
427
+ } catch { return false; }
428
+ }
429
+ async analyze(node) {
430
+ if (node.rawCode?.includes('new Elysia()')) node.isEntry = true;
431
+ }
432
+ }
433
+
434
+ // ─── REAL-TIME ────────────────────────────────────────────────────────────────
435
+
436
+ export class SocketIoPlugin extends BasePlugin {
437
+ get name() { return 'socketio'; }
438
+ getConfigFiles() { return ['package.json']; }
439
+ getRequiredPackages() { return [{ name: 'socket.io', dev: false }]; }
440
+ async isActive(baseDir) {
441
+ try {
442
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
443
+ return !!(pkgJson.dependencies?.['socket.io'] || pkgJson.devDependencies?.['socket.io']);
444
+ } catch { return false; }
445
+ }
446
+ async analyze(node) {
447
+ if (node.rawCode?.includes('io.on(') || node.rawCode?.includes('socket.on(')) node.isEntry = true;
448
+ }
449
+ }
450
+
451
+ // ─── PACKAGE MANAGER DETECTION ───────────────────────────────────────────────
452
+
453
+ export class PnpmPlugin extends BasePlugin {
454
+ get name() { return 'pnpm'; }
455
+ getConfigFiles() { return ['pnpm-lock.yaml', 'pnpm-workspace.yaml', '.npmrc']; }
456
+ async isActive(baseDir) {
457
+ try { await fs.access(path.join(baseDir, 'pnpm-lock.yaml')); return true; } catch { return false; }
458
+ }
459
+ }
460
+
461
+ export class YarnPlugin extends BasePlugin {
462
+ get name() { return 'yarn'; }
463
+ getConfigFiles() { return ['yarn.lock', '.yarnrc.yml', '.yarnrc']; }
464
+ async isActive(baseDir) {
465
+ try { await fs.access(path.join(baseDir, 'yarn.lock')); return true; } catch { return false; }
466
+ }
467
+ }
468
+
469
+ export class BunPlugin extends BasePlugin {
470
+ get name() { return 'bun'; }
471
+ getConfigFiles() { return ['bun.lockb', 'bunfig.toml']; }
472
+ async isActive(baseDir) {
473
+ for (const f of this.getConfigFiles()) {
474
+ try { await fs.access(path.join(baseDir, f)); return true; } catch {}
475
+ }
476
+ return false;
477
+ }
478
+ }
479
+
480
+ // ─── MISC UTILITIES ──────────────────────────────────────────────────────────
481
+
482
+ export class SwiperPlugin extends BasePlugin {
483
+ get name() { return 'swiper'; }
484
+ getConfigFiles() { return ['package.json']; }
485
+ getRequiredPackages() { return [{ name: 'swiper', dev: false }]; }
486
+ async isActive(baseDir) {
487
+ try {
488
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
489
+ return !!(pkgJson.dependencies?.swiper || pkgJson.devDependencies?.swiper);
490
+ } catch { return false; }
491
+ }
492
+ async analyze(node) {
493
+ if (node.rawCode?.includes('new Swiper(')) node.isEntry = true;
494
+ }
495
+ }
496
+
497
+ export class QuillPlugin extends BasePlugin {
498
+ get name() { return 'quill'; }
499
+ getConfigFiles() { return ['package.json']; }
500
+ getRequiredPackages() { return [{ name: 'quill', dev: false }]; }
501
+ async isActive(baseDir) {
502
+ try {
503
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
504
+ return !!(pkgJson.dependencies?.quill || pkgJson.devDependencies?.quill);
505
+ } catch { return false; }
506
+ }
507
+ async analyze(node) {
508
+ if (node.rawCode?.includes('new Quill(')) node.isEntry = true;
509
+ }
510
+ }
511
+
512
+ export class EnvelopPlugin extends BasePlugin {
513
+ get name() { return 'envelop'; }
514
+ getConfigFiles() { return ['package.json']; }
515
+ getRequiredPackages() { return [{ name: '@envelop/core', dev: false }]; }
516
+ async isActive(baseDir) {
517
+ try {
518
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
519
+ const allDeps = { ...(pkgJson.dependencies || {}), ...(pkgJson.devDependencies || {}) };
520
+ return Object.keys(allDeps).some(k => k.startsWith('@envelop/'));
521
+ } catch { return false; }
522
+ }
523
+ async analyze(node) {
524
+ if (node.rawCode?.includes('useEnvelop(')) node.isEntry = true;
525
+ }
526
+ }
@@ -0,0 +1,45 @@
1
+ import path from 'path';
2
+ import fs from 'fs/promises';
3
+ import { BasePlugin } from '../BasePlugin.mjs';
4
+
5
+ /**
6
+ * Next.js Plugin for entkapp v5.0.0.
7
+ * Handles next.config detection, App Router and Pages Router patterns,
8
+ * and missing dependency detection.
9
+ */
10
+ export class NextJsPlugin extends BasePlugin {
11
+ get name() { return 'nextjs'; }
12
+ getConfigFiles() {
13
+ return ['next.config.mjs', 'next.config.mjs', 'next.config.ts', 'next.config.cjs'];
14
+ }
15
+ getRequiredPackages() {
16
+ return [
17
+ { name: 'next', dev: false },
18
+ { name: 'react', dev: false },
19
+ { name: 'react-dom', dev: false },
20
+ ];
21
+ }
22
+ getRoutePatterns() {
23
+ return [
24
+ /\/pages\/api\//,
25
+ /\/pages\/[a-zA-Z0-9_\-\[\]]+/i,
26
+ /\/app\/([\w\-\[\]]+\/)+(page|route|layout|loading|error|not-found)\.(ts|tsx|js|jsx)$/
27
+ ];
28
+ }
29
+ getRequiredSystemContracts() {
30
+ return ['default', 'getServerSideProps', 'getStaticProps', 'getStaticPaths', 'generateMetadata', 'middleware'];
31
+ }
32
+ async isActive(baseDir) {
33
+ for (const file of this.getConfigFiles()) {
34
+ try {
35
+ await fs.access(path.join(baseDir, file));
36
+ return true;
37
+ } catch {}
38
+ }
39
+ // Also check if next is in package.json
40
+ try {
41
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
42
+ return !!(pkgJson.dependencies?.next || pkgJson.devDependencies?.next);
43
+ } catch { return false; }
44
+ }
45
+ }