@nahisaho/musubix-core 1.0.0 → 1.0.2

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 (33) hide show
  1. package/dist/cli/commands/codegen.d.ts +125 -0
  2. package/dist/cli/commands/codegen.d.ts.map +1 -0
  3. package/dist/cli/commands/codegen.js +684 -0
  4. package/dist/cli/commands/codegen.js.map +1 -0
  5. package/dist/cli/commands/design.d.ts +158 -0
  6. package/dist/cli/commands/design.d.ts.map +1 -0
  7. package/dist/cli/commands/design.js +562 -0
  8. package/dist/cli/commands/design.js.map +1 -0
  9. package/dist/cli/commands/explain.d.ts +116 -0
  10. package/dist/cli/commands/explain.d.ts.map +1 -0
  11. package/dist/cli/commands/explain.js +419 -0
  12. package/dist/cli/commands/explain.js.map +1 -0
  13. package/dist/cli/commands/index.d.ts +13 -0
  14. package/dist/cli/commands/index.d.ts.map +1 -1
  15. package/dist/cli/commands/index.js +31 -7
  16. package/dist/cli/commands/index.js.map +1 -1
  17. package/dist/cli/commands/requirements.d.ts +103 -0
  18. package/dist/cli/commands/requirements.d.ts.map +1 -0
  19. package/dist/cli/commands/requirements.js +403 -0
  20. package/dist/cli/commands/requirements.js.map +1 -0
  21. package/dist/cli/commands/skills.d.ts +99 -0
  22. package/dist/cli/commands/skills.d.ts.map +1 -0
  23. package/dist/cli/commands/skills.js +363 -0
  24. package/dist/cli/commands/skills.js.map +1 -0
  25. package/dist/cli/commands/test.d.ts +113 -0
  26. package/dist/cli/commands/test.d.ts.map +1 -0
  27. package/dist/cli/commands/test.js +532 -0
  28. package/dist/cli/commands/test.js.map +1 -0
  29. package/dist/cli/commands/trace.d.ts +132 -0
  30. package/dist/cli/commands/trace.d.ts.map +1 -0
  31. package/dist/cli/commands/trace.js +553 -0
  32. package/dist/cli/commands/trace.js.map +1 -0
  33. package/package.json +5 -3
