@stackguide/mcp-server 2.3.2 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/README.md +82 -16
  2. package/dist/config/healthWeights.d.ts +87 -0
  3. package/dist/config/healthWeights.d.ts.map +1 -0
  4. package/dist/config/healthWeights.js +238 -0
  5. package/dist/config/healthWeights.js.map +1 -0
  6. package/dist/config/types.d.ts +104 -0
  7. package/dist/config/types.d.ts.map +1 -1
  8. package/dist/config/types.js.map +1 -1
  9. package/dist/handlers/generate.d.ts +24 -0
  10. package/dist/handlers/generate.d.ts.map +1 -0
  11. package/dist/handlers/generate.js +845 -0
  12. package/dist/handlers/generate.js.map +1 -0
  13. package/dist/handlers/health.d.ts +19 -0
  14. package/dist/handlers/health.d.ts.map +1 -0
  15. package/dist/handlers/health.js +401 -0
  16. package/dist/handlers/health.js.map +1 -0
  17. package/dist/handlers/help.d.ts +1 -1
  18. package/dist/handlers/help.d.ts.map +1 -1
  19. package/dist/handlers/help.js +70 -10
  20. package/dist/handlers/help.js.map +1 -1
  21. package/dist/handlers/index.d.ts +2 -0
  22. package/dist/handlers/index.d.ts.map +1 -1
  23. package/dist/handlers/index.js +2 -0
  24. package/dist/handlers/index.js.map +1 -1
  25. package/dist/handlers/review.d.ts +12 -0
  26. package/dist/handlers/review.d.ts.map +1 -1
  27. package/dist/handlers/review.js +220 -21
  28. package/dist/handlers/review.js.map +1 -1
  29. package/dist/handlers/setup.d.ts +1 -0
  30. package/dist/handlers/setup.d.ts.map +1 -1
  31. package/dist/handlers/setup.js +102 -5
  32. package/dist/handlers/setup.js.map +1 -1
  33. package/dist/index.js +6 -2
  34. package/dist/index.js.map +1 -1
  35. package/dist/services/analysisCache.d.ts +110 -0
  36. package/dist/services/analysisCache.d.ts.map +1 -0
  37. package/dist/services/analysisCache.js +233 -0
  38. package/dist/services/analysisCache.js.map +1 -0
  39. package/dist/services/codeAnalyzer.d.ts +73 -22
  40. package/dist/services/codeAnalyzer.d.ts.map +1 -1
  41. package/dist/services/codeAnalyzer.js +462 -44
  42. package/dist/services/codeAnalyzer.js.map +1 -1
  43. package/dist/services/conventionDetector.d.ts +40 -0
  44. package/dist/services/conventionDetector.d.ts.map +1 -0
  45. package/dist/services/conventionDetector.js +465 -0
  46. package/dist/services/conventionDetector.js.map +1 -0
  47. package/dist/services/cursorDirectory.d.ts +29 -2
  48. package/dist/services/cursorDirectory.d.ts.map +1 -1
  49. package/dist/services/cursorDirectory.js +260 -9
  50. package/dist/services/cursorDirectory.js.map +1 -1
  51. package/dist/tools/definitions.d.ts +125 -0
  52. package/dist/tools/definitions.d.ts.map +1 -1
  53. package/dist/tools/definitions.js +62 -1
  54. package/dist/tools/definitions.js.map +1 -1
  55. package/dist/utils/validation.d.ts +2 -2
  56. package/package.json +1 -1
