|
4 | 4 | * This module aggregates and transforms manifest data for the /ai-coding-landscape page. |
5 | 5 | * It provides utilities for: |
6 | 6 | * - Building vendor-to-product mappings |
7 | | - * - Calculating ecosystem statistics |
8 | | - * - Creating relationship graphs between products |
9 | 7 | * - Extension-IDE compatibility mappings |
10 | 8 | */ |
11 | 9 |
|
@@ -79,55 +77,6 @@ export interface ExtensionIDECompatibility { |
79 | 77 | }> |
80 | 78 | } |
81 | 79 |
|
82 | | -export interface LandscapeStats { |
83 | | - totalProducts: number |
84 | | - totalVendors: number |
85 | | - counts: { |
86 | | - ides: number |
87 | | - clis: number |
88 | | - extensions: number |
89 | | - models: number |
90 | | - providers: number |
91 | | - } |
92 | | - openSourceCount: number |
93 | | - proprietaryCount: number |
94 | | - platformSupport: { |
95 | | - macOS: number |
96 | | - windows: number |
97 | | - linux: number |
98 | | - } |
99 | | - topByStars: Array<{ |
100 | | - id: string |
101 | | - name: string |
102 | | - category: ProductCategory |
103 | | - stars: number |
104 | | - }> |
105 | | - vendorsByProductCount: Array<{ |
106 | | - vendorId: string |
107 | | - vendorName: string |
108 | | - productCount: number |
109 | | - }> |
110 | | -} |
111 | | - |
112 | | -export interface RelationshipNode { |
113 | | - id: string |
114 | | - type: 'vendor' | ProductCategory |
115 | | - data: { |
116 | | - label: string |
117 | | - description?: string |
118 | | - category?: ProductCategory |
119 | | - vendorId?: string |
120 | | - } |
121 | | -} |
122 | | - |
123 | | -export interface RelationshipEdge { |
124 | | - id: string |
125 | | - source: string |
126 | | - target: string |
127 | | - type: 'vendor-product' | 'extension-ide' | 'related-product' |
128 | | - label?: string |
129 | | -} |
130 | | - |
131 | 80 | // ============================================================================= |
132 | 81 | // DATA TRANSFORMATION HELPERS |
133 | 82 | // ============================================================================= |
@@ -230,19 +179,6 @@ export function getAllProducts(): LandscapeProduct[] { |
230 | 179 | return products |
231 | 180 | } |
232 | 181 |
|
233 | | -/** |
234 | | - * Get products grouped by category |
235 | | - */ |
236 | | -export function getProductsByCategory() { |
237 | | - return { |
238 | | - ides: idesData.map(ideToProduct), |
239 | | - clis: clisData.map(cliToProduct), |
240 | | - extensions: extensionsData.map(extensionToProduct), |
241 | | - models: modelsData.map(modelToProduct), |
242 | | - providers: providersData.map(providerToProduct), |
243 | | - } |
244 | | -} |
245 | | - |
246 | 182 | /** |
247 | 183 | * Get products by a specific vendor |
248 | 184 | */ |
@@ -396,200 +332,6 @@ export function buildExtensionIDECompatibility(): ExtensionIDECompatibility[] { |
396 | 332 | return compatibilities |
397 | 333 | } |
398 | 334 |
|
399 | | -/** |
400 | | - * Calculate ecosystem statistics |
401 | | - */ |
402 | | -export function calculateLandscapeStats(): LandscapeStats { |
403 | | - const allProducts = getAllProducts() |
404 | | - |
405 | | - // Count by category |
406 | | - const counts = { |
407 | | - ides: idesData.length, |
408 | | - clis: clisData.length, |
409 | | - extensions: extensionsData.length, |
410 | | - models: modelsData.length, |
411 | | - providers: providersData.length, |
412 | | - } |
413 | | - |
414 | | - // License statistics |
415 | | - let openSourceCount = 0 |
416 | | - let proprietaryCount = 0 |
417 | | - |
418 | | - ;[...idesData, ...clisData, ...extensionsData].forEach(product => { |
419 | | - if (product.license && product.license.toLowerCase() !== 'proprietary') { |
420 | | - openSourceCount++ |
421 | | - } else { |
422 | | - proprietaryCount++ |
423 | | - } |
424 | | - }) |
425 | | - |
426 | | - // Platform support |
427 | | - const platformSupport = { |
428 | | - macOS: 0, |
429 | | - windows: 0, |
430 | | - linux: 0, |
431 | | - } |
432 | | - |
433 | | - ;[...idesData, ...clisData].forEach(product => { |
434 | | - if (product.platforms) { |
435 | | - product.platforms.forEach(platform => { |
436 | | - if (platform.os === 'macOS') platformSupport.macOS++ |
437 | | - if (platform.os === 'Windows') platformSupport.windows++ |
438 | | - if (platform.os === 'Linux') platformSupport.linux++ |
439 | | - }) |
440 | | - } |
441 | | - }) |
442 | | - |
443 | | - // Top by GitHub stars |
444 | | - const productsWithStars = allProducts |
445 | | - .filter(p => p.githubStars && p.githubStars > 0) |
446 | | - .map(p => ({ |
447 | | - id: p.id, |
448 | | - name: p.name, |
449 | | - category: p.category, |
450 | | - stars: p.githubStars!, |
451 | | - })) |
452 | | - .sort((a, b) => b.stars - a.stars) |
453 | | - .slice(0, 10) |
454 | | - |
455 | | - // Vendors by product count |
456 | | - const vendorProductCounts = new Map<string, { name: string; count: number }>() |
457 | | - |
458 | | - allProducts.forEach(product => { |
459 | | - const existing = vendorProductCounts.get(product.vendor) |
460 | | - if (existing) { |
461 | | - existing.count++ |
462 | | - } else { |
463 | | - vendorProductCounts.set(product.vendor, { |
464 | | - name: product.vendor, |
465 | | - count: 1, |
466 | | - }) |
467 | | - } |
468 | | - }) |
469 | | - |
470 | | - const vendorsByProductCount = Array.from(vendorProductCounts.entries()) |
471 | | - .map(([id, data]) => ({ |
472 | | - vendorId: id.toLowerCase().replace(/\s+/g, '-'), |
473 | | - vendorName: data.name, |
474 | | - productCount: data.count, |
475 | | - })) |
476 | | - .sort((a, b) => b.productCount - a.productCount) |
477 | | - |
478 | | - return { |
479 | | - totalProducts: allProducts.length, |
480 | | - totalVendors: vendorsData.length, |
481 | | - counts, |
482 | | - openSourceCount, |
483 | | - proprietaryCount, |
484 | | - platformSupport, |
485 | | - topByStars: productsWithStars, |
486 | | - vendorsByProductCount, |
487 | | - } |
488 | | -} |
489 | | - |
490 | | -/** |
491 | | - * Build relationship graph data for visualization |
492 | | - */ |
493 | | -export function buildRelationshipGraph(): { |
494 | | - nodes: RelationshipNode[] |
495 | | - edges: RelationshipEdge[] |
496 | | -} { |
497 | | - const nodes: RelationshipNode[] = [] |
498 | | - const edges: RelationshipEdge[] = [] |
499 | | - const nodeIds = new Set<string>() |
500 | | - |
501 | | - // Add vendor nodes |
502 | | - vendorsData.forEach(vendor => { |
503 | | - const vendorNodeId = `vendor-${vendor.id}` |
504 | | - nodes.push({ |
505 | | - id: vendorNodeId, |
506 | | - type: 'vendor', |
507 | | - data: { |
508 | | - label: vendor.name, |
509 | | - description: vendor.description, |
510 | | - }, |
511 | | - }) |
512 | | - nodeIds.add(vendorNodeId) |
513 | | - }) |
514 | | - |
515 | | - // Add product nodes and vendor-product edges |
516 | | - const allProducts = getAllProducts() |
517 | | - |
518 | | - allProducts.forEach(product => { |
519 | | - const productNodeId = `${product.category}-${product.id}` |
520 | | - |
521 | | - // Add product node |
522 | | - if (!nodeIds.has(productNodeId)) { |
523 | | - nodes.push({ |
524 | | - id: productNodeId, |
525 | | - type: product.category, |
526 | | - data: { |
527 | | - label: product.name, |
528 | | - description: product.description, |
529 | | - category: product.category, |
530 | | - vendorId: product.vendor.toLowerCase().replace(/\s+/g, '-'), |
531 | | - }, |
532 | | - }) |
533 | | - nodeIds.add(productNodeId) |
534 | | - } |
535 | | - |
536 | | - // Add vendor-product edge |
537 | | - const vendorNodeId = `vendor-${product.vendor.toLowerCase().replace(/\s+/g, '-')}` |
538 | | - if (nodeIds.has(vendorNodeId)) { |
539 | | - edges.push({ |
540 | | - id: `edge-${vendorNodeId}-${productNodeId}`, |
541 | | - source: vendorNodeId, |
542 | | - target: productNodeId, |
543 | | - type: 'vendor-product', |
544 | | - }) |
545 | | - } |
546 | | - }) |
547 | | - |
548 | | - // Add extension-IDE compatibility edges |
549 | | - const compatibilities = buildExtensionIDECompatibility() |
550 | | - |
551 | | - compatibilities.forEach(compat => { |
552 | | - const extensionNodeId = `extension-${compat.extensionId}` |
553 | | - |
554 | | - compat.supportedIdes.forEach(ide => { |
555 | | - const ideNodeId = `ide-${ide.ideId}` |
556 | | - |
557 | | - if (nodeIds.has(extensionNodeId) && nodeIds.has(ideNodeId)) { |
558 | | - edges.push({ |
559 | | - id: `edge-${extensionNodeId}-${ideNodeId}`, |
560 | | - source: extensionNodeId, |
561 | | - target: ideNodeId, |
562 | | - type: 'extension-ide', |
563 | | - label: 'supports', |
564 | | - }) |
565 | | - } |
566 | | - }) |
567 | | - }) |
568 | | - |
569 | | - // Add related product edges |
570 | | - ;[...idesData, ...clisData, ...extensionsData].forEach(product => { |
571 | | - if (product.relatedProducts && product.relatedProducts.length > 0) { |
572 | | - const sourceNodeId = `${product.id.includes('ide') ? 'ide' : product.id.includes('cli') ? 'cli' : 'extension'}-${product.id}` |
573 | | - |
574 | | - product.relatedProducts.forEach(related => { |
575 | | - const targetNodeId = `${related.type}-${related.productId}` |
576 | | - |
577 | | - if (nodeIds.has(sourceNodeId) && nodeIds.has(targetNodeId)) { |
578 | | - edges.push({ |
579 | | - id: `edge-${sourceNodeId}-${targetNodeId}`, |
580 | | - source: sourceNodeId, |
581 | | - target: targetNodeId, |
582 | | - type: 'related-product', |
583 | | - label: 'related to', |
584 | | - }) |
585 | | - } |
586 | | - }) |
587 | | - } |
588 | | - }) |
589 | | - |
590 | | - return { nodes, edges } |
591 | | -} |
592 | | - |
593 | 335 | // ============================================================================= |
594 | 336 | // MATRIX DATA BUILDER |
595 | 337 | // ============================================================================= |
|
0 commit comments