@@ -0,0 +1,684 @@
1
+ /**
2
+ * Codegen Command
3
+ *
4
+ * CLI commands for code generation and analysis
5
+ *
6
+ * @packageDocumentation
7
+ * @module cli/commands/codegen
8
+ *
9
+ * @see REQ-CLI-003 - Codegen CLI
10
+ * @see REQ-CG-001 - Code Generation
11
+ * @see REQ-CG-002 - Static Analysis
12
+ * @see DES-MUSUBIX-001 Section 16-C.3 - codegenコマンド設計
13
+ * @see TSK-071〜073 - Codegen CLI実装
14
+ */
15
+ import { readFile, writeFile, mkdir, readdir, stat } from 'fs/promises';
16
+ import { resolve, dirname, extname, join } from 'path';
17
+ import { ExitCode, getGlobalOptions, outputResult } from '../base.js';
18
+ /**
19
+ * Security patterns to check
20
+ */
21
+ const SECURITY_PATTERNS = [
22
+ {
23
+ pattern: /eval\s*\(/g,
24
+ type: 'Code Injection',
25
+ severity: 'critical',
26
+ cwe: 'CWE-94',
27
+ description: 'Use of eval() can lead to code injection vulnerabilities',
28
+ recommendation: 'Avoid eval(). Use safer alternatives like JSON.parse() for data parsing.',
29
+ },
30
+ {
31
+ pattern: /new\s+Function\s*\(/g,
32
+ type: 'Code Injection',
33
+ severity: 'high',
34
+ cwe: 'CWE-94',
35
+ description: 'Dynamic function creation can lead to code injection',
36
+ recommendation: 'Avoid dynamic function creation. Use predefined functions instead.',
37
+ },
38
+ {
39
+ pattern: /innerHTML\s*=/g,
40
+ type: 'XSS',
41
+ severity: 'high',
42
+ cwe: 'CWE-79',
43
+ description: 'Direct innerHTML assignment can lead to XSS vulnerabilities',
44
+ recommendation: 'Use textContent or sanitize HTML before assignment.',
45
+ },
46
+ {
47
+ pattern: /document\.write\s*\(/g,
48
+ type: 'XSS',
49
+ severity: 'high',
50
+ cwe: 'CWE-79',
51
+ description: 'document.write can be exploited for XSS attacks',
52
+ recommendation: 'Use DOM manipulation methods instead of document.write.',
53
+ },
54
+ {
55
+ pattern: /password\s*[:=]\s*['"][^'"]+['"]/gi,
56
+ type: 'Hardcoded Credentials',
57
+ severity: 'critical',
58
+ cwe: 'CWE-798',
59
+ description: 'Hardcoded passwords detected',
60
+ recommendation: 'Use environment variables or secure credential stores.',
61
+ },
62
+ {
63
+ pattern: /api[_-]?key\s*[:=]\s*['"][^'"]+['"]/gi,
64
+ type: 'Hardcoded Credentials',
65
+ severity: 'high',
66
+ cwe: 'CWE-798',
67
+ description: 'Hardcoded API key detected',
68
+ recommendation: 'Use environment variables for API keys.',
69
+ },
70
+ {
71
+ pattern: /exec\s*\(/g,
72
+ type: 'Command Injection',
73
+ severity: 'high',
74
+ cwe: 'CWE-78',
75
+ description: 'Use of exec() can lead to command injection',
76
+ recommendation: 'Use execFile() or spawn() with explicit arguments.',
77
+ },
78
+ {
79
+ pattern: /dangerouslySetInnerHTML/g,
80
+ type: 'XSS',
81
+ severity: 'medium',
82
+ cwe: 'CWE-79',
83
+ description: 'React dangerouslySetInnerHTML can lead to XSS',
84
+ recommendation: 'Sanitize HTML content before using dangerouslySetInnerHTML.',
85
+ },
86
+ {
87
+ pattern: /\bhttp:\/\//g,
88
+ type: 'Insecure Communication',
89
+ severity: 'medium',
90
+ cwe: 'CWE-319',
91
+ description: 'Use of HTTP instead of HTTPS',
92
+ recommendation: 'Use HTTPS for all external communications.',
93
+ },
94
+ {
95
+ pattern: /Math\.random\(\)/g,
96
+ type: 'Weak Randomness',
97
+ severity: 'low',
98
+ cwe: 'CWE-338',
99
+ description: 'Math.random() is not cryptographically secure',
100
+ recommendation: 'Use crypto.getRandomValues() for security-sensitive randomness.',
101
+ },
102
+ ];
103
+ /**
104
+ * Code analysis rules
105
+ */
106
+ const ANALYSIS_RULES = [
107
+ {
108
+ name: 'no-any',
109
+ pattern: /:\s*any\b/g,
110
+ severity: 'warning',
111
+ message: 'Avoid using "any" type. Use proper types for better type safety.',
112
+ },
113
+ {
114
+ name: 'no-console',
115
+ pattern: /console\.(log|warn|error|info|debug)\s*\(/g,
116
+ severity: 'info',
117
+ message: 'Console statements should be removed in production code.',
118
+ },
119
+ {
120
+ name: 'max-line-length',
121
+ check: (line) => line.length > 120,
122
+ severity: 'info',
123
+ message: 'Line exceeds 120 characters.',
124
+ },
125
+ {
126
+ name: 'no-magic-numbers',
127
+ pattern: /[^0-9a-z_]([2-9]|[1-9]\d+)(?=[^0-9]|$)/gi,
128
+ severity: 'info',
129
+ message: 'Avoid magic numbers. Use named constants instead.',
130
+ },
131
+ {
132
+ name: 'prefer-const',
133
+ pattern: /\blet\s+\w+\s*=/g,
134
+ severity: 'info',
135
+ message: 'Consider using const if variable is not reassigned.',
136
+ },
137
+ ];
138
+ /**
139
+ * Register codegen command
140
+ */
141
+ export function registerCodegenCommand(program) {
142
+ const codegen = program
143
+ .command('codegen')
144
+ .description('Code generation and analysis');
145
+ // codegen generate
146
+ codegen
147
+ .command('generate <design>')
148
+ .description('Generate code from design')
149
+ .option('-o, --output <dir>', 'Output directory', 'src/generated')
150
+ .option('-l, --language <lang>', 'Target language', 'typescript')
151
+ .option('-t, --template <name>', 'Code template to use')
152
+ .action(async (design, options) => {
153
+ const globalOpts = getGlobalOptions(program);
154
+ try {
155
+ const designPath = resolve(process.cwd(), design);
156
+ const content = await readFile(designPath, 'utf-8');
157
+ // Parse design and generate code
158
+ const files = generateCodeFromDesign(content, options);
159
+ const outputDir = resolve(process.cwd(), options.output ?? 'src/generated');
160
+ await mkdir(outputDir, { recursive: true });
161
+ let totalLines = 0;
162
+ const languages = new Set();
163
+ for (const file of files) {
164
+ const filePath = resolve(outputDir, file.filename);
165
+ await mkdir(dirname(filePath), { recursive: true });
166
+ await writeFile(filePath, file.content, 'utf-8');
167
+ totalLines += file.content.split('\n').length;
168
+ languages.add(file.language);
169
+ }
170
+ const result = {
171
+ success: true,
172
+ files,
173
+ summary: {
174
+ totalFiles: files.length,
175
+ totalLines,
176
+ languages: Array.from(languages),
177
+ },
178
+ message: `Generated ${files.length} files (${totalLines} lines)`,
179
+ };
180
+ if (!globalOpts.quiet) {
181
+ console.log(`✅ Code generated in ${outputDir}`);
182
+ for (const file of files) {
183
+ console.log(` - ${file.filename}`);
184
+ }
185
+ }
186
+ if (globalOpts.json) {
187
+ outputResult(result, globalOpts);
188
+ }
189
+ process.exit(ExitCode.SUCCESS);
190
+ }
191
+ catch (error) {
192
+ if (!globalOpts.quiet) {
193
+ console.error(`❌ Code generation failed: ${error.message}`);
194
+ }
195
+ process.exit(ExitCode.GENERAL_ERROR);
196
+ }
197
+ });
198
+ // codegen analyze
199
+ codegen
200
+ .command('analyze <path>')
201
+ .description('Static code analysis')
202
+ .option('--strict', 'Enable strict mode', false)
203
+ .action(async (path, _options) => {
204
+ const globalOpts = getGlobalOptions(program);
205
+ try {
206
+ const targetPath = resolve(process.cwd(), path);
207
+ const issues = [];
208
+ let fileCount = 0;
209
+ let totalLines = 0;
210
+ // Check if path is file or directory
211
+ const pathStat = await stat(targetPath);
212
+ if (pathStat.isDirectory()) {
213
+ await analyzeDirectory(targetPath, issues, (lines) => {
214
+ fileCount++;
215
+ totalLines += lines;
216
+ });
217
+ }
218
+ else {
219
+ const content = await readFile(targetPath, 'utf-8');
220
+ const lines = content.split('\n');
221
+ analyzeFile(targetPath, lines, issues);
222
+ fileCount = 1;
223
+ totalLines = lines.length;
224
+ }
225
+ const errors = issues.filter(i => i.severity === 'error').length;
226
+ const warnings = issues.filter(i => i.severity === 'warning').length;
227
+ const info = issues.filter(i => i.severity === 'info').length;
228
+ // Calculate metrics
229
+ const complexity = Math.round(totalLines / 10); // Simplified
230
+ const maintainabilityIndex = Math.max(0, 100 - errors * 10 - warnings * 2);
231
+ const result = {
232
+ success: true,
233
+ issues,
234
+ metrics: {
235
+ files: fileCount,
236
+ lines: totalLines,
237
+ complexity,
238
+ maintainabilityIndex,
239
+ },
240
+ summary: { errors, warnings, info },
241
+ message: errors === 0
242
+ ? `✅ Analyzed ${fileCount} files - No errors found`
243
+ : `⚠️ Found ${errors} errors, ${warnings} warnings`,
244
+ };
245
+ outputResult(result, globalOpts);
246
+ process.exit(errors === 0 ? ExitCode.SUCCESS : ExitCode.VALIDATION_ERROR);
247
+ }
248
+ catch (error) {
249
+ if (!globalOpts.quiet) {
250
+ console.error(`❌ Analysis failed: ${error.message}`);
251
+ }
252
+ process.exit(ExitCode.GENERAL_ERROR);
253
+ }
254
+ });
255
+ // codegen security
256
+ codegen
257
+ .command('security <path>')
258
+ .description('Security scan')
259
+ .option('--severity <level>', 'Minimum severity to report', 'low')
260
+ .action(async (path, options) => {
261
+ const globalOpts = getGlobalOptions(program);
262
+ try {
263
+ const targetPath = resolve(process.cwd(), path);
264
+ const vulnerabilities = [];
265
+ // Check if path is file or directory
266
+ const pathStat = await stat(targetPath);
267
+ if (pathStat.isDirectory()) {
268
+ await scanDirectory(targetPath, vulnerabilities);
269
+ }
270
+ else {
271
+ const content = await readFile(targetPath, 'utf-8');
272
+ scanFile(targetPath, content, vulnerabilities);
273
+ }
274
+ // Filter by severity
275
+ const severityOrder = ['critical', 'high', 'medium', 'low'];
276
+ const minSeverityIndex = severityOrder.indexOf(options.severity ?? 'low');
277
+ const filtered = vulnerabilities.filter(v => severityOrder.indexOf(v.severity) <= minSeverityIndex);
278
+ const critical = filtered.filter(v => v.severity === 'critical').length;
279
+ const high = filtered.filter(v => v.severity === 'high').length;
280
+ const medium = filtered.filter(v => v.severity === 'medium').length;
281
+ const low = filtered.filter(v => v.severity === 'low').length;
282
+ // Calculate security score (0-100)
283
+ const score = Math.max(0, 100 - critical * 30 - high * 15 - medium * 5 - low * 1);
284
+ const result = {
285
+ success: true,
286
+ vulnerabilities: filtered,
287
+ summary: { critical, high, medium, low },
288
+ score,
289
+ message: critical + high === 0
290
+ ? `✅ Security score: ${score}/100 - No critical issues`
291
+ : `🔴 Security score: ${score}/100 - ${critical} critical, ${high} high severity issues`,
292
+ };
293
+ outputResult(result, globalOpts);
294
+ process.exit(critical === 0 ? ExitCode.SUCCESS : ExitCode.VALIDATION_ERROR);
295
+ }
296
+ catch (error) {
297
+ if (!globalOpts.quiet) {
298
+ console.error(`❌ Security scan failed: ${error.message}`);
299
+ }
300
+ process.exit(ExitCode.GENERAL_ERROR);
301
+ }
302
+ });
303
+ }
304
+ /**
305
+ * Generate code from design
306
+ */
307
+ function generateCodeFromDesign(content, options) {
308
+ const files = [];
309
+ const language = options.language ?? 'typescript';
310
+ const ext = language === 'typescript' ? '.ts' : language === 'javascript' ? '.js' : '.py';
311
+ // Extract components from design
312
+ const componentMatches = content.match(/component\s+["']?([A-Za-z0-9_-]+)["']?/gi) || [];
313
+ const classMatches = content.match(/class\s+["']?([A-Za-z0-9_-]+)["']?/gi) || [];
314
+ const interfaceMatches = content.match(/interface\s+["']?([A-Za-z0-9_-]+)["']?/gi) || [];
315
+ // Extract requirement references
316
+ const reqMatches = content.match(/REQ-[A-Z]+-\d+/g) || [];
317
+ const desMatches = content.match(/DES-[A-Z]+-\d+/g) || [];
318
+ // Generate files for components
319
+ const seen = new Set();
320
+ const allMatches = [...componentMatches, ...classMatches, ...interfaceMatches];
321
+ for (const match of allMatches) {
322
+ const name = match.split(/\s+/).pop()?.replace(/["']/g, '') || 'Unknown';
323
+ if (seen.has(name))
324
+ continue;
325
+ seen.add(name);
326
+ const code = generateComponentCode(name, language);
327
+ files.push({
328
+ filename: `${toKebabCase(name)}${ext}`,
329
+ language,
330
+ content: code,
331
+ metadata: {
332
+ requirements: reqMatches.slice(0, 5),
333
+ designElements: desMatches.slice(0, 5),
334
+ patterns: [],
335
+ },
336
+ });
337
+ }
338
+ // Generate index file
339
+ if (files.length > 0) {
340
+ const indexContent = files
341
+ .map(f => {
342
+ const baseName = f.filename.replace(ext, '');
343
+ return `export * from './${baseName}';`;
344
+ })
345
+ .join('\n');
346
+ files.push({
347
+ filename: `index${ext}`,
348
+ language,
349
+ content: `/**\n * Generated index file\n * @generated\n */\n\n${indexContent}\n`,
350
+ metadata: {
351
+ requirements: [],
352
+ designElements: [],
353
+ patterns: [],
354
+ },
355
+ });
356
+ }
357
+ return files;
358
+ }
359
+ /**
360
+ * Generate component code
361
+ */
362
+ function generateComponentCode(name, language) {
363
+ const className = toPascalCase(name);
364
+ if (language === 'typescript') {
365
+ return `/**
366
+ * ${className}
367
+ *
368
+ * @generated
369
+ * @module ${toKebabCase(name)}
370
+ */
371
+
372
+ /**
373
+ * ${className} interface
374
+ */
375
+ export interface I${className} {
376
+ /**
377
+ * Initialize the component
378
+ */
379
+ initialize(): Promise<void>;
380
+
381
+ /**
382
+ * Execute main logic
383
+ */
384
+ execute(): Promise<void>;
385
+
386
+ /**
387
+ * Cleanup resources
388
+ */
389
+ dispose(): Promise<void>;
390
+ }
391
+
392
+ /**
393
+ * ${className} implementation
394
+ */
395
+ export class ${className} implements I${className} {
396
+ private initialized = false;
397
+
398
+ /**
399
+ * Create a new ${className} instance
400
+ */
401
+ constructor() {
402
+ // Initialize
403
+ }
404
+
405
+ /**
406
+ * Initialize the component
407
+ */
408
+ async initialize(): Promise<void> {
409
+ if (this.initialized) return;
410
+ // TODO: Add initialization logic
411
+ this.initialized = true;
412
+ }
413
+
414
+ /**
415
+ * Execute main logic
416
+ */
417
+ async execute(): Promise<void> {
418
+ if (!this.initialized) {
419
+ await this.initialize();
420
+ }
421
+ // TODO: Add execution logic
422
+ }
423
+
424
+ /**
425
+ * Cleanup resources
426
+ */
427
+ async dispose(): Promise<void> {
428
+ // TODO: Add cleanup logic
429
+ this.initialized = false;
430
+ }
431
+ }
432
+
433
+ /**
434
+ * Create a new ${className} instance
435
+ */
436
+ export function create${className}(): ${className} {
437
+ return new ${className}();
438
+ }
439
+ `;
440
+ }
441
+ else if (language === 'python') {
442
+ return `"""
443
+ ${className}
444
+
445
+ Generated module
446
+ """
447
+
448
+ from abc import ABC, abstractmethod
449
+ from typing import Optional
450
+
451
+
452
+ class I${className}(ABC):
453
+ """${className} interface."""
454
+
455
+ @abstractmethod
456
+ async def initialize(self) -> None:
457
+ """Initialize the component."""
458
+ pass
459
+
460
+ @abstractmethod
461
+ async def execute(self) -> None:
462
+ """Execute main logic."""
463
+ pass
464
+
465
+ @abstractmethod
466
+ async def dispose(self) -> None:
467
+ """Cleanup resources."""
468
+ pass
469
+
470
+
471
+ class ${className}(I${className}):
472
+ """${className} implementation."""
473
+
474
+ def __init__(self) -> None:
475
+ """Create a new ${className} instance."""
476
+ self._initialized = False
477
+
478
+ async def initialize(self) -> None:
479
+ """Initialize the component."""
480
+ if self._initialized:
481
+ return
482
+ # TODO: Add initialization logic
483
+ self._initialized = True
484
+
485
+ async def execute(self) -> None:
486
+ """Execute main logic."""
487
+ if not self._initialized:
488
+ await self.initialize()
489
+ # TODO: Add execution logic
490
+
491
+ async def dispose(self) -> None:
492
+ """Cleanup resources."""
493
+ # TODO: Add cleanup logic
494
+ self._initialized = False
495
+
496
+
497
+ def create_${toSnakeCase(name)}() -> ${className}:
498
+ """Create a new ${className} instance."""
499
+ return ${className}()
500
+ `;
501
+ }
502
+ // JavaScript
503
+ return `/**
504
+ * ${className}
505
+ *
506
+ * @generated
507
+ * @module ${toKebabCase(name)}
508
+ */
509
+
510
+ /**
511
+ * ${className} implementation
512
+ */
513
+ export class ${className} {
514
+ #initialized = false;
515
+
516
+ /**
517
+ * Create a new ${className} instance
518
+ */
519
+ constructor() {
520
+ // Initialize
521
+ }
522
+
523
+ /**
524
+ * Initialize the component
525
+ */
526
+ async initialize() {
527
+ if (this.#initialized) return;
528
+ // TODO: Add initialization logic
529
+ this.#initialized = true;
530
+ }
531
+
532
+ /**
533
+ * Execute main logic
534
+ */
535
+ async execute() {
536
+ if (!this.#initialized) {
537
+ await this.initialize();
538
+ }
539
+ // TODO: Add execution logic
540
+ }
541
+
542
+ /**
543
+ * Dispose resources
544
+ */
545
+ async dispose() {
546
+ // TODO: Add cleanup logic
547
+ this.#initialized = false;
548
+ }
549
+ }
550
+
551
+ /**
552
+ * Create a new ${className} instance
553
+ */
554
+ export function create${className}() {
555
+ return new ${className}();
556
+ }
557
+ `;
558
+ }
559
+ /**
560
+ * Analyze directory
561
+ */
562
+ async function analyzeDirectory(dir, issues, onFile) {
563
+ const entries = await readdir(dir, { withFileTypes: true });
564
+ for (const entry of entries) {
565
+ const fullPath = join(dir, entry.name);
566
+ if (entry.isDirectory()) {
567
+ if (!entry.name.startsWith('.') && entry.name !== 'node_modules') {
568
+ await analyzeDirectory(fullPath, issues, onFile);
569
+ }
570
+ }
571
+ else if (entry.isFile()) {
572
+ const ext = extname(entry.name);
573
+ if (['.ts', '.js', '.tsx', '.jsx', '.py'].includes(ext)) {
574
+ const content = await readFile(fullPath, 'utf-8');
575
+ const lines = content.split('\n');
576
+ analyzeFile(fullPath, lines, issues);
577
+ onFile(lines.length);
578
+ }
579
+ }
580
+ }
581
+ }
582
+ /**
583
+ * Analyze file
584
+ */
585
+ function analyzeFile(file, lines, issues) {
586
+ for (let i = 0; i < lines.length; i++) {
587
+ const line = lines[i];
588
+ for (const rule of ANALYSIS_RULES) {
589
+ if ('pattern' in rule && rule.pattern) {
590
+ rule.pattern.lastIndex = 0;
591
+ if (rule.pattern.test(line)) {
592
+ issues.push({
593
+ file,
594
+ line: i + 1,
595
+ severity: rule.severity,
596
+ rule: rule.name,
597
+ message: rule.message,
598
+ });
599
+ }
600
+ }
601
+ else if ('check' in rule && rule.check?.(line)) {
602
+ issues.push({
603
+ file,
604
+ line: i + 1,
605
+ severity: rule.severity,
606
+ rule: rule.name,
607
+ message: rule.message,
608
+ });
609
+ }
610
+ }
611
+ }
612
+ }
613
+ /**
614
+ * Scan directory for security issues
615
+ */
616
+ async function scanDirectory(dir, vulnerabilities) {
617
+ const entries = await readdir(dir, { withFileTypes: true });
618
+ for (const entry of entries) {
619
+ const fullPath = join(dir, entry.name);
620
+ if (entry.isDirectory()) {
621
+ if (!entry.name.startsWith('.') && entry.name !== 'node_modules') {
622
+ await scanDirectory(fullPath, vulnerabilities);
623
+ }
624
+ }
625
+ else if (entry.isFile()) {
626
+ const ext = extname(entry.name);
627
+ if (['.ts', '.js', '.tsx', '.jsx', '.py', '.json', '.yml', '.yaml'].includes(ext)) {
628
+ const content = await readFile(fullPath, 'utf-8');
629
+ scanFile(fullPath, content, vulnerabilities);
630
+ }
631
+ }
632
+ }
633
+ }
634
+ /**
635
+ * Scan file for security issues
636
+ */
637
+ function scanFile(file, content, vulnerabilities) {
638
+ const lines = content.split('\n');
639
+ for (const pattern of SECURITY_PATTERNS) {
640
+ pattern.pattern.lastIndex = 0;
641
+ for (let i = 0; i < lines.length; i++) {
642
+ pattern.pattern.lastIndex = 0;
643
+ if (pattern.pattern.test(lines[i])) {
644
+ vulnerabilities.push({
645
+ severity: pattern.severity,
646
+ type: pattern.type,
647
+ file,
648
+ line: i + 1,
649
+ description: pattern.description,
650
+ recommendation: pattern.recommendation,
651
+ cwe: pattern.cwe,
652
+ });
653
+ }
654
+ }
655
+ }
656
+ }
657
+ /**
658
+ * Convert to kebab-case
659
+ */
660
+ function toKebabCase(str) {
661
+ return str
662
+ .replace(/([a-z])([A-Z])/g, '$1-$2')
663
+ .replace(/[\s_]+/g, '-')
664
+ .toLowerCase();
665
+ }
666
+ /**
667
+ * Convert to PascalCase
668
+ */
669
+ function toPascalCase(str) {
670
+ return str
671
+ .replace(/[-_\s]+(.)?/g, (_, c) => (c ? c.toUpperCase() : ''))
672
+ .replace(/^./, s => s.toUpperCase());
673
+ }
674
+ /**
675
+ * Convert to snake_case
676
+ */
677
+ function toSnakeCase(str) {
678
+ return str
679
+ .replace(/([a-z])([A-Z])/g, '$1_$2')
680
+ .replace(/[-\s]+/g, '_')
681
+ .toLowerCase();
682
+ }
683
+ export { generateCodeFromDesign, analyzeFile, scanFile, };
684
+ //# sourceMappingURL=codegen.js.map