@@ -0,0 +1,845 @@
1
+ /**
2
+ * Generate handler - Generate boilerplate code from templates
3
+ * Phase 6: Advanced Features
4
+ *
5
+ * Improvements:
6
+ * - Detects project conventions (quotes, semicolons, indentation)
7
+ * - Adapts templates based on state management in use
8
+ * - Respects existing code patterns
9
+ */
10
+ import { jsonResponse } from './types.js';
11
+ import { logger } from '../utils/logger.js';
12
+ import { detectConventions } from '../services/conventionDetector.js';
13
+ // Cached conventions
14
+ let cachedConventions = null;
15
+ let cachedProjectPath = null;
16
+ /**
17
+ * Get conventions for current project (with caching)
18
+ */
19
+ function getProjectConventions() {
20
+ const projectPath = process.cwd();
21
+ if (cachedConventions && cachedProjectPath === projectPath) {
22
+ return cachedConventions;
23
+ }
24
+ cachedConventions = detectConventions(projectPath);
25
+ cachedProjectPath = projectPath;
26
+ return cachedConventions;
27
+ }
28
+ /**
29
+ * Apply conventions to generated code
30
+ */
31
+ function applyConventions(code, conventions) {
32
+ let result = code;
33
+ // Apply indentation
34
+ if (conventions.indentation === 'tabs') {
35
+ result = result.replace(/^( {2})/gm, '\t');
36
+ result = result.replace(/^( {4})/gm, '\t\t');
37
+ result = result.replace(/^( {6})/gm, '\t\t\t');
38
+ result = result.replace(/^( {8})/gm, '\t\t\t\t');
39
+ }
40
+ else if (conventions.indentSize !== 2) {
41
+ const spaces = ' '.repeat(conventions.indentSize);
42
+ result = result.replace(/^ /gm, spaces);
43
+ result = result.replace(/^ /gm, spaces + spaces);
44
+ result = result.replace(/^ /gm, spaces + spaces + spaces);
45
+ }
46
+ // Apply quote style (careful with JSX)
47
+ if (conventions.quotes === 'double') {
48
+ // Only change quotes outside of JSX attributes
49
+ result = result.replace(/(?<!=)'([^']*)'(?!>)/g, '"$1"');
50
+ }
51
+ // Apply semicolons
52
+ if (!conventions.semicolons) {
53
+ // Remove trailing semicolons (simple cases)
54
+ result = result.replace(/;(\s*\n)/g, '$1');
55
+ result = result.replace(/;(\s*$)/g, '$1');
56
+ }
57
+ return result;
58
+ }
59
+ // Template generators by type
60
+ const templates = {
61
+ // React Component
62
+ component: (name, opts) => {
63
+ const ts = opts?.typescript !== false;
64
+ const withStyles = opts?.withStyles;
65
+ if (ts) {
66
+ return `import React from 'react';
67
+ ${withStyles ? `import styles from './${name}.module.css';\n` : ''}
68
+ interface ${name}Props {
69
+ /** Add your props here */
70
+ className?: string;
71
+ children?: React.ReactNode;
72
+ }
73
+
74
+ /**
75
+ * ${name} Component
76
+ *
77
+ * @example
78
+ * <${name}>Content</${name}>
79
+ */
80
+ export const ${name}: React.FC<${name}Props> = ({
81
+ className,
82
+ children,
83
+ }) => {
84
+ return (
85
+ <div className={\`${withStyles ? '${styles.container} ' : ''}$\{className || ''}\`}>
86
+ {children}
87
+ </div>
88
+ );
89
+ };
90
+
91
+ export default ${name};
92
+ `;
93
+ }
94
+ return `import React from 'react';
95
+ ${withStyles ? `import styles from './${name}.module.css';\n` : ''}
96
+ /**
97
+ * ${name} Component
98
+ */
99
+ export const ${name} = ({ className, children }) => {
100
+ return (
101
+ <div className={className}>
102
+ {children}
103
+ </div>
104
+ );
105
+ };
106
+
107
+ export default ${name};
108
+ `;
109
+ },
110
+ // React Hook
111
+ hook: (name, opts) => {
112
+ const hookName = name.startsWith('use') ? name : `use${name}`;
113
+ const ts = opts?.typescript !== false;
114
+ if (ts) {
115
+ return `import { useState, useEffect, useCallback } from 'react';
116
+
117
+ interface ${hookName}Options {
118
+ /** Initial value */
119
+ initialValue?: unknown;
120
+ }
121
+
122
+ interface ${hookName}Result {
123
+ /** Current state */
124
+ data: unknown;
125
+ /** Loading state */
126
+ loading: boolean;
127
+ /** Error state */
128
+ error: Error | null;
129
+ /** Refetch function */
130
+ refetch: () => Promise<void>;
131
+ }
132
+
133
+ /**
134
+ * ${hookName} - Custom React Hook
135
+ *
136
+ * @example
137
+ * const { data, loading, error } = ${hookName}();
138
+ */
139
+ export function ${hookName}(options: ${hookName}Options = {}): ${hookName}Result {
140
+ const [data, setData] = useState<unknown>(options.initialValue);
141
+ const [loading, setLoading] = useState(false);
142
+ const [error, setError] = useState<Error | null>(null);
143
+
144
+ const refetch = useCallback(async () => {
145
+ setLoading(true);
146
+ setError(null);
147
+ try {
148
+ // TODO: Implement fetch logic
149
+ // const result = await fetchData();
150
+ // setData(result);
151
+ } catch (e) {
152
+ setError(e instanceof Error ? e : new Error('Unknown error'));
153
+ } finally {
154
+ setLoading(false);
155
+ }
156
+ }, []);
157
+
158
+ useEffect(() => {
159
+ refetch();
160
+ }, [refetch]);
161
+
162
+ return { data, loading, error, refetch };
163
+ }
164
+
165
+ export default ${hookName};
166
+ `;
167
+ }
168
+ return `import { useState, useEffect, useCallback } from 'react';
169
+
170
+ /**
171
+ * ${hookName} - Custom React Hook
172
+ */
173
+ export function ${hookName}(options = {}) {
174
+ const [data, setData] = useState(options.initialValue);
175
+ const [loading, setLoading] = useState(false);
176
+ const [error, setError] = useState(null);
177
+
178
+ const refetch = useCallback(async () => {
179
+ setLoading(true);
180
+ try {
181
+ // TODO: Implement fetch logic
182
+ } catch (e) {
183
+ setError(e);
184
+ } finally {
185
+ setLoading(false);
186
+ }
187
+ }, []);
188
+
189
+ useEffect(() => {
190
+ refetch();
191
+ }, [refetch]);
192
+
193
+ return { data, loading, error, refetch };
194
+ }
195
+ `;
196
+ },
197
+ // Service
198
+ service: (name, opts) => {
199
+ const ts = opts?.typescript !== false;
200
+ const serviceName = name.endsWith('Service') ? name : `${name}Service`;
201
+ if (ts) {
202
+ return `/**
203
+ * ${serviceName}
204
+ *
205
+ * Service layer for ${name.replace('Service', '')} operations
206
+ */
207
+
208
+ interface ${serviceName}Config {
209
+ baseUrl?: string;
210
+ timeout?: number;
211
+ }
212
+
213
+ interface ApiResponse<T> {
214
+ data: T;
215
+ status: number;
216
+ message?: string;
217
+ }
218
+
219
+ class ${serviceName} {
220
+ private baseUrl: string;
221
+ private timeout: number;
222
+
223
+ constructor(config: ${serviceName}Config = {}) {
224
+ this.baseUrl = config.baseUrl || '/api';
225
+ this.timeout = config.timeout || 10000;
226
+ }
227
+
228
+ private async request<T>(
229
+ endpoint: string,
230
+ options: RequestInit = {}
231
+ ): Promise<ApiResponse<T>> {
232
+ const controller = new AbortController();
233
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
234
+
235
+ try {
236
+ const response = await fetch(\`\${this.baseUrl}\${endpoint}\`, {
237
+ ...options,
238
+ signal: controller.signal,
239
+ headers: {
240
+ 'Content-Type': 'application/json',
241
+ ...options.headers,
242
+ },
243
+ });
244
+
245
+ clearTimeout(timeoutId);
246
+
247
+ if (!response.ok) {
248
+ throw new Error(\`HTTP \${response.status}: \${response.statusText}\`);
249
+ }
250
+
251
+ const data = await response.json();
252
+ return { data, status: response.status };
253
+ } catch (error) {
254
+ clearTimeout(timeoutId);
255
+ throw error;
256
+ }
257
+ }
258
+
259
+ async getAll<T>(): Promise<T[]> {
260
+ const response = await this.request<T[]>('');
261
+ return response.data;
262
+ }
263
+
264
+ async getById<T>(id: string | number): Promise<T> {
265
+ const response = await this.request<T>(\`/\${id}\`);
266
+ return response.data;
267
+ }
268
+
269
+ async create<T>(data: Partial<T>): Promise<T> {
270
+ const response = await this.request<T>('', {
271
+ method: 'POST',
272
+ body: JSON.stringify(data),
273
+ });
274
+ return response.data;
275
+ }
276
+
277
+ async update<T>(id: string | number, data: Partial<T>): Promise<T> {
278
+ const response = await this.request<T>(\`/\${id}\`, {
279
+ method: 'PUT',
280
+ body: JSON.stringify(data),
281
+ });
282
+ return response.data;
283
+ }
284
+
285
+ async delete(id: string | number): Promise<void> {
286
+ await this.request(\`/\${id}\`, { method: 'DELETE' });
287
+ }
288
+ }
289
+
290
+ export const ${name.toLowerCase()}Service = new ${serviceName}();
291
+ export default ${serviceName};
292
+ `;
293
+ }
294
+ return `/**
295
+ * ${serviceName}
296
+ */
297
+
298
+ class ${serviceName} {
299
+ constructor(config = {}) {
300
+ this.baseUrl = config.baseUrl || '/api';
301
+ }
302
+
303
+ async getAll() {
304
+ const response = await fetch(this.baseUrl);
305
+ return response.json();
306
+ }
307
+
308
+ async getById(id) {
309
+ const response = await fetch(\`\${this.baseUrl}/\${id}\`);
310
+ return response.json();
311
+ }
312
+
313
+ async create(data) {
314
+ const response = await fetch(this.baseUrl, {
315
+ method: 'POST',
316
+ headers: { 'Content-Type': 'application/json' },
317
+ body: JSON.stringify(data),
318
+ });
319
+ return response.json();
320
+ }
321
+
322
+ async update(id, data) {
323
+ const response = await fetch(\`\${this.baseUrl}/\${id}\`, {
324
+ method: 'PUT',
325
+ headers: { 'Content-Type': 'application/json' },
326
+ body: JSON.stringify(data),
327
+ });
328
+ return response.json();
329
+ }
330
+
331
+ async delete(id) {
332
+ await fetch(\`\${this.baseUrl}/\${id}\`, { method: 'DELETE' });
333
+ }
334
+ }
335
+
336
+ export default ${serviceName};
337
+ `;
338
+ },
339
+ // Test file
340
+ test: (name, opts) => {
341
+ const framework = opts?.framework || 'vitest';
342
+ if (framework === 'jest') {
343
+ return `/**
344
+ * Tests for ${name}
345
+ */
346
+
347
+ describe('${name}', () => {
348
+ beforeEach(() => {
349
+ // Setup before each test
350
+ });
351
+
352
+ afterEach(() => {
353
+ // Cleanup after each test
354
+ });
355
+
356
+ describe('initialization', () => {
357
+ it('should initialize correctly', () => {
358
+ // Arrange
359
+ // Act
360
+ // Assert
361
+ expect(true).toBe(true);
362
+ });
363
+ });
364
+
365
+ describe('main functionality', () => {
366
+ it('should perform main operation', () => {
367
+ // TODO: Implement test
368
+ });
369
+
370
+ it('should handle edge cases', () => {
371
+ // TODO: Implement test
372
+ });
373
+
374
+ it('should handle errors gracefully', () => {
375
+ // TODO: Implement test
376
+ });
377
+ });
378
+ });
379
+ `;
380
+ }
381
+ return `/**
382
+ * Tests for ${name}
383
+ */
384
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
385
+
386
+ describe('${name}', () => {
387
+ beforeEach(() => {
388
+ // Setup before each test
389
+ });
390
+
391
+ afterEach(() => {
392
+ vi.restoreAllMocks();
393
+ });
394
+
395
+ describe('initialization', () => {
396
+ it('should initialize correctly', () => {
397
+ // Arrange
398
+ // Act
399
+ // Assert
400
+ expect(true).toBe(true);
401
+ });
402
+ });
403
+
404
+ describe('main functionality', () => {
405
+ it('should perform main operation', async () => {
406
+ // TODO: Implement test
407
+ });
408
+
409
+ it('should handle edge cases', () => {
410
+ // TODO: Implement test
411
+ });
412
+
413
+ it('should handle errors gracefully', () => {
414
+ // TODO: Implement test
415
+ });
416
+ });
417
+
418
+ describe('integration', () => {
419
+ it('should work with other components', () => {
420
+ // TODO: Implement integration test
421
+ });
422
+ });
423
+ });
424
+ `;
425
+ },
426
+ // API endpoint
427
+ api: (name, opts) => {
428
+ const ts = opts?.typescript !== false;
429
+ const framework = opts?.framework || 'express';
430
+ if (framework === 'nextjs') {
431
+ return `/**
432
+ * API Route: /api/${name.toLowerCase()}
433
+ */
434
+ import { NextRequest, NextResponse } from 'next/server';
435
+
436
+ // GET /api/${name.toLowerCase()}
437
+ export async function GET(request: NextRequest) {
438
+ try {
439
+ // TODO: Implement GET logic
440
+ const data = { message: '${name} endpoint' };
441
+
442
+ return NextResponse.json(data);
443
+ } catch (error) {
444
+ return NextResponse.json(
445
+ { error: 'Internal Server Error' },
446
+ { status: 500 }
447
+ );
448
+ }
449
+ }
450
+
451
+ // POST /api/${name.toLowerCase()}
452
+ export async function POST(request: NextRequest) {
453
+ try {
454
+ const body = await request.json();
455
+
456
+ // TODO: Implement POST logic
457
+ // Validate body
458
+ // Create resource
459
+
460
+ return NextResponse.json(
461
+ { message: 'Created', data: body },
462
+ { status: 201 }
463
+ );
464
+ } catch (error) {
465
+ return NextResponse.json(
466
+ { error: 'Internal Server Error' },
467
+ { status: 500 }
468
+ );
469
+ }
470
+ }
471
+
472
+ // PUT /api/${name.toLowerCase()}
473
+ export async function PUT(request: NextRequest) {
474
+ try {
475
+ const body = await request.json();
476
+
477
+ // TODO: Implement PUT logic
478
+
479
+ return NextResponse.json({ message: 'Updated', data: body });
480
+ } catch (error) {
481
+ return NextResponse.json(
482
+ { error: 'Internal Server Error' },
483
+ { status: 500 }
484
+ );
485
+ }
486
+ }
487
+
488
+ // DELETE /api/${name.toLowerCase()}
489
+ export async function DELETE(request: NextRequest) {
490
+ try {
491
+ // TODO: Implement DELETE logic
492
+
493
+ return NextResponse.json({ message: 'Deleted' });
494
+ } catch (error) {
495
+ return NextResponse.json(
496
+ { error: 'Internal Server Error' },
497
+ { status: 500 }
498
+ );
499
+ }
500
+ }
501
+ `;
502
+ }
503
+ // Express
504
+ if (ts) {
505
+ return `/**
506
+ * ${name} API Routes
507
+ */
508
+ import { Router, Request, Response, NextFunction } from 'express';
509
+
510
+ const router = Router();
511
+
512
+ // Middleware for this router
513
+ router.use((req: Request, res: Response, next: NextFunction) => {
514
+ // Add any route-specific middleware here
515
+ next();
516
+ });
517
+
518
+ // GET /api/${name.toLowerCase()}
519
+ router.get('/', async (req: Request, res: Response) => {
520
+ try {
521
+ // TODO: Implement GET logic
522
+ res.json({ message: '${name} list' });
523
+ } catch (error) {
524
+ res.status(500).json({ error: 'Internal Server Error' });
525
+ }
526
+ });
527
+
528
+ // GET /api/${name.toLowerCase()}/:id
529
+ router.get('/:id', async (req: Request, res: Response) => {
530
+ try {
531
+ const { id } = req.params;
532
+ // TODO: Implement GET by ID logic
533
+ res.json({ id, message: '${name} details' });
534
+ } catch (error) {
535
+ res.status(500).json({ error: 'Internal Server Error' });
536
+ }
537
+ });
538
+
539
+ // POST /api/${name.toLowerCase()}
540
+ router.post('/', async (req: Request, res: Response) => {
541
+ try {
542
+ const data = req.body;
543
+ // TODO: Implement POST logic
544
+ res.status(201).json({ message: 'Created', data });
545
+ } catch (error) {
546
+ res.status(500).json({ error: 'Internal Server Error' });
547
+ }
548
+ });
549
+
550
+ // PUT /api/${name.toLowerCase()}/:id
551
+ router.put('/:id', async (req: Request, res: Response) => {
552
+ try {
553
+ const { id } = req.params;
554
+ const data = req.body;
555
+ // TODO: Implement PUT logic
556
+ res.json({ id, message: 'Updated', data });
557
+ } catch (error) {
558
+ res.status(500).json({ error: 'Internal Server Error' });
559
+ }
560
+ });
561
+
562
+ // DELETE /api/${name.toLowerCase()}/:id
563
+ router.delete('/:id', async (req: Request, res: Response) => {
564
+ try {
565
+ const { id } = req.params;
566
+ // TODO: Implement DELETE logic
567
+ res.json({ id, message: 'Deleted' });
568
+ } catch (error) {
569
+ res.status(500).json({ error: 'Internal Server Error' });
570
+ }
571
+ });
572
+
573
+ export default router;
574
+ `;
575
+ }
576
+ return `/**
577
+ * ${name} API Routes
578
+ */
579
+ const express = require('express');
580
+ const router = express.Router();
581
+
582
+ router.get('/', async (req, res) => {
583
+ res.json({ message: '${name} list' });
584
+ });
585
+
586
+ router.get('/:id', async (req, res) => {
587
+ res.json({ id: req.params.id });
588
+ });
589
+
590
+ router.post('/', async (req, res) => {
591
+ res.status(201).json({ data: req.body });
592
+ });
593
+
594
+ router.put('/:id', async (req, res) => {
595
+ res.json({ id: req.params.id, data: req.body });
596
+ });
597
+
598
+ router.delete('/:id', async (req, res) => {
599
+ res.json({ message: 'Deleted' });
600
+ });
601
+
602
+ module.exports = router;
603
+ `;
604
+ },
605
+ // Model/Entity
606
+ model: (name, opts) => {
607
+ const ts = opts?.typescript !== false;
608
+ if (ts) {
609
+ return `/**
610
+ * ${name} Model
611
+ */
612
+
613
+ export interface ${name} {
614
+ id: string;
615
+ createdAt: Date;
616
+ updatedAt: Date;
617
+ // Add your fields here
618
+ }
619
+
620
+ export interface Create${name}Input {
621
+ // Fields required to create a ${name}
622
+ }
623
+
624
+ export interface Update${name}Input {
625
+ // Fields that can be updated
626
+ }
627
+
628
+ /**
629
+ * ${name} validation schema
630
+ */
631
+ export const ${name.toLowerCase()}Schema = {
632
+ id: { type: 'string', required: true },
633
+ createdAt: { type: 'date', required: true },
634
+ updatedAt: { type: 'date', required: true },
635
+ };
636
+
637
+ /**
638
+ * Create a new ${name} instance
639
+ */
640
+ export function create${name}(input: Create${name}Input): ${name} {
641
+ const now = new Date();
642
+ return {
643
+ id: crypto.randomUUID(),
644
+ createdAt: now,
645
+ updatedAt: now,
646
+ ...input,
647
+ };
648
+ }
649
+
650
+ /**
651
+ * Validate ${name} data
652
+ */
653
+ export function validate${name}(data: unknown): data is ${name} {
654
+ if (!data || typeof data !== 'object') return false;
655
+ const obj = data as Record<string, unknown>;
656
+ return (
657
+ typeof obj.id === 'string' &&
658
+ obj.createdAt instanceof Date &&
659
+ obj.updatedAt instanceof Date
660
+ );
661
+ }
662
+
663
+ export default ${name};
664
+ `;
665
+ }
666
+ return `/**
667
+ * ${name} Model
668
+ */
669
+
670
+ function create${name}(input) {
671
+ const now = new Date();
672
+ return {
673
+ id: crypto.randomUUID(),
674
+ createdAt: now,
675
+ updatedAt: now,
676
+ ...input,
677
+ };
678
+ }
679
+
680
+ function validate${name}(data) {
681
+ return data && typeof data.id === 'string';
682
+ }
683
+
684
+ module.exports = { create${name}, validate${name} };
685
+ `;
686
+ },
687
+ // Utility module
688
+ util: (name, opts) => {
689
+ const ts = opts?.typescript !== false;
690
+ if (ts) {
691
+ return `/**
692
+ * ${name} Utilities
693
+ */
694
+
695
+ /**
696
+ * Format a value for display
697
+ */
698
+ export function format${name}(value: unknown): string {
699
+ if (value === null || value === undefined) return '';
700
+ return String(value);
701
+ }
702
+
703
+ /**
704
+ * Parse a string value
705
+ */
706
+ export function parse${name}(value: string): unknown {
707
+ try {
708
+ return JSON.parse(value);
709
+ } catch {
710
+ return value;
711
+ }
712
+ }
713
+
714
+ /**
715
+ * Validate a ${name.toLowerCase()} value
716
+ */
717
+ export function isValid${name}(value: unknown): boolean {
718
+ return value !== null && value !== undefined;
719
+ }
720
+
721
+ /**
722
+ * Compare two ${name.toLowerCase()} values
723
+ */
724
+ export function compare${name}(a: unknown, b: unknown): number {
725
+ const strA = String(a);
726
+ const strB = String(b);
727
+ return strA.localeCompare(strB);
728
+ }
729
+
730
+ /**
731
+ * Create a default ${name.toLowerCase()} value
732
+ */
733
+ export function createDefault${name}(): unknown {
734
+ return null;
735
+ }
736
+
737
+ /**
738
+ * Deep clone a ${name.toLowerCase()} value
739
+ */
740
+ export function clone${name}<T>(value: T): T {
741
+ return JSON.parse(JSON.stringify(value));
742
+ }
743
+
744
+ export default {
745
+ format${name},
746
+ parse${name},
747
+ isValid${name},
748
+ compare${name},
749
+ createDefault${name},
750
+ clone${name},
751
+ };
752
+ `;
753
+ }
754
+ return `/**
755
+ * ${name} Utilities
756
+ */
757
+
758
+ function format${name}(value) {
759
+ if (value == null) return '';
760
+ return String(value);
761
+ }
762
+
763
+ function parse${name}(value) {
764
+ try {
765
+ return JSON.parse(value);
766
+ } catch {
767
+ return value;
768
+ }
769
+ }
770
+
771
+ function isValid${name}(value) {
772
+ return value != null;
773
+ }
774
+
775
+ module.exports = { format${name}, parse${name}, isValid${name} };
776
+ `;
777
+ },
778
+ };
779
+ export async function handleGenerate(args, state) {
780
+ const { type, name, options = {} } = args;
781
+ if (!type || !name) {
782
+ return jsonResponse({
783
+ error: 'Both type and name are required',
784
+ availableTypes: Object.keys(templates),
785
+ example: 'generate type:"component" name:"UserCard"'
786
+ });
787
+ }
788
+ // Detect project conventions
789
+ const conventions = options.scanProject !== false ? getProjectConventions() : null;
790
+ // Infer TypeScript from project type or conventions
791
+ if (options.typescript === undefined) {
792
+ if (state.activeProjectType?.includes('typescript')) {
793
+ options.typescript = true;
794
+ }
795
+ else if (conventions?.strictMode) {
796
+ options.typescript = true;
797
+ }
798
+ }
799
+ // Infer framework from conventions
800
+ if (!options.framework && conventions) {
801
+ if (conventions.stateManagement === 'zustand') {
802
+ options.framework = 'zustand';
803
+ }
804
+ }
805
+ const generator = templates[type];
806
+ if (!generator) {
807
+ return jsonResponse({
808
+ error: `Unknown template type: ${type}`,
809
+ availableTypes: Object.keys(templates)
810
+ });
811
+ }
812
+ logger.info('Generating template', { type, name, options, conventions: conventions?.sources });
813
+ let code = generator(name, options);
814
+ // Apply detected conventions to generated code
815
+ if (conventions && conventions.confidence !== 'low') {
816
+ code = applyConventions(code, conventions);
817
+ }
818
+ const ext = options.typescript !== false ? 'ts' : 'js';
819
+ const filename = type === 'test'
820
+ ? `${name}.test.${ext}`
821
+ : type === 'component'
822
+ ? `${name}.tsx`
823
+ : `${name}.${ext}`;
824
+ return jsonResponse({
825
+ success: true,
826
+ type,
827
+ name,
828
+ filename,
829
+ code,
830
+ conventions: conventions ? {
831
+ applied: conventions.confidence !== 'low',
832
+ sources: conventions.sources,
833
+ indentation: conventions.indentation,
834
+ quotes: conventions.quotes,
835
+ semicolons: conventions.semicolons
836
+ } : null,
837
+ instructions: [
838
+ `1. Create file: ${filename}`,
839
+ '2. Paste the generated code',
840
+ '3. Customize the TODO sections',
841
+ options.withTests ? `4. Run: npm test ${name}` : null,
842
+ ].filter(Boolean)
843
+ });
844
+ }
845
+ //# sourceMappingURL=generate.js.map