@principal-ai/quality-lens-registry 0.1.0 → 0.2.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.
package/dist/index.cjs CHANGED
@@ -29,8 +29,12 @@ __export(index_exports, {
29
29
  getAlternatives: () => getAlternatives,
30
30
  getCategoryConfig: () => getCategoryConfig,
31
31
  getCategoryDisplayName: () => getCategoryDisplayName,
32
+ getCategoryForHexagonMetric: () => getCategoryForHexagonMetric,
32
33
  getCategoryForLens: () => getCategoryForLens,
33
34
  getColorModeForCategory: () => getColorModeForCategory,
35
+ getColorModeForHexagonMetric: () => getColorModeForHexagonMetric,
36
+ getHexagonMetricForCategory: () => getHexagonMetricForCategory,
37
+ getHexagonMetricKeys: () => getHexagonMetricKeys,
34
38
  getLanguageConfig: () => getLanguageConfig,
35
39
  getLanguagesForCategory: () => getLanguagesForCategory,
36
40
  getLensById: () => getLensById,
@@ -42,6 +46,8 @@ __export(index_exports, {
42
46
  getLensesWithAggregates: () => getLensesWithAggregates,
43
47
  getLensesWithFileMetrics: () => getLensesWithFileMetrics,
44
48
  isCategoryInverted: () => isCategoryInverted,
49
+ isHexagonMetricConfigured: () => isHexagonMetricConfigured,
50
+ isLensInHexagonMetric: () => isLensInHexagonMetric,
45
51
  isValidLensId: () => isValidLensId,
46
52
  validateLensOutputs: () => validateLensOutputs
47
53
  });
@@ -608,6 +614,49 @@ function getLanguagesForCategory(category) {
608
614
  }
609
615
  return Array.from(languages);
610
616
  }
617
+ var HEXAGON_METRIC_TO_CATEGORY = {
618
+ linting: "linting",
619
+ formatting: "formatting",
620
+ types: "types",
621
+ tests: "tests",
622
+ deadCode: "dead-code",
623
+ documentation: "documentation"
624
+ };
625
+ var CATEGORY_TO_HEXAGON_METRIC = {
626
+ "linting": "linting",
627
+ "formatting": "formatting",
628
+ "types": "types",
629
+ "tests": "tests",
630
+ "dead-code": "deadCode",
631
+ "documentation": "documentation"
632
+ };
633
+ function getCategoryForHexagonMetric(metric) {
634
+ return HEXAGON_METRIC_TO_CATEGORY[metric];
635
+ }
636
+ function getHexagonMetricForCategory(category) {
637
+ return CATEGORY_TO_HEXAGON_METRIC[category];
638
+ }
639
+ function isLensInHexagonMetric(lensId, metric) {
640
+ const lensCategory = getCategoryForLens(lensId);
641
+ if (!lensCategory) return false;
642
+ return HEXAGON_METRIC_TO_CATEGORY[metric] === lensCategory;
643
+ }
644
+ function getColorModeForHexagonMetric(metric, lensesRan) {
645
+ const category = HEXAGON_METRIC_TO_CATEGORY[metric];
646
+ return getColorModeForCategory(category, lensesRan);
647
+ }
648
+ function isHexagonMetricConfigured(metric, lensesRan) {
649
+ if (lensesRan === void 0) {
650
+ return true;
651
+ }
652
+ if (lensesRan.length === 0) {
653
+ return false;
654
+ }
655
+ return lensesRan.some((lensId) => isLensInHexagonMetric(lensId, metric));
656
+ }
657
+ function getHexagonMetricKeys() {
658
+ return Object.keys(HEXAGON_METRIC_TO_CATEGORY);
659
+ }
611
660
  function isValidLensId(lensId) {
612
661
  return getLensById(lensId) !== void 0;
613
662
  }
@@ -658,8 +707,12 @@ function validateLensOutputs(lensesRan, fileMetricsProduced, aggregatesProduced)
658
707
  getAlternatives,
659
708
  getCategoryConfig,
660
709
  getCategoryDisplayName,
710
+ getCategoryForHexagonMetric,
661
711
  getCategoryForLens,
662
712
  getColorModeForCategory,
713
+ getColorModeForHexagonMetric,
714
+ getHexagonMetricForCategory,
715
+ getHexagonMetricKeys,
663
716
  getLanguageConfig,
664
717
  getLanguagesForCategory,
665
718
  getLensById,
@@ -671,6 +724,8 @@ function validateLensOutputs(lensesRan, fileMetricsProduced, aggregatesProduced)
671
724
  getLensesWithAggregates,
672
725
  getLensesWithFileMetrics,
673
726
  isCategoryInverted,
727
+ isHexagonMetricConfigured,
728
+ isLensInHexagonMetric,
674
729
  isValidLensId,
675
730
  validateLensOutputs
676
731
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/registry.ts","../src/helpers.ts"],"sourcesContent":["/**\n * @principal-ai/quality-lens-registry\n *\n * Centralized registry of quality lens metadata for the Principal AI quality toolchain.\n *\n * This package provides a single source of truth for:\n * - Lens metadata (what lenses exist, what they do)\n * - Category definitions (linting, formatting, types, etc.)\n * - Language support (which lenses work with which languages)\n * - Helper functions for lookups and validation\n *\n * When adding a new lens:\n * 1. Add it to LENS_REGISTRY in src/registry.ts\n * 2. Implement the lens in @principal-ai/codebase-quality-lenses\n * 3. The UI packages will automatically discover and support it\n *\n * @example\n * ```typescript\n * import {\n * getLensById,\n * getLensesByCategory,\n * getColorModeForCategory,\n * LENS_REGISTRY\n * } from '@principal-ai/quality-lens-registry';\n *\n * // Get metadata for a specific lens\n * const eslint = getLensById('eslint');\n *\n * // Get all linting tools\n * const linters = getLensesByCategory('linting');\n *\n * // Determine which color mode to use based on lenses that ran\n * const colorMode = getColorModeForCategory('linting', ['biome-lint', 'typescript']);\n * // Returns 'biome-lint'\n * ```\n */\n\n// Export types\nexport type {\n Language,\n LensCategory,\n ColorScheme,\n LensMetadata,\n CategoryConfig,\n LanguageConfig,\n} from './types.js';\n\n// Export registry data\nexport {\n LENS_REGISTRY,\n CATEGORY_CONFIGS,\n LANGUAGE_CONFIGS,\n} from './registry.js';\n\n// Export helper functions\nexport {\n // Lens lookups\n getLensById,\n getLensesByCategory,\n getLensesByLanguage,\n getLensesByCategoryAndLanguage,\n getCategoryForLens,\n getAlternatives,\n areLensesAlternatives,\n getLensesWithFileMetrics,\n getLensesWithAggregates,\n\n // Color mode helpers\n getColorModeForCategory,\n getLensDisplayName,\n getLensColorScheme,\n\n // Category helpers\n getCategoryConfig,\n getCategoryDisplayName,\n isCategoryInverted,\n\n // Language helpers\n getLanguageConfig,\n detectLanguageFromExtension,\n getLanguagesForCategory,\n\n // Validation helpers\n isValidLensId,\n findCategoryConflicts,\n validateLensOutputs,\n} from './helpers.js';\n","import type { LensMetadata, CategoryConfig, LanguageConfig } from './types.js';\n\n/**\n * Central registry of all quality lenses\n *\n * When adding a new lens:\n * 1. Add it to this registry with complete metadata\n * 2. Implement the lens in @principal-ai/codebase-quality-lenses\n * 3. The UI packages will automatically discover and support it\n */\nexport const LENS_REGISTRY: LensMetadata[] = [\n // ============================================================\n // LINTING - Code style and bug detection\n // ============================================================\n\n // TypeScript/JavaScript linting\n {\n id: 'eslint',\n name: 'ESLint',\n category: 'linting',\n languages: ['typescript', 'javascript'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Pluggable linting utility for JavaScript and TypeScript',\n command: 'eslint',\n },\n {\n id: 'biome-lint',\n name: 'Biome Lint',\n category: 'linting',\n languages: ['typescript', 'javascript'],\n alternativeTo: ['eslint'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Fast linter for JavaScript and TypeScript',\n command: 'biome lint',\n },\n {\n id: 'oxlint',\n name: 'OxLint',\n category: 'linting',\n languages: ['typescript', 'javascript'],\n alternativeTo: ['eslint', 'biome-lint'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Blazing fast JavaScript/TypeScript linter',\n command: 'oxlint',\n },\n\n // Python linting\n {\n id: 'ruff',\n name: 'Ruff',\n category: 'linting',\n languages: ['python'],\n alternativeTo: ['pylint', 'flake8'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Extremely fast Python linter',\n command: 'ruff check',\n },\n {\n id: 'pylint',\n name: 'Pylint',\n category: 'linting',\n languages: ['python'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Python static code analyzer',\n command: 'pylint',\n },\n\n // Go linting\n {\n id: 'golangci-lint',\n name: 'golangci-lint',\n category: 'linting',\n languages: ['go'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Fast linters runner for Go',\n command: 'golangci-lint run',\n },\n\n // Rust linting\n {\n id: 'clippy',\n name: 'Clippy',\n category: 'linting',\n languages: ['rust'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Rust linter',\n command: 'cargo clippy',\n },\n\n // ============================================================\n // FORMATTING - Code formatting\n // ============================================================\n\n // TypeScript/JavaScript formatting\n {\n id: 'prettier',\n name: 'Prettier',\n category: 'formatting',\n languages: ['typescript', 'javascript'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'binary',\n description: 'Opinionated code formatter',\n command: 'prettier --check',\n },\n {\n id: 'biome-format',\n name: 'Biome Format',\n category: 'formatting',\n languages: ['typescript', 'javascript'],\n alternativeTo: ['prettier'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'binary',\n description: 'Fast code formatter for JavaScript and TypeScript',\n command: 'biome format',\n },\n\n // Python formatting\n {\n id: 'black',\n name: 'Black',\n category: 'formatting',\n languages: ['python'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'binary',\n description: 'The uncompromising Python code formatter',\n command: 'black --check',\n },\n {\n id: 'ruff-format',\n name: 'Ruff Format',\n category: 'formatting',\n languages: ['python'],\n alternativeTo: ['black'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'binary',\n description: 'Fast Python formatter (Ruff)',\n command: 'ruff format --check',\n },\n\n // Go formatting\n {\n id: 'gofmt',\n name: 'gofmt',\n category: 'formatting',\n languages: ['go'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'binary',\n description: 'Go code formatter',\n command: 'gofmt -l',\n },\n\n // Rust formatting\n {\n id: 'rustfmt',\n name: 'rustfmt',\n category: 'formatting',\n languages: ['rust'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'binary',\n description: 'Rust code formatter',\n command: 'cargo fmt --check',\n },\n\n // ============================================================\n // TYPES - Type checking\n // ============================================================\n\n // TypeScript\n {\n id: 'typescript',\n name: 'TypeScript',\n category: 'types',\n languages: ['typescript'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'TypeScript type checker',\n command: 'tsc --noEmit',\n },\n\n // Python type checking\n {\n id: 'mypy',\n name: 'MyPy',\n category: 'types',\n languages: ['python'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Static type checker for Python',\n command: 'mypy',\n },\n {\n id: 'pyright',\n name: 'Pyright',\n category: 'types',\n languages: ['python'],\n alternativeTo: ['mypy'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Static type checker for Python',\n command: 'pyright',\n },\n\n // Go type checking (built into compiler)\n {\n id: 'go-vet',\n name: 'Go Vet',\n category: 'types',\n languages: ['go'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Go static analyzer',\n command: 'go vet',\n },\n\n // ============================================================\n // TESTS - Test coverage and results\n // ============================================================\n\n // JavaScript/TypeScript testing\n {\n id: 'jest',\n name: 'Jest',\n category: 'tests',\n languages: ['typescript', 'javascript'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'coverage',\n description: 'JavaScript testing framework',\n command: 'jest --coverage',\n },\n {\n id: 'vitest',\n name: 'Vitest',\n category: 'tests',\n languages: ['typescript', 'javascript'],\n alternativeTo: ['jest'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'coverage',\n description: 'Vite-native testing framework',\n command: 'vitest run --coverage',\n },\n {\n id: 'bun-test',\n name: 'Bun Test',\n category: 'tests',\n languages: ['typescript', 'javascript'],\n alternativeTo: ['jest', 'vitest'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'coverage',\n description: 'Bun native test runner',\n command: 'bun test',\n },\n\n // Python testing\n {\n id: 'pytest',\n name: 'Pytest',\n category: 'tests',\n languages: ['python'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'coverage',\n description: 'Python testing framework',\n command: 'pytest --cov',\n },\n\n // Go testing\n {\n id: 'go-test',\n name: 'Go Test',\n category: 'tests',\n languages: ['go'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'coverage',\n description: 'Go test runner',\n command: 'go test -cover',\n },\n\n // Rust testing\n {\n id: 'cargo-test',\n name: 'Cargo Test',\n category: 'tests',\n languages: ['rust'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'coverage',\n description: 'Rust test runner',\n command: 'cargo test',\n },\n\n // ============================================================\n // DEAD CODE - Unused code detection\n // ============================================================\n\n // TypeScript/JavaScript\n {\n id: 'knip',\n name: 'Knip',\n category: 'dead-code',\n languages: ['typescript', 'javascript'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Find unused files, dependencies and exports',\n command: 'knip',\n },\n\n // Python\n {\n id: 'vulture',\n name: 'Vulture',\n category: 'dead-code',\n languages: ['python'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Find dead Python code',\n command: 'vulture',\n },\n\n // ============================================================\n // DOCUMENTATION - Documentation coverage\n // ============================================================\n\n {\n id: 'alexandria',\n name: 'Alexandria',\n category: 'documentation',\n languages: ['typescript', 'javascript'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'binary',\n description: 'Documentation coverage checker',\n command: 'alexandria lint',\n },\n {\n id: 'typedoc',\n name: 'TypeDoc',\n category: 'documentation',\n languages: ['typescript'],\n outputsFileMetrics: false,\n outputsAggregate: true,\n colorScheme: 'coverage',\n description: 'TypeScript documentation generator',\n command: 'typedoc',\n },\n\n // ============================================================\n // SECURITY - Security scanning\n // ============================================================\n\n {\n id: 'npm-audit',\n name: 'npm audit',\n category: 'security',\n languages: ['typescript', 'javascript'],\n outputsFileMetrics: false,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Check for known vulnerabilities in dependencies',\n command: 'npm audit',\n },\n {\n id: 'bandit',\n name: 'Bandit',\n category: 'security',\n languages: ['python'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Python security linter',\n command: 'bandit -r',\n },\n];\n\n/**\n * Category configurations for UI display\n */\nexport const CATEGORY_CONFIGS: CategoryConfig[] = [\n {\n id: 'linting',\n name: 'Linting',\n description: 'Code style and bug detection',\n icon: 'AlertCircle',\n },\n {\n id: 'formatting',\n name: 'Formatting',\n description: 'Code formatting consistency',\n icon: 'AlignLeft',\n },\n {\n id: 'types',\n name: 'Types',\n description: 'Type safety and checking',\n icon: 'FileType',\n },\n {\n id: 'tests',\n name: 'Tests',\n description: 'Test coverage and results',\n icon: 'TestTube',\n },\n {\n id: 'dead-code',\n name: 'Dead Code',\n description: 'Unused code detection',\n icon: 'Trash2',\n invertedScale: true,\n },\n {\n id: 'documentation',\n name: 'Documentation',\n description: 'Documentation coverage',\n icon: 'FileText',\n },\n {\n id: 'security',\n name: 'Security',\n description: 'Security vulnerability scanning',\n icon: 'Shield',\n },\n {\n id: 'complexity',\n name: 'Complexity',\n description: 'Code complexity metrics',\n icon: 'GitBranch',\n },\n];\n\n/**\n * Language configurations for UI display\n */\nexport const LANGUAGE_CONFIGS: LanguageConfig[] = [\n {\n id: 'typescript',\n name: 'TypeScript',\n extensions: ['.ts', '.tsx', '.mts', '.cts'],\n icon: 'TS',\n },\n {\n id: 'javascript',\n name: 'JavaScript',\n extensions: ['.js', '.jsx', '.mjs', '.cjs'],\n icon: 'JS',\n },\n {\n id: 'python',\n name: 'Python',\n extensions: ['.py', '.pyi'],\n icon: 'PY',\n },\n {\n id: 'go',\n name: 'Go',\n extensions: ['.go'],\n icon: 'GO',\n },\n {\n id: 'rust',\n name: 'Rust',\n extensions: ['.rs'],\n icon: 'RS',\n },\n {\n id: 'java',\n name: 'Java',\n extensions: ['.java'],\n icon: 'JV',\n },\n {\n id: 'csharp',\n name: 'C#',\n extensions: ['.cs'],\n icon: 'C#',\n },\n {\n id: 'ruby',\n name: 'Ruby',\n extensions: ['.rb'],\n icon: 'RB',\n },\n {\n id: 'php',\n name: 'PHP',\n extensions: ['.php'],\n icon: 'PHP',\n },\n];\n","import type { LensMetadata, LensCategory, Language, CategoryConfig, LanguageConfig } from './types.js';\nimport { LENS_REGISTRY, CATEGORY_CONFIGS, LANGUAGE_CONFIGS } from './registry.js';\n\n// ============================================================\n// Lens Lookups\n// ============================================================\n\n/**\n * Get lens metadata by ID\n */\nexport function getLensById(id: string): LensMetadata | undefined {\n return LENS_REGISTRY.find((lens) => lens.id === id);\n}\n\n/**\n * Get all lenses in a category\n */\nexport function getLensesByCategory(category: LensCategory): LensMetadata[] {\n return LENS_REGISTRY.filter((lens) => lens.category === category);\n}\n\n/**\n * Get all lenses that support a language\n */\nexport function getLensesByLanguage(language: Language): LensMetadata[] {\n return LENS_REGISTRY.filter((lens) => lens.languages.includes(language));\n}\n\n/**\n * Get lenses that support a category for a specific language\n */\nexport function getLensesByCategoryAndLanguage(\n category: LensCategory,\n language: Language\n): LensMetadata[] {\n return LENS_REGISTRY.filter(\n (lens) => lens.category === category && lens.languages.includes(language)\n );\n}\n\n/**\n * Get the category for a lens ID\n */\nexport function getCategoryForLens(lensId: string): LensCategory | undefined {\n return getLensById(lensId)?.category;\n}\n\n/**\n * Get alternative lenses for a given lens ID\n */\nexport function getAlternatives(lensId: string): LensMetadata[] {\n const lens = getLensById(lensId);\n if (!lens) return [];\n\n // Find lenses that list this one as an alternative\n const listedAsAlternative = LENS_REGISTRY.filter(\n (other) => other.alternativeTo?.includes(lensId)\n );\n\n // Find lenses that this one lists as alternatives\n const thisListsAsAlternative = lens.alternativeTo\n ? LENS_REGISTRY.filter((other) => lens.alternativeTo!.includes(other.id))\n : [];\n\n // Combine and dedupe\n const all = [...listedAsAlternative, ...thisListsAsAlternative];\n return Array.from(new Map(all.map((l) => [l.id, l])).values());\n}\n\n/**\n * Check if two lenses are alternatives to each other\n */\nexport function areLensesAlternatives(lensId1: string, lensId2: string): boolean {\n const lens1 = getLensById(lensId1);\n const lens2 = getLensById(lensId2);\n\n if (!lens1 || !lens2) return false;\n if (lens1.category !== lens2.category) return false;\n\n return (\n lens1.alternativeTo?.includes(lensId2) ||\n lens2.alternativeTo?.includes(lensId1) ||\n false\n );\n}\n\n/**\n * Get all lenses that output file metrics (for File City visualization)\n */\nexport function getLensesWithFileMetrics(): LensMetadata[] {\n return LENS_REGISTRY.filter((lens) => lens.outputsFileMetrics);\n}\n\n/**\n * Get all lenses that output aggregate scores (for Quality Hexagon)\n */\nexport function getLensesWithAggregates(): LensMetadata[] {\n return LENS_REGISTRY.filter((lens) => lens.outputsAggregate);\n}\n\n// ============================================================\n// Color Mode Helpers (for File City)\n// ============================================================\n\n/**\n * Get the appropriate color mode (lens ID) for a category based on which lenses ran\n * Returns the first lens that ran for the category, preferring alternatives in order\n */\nexport function getColorModeForCategory(\n category: LensCategory,\n lensesRan: string[]\n): string | null {\n const lensesInCategory = getLensesByCategory(category);\n\n // Find the first lens that ran\n for (const lensId of lensesRan) {\n if (lensesInCategory.some((lens) => lens.id === lensId)) {\n return lensId;\n }\n }\n\n return null;\n}\n\n/**\n * Get display name for a lens (for UI labels)\n */\nexport function getLensDisplayName(lensId: string): string {\n return getLensById(lensId)?.name ?? lensId;\n}\n\n/**\n * Get color scheme for a lens (for File City layer rendering)\n */\nexport function getLensColorScheme(lensId: string): 'issues' | 'coverage' | 'binary' {\n return getLensById(lensId)?.colorScheme ?? 'issues';\n}\n\n// ============================================================\n// Category Helpers\n// ============================================================\n\n/**\n * Get category configuration\n */\nexport function getCategoryConfig(category: LensCategory): CategoryConfig | undefined {\n return CATEGORY_CONFIGS.find((c) => c.id === category);\n}\n\n/**\n * Get category display name\n */\nexport function getCategoryDisplayName(category: LensCategory): string {\n return getCategoryConfig(category)?.name ?? category;\n}\n\n/**\n * Check if a category uses inverted scale (lower is better)\n */\nexport function isCategoryInverted(category: LensCategory): boolean {\n return getCategoryConfig(category)?.invertedScale ?? false;\n}\n\n// ============================================================\n// Language Helpers\n// ============================================================\n\n/**\n * Get language configuration\n */\nexport function getLanguageConfig(language: Language): LanguageConfig | undefined {\n return LANGUAGE_CONFIGS.find((l) => l.id === language);\n}\n\n/**\n * Detect language from file extension\n */\nexport function detectLanguageFromExtension(extension: string): Language | undefined {\n const normalizedExt = extension.startsWith('.') ? extension : `.${extension}`;\n const config = LANGUAGE_CONFIGS.find((l) =>\n l.extensions.includes(normalizedExt.toLowerCase())\n );\n return config?.id;\n}\n\n/**\n * Get all languages that have lenses in a category\n */\nexport function getLanguagesForCategory(category: LensCategory): Language[] {\n const lenses = getLensesByCategory(category);\n const languages = new Set<Language>();\n for (const lens of lenses) {\n for (const lang of lens.languages) {\n languages.add(lang);\n }\n }\n return Array.from(languages);\n}\n\n// ============================================================\n// Validation Helpers\n// ============================================================\n\n/**\n * Validate that a lens ID exists in the registry\n */\nexport function isValidLensId(lensId: string): boolean {\n return getLensById(lensId) !== undefined;\n}\n\n/**\n * Find lenses that ran for the same category (potential conflicts)\n */\nexport function findCategoryConflicts(\n lensesRan: string[]\n): Array<{ category: LensCategory; lenses: string[] }> {\n const byCategory = new Map<LensCategory, string[]>();\n\n for (const lensId of lensesRan) {\n const category = getCategoryForLens(lensId);\n if (category) {\n const existing = byCategory.get(category) || [];\n existing.push(lensId);\n byCategory.set(category, existing);\n }\n }\n\n const conflicts: Array<{ category: LensCategory; lenses: string[] }> = [];\n for (const [category, lenses] of byCategory) {\n if (lenses.length > 1) {\n conflicts.push({ category, lenses });\n }\n }\n\n return conflicts;\n}\n\n/**\n * Check if all required lenses produced expected outputs\n */\nexport function validateLensOutputs(\n lensesRan: string[],\n fileMetricsProduced: string[],\n aggregatesProduced: string[]\n): Array<{ lensId: string; missing: ('fileMetrics' | 'aggregate')[] }> {\n const issues: Array<{ lensId: string; missing: ('fileMetrics' | 'aggregate')[] }> = [];\n\n for (const lensId of lensesRan) {\n const lens = getLensById(lensId);\n if (!lens) continue;\n\n const missing: ('fileMetrics' | 'aggregate')[] = [];\n\n if (lens.outputsFileMetrics && !fileMetricsProduced.includes(lensId)) {\n missing.push('fileMetrics');\n }\n if (lens.outputsAggregate && !aggregatesProduced.includes(lensId)) {\n missing.push('aggregate');\n }\n\n if (missing.length > 0) {\n issues.push({ lensId, missing });\n }\n }\n\n return issues;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACUO,IAAM,gBAAgC;AAAA;AAAA;AAAA;AAAA;AAAA,EAM3C;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,cAAc,YAAY;AAAA,IACtC,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,cAAc,YAAY;AAAA,IACtC,eAAe,CAAC,QAAQ;AAAA,IACxB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,cAAc,YAAY;AAAA,IACtC,eAAe,CAAC,UAAU,YAAY;AAAA,IACtC,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA;AAAA,EAGA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,QAAQ;AAAA,IACpB,eAAe,CAAC,UAAU,QAAQ;AAAA,IAClC,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,QAAQ;AAAA,IACpB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA;AAAA,EAGA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,IAAI;AAAA,IAChB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA;AAAA,EAGA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,MAAM;AAAA,IAClB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,cAAc,YAAY;AAAA,IACtC,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,cAAc,YAAY;AAAA,IACtC,eAAe,CAAC,UAAU;AAAA,IAC1B,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA;AAAA,EAGA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,QAAQ;AAAA,IACpB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,QAAQ;AAAA,IACpB,eAAe,CAAC,OAAO;AAAA,IACvB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA;AAAA,EAGA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,IAAI;AAAA,IAChB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA;AAAA,EAGA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,MAAM;AAAA,IAClB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,YAAY;AAAA,IACxB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA;AAAA,EAGA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,QAAQ;AAAA,IACpB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,QAAQ;AAAA,IACpB,eAAe,CAAC,MAAM;AAAA,IACtB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA;AAAA,EAGA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,IAAI;AAAA,IAChB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,cAAc,YAAY;AAAA,IACtC,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,cAAc,YAAY;AAAA,IACtC,eAAe,CAAC,MAAM;AAAA,IACtB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,cAAc,YAAY;AAAA,IACtC,eAAe,CAAC,QAAQ,QAAQ;AAAA,IAChC,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA;AAAA,EAGA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,QAAQ;AAAA,IACpB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA;AAAA,EAGA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,IAAI;AAAA,IAChB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA;AAAA,EAGA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,MAAM;AAAA,IAClB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,cAAc,YAAY;AAAA,IACtC,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA;AAAA,EAGA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,QAAQ;AAAA,IACpB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA;AAAA;AAAA;AAAA,EAMA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,cAAc,YAAY;AAAA,IACtC,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,YAAY;AAAA,IACxB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA;AAAA;AAAA;AAAA,EAMA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,cAAc,YAAY;AAAA,IACtC,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,QAAQ;AAAA,IACpB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AACF;AAKO,IAAM,mBAAqC;AAAA,EAChD;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,IACb,MAAM;AAAA,EACR;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,IACb,MAAM;AAAA,EACR;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,IACb,MAAM;AAAA,EACR;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,IACb,MAAM;AAAA,EACR;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,IACb,MAAM;AAAA,IACN,eAAe;AAAA,EACjB;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,IACb,MAAM;AAAA,EACR;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,IACb,MAAM;AAAA,EACR;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,IACb,MAAM;AAAA,EACR;AACF;AAKO,IAAM,mBAAqC;AAAA,EAChD;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,YAAY,CAAC,OAAO,QAAQ,QAAQ,MAAM;AAAA,IAC1C,MAAM;AAAA,EACR;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,YAAY,CAAC,OAAO,QAAQ,QAAQ,MAAM;AAAA,IAC1C,MAAM;AAAA,EACR;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,YAAY,CAAC,OAAO,MAAM;AAAA,IAC1B,MAAM;AAAA,EACR;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,YAAY,CAAC,KAAK;AAAA,IAClB,MAAM;AAAA,EACR;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,YAAY,CAAC,KAAK;AAAA,IAClB,MAAM;AAAA,EACR;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,YAAY,CAAC,OAAO;AAAA,IACpB,MAAM;AAAA,EACR;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,YAAY,CAAC,KAAK;AAAA,IAClB,MAAM;AAAA,EACR;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,YAAY,CAAC,KAAK;AAAA,IAClB,MAAM;AAAA,EACR;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,YAAY,CAAC,MAAM;AAAA,IACnB,MAAM;AAAA,EACR;AACF;;;AC1fO,SAAS,YAAY,IAAsC;AAChE,SAAO,cAAc,KAAK,CAAC,SAAS,KAAK,OAAO,EAAE;AACpD;AAKO,SAAS,oBAAoB,UAAwC;AAC1E,SAAO,cAAc,OAAO,CAAC,SAAS,KAAK,aAAa,QAAQ;AAClE;AAKO,SAAS,oBAAoB,UAAoC;AACtE,SAAO,cAAc,OAAO,CAAC,SAAS,KAAK,UAAU,SAAS,QAAQ,CAAC;AACzE;AAKO,SAAS,+BACd,UACA,UACgB;AAChB,SAAO,cAAc;AAAA,IACnB,CAAC,SAAS,KAAK,aAAa,YAAY,KAAK,UAAU,SAAS,QAAQ;AAAA,EAC1E;AACF;AAKO,SAAS,mBAAmB,QAA0C;AAC3E,SAAO,YAAY,MAAM,GAAG;AAC9B;AAKO,SAAS,gBAAgB,QAAgC;AAC9D,QAAM,OAAO,YAAY,MAAM;AAC/B,MAAI,CAAC,KAAM,QAAO,CAAC;AAGnB,QAAM,sBAAsB,cAAc;AAAA,IACxC,CAAC,UAAU,MAAM,eAAe,SAAS,MAAM;AAAA,EACjD;AAGA,QAAM,yBAAyB,KAAK,gBAChC,cAAc,OAAO,CAAC,UAAU,KAAK,cAAe,SAAS,MAAM,EAAE,CAAC,IACtE,CAAC;AAGL,QAAM,MAAM,CAAC,GAAG,qBAAqB,GAAG,sBAAsB;AAC9D,SAAO,MAAM,KAAK,IAAI,IAAI,IAAI,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC;AAC/D;AAKO,SAAS,sBAAsB,SAAiB,SAA0B;AAC/E,QAAM,QAAQ,YAAY,OAAO;AACjC,QAAM,QAAQ,YAAY,OAAO;AAEjC,MAAI,CAAC,SAAS,CAAC,MAAO,QAAO;AAC7B,MAAI,MAAM,aAAa,MAAM,SAAU,QAAO;AAE9C,SACE,MAAM,eAAe,SAAS,OAAO,KACrC,MAAM,eAAe,SAAS,OAAO,KACrC;AAEJ;AAKO,SAAS,2BAA2C;AACzD,SAAO,cAAc,OAAO,CAAC,SAAS,KAAK,kBAAkB;AAC/D;AAKO,SAAS,0BAA0C;AACxD,SAAO,cAAc,OAAO,CAAC,SAAS,KAAK,gBAAgB;AAC7D;AAUO,SAAS,wBACd,UACA,WACe;AACf,QAAM,mBAAmB,oBAAoB,QAAQ;AAGrD,aAAW,UAAU,WAAW;AAC9B,QAAI,iBAAiB,KAAK,CAAC,SAAS,KAAK,OAAO,MAAM,GAAG;AACvD,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AACT;AAKO,SAAS,mBAAmB,QAAwB;AACzD,SAAO,YAAY,MAAM,GAAG,QAAQ;AACtC;AAKO,SAAS,mBAAmB,QAAkD;AACnF,SAAO,YAAY,MAAM,GAAG,eAAe;AAC7C;AASO,SAAS,kBAAkB,UAAoD;AACpF,SAAO,iBAAiB,KAAK,CAAC,MAAM,EAAE,OAAO,QAAQ;AACvD;AAKO,SAAS,uBAAuB,UAAgC;AACrE,SAAO,kBAAkB,QAAQ,GAAG,QAAQ;AAC9C;AAKO,SAAS,mBAAmB,UAAiC;AAClE,SAAO,kBAAkB,QAAQ,GAAG,iBAAiB;AACvD;AASO,SAAS,kBAAkB,UAAgD;AAChF,SAAO,iBAAiB,KAAK,CAAC,MAAM,EAAE,OAAO,QAAQ;AACvD;AAKO,SAAS,4BAA4B,WAAyC;AACnF,QAAM,gBAAgB,UAAU,WAAW,GAAG,IAAI,YAAY,IAAI,SAAS;AAC3E,QAAM,SAAS,iBAAiB;AAAA,IAAK,CAAC,MACpC,EAAE,WAAW,SAAS,cAAc,YAAY,CAAC;AAAA,EACnD;AACA,SAAO,QAAQ;AACjB;AAKO,SAAS,wBAAwB,UAAoC;AAC1E,QAAM,SAAS,oBAAoB,QAAQ;AAC3C,QAAM,YAAY,oBAAI,IAAc;AACpC,aAAW,QAAQ,QAAQ;AACzB,eAAW,QAAQ,KAAK,WAAW;AACjC,gBAAU,IAAI,IAAI;AAAA,IACpB;AAAA,EACF;AACA,SAAO,MAAM,KAAK,SAAS;AAC7B;AASO,SAAS,cAAc,QAAyB;AACrD,SAAO,YAAY,MAAM,MAAM;AACjC;AAKO,SAAS,sBACd,WACqD;AACrD,QAAM,aAAa,oBAAI,IAA4B;AAEnD,aAAW,UAAU,WAAW;AAC9B,UAAM,WAAW,mBAAmB,MAAM;AAC1C,QAAI,UAAU;AACZ,YAAM,WAAW,WAAW,IAAI,QAAQ,KAAK,CAAC;AAC9C,eAAS,KAAK,MAAM;AACpB,iBAAW,IAAI,UAAU,QAAQ;AAAA,IACnC;AAAA,EACF;AAEA,QAAM,YAAiE,CAAC;AACxE,aAAW,CAAC,UAAU,MAAM,KAAK,YAAY;AAC3C,QAAI,OAAO,SAAS,GAAG;AACrB,gBAAU,KAAK,EAAE,UAAU,OAAO,CAAC;AAAA,IACrC;AAAA,EACF;AAEA,SAAO;AACT;AAKO,SAAS,oBACd,WACA,qBACA,oBACqE;AACrE,QAAM,SAA8E,CAAC;AAErF,aAAW,UAAU,WAAW;AAC9B,UAAM,OAAO,YAAY,MAAM;AAC/B,QAAI,CAAC,KAAM;AAEX,UAAM,UAA2C,CAAC;AAElD,QAAI,KAAK,sBAAsB,CAAC,oBAAoB,SAAS,MAAM,GAAG;AACpE,cAAQ,KAAK,aAAa;AAAA,IAC5B;AACA,QAAI,KAAK,oBAAoB,CAAC,mBAAmB,SAAS,MAAM,GAAG;AACjE,cAAQ,KAAK,WAAW;AAAA,IAC1B;AAEA,QAAI,QAAQ,SAAS,GAAG;AACtB,aAAO,KAAK,EAAE,QAAQ,QAAQ,CAAC;AAAA,IACjC;AAAA,EACF;AAEA,SAAO;AACT;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/registry.ts","../src/helpers.ts"],"sourcesContent":["/**\n * @principal-ai/quality-lens-registry\n *\n * Centralized registry of quality lens metadata for the Principal AI quality toolchain.\n *\n * This package provides a single source of truth for:\n * - Lens metadata (what lenses exist, what they do)\n * - Category definitions (linting, formatting, types, etc.)\n * - Language support (which lenses work with which languages)\n * - Helper functions for lookups and validation\n *\n * When adding a new lens:\n * 1. Add it to LENS_REGISTRY in src/registry.ts\n * 2. Implement the lens in @principal-ai/codebase-quality-lenses\n * 3. The UI packages will automatically discover and support it\n *\n * @example\n * ```typescript\n * import {\n * getLensById,\n * getLensesByCategory,\n * getColorModeForCategory,\n * LENS_REGISTRY\n * } from '@principal-ai/quality-lens-registry';\n *\n * // Get metadata for a specific lens\n * const eslint = getLensById('eslint');\n *\n * // Get all linting tools\n * const linters = getLensesByCategory('linting');\n *\n * // Determine which color mode to use based on lenses that ran\n * const colorMode = getColorModeForCategory('linting', ['biome-lint', 'typescript']);\n * // Returns 'biome-lint'\n * ```\n */\n\n// Export types\nexport type {\n Language,\n LensCategory,\n ColorScheme,\n LensMetadata,\n CategoryConfig,\n LanguageConfig,\n} from './types.js';\n\n// Export registry data\nexport {\n LENS_REGISTRY,\n CATEGORY_CONFIGS,\n LANGUAGE_CONFIGS,\n} from './registry.js';\n\n// Export helper functions\nexport {\n // Lens lookups\n getLensById,\n getLensesByCategory,\n getLensesByLanguage,\n getLensesByCategoryAndLanguage,\n getCategoryForLens,\n getAlternatives,\n areLensesAlternatives,\n getLensesWithFileMetrics,\n getLensesWithAggregates,\n\n // Color mode helpers\n getColorModeForCategory,\n getLensDisplayName,\n getLensColorScheme,\n\n // Category helpers\n getCategoryConfig,\n getCategoryDisplayName,\n isCategoryInverted,\n\n // Language helpers\n getLanguageConfig,\n detectLanguageFromExtension,\n getLanguagesForCategory,\n\n // Hexagon metric helpers\n type HexagonMetricKey,\n getCategoryForHexagonMetric,\n getHexagonMetricForCategory,\n isLensInHexagonMetric,\n getColorModeForHexagonMetric,\n isHexagonMetricConfigured,\n getHexagonMetricKeys,\n\n // Validation helpers\n isValidLensId,\n findCategoryConflicts,\n validateLensOutputs,\n} from './helpers.js';\n","import type { LensMetadata, CategoryConfig, LanguageConfig } from './types.js';\n\n/**\n * Central registry of all quality lenses\n *\n * When adding a new lens:\n * 1. Add it to this registry with complete metadata\n * 2. Implement the lens in @principal-ai/codebase-quality-lenses\n * 3. The UI packages will automatically discover and support it\n */\nexport const LENS_REGISTRY: LensMetadata[] = [\n // ============================================================\n // LINTING - Code style and bug detection\n // ============================================================\n\n // TypeScript/JavaScript linting\n {\n id: 'eslint',\n name: 'ESLint',\n category: 'linting',\n languages: ['typescript', 'javascript'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Pluggable linting utility for JavaScript and TypeScript',\n command: 'eslint',\n },\n {\n id: 'biome-lint',\n name: 'Biome Lint',\n category: 'linting',\n languages: ['typescript', 'javascript'],\n alternativeTo: ['eslint'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Fast linter for JavaScript and TypeScript',\n command: 'biome lint',\n },\n {\n id: 'oxlint',\n name: 'OxLint',\n category: 'linting',\n languages: ['typescript', 'javascript'],\n alternativeTo: ['eslint', 'biome-lint'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Blazing fast JavaScript/TypeScript linter',\n command: 'oxlint',\n },\n\n // Python linting\n {\n id: 'ruff',\n name: 'Ruff',\n category: 'linting',\n languages: ['python'],\n alternativeTo: ['pylint', 'flake8'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Extremely fast Python linter',\n command: 'ruff check',\n },\n {\n id: 'pylint',\n name: 'Pylint',\n category: 'linting',\n languages: ['python'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Python static code analyzer',\n command: 'pylint',\n },\n\n // Go linting\n {\n id: 'golangci-lint',\n name: 'golangci-lint',\n category: 'linting',\n languages: ['go'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Fast linters runner for Go',\n command: 'golangci-lint run',\n },\n\n // Rust linting\n {\n id: 'clippy',\n name: 'Clippy',\n category: 'linting',\n languages: ['rust'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Rust linter',\n command: 'cargo clippy',\n },\n\n // ============================================================\n // FORMATTING - Code formatting\n // ============================================================\n\n // TypeScript/JavaScript formatting\n {\n id: 'prettier',\n name: 'Prettier',\n category: 'formatting',\n languages: ['typescript', 'javascript'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'binary',\n description: 'Opinionated code formatter',\n command: 'prettier --check',\n },\n {\n id: 'biome-format',\n name: 'Biome Format',\n category: 'formatting',\n languages: ['typescript', 'javascript'],\n alternativeTo: ['prettier'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'binary',\n description: 'Fast code formatter for JavaScript and TypeScript',\n command: 'biome format',\n },\n\n // Python formatting\n {\n id: 'black',\n name: 'Black',\n category: 'formatting',\n languages: ['python'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'binary',\n description: 'The uncompromising Python code formatter',\n command: 'black --check',\n },\n {\n id: 'ruff-format',\n name: 'Ruff Format',\n category: 'formatting',\n languages: ['python'],\n alternativeTo: ['black'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'binary',\n description: 'Fast Python formatter (Ruff)',\n command: 'ruff format --check',\n },\n\n // Go formatting\n {\n id: 'gofmt',\n name: 'gofmt',\n category: 'formatting',\n languages: ['go'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'binary',\n description: 'Go code formatter',\n command: 'gofmt -l',\n },\n\n // Rust formatting\n {\n id: 'rustfmt',\n name: 'rustfmt',\n category: 'formatting',\n languages: ['rust'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'binary',\n description: 'Rust code formatter',\n command: 'cargo fmt --check',\n },\n\n // ============================================================\n // TYPES - Type checking\n // ============================================================\n\n // TypeScript\n {\n id: 'typescript',\n name: 'TypeScript',\n category: 'types',\n languages: ['typescript'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'TypeScript type checker',\n command: 'tsc --noEmit',\n },\n\n // Python type checking\n {\n id: 'mypy',\n name: 'MyPy',\n category: 'types',\n languages: ['python'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Static type checker for Python',\n command: 'mypy',\n },\n {\n id: 'pyright',\n name: 'Pyright',\n category: 'types',\n languages: ['python'],\n alternativeTo: ['mypy'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Static type checker for Python',\n command: 'pyright',\n },\n\n // Go type checking (built into compiler)\n {\n id: 'go-vet',\n name: 'Go Vet',\n category: 'types',\n languages: ['go'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Go static analyzer',\n command: 'go vet',\n },\n\n // ============================================================\n // TESTS - Test coverage and results\n // ============================================================\n\n // JavaScript/TypeScript testing\n {\n id: 'jest',\n name: 'Jest',\n category: 'tests',\n languages: ['typescript', 'javascript'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'coverage',\n description: 'JavaScript testing framework',\n command: 'jest --coverage',\n },\n {\n id: 'vitest',\n name: 'Vitest',\n category: 'tests',\n languages: ['typescript', 'javascript'],\n alternativeTo: ['jest'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'coverage',\n description: 'Vite-native testing framework',\n command: 'vitest run --coverage',\n },\n {\n id: 'bun-test',\n name: 'Bun Test',\n category: 'tests',\n languages: ['typescript', 'javascript'],\n alternativeTo: ['jest', 'vitest'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'coverage',\n description: 'Bun native test runner',\n command: 'bun test',\n },\n\n // Python testing\n {\n id: 'pytest',\n name: 'Pytest',\n category: 'tests',\n languages: ['python'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'coverage',\n description: 'Python testing framework',\n command: 'pytest --cov',\n },\n\n // Go testing\n {\n id: 'go-test',\n name: 'Go Test',\n category: 'tests',\n languages: ['go'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'coverage',\n description: 'Go test runner',\n command: 'go test -cover',\n },\n\n // Rust testing\n {\n id: 'cargo-test',\n name: 'Cargo Test',\n category: 'tests',\n languages: ['rust'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'coverage',\n description: 'Rust test runner',\n command: 'cargo test',\n },\n\n // ============================================================\n // DEAD CODE - Unused code detection\n // ============================================================\n\n // TypeScript/JavaScript\n {\n id: 'knip',\n name: 'Knip',\n category: 'dead-code',\n languages: ['typescript', 'javascript'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Find unused files, dependencies and exports',\n command: 'knip',\n },\n\n // Python\n {\n id: 'vulture',\n name: 'Vulture',\n category: 'dead-code',\n languages: ['python'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Find dead Python code',\n command: 'vulture',\n },\n\n // ============================================================\n // DOCUMENTATION - Documentation coverage\n // ============================================================\n\n {\n id: 'alexandria',\n name: 'Alexandria',\n category: 'documentation',\n languages: ['typescript', 'javascript'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'binary',\n description: 'Documentation coverage checker',\n command: 'alexandria lint',\n },\n {\n id: 'typedoc',\n name: 'TypeDoc',\n category: 'documentation',\n languages: ['typescript'],\n outputsFileMetrics: false,\n outputsAggregate: true,\n colorScheme: 'coverage',\n description: 'TypeScript documentation generator',\n command: 'typedoc',\n },\n\n // ============================================================\n // SECURITY - Security scanning\n // ============================================================\n\n {\n id: 'npm-audit',\n name: 'npm audit',\n category: 'security',\n languages: ['typescript', 'javascript'],\n outputsFileMetrics: false,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Check for known vulnerabilities in dependencies',\n command: 'npm audit',\n },\n {\n id: 'bandit',\n name: 'Bandit',\n category: 'security',\n languages: ['python'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Python security linter',\n command: 'bandit -r',\n },\n];\n\n/**\n * Category configurations for UI display\n */\nexport const CATEGORY_CONFIGS: CategoryConfig[] = [\n {\n id: 'linting',\n name: 'Linting',\n description: 'Code style and bug detection',\n icon: 'AlertCircle',\n },\n {\n id: 'formatting',\n name: 'Formatting',\n description: 'Code formatting consistency',\n icon: 'AlignLeft',\n },\n {\n id: 'types',\n name: 'Types',\n description: 'Type safety and checking',\n icon: 'FileType',\n },\n {\n id: 'tests',\n name: 'Tests',\n description: 'Test coverage and results',\n icon: 'TestTube',\n },\n {\n id: 'dead-code',\n name: 'Dead Code',\n description: 'Unused code detection',\n icon: 'Trash2',\n invertedScale: true,\n },\n {\n id: 'documentation',\n name: 'Documentation',\n description: 'Documentation coverage',\n icon: 'FileText',\n },\n {\n id: 'security',\n name: 'Security',\n description: 'Security vulnerability scanning',\n icon: 'Shield',\n },\n {\n id: 'complexity',\n name: 'Complexity',\n description: 'Code complexity metrics',\n icon: 'GitBranch',\n },\n];\n\n/**\n * Language configurations for UI display\n */\nexport const LANGUAGE_CONFIGS: LanguageConfig[] = [\n {\n id: 'typescript',\n name: 'TypeScript',\n extensions: ['.ts', '.tsx', '.mts', '.cts'],\n icon: 'TS',\n },\n {\n id: 'javascript',\n name: 'JavaScript',\n extensions: ['.js', '.jsx', '.mjs', '.cjs'],\n icon: 'JS',\n },\n {\n id: 'python',\n name: 'Python',\n extensions: ['.py', '.pyi'],\n icon: 'PY',\n },\n {\n id: 'go',\n name: 'Go',\n extensions: ['.go'],\n icon: 'GO',\n },\n {\n id: 'rust',\n name: 'Rust',\n extensions: ['.rs'],\n icon: 'RS',\n },\n {\n id: 'java',\n name: 'Java',\n extensions: ['.java'],\n icon: 'JV',\n },\n {\n id: 'csharp',\n name: 'C#',\n extensions: ['.cs'],\n icon: 'C#',\n },\n {\n id: 'ruby',\n name: 'Ruby',\n extensions: ['.rb'],\n icon: 'RB',\n },\n {\n id: 'php',\n name: 'PHP',\n extensions: ['.php'],\n icon: 'PHP',\n },\n];\n","import type { LensMetadata, LensCategory, Language, CategoryConfig, LanguageConfig } from './types.js';\nimport { LENS_REGISTRY, CATEGORY_CONFIGS, LANGUAGE_CONFIGS } from './registry.js';\n\n// ============================================================\n// Lens Lookups\n// ============================================================\n\n/**\n * Get lens metadata by ID\n */\nexport function getLensById(id: string): LensMetadata | undefined {\n return LENS_REGISTRY.find((lens) => lens.id === id);\n}\n\n/**\n * Get all lenses in a category\n */\nexport function getLensesByCategory(category: LensCategory): LensMetadata[] {\n return LENS_REGISTRY.filter((lens) => lens.category === category);\n}\n\n/**\n * Get all lenses that support a language\n */\nexport function getLensesByLanguage(language: Language): LensMetadata[] {\n return LENS_REGISTRY.filter((lens) => lens.languages.includes(language));\n}\n\n/**\n * Get lenses that support a category for a specific language\n */\nexport function getLensesByCategoryAndLanguage(\n category: LensCategory,\n language: Language\n): LensMetadata[] {\n return LENS_REGISTRY.filter(\n (lens) => lens.category === category && lens.languages.includes(language)\n );\n}\n\n/**\n * Get the category for a lens ID\n */\nexport function getCategoryForLens(lensId: string): LensCategory | undefined {\n return getLensById(lensId)?.category;\n}\n\n/**\n * Get alternative lenses for a given lens ID\n */\nexport function getAlternatives(lensId: string): LensMetadata[] {\n const lens = getLensById(lensId);\n if (!lens) return [];\n\n // Find lenses that list this one as an alternative\n const listedAsAlternative = LENS_REGISTRY.filter(\n (other) => other.alternativeTo?.includes(lensId)\n );\n\n // Find lenses that this one lists as alternatives\n const thisListsAsAlternative = lens.alternativeTo\n ? LENS_REGISTRY.filter((other) => lens.alternativeTo!.includes(other.id))\n : [];\n\n // Combine and dedupe\n const all = [...listedAsAlternative, ...thisListsAsAlternative];\n return Array.from(new Map(all.map((l) => [l.id, l])).values());\n}\n\n/**\n * Check if two lenses are alternatives to each other\n */\nexport function areLensesAlternatives(lensId1: string, lensId2: string): boolean {\n const lens1 = getLensById(lensId1);\n const lens2 = getLensById(lensId2);\n\n if (!lens1 || !lens2) return false;\n if (lens1.category !== lens2.category) return false;\n\n return (\n lens1.alternativeTo?.includes(lensId2) ||\n lens2.alternativeTo?.includes(lensId1) ||\n false\n );\n}\n\n/**\n * Get all lenses that output file metrics (for File City visualization)\n */\nexport function getLensesWithFileMetrics(): LensMetadata[] {\n return LENS_REGISTRY.filter((lens) => lens.outputsFileMetrics);\n}\n\n/**\n * Get all lenses that output aggregate scores (for Quality Hexagon)\n */\nexport function getLensesWithAggregates(): LensMetadata[] {\n return LENS_REGISTRY.filter((lens) => lens.outputsAggregate);\n}\n\n// ============================================================\n// Color Mode Helpers (for File City)\n// ============================================================\n\n/**\n * Get the appropriate color mode (lens ID) for a category based on which lenses ran\n * Returns the first lens that ran for the category, preferring alternatives in order\n */\nexport function getColorModeForCategory(\n category: LensCategory,\n lensesRan: string[]\n): string | null {\n const lensesInCategory = getLensesByCategory(category);\n\n // Find the first lens that ran\n for (const lensId of lensesRan) {\n if (lensesInCategory.some((lens) => lens.id === lensId)) {\n return lensId;\n }\n }\n\n return null;\n}\n\n/**\n * Get display name for a lens (for UI labels)\n */\nexport function getLensDisplayName(lensId: string): string {\n return getLensById(lensId)?.name ?? lensId;\n}\n\n/**\n * Get color scheme for a lens (for File City layer rendering)\n */\nexport function getLensColorScheme(lensId: string): 'issues' | 'coverage' | 'binary' {\n return getLensById(lensId)?.colorScheme ?? 'issues';\n}\n\n// ============================================================\n// Category Helpers\n// ============================================================\n\n/**\n * Get category configuration\n */\nexport function getCategoryConfig(category: LensCategory): CategoryConfig | undefined {\n return CATEGORY_CONFIGS.find((c) => c.id === category);\n}\n\n/**\n * Get category display name\n */\nexport function getCategoryDisplayName(category: LensCategory): string {\n return getCategoryConfig(category)?.name ?? category;\n}\n\n/**\n * Check if a category uses inverted scale (lower is better)\n */\nexport function isCategoryInverted(category: LensCategory): boolean {\n return getCategoryConfig(category)?.invertedScale ?? false;\n}\n\n// ============================================================\n// Language Helpers\n// ============================================================\n\n/**\n * Get language configuration\n */\nexport function getLanguageConfig(language: Language): LanguageConfig | undefined {\n return LANGUAGE_CONFIGS.find((l) => l.id === language);\n}\n\n/**\n * Detect language from file extension\n */\nexport function detectLanguageFromExtension(extension: string): Language | undefined {\n const normalizedExt = extension.startsWith('.') ? extension : `.${extension}`;\n const config = LANGUAGE_CONFIGS.find((l) =>\n l.extensions.includes(normalizedExt.toLowerCase())\n );\n return config?.id;\n}\n\n/**\n * Get all languages that have lenses in a category\n */\nexport function getLanguagesForCategory(category: LensCategory): Language[] {\n const lenses = getLensesByCategory(category);\n const languages = new Set<Language>();\n for (const lens of lenses) {\n for (const lang of lens.languages) {\n languages.add(lang);\n }\n }\n return Array.from(languages);\n}\n\n// ============================================================\n// Hexagon Metric Helpers (for Quality Hexagon UI)\n// ============================================================\n\n/**\n * Hexagon metric keys use camelCase (from QualityMetrics interface)\n * These map to LensCategory which uses kebab-case\n */\nexport type HexagonMetricKey =\n | 'linting'\n | 'formatting'\n | 'types'\n | 'tests'\n | 'deadCode'\n | 'documentation';\n\n/**\n * Map hexagon metric keys to registry LensCategory\n */\nconst HEXAGON_METRIC_TO_CATEGORY: Record<HexagonMetricKey, LensCategory> = {\n linting: 'linting',\n formatting: 'formatting',\n types: 'types',\n tests: 'tests',\n deadCode: 'dead-code',\n documentation: 'documentation',\n};\n\n/**\n * Map LensCategory back to hexagon metric keys\n */\nconst CATEGORY_TO_HEXAGON_METRIC: Partial<Record<LensCategory, HexagonMetricKey>> = {\n 'linting': 'linting',\n 'formatting': 'formatting',\n 'types': 'types',\n 'tests': 'tests',\n 'dead-code': 'deadCode',\n 'documentation': 'documentation',\n};\n\n/**\n * Get the LensCategory for a hexagon metric key\n */\nexport function getCategoryForHexagonMetric(metric: HexagonMetricKey): LensCategory {\n return HEXAGON_METRIC_TO_CATEGORY[metric];\n}\n\n/**\n * Get the hexagon metric key for a LensCategory\n */\nexport function getHexagonMetricForCategory(category: LensCategory): HexagonMetricKey | undefined {\n return CATEGORY_TO_HEXAGON_METRIC[category];\n}\n\n/**\n * Check if a lens ID belongs to a hexagon metric\n */\nexport function isLensInHexagonMetric(lensId: string, metric: HexagonMetricKey): boolean {\n const lensCategory = getCategoryForLens(lensId);\n if (!lensCategory) return false;\n return HEXAGON_METRIC_TO_CATEGORY[metric] === lensCategory;\n}\n\n/**\n * Get the color mode for a hexagon metric based on which lenses ran.\n * This is the main entry point for the QualityHexagon panel.\n */\nexport function getColorModeForHexagonMetric(\n metric: HexagonMetricKey,\n lensesRan: string[]\n): string | null {\n const category = HEXAGON_METRIC_TO_CATEGORY[metric];\n return getColorModeForCategory(category, lensesRan);\n}\n\n/**\n * Check if a hexagon metric is configured (has at least one lens that ran)\n */\nexport function isHexagonMetricConfigured(\n metric: HexagonMetricKey,\n lensesRan: string[] | undefined\n): boolean {\n // undefined = old data without lensesRan tracking, assume all configured (backwards compatibility)\n if (lensesRan === undefined) {\n return true;\n }\n // Empty array = new data, explicitly no lenses ran for this package\n if (lensesRan.length === 0) {\n return false;\n }\n return lensesRan.some((lensId) => isLensInHexagonMetric(lensId, metric));\n}\n\n/**\n * Get all hexagon metric keys\n */\nexport function getHexagonMetricKeys(): HexagonMetricKey[] {\n return Object.keys(HEXAGON_METRIC_TO_CATEGORY) as HexagonMetricKey[];\n}\n\n// ============================================================\n// Validation Helpers\n// ============================================================\n\n/**\n * Validate that a lens ID exists in the registry\n */\nexport function isValidLensId(lensId: string): boolean {\n return getLensById(lensId) !== undefined;\n}\n\n/**\n * Find lenses that ran for the same category (potential conflicts)\n */\nexport function findCategoryConflicts(\n lensesRan: string[]\n): Array<{ category: LensCategory; lenses: string[] }> {\n const byCategory = new Map<LensCategory, string[]>();\n\n for (const lensId of lensesRan) {\n const category = getCategoryForLens(lensId);\n if (category) {\n const existing = byCategory.get(category) || [];\n existing.push(lensId);\n byCategory.set(category, existing);\n }\n }\n\n const conflicts: Array<{ category: LensCategory; lenses: string[] }> = [];\n for (const [category, lenses] of byCategory) {\n if (lenses.length > 1) {\n conflicts.push({ category, lenses });\n }\n }\n\n return conflicts;\n}\n\n/**\n * Check if all required lenses produced expected outputs\n */\nexport function validateLensOutputs(\n lensesRan: string[],\n fileMetricsProduced: string[],\n aggregatesProduced: string[]\n): Array<{ lensId: string; missing: ('fileMetrics' | 'aggregate')[] }> {\n const issues: Array<{ lensId: string; missing: ('fileMetrics' | 'aggregate')[] }> = [];\n\n for (const lensId of lensesRan) {\n const lens = getLensById(lensId);\n if (!lens) continue;\n\n const missing: ('fileMetrics' | 'aggregate')[] = [];\n\n if (lens.outputsFileMetrics && !fileMetricsProduced.includes(lensId)) {\n missing.push('fileMetrics');\n }\n if (lens.outputsAggregate && !aggregatesProduced.includes(lensId)) {\n missing.push('aggregate');\n }\n\n if (missing.length > 0) {\n issues.push({ lensId, missing });\n }\n }\n\n return issues;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACUO,IAAM,gBAAgC;AAAA;AAAA;AAAA;AAAA;AAAA,EAM3C;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,cAAc,YAAY;AAAA,IACtC,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,cAAc,YAAY;AAAA,IACtC,eAAe,CAAC,QAAQ;AAAA,IACxB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,cAAc,YAAY;AAAA,IACtC,eAAe,CAAC,UAAU,YAAY;AAAA,IACtC,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA;AAAA,EAGA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,QAAQ;AAAA,IACpB,eAAe,CAAC,UAAU,QAAQ;AAAA,IAClC,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,QAAQ;AAAA,IACpB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA;AAAA,EAGA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,IAAI;AAAA,IAChB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA;AAAA,EAGA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,MAAM;AAAA,IAClB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,cAAc,YAAY;AAAA,IACtC,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,cAAc,YAAY;AAAA,IACtC,eAAe,CAAC,UAAU;AAAA,IAC1B,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA;AAAA,EAGA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,QAAQ;AAAA,IACpB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,QAAQ;AAAA,IACpB,eAAe,CAAC,OAAO;AAAA,IACvB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA;AAAA,EAGA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,IAAI;AAAA,IAChB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA;AAAA,EAGA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,MAAM;AAAA,IAClB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,YAAY;AAAA,IACxB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA;AAAA,EAGA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,QAAQ;AAAA,IACpB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,QAAQ;AAAA,IACpB,eAAe,CAAC,MAAM;AAAA,IACtB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA;AAAA,EAGA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,IAAI;AAAA,IAChB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,cAAc,YAAY;AAAA,IACtC,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,cAAc,YAAY;AAAA,IACtC,eAAe,CAAC,MAAM;AAAA,IACtB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,cAAc,YAAY;AAAA,IACtC,eAAe,CAAC,QAAQ,QAAQ;AAAA,IAChC,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA;AAAA,EAGA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,QAAQ;AAAA,IACpB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA;AAAA,EAGA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,IAAI;AAAA,IAChB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA;AAAA,EAGA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,MAAM;AAAA,IAClB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,cAAc,YAAY;AAAA,IACtC,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA;AAAA,EAGA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,QAAQ;AAAA,IACpB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA;AAAA;AAAA;AAAA,EAMA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,cAAc,YAAY;AAAA,IACtC,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,YAAY;AAAA,IACxB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA;AAAA;AAAA;AAAA,EAMA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,cAAc,YAAY;AAAA,IACtC,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC,QAAQ;AAAA,IACpB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AACF;AAKO,IAAM,mBAAqC;AAAA,EAChD;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,IACb,MAAM;AAAA,EACR;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,IACb,MAAM;AAAA,EACR;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,IACb,MAAM;AAAA,EACR;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,IACb,MAAM;AAAA,EACR;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,IACb,MAAM;AAAA,IACN,eAAe;AAAA,EACjB;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,IACb,MAAM;AAAA,EACR;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,IACb,MAAM;AAAA,EACR;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,IACb,MAAM;AAAA,EACR;AACF;AAKO,IAAM,mBAAqC;AAAA,EAChD;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,YAAY,CAAC,OAAO,QAAQ,QAAQ,MAAM;AAAA,IAC1C,MAAM;AAAA,EACR;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,YAAY,CAAC,OAAO,QAAQ,QAAQ,MAAM;AAAA,IAC1C,MAAM;AAAA,EACR;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,YAAY,CAAC,OAAO,MAAM;AAAA,IAC1B,MAAM;AAAA,EACR;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,YAAY,CAAC,KAAK;AAAA,IAClB,MAAM;AAAA,EACR;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,YAAY,CAAC,KAAK;AAAA,IAClB,MAAM;AAAA,EACR;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,YAAY,CAAC,OAAO;AAAA,IACpB,MAAM;AAAA,EACR;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,YAAY,CAAC,KAAK;AAAA,IAClB,MAAM;AAAA,EACR;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,YAAY,CAAC,KAAK;AAAA,IAClB,MAAM;AAAA,EACR;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,YAAY,CAAC,MAAM;AAAA,IACnB,MAAM;AAAA,EACR;AACF;;;AC1fO,SAAS,YAAY,IAAsC;AAChE,SAAO,cAAc,KAAK,CAAC,SAAS,KAAK,OAAO,EAAE;AACpD;AAKO,SAAS,oBAAoB,UAAwC;AAC1E,SAAO,cAAc,OAAO,CAAC,SAAS,KAAK,aAAa,QAAQ;AAClE;AAKO,SAAS,oBAAoB,UAAoC;AACtE,SAAO,cAAc,OAAO,CAAC,SAAS,KAAK,UAAU,SAAS,QAAQ,CAAC;AACzE;AAKO,SAAS,+BACd,UACA,UACgB;AAChB,SAAO,cAAc;AAAA,IACnB,CAAC,SAAS,KAAK,aAAa,YAAY,KAAK,UAAU,SAAS,QAAQ;AAAA,EAC1E;AACF;AAKO,SAAS,mBAAmB,QAA0C;AAC3E,SAAO,YAAY,MAAM,GAAG;AAC9B;AAKO,SAAS,gBAAgB,QAAgC;AAC9D,QAAM,OAAO,YAAY,MAAM;AAC/B,MAAI,CAAC,KAAM,QAAO,CAAC;AAGnB,QAAM,sBAAsB,cAAc;AAAA,IACxC,CAAC,UAAU,MAAM,eAAe,SAAS,MAAM;AAAA,EACjD;AAGA,QAAM,yBAAyB,KAAK,gBAChC,cAAc,OAAO,CAAC,UAAU,KAAK,cAAe,SAAS,MAAM,EAAE,CAAC,IACtE,CAAC;AAGL,QAAM,MAAM,CAAC,GAAG,qBAAqB,GAAG,sBAAsB;AAC9D,SAAO,MAAM,KAAK,IAAI,IAAI,IAAI,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC;AAC/D;AAKO,SAAS,sBAAsB,SAAiB,SAA0B;AAC/E,QAAM,QAAQ,YAAY,OAAO;AACjC,QAAM,QAAQ,YAAY,OAAO;AAEjC,MAAI,CAAC,SAAS,CAAC,MAAO,QAAO;AAC7B,MAAI,MAAM,aAAa,MAAM,SAAU,QAAO;AAE9C,SACE,MAAM,eAAe,SAAS,OAAO,KACrC,MAAM,eAAe,SAAS,OAAO,KACrC;AAEJ;AAKO,SAAS,2BAA2C;AACzD,SAAO,cAAc,OAAO,CAAC,SAAS,KAAK,kBAAkB;AAC/D;AAKO,SAAS,0BAA0C;AACxD,SAAO,cAAc,OAAO,CAAC,SAAS,KAAK,gBAAgB;AAC7D;AAUO,SAAS,wBACd,UACA,WACe;AACf,QAAM,mBAAmB,oBAAoB,QAAQ;AAGrD,aAAW,UAAU,WAAW;AAC9B,QAAI,iBAAiB,KAAK,CAAC,SAAS,KAAK,OAAO,MAAM,GAAG;AACvD,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AACT;AAKO,SAAS,mBAAmB,QAAwB;AACzD,SAAO,YAAY,MAAM,GAAG,QAAQ;AACtC;AAKO,SAAS,mBAAmB,QAAkD;AACnF,SAAO,YAAY,MAAM,GAAG,eAAe;AAC7C;AASO,SAAS,kBAAkB,UAAoD;AACpF,SAAO,iBAAiB,KAAK,CAAC,MAAM,EAAE,OAAO,QAAQ;AACvD;AAKO,SAAS,uBAAuB,UAAgC;AACrE,SAAO,kBAAkB,QAAQ,GAAG,QAAQ;AAC9C;AAKO,SAAS,mBAAmB,UAAiC;AAClE,SAAO,kBAAkB,QAAQ,GAAG,iBAAiB;AACvD;AASO,SAAS,kBAAkB,UAAgD;AAChF,SAAO,iBAAiB,KAAK,CAAC,MAAM,EAAE,OAAO,QAAQ;AACvD;AAKO,SAAS,4BAA4B,WAAyC;AACnF,QAAM,gBAAgB,UAAU,WAAW,GAAG,IAAI,YAAY,IAAI,SAAS;AAC3E,QAAM,SAAS,iBAAiB;AAAA,IAAK,CAAC,MACpC,EAAE,WAAW,SAAS,cAAc,YAAY,CAAC;AAAA,EACnD;AACA,SAAO,QAAQ;AACjB;AAKO,SAAS,wBAAwB,UAAoC;AAC1E,QAAM,SAAS,oBAAoB,QAAQ;AAC3C,QAAM,YAAY,oBAAI,IAAc;AACpC,aAAW,QAAQ,QAAQ;AACzB,eAAW,QAAQ,KAAK,WAAW;AACjC,gBAAU,IAAI,IAAI;AAAA,IACpB;AAAA,EACF;AACA,SAAO,MAAM,KAAK,SAAS;AAC7B;AAqBA,IAAM,6BAAqE;AAAA,EACzE,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,OAAO;AAAA,EACP,OAAO;AAAA,EACP,UAAU;AAAA,EACV,eAAe;AACjB;AAKA,IAAM,6BAA8E;AAAA,EAClF,WAAW;AAAA,EACX,cAAc;AAAA,EACd,SAAS;AAAA,EACT,SAAS;AAAA,EACT,aAAa;AAAA,EACb,iBAAiB;AACnB;AAKO,SAAS,4BAA4B,QAAwC;AAClF,SAAO,2BAA2B,MAAM;AAC1C;AAKO,SAAS,4BAA4B,UAAsD;AAChG,SAAO,2BAA2B,QAAQ;AAC5C;AAKO,SAAS,sBAAsB,QAAgB,QAAmC;AACvF,QAAM,eAAe,mBAAmB,MAAM;AAC9C,MAAI,CAAC,aAAc,QAAO;AAC1B,SAAO,2BAA2B,MAAM,MAAM;AAChD;AAMO,SAAS,6BACd,QACA,WACe;AACf,QAAM,WAAW,2BAA2B,MAAM;AAClD,SAAO,wBAAwB,UAAU,SAAS;AACpD;AAKO,SAAS,0BACd,QACA,WACS;AAET,MAAI,cAAc,QAAW;AAC3B,WAAO;AAAA,EACT;AAEA,MAAI,UAAU,WAAW,GAAG;AAC1B,WAAO;AAAA,EACT;AACA,SAAO,UAAU,KAAK,CAAC,WAAW,sBAAsB,QAAQ,MAAM,CAAC;AACzE;AAKO,SAAS,uBAA2C;AACzD,SAAO,OAAO,KAAK,0BAA0B;AAC/C;AASO,SAAS,cAAc,QAAyB;AACrD,SAAO,YAAY,MAAM,MAAM;AACjC;AAKO,SAAS,sBACd,WACqD;AACrD,QAAM,aAAa,oBAAI,IAA4B;AAEnD,aAAW,UAAU,WAAW;AAC9B,UAAM,WAAW,mBAAmB,MAAM;AAC1C,QAAI,UAAU;AACZ,YAAM,WAAW,WAAW,IAAI,QAAQ,KAAK,CAAC;AAC9C,eAAS,KAAK,MAAM;AACpB,iBAAW,IAAI,UAAU,QAAQ;AAAA,IACnC;AAAA,EACF;AAEA,QAAM,YAAiE,CAAC;AACxE,aAAW,CAAC,UAAU,MAAM,KAAK,YAAY;AAC3C,QAAI,OAAO,SAAS,GAAG;AACrB,gBAAU,KAAK,EAAE,UAAU,OAAO,CAAC;AAAA,IACrC;AAAA,EACF;AAEA,SAAO;AACT;AAKO,SAAS,oBACd,WACA,qBACA,oBACqE;AACrE,QAAM,SAA8E,CAAC;AAErF,aAAW,UAAU,WAAW;AAC9B,UAAM,OAAO,YAAY,MAAM;AAC/B,QAAI,CAAC,KAAM;AAEX,UAAM,UAA2C,CAAC;AAElD,QAAI,KAAK,sBAAsB,CAAC,oBAAoB,SAAS,MAAM,GAAG;AACpE,cAAQ,KAAK,aAAa;AAAA,IAC5B;AACA,QAAI,KAAK,oBAAoB,CAAC,mBAAmB,SAAS,MAAM,GAAG;AACjE,cAAQ,KAAK,WAAW;AAAA,IAC1B;AAEA,QAAI,QAAQ,SAAS,GAAG;AACtB,aAAO,KAAK,EAAE,QAAQ,QAAQ,CAAC;AAAA,IACjC;AAAA,EACF;AAEA,SAAO;AACT;","names":[]}
package/dist/index.d.cts CHANGED
@@ -158,6 +158,36 @@ declare function detectLanguageFromExtension(extension: string): Language | unde
158
158
  * Get all languages that have lenses in a category
159
159
  */
160
160
  declare function getLanguagesForCategory(category: LensCategory): Language[];
161
+ /**
162
+ * Hexagon metric keys use camelCase (from QualityMetrics interface)
163
+ * These map to LensCategory which uses kebab-case
164
+ */
165
+ type HexagonMetricKey = 'linting' | 'formatting' | 'types' | 'tests' | 'deadCode' | 'documentation';
166
+ /**
167
+ * Get the LensCategory for a hexagon metric key
168
+ */
169
+ declare function getCategoryForHexagonMetric(metric: HexagonMetricKey): LensCategory;
170
+ /**
171
+ * Get the hexagon metric key for a LensCategory
172
+ */
173
+ declare function getHexagonMetricForCategory(category: LensCategory): HexagonMetricKey | undefined;
174
+ /**
175
+ * Check if a lens ID belongs to a hexagon metric
176
+ */
177
+ declare function isLensInHexagonMetric(lensId: string, metric: HexagonMetricKey): boolean;
178
+ /**
179
+ * Get the color mode for a hexagon metric based on which lenses ran.
180
+ * This is the main entry point for the QualityHexagon panel.
181
+ */
182
+ declare function getColorModeForHexagonMetric(metric: HexagonMetricKey, lensesRan: string[]): string | null;
183
+ /**
184
+ * Check if a hexagon metric is configured (has at least one lens that ran)
185
+ */
186
+ declare function isHexagonMetricConfigured(metric: HexagonMetricKey, lensesRan: string[] | undefined): boolean;
187
+ /**
188
+ * Get all hexagon metric keys
189
+ */
190
+ declare function getHexagonMetricKeys(): HexagonMetricKey[];
161
191
  /**
162
192
  * Validate that a lens ID exists in the registry
163
193
  */
@@ -177,4 +207,4 @@ declare function validateLensOutputs(lensesRan: string[], fileMetricsProduced: s
177
207
  missing: ('fileMetrics' | 'aggregate')[];
178
208
  }>;
179
209
 
180
- export { CATEGORY_CONFIGS, type CategoryConfig, type ColorScheme, LANGUAGE_CONFIGS, LENS_REGISTRY, type Language, type LanguageConfig, type LensCategory, type LensMetadata, areLensesAlternatives, detectLanguageFromExtension, findCategoryConflicts, getAlternatives, getCategoryConfig, getCategoryDisplayName, getCategoryForLens, getColorModeForCategory, getLanguageConfig, getLanguagesForCategory, getLensById, getLensColorScheme, getLensDisplayName, getLensesByCategory, getLensesByCategoryAndLanguage, getLensesByLanguage, getLensesWithAggregates, getLensesWithFileMetrics, isCategoryInverted, isValidLensId, validateLensOutputs };
210
+ export { CATEGORY_CONFIGS, type CategoryConfig, type ColorScheme, type HexagonMetricKey, LANGUAGE_CONFIGS, LENS_REGISTRY, type Language, type LanguageConfig, type LensCategory, type LensMetadata, areLensesAlternatives, detectLanguageFromExtension, findCategoryConflicts, getAlternatives, getCategoryConfig, getCategoryDisplayName, getCategoryForHexagonMetric, getCategoryForLens, getColorModeForCategory, getColorModeForHexagonMetric, getHexagonMetricForCategory, getHexagonMetricKeys, getLanguageConfig, getLanguagesForCategory, getLensById, getLensColorScheme, getLensDisplayName, getLensesByCategory, getLensesByCategoryAndLanguage, getLensesByLanguage, getLensesWithAggregates, getLensesWithFileMetrics, isCategoryInverted, isHexagonMetricConfigured, isLensInHexagonMetric, isValidLensId, validateLensOutputs };
package/dist/index.d.ts CHANGED
@@ -158,6 +158,36 @@ declare function detectLanguageFromExtension(extension: string): Language | unde
158
158
  * Get all languages that have lenses in a category
159
159
  */
160
160
  declare function getLanguagesForCategory(category: LensCategory): Language[];
161
+ /**
162
+ * Hexagon metric keys use camelCase (from QualityMetrics interface)
163
+ * These map to LensCategory which uses kebab-case
164
+ */
165
+ type HexagonMetricKey = 'linting' | 'formatting' | 'types' | 'tests' | 'deadCode' | 'documentation';
166
+ /**
167
+ * Get the LensCategory for a hexagon metric key
168
+ */
169
+ declare function getCategoryForHexagonMetric(metric: HexagonMetricKey): LensCategory;
170
+ /**
171
+ * Get the hexagon metric key for a LensCategory
172
+ */
173
+ declare function getHexagonMetricForCategory(category: LensCategory): HexagonMetricKey | undefined;
174
+ /**
175
+ * Check if a lens ID belongs to a hexagon metric
176
+ */
177
+ declare function isLensInHexagonMetric(lensId: string, metric: HexagonMetricKey): boolean;
178
+ /**
179
+ * Get the color mode for a hexagon metric based on which lenses ran.
180
+ * This is the main entry point for the QualityHexagon panel.
181
+ */
182
+ declare function getColorModeForHexagonMetric(metric: HexagonMetricKey, lensesRan: string[]): string | null;
183
+ /**
184
+ * Check if a hexagon metric is configured (has at least one lens that ran)
185
+ */
186
+ declare function isHexagonMetricConfigured(metric: HexagonMetricKey, lensesRan: string[] | undefined): boolean;
187
+ /**
188
+ * Get all hexagon metric keys
189
+ */
190
+ declare function getHexagonMetricKeys(): HexagonMetricKey[];
161
191
  /**
162
192
  * Validate that a lens ID exists in the registry
163
193
  */
@@ -177,4 +207,4 @@ declare function validateLensOutputs(lensesRan: string[], fileMetricsProduced: s
177
207
  missing: ('fileMetrics' | 'aggregate')[];
178
208
  }>;
179
209
 
180
- export { CATEGORY_CONFIGS, type CategoryConfig, type ColorScheme, LANGUAGE_CONFIGS, LENS_REGISTRY, type Language, type LanguageConfig, type LensCategory, type LensMetadata, areLensesAlternatives, detectLanguageFromExtension, findCategoryConflicts, getAlternatives, getCategoryConfig, getCategoryDisplayName, getCategoryForLens, getColorModeForCategory, getLanguageConfig, getLanguagesForCategory, getLensById, getLensColorScheme, getLensDisplayName, getLensesByCategory, getLensesByCategoryAndLanguage, getLensesByLanguage, getLensesWithAggregates, getLensesWithFileMetrics, isCategoryInverted, isValidLensId, validateLensOutputs };
210
+ export { CATEGORY_CONFIGS, type CategoryConfig, type ColorScheme, type HexagonMetricKey, LANGUAGE_CONFIGS, LENS_REGISTRY, type Language, type LanguageConfig, type LensCategory, type LensMetadata, areLensesAlternatives, detectLanguageFromExtension, findCategoryConflicts, getAlternatives, getCategoryConfig, getCategoryDisplayName, getCategoryForHexagonMetric, getCategoryForLens, getColorModeForCategory, getColorModeForHexagonMetric, getHexagonMetricForCategory, getHexagonMetricKeys, getLanguageConfig, getLanguagesForCategory, getLensById, getLensColorScheme, getLensDisplayName, getLensesByCategory, getLensesByCategoryAndLanguage, getLensesByLanguage, getLensesWithAggregates, getLensesWithFileMetrics, isCategoryInverted, isHexagonMetricConfigured, isLensInHexagonMetric, isValidLensId, validateLensOutputs };
package/dist/index.js CHANGED
@@ -559,6 +559,49 @@ function getLanguagesForCategory(category) {
559
559
  }
560
560
  return Array.from(languages);
561
561
  }
562
+ var HEXAGON_METRIC_TO_CATEGORY = {
563
+ linting: "linting",
564
+ formatting: "formatting",
565
+ types: "types",
566
+ tests: "tests",
567
+ deadCode: "dead-code",
568
+ documentation: "documentation"
569
+ };
570
+ var CATEGORY_TO_HEXAGON_METRIC = {
571
+ "linting": "linting",
572
+ "formatting": "formatting",
573
+ "types": "types",
574
+ "tests": "tests",
575
+ "dead-code": "deadCode",
576
+ "documentation": "documentation"
577
+ };
578
+ function getCategoryForHexagonMetric(metric) {
579
+ return HEXAGON_METRIC_TO_CATEGORY[metric];
580
+ }
581
+ function getHexagonMetricForCategory(category) {
582
+ return CATEGORY_TO_HEXAGON_METRIC[category];
583
+ }
584
+ function isLensInHexagonMetric(lensId, metric) {
585
+ const lensCategory = getCategoryForLens(lensId);
586
+ if (!lensCategory) return false;
587
+ return HEXAGON_METRIC_TO_CATEGORY[metric] === lensCategory;
588
+ }
589
+ function getColorModeForHexagonMetric(metric, lensesRan) {
590
+ const category = HEXAGON_METRIC_TO_CATEGORY[metric];
591
+ return getColorModeForCategory(category, lensesRan);
592
+ }
593
+ function isHexagonMetricConfigured(metric, lensesRan) {
594
+ if (lensesRan === void 0) {
595
+ return true;
596
+ }
597
+ if (lensesRan.length === 0) {
598
+ return false;
599
+ }
600
+ return lensesRan.some((lensId) => isLensInHexagonMetric(lensId, metric));
601
+ }
602
+ function getHexagonMetricKeys() {
603
+ return Object.keys(HEXAGON_METRIC_TO_CATEGORY);
604
+ }
562
605
  function isValidLensId(lensId) {
563
606
  return getLensById(lensId) !== void 0;
564
607
  }
@@ -608,8 +651,12 @@ export {
608
651
  getAlternatives,
609
652
  getCategoryConfig,
610
653
  getCategoryDisplayName,
654
+ getCategoryForHexagonMetric,
611
655
  getCategoryForLens,
612
656
  getColorModeForCategory,
657
+ getColorModeForHexagonMetric,
658
+ getHexagonMetricForCategory,
659
+ getHexagonMetricKeys,
613
660
  getLanguageConfig,
614
661
  getLanguagesForCategory,
615
662
  getLensById,
@@ -621,6 +668,8 @@ export {
621
668
  getLensesWithAggregates,
622
669
  getLensesWithFileMetrics,
623
670
  isCategoryInverted,
671
+ isHexagonMetricConfigured,
672
+ isLensInHexagonMetric,
624
673
  isValidLensId,
625
674
  validateLensOutputs
626
675
  };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/registry.ts","../src/helpers.ts"],"sourcesContent":["import type { LensMetadata, CategoryConfig, LanguageConfig } from './types.js';\n\n/**\n * Central registry of all quality lenses\n *\n * When adding a new lens:\n * 1. Add it to this registry with complete metadata\n * 2. Implement the lens in @principal-ai/codebase-quality-lenses\n * 3. The UI packages will automatically discover and support it\n */\nexport const LENS_REGISTRY: LensMetadata[] = [\n // ============================================================\n // LINTING - Code style and bug detection\n // ============================================================\n\n // TypeScript/JavaScript linting\n {\n id: 'eslint',\n name: 'ESLint',\n category: 'linting',\n languages: ['typescript', 'javascript'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Pluggable linting utility for JavaScript and TypeScript',\n command: 'eslint',\n },\n {\n id: 'biome-lint',\n name: 'Biome Lint',\n category: 'linting',\n languages: ['typescript', 'javascript'],\n alternativeTo: ['eslint'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Fast linter for JavaScript and TypeScript',\n command: 'biome lint',\n },\n {\n id: 'oxlint',\n name: 'OxLint',\n category: 'linting',\n languages: ['typescript', 'javascript'],\n alternativeTo: ['eslint', 'biome-lint'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Blazing fast JavaScript/TypeScript linter',\n command: 'oxlint',\n },\n\n // Python linting\n {\n id: 'ruff',\n name: 'Ruff',\n category: 'linting',\n languages: ['python'],\n alternativeTo: ['pylint', 'flake8'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Extremely fast Python linter',\n command: 'ruff check',\n },\n {\n id: 'pylint',\n name: 'Pylint',\n category: 'linting',\n languages: ['python'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Python static code analyzer',\n command: 'pylint',\n },\n\n // Go linting\n {\n id: 'golangci-lint',\n name: 'golangci-lint',\n category: 'linting',\n languages: ['go'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Fast linters runner for Go',\n command: 'golangci-lint run',\n },\n\n // Rust linting\n {\n id: 'clippy',\n name: 'Clippy',\n category: 'linting',\n languages: ['rust'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Rust linter',\n command: 'cargo clippy',\n },\n\n // ============================================================\n // FORMATTING - Code formatting\n // ============================================================\n\n // TypeScript/JavaScript formatting\n {\n id: 'prettier',\n name: 'Prettier',\n category: 'formatting',\n languages: ['typescript', 'javascript'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'binary',\n description: 'Opinionated code formatter',\n command: 'prettier --check',\n },\n {\n id: 'biome-format',\n name: 'Biome Format',\n category: 'formatting',\n languages: ['typescript', 'javascript'],\n alternativeTo: ['prettier'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'binary',\n description: 'Fast code formatter for JavaScript and TypeScript',\n command: 'biome format',\n },\n\n // Python formatting\n {\n id: 'black',\n name: 'Black',\n category: 'formatting',\n languages: ['python'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'binary',\n description: 'The uncompromising Python code formatter',\n command: 'black --check',\n },\n {\n id: 'ruff-format',\n name: 'Ruff Format',\n category: 'formatting',\n languages: ['python'],\n alternativeTo: ['black'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'binary',\n description: 'Fast Python formatter (Ruff)',\n command: 'ruff format --check',\n },\n\n // Go formatting\n {\n id: 'gofmt',\n name: 'gofmt',\n category: 'formatting',\n languages: ['go'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'binary',\n description: 'Go code formatter',\n command: 'gofmt -l',\n },\n\n // Rust formatting\n {\n id: 'rustfmt',\n name: 'rustfmt',\n category: 'formatting',\n languages: ['rust'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'binary',\n description: 'Rust code formatter',\n command: 'cargo fmt --check',\n },\n\n // ============================================================\n // TYPES - Type checking\n // ============================================================\n\n // TypeScript\n {\n id: 'typescript',\n name: 'TypeScript',\n category: 'types',\n languages: ['typescript'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'TypeScript type checker',\n command: 'tsc --noEmit',\n },\n\n // Python type checking\n {\n id: 'mypy',\n name: 'MyPy',\n category: 'types',\n languages: ['python'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Static type checker for Python',\n command: 'mypy',\n },\n {\n id: 'pyright',\n name: 'Pyright',\n category: 'types',\n languages: ['python'],\n alternativeTo: ['mypy'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Static type checker for Python',\n command: 'pyright',\n },\n\n // Go type checking (built into compiler)\n {\n id: 'go-vet',\n name: 'Go Vet',\n category: 'types',\n languages: ['go'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Go static analyzer',\n command: 'go vet',\n },\n\n // ============================================================\n // TESTS - Test coverage and results\n // ============================================================\n\n // JavaScript/TypeScript testing\n {\n id: 'jest',\n name: 'Jest',\n category: 'tests',\n languages: ['typescript', 'javascript'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'coverage',\n description: 'JavaScript testing framework',\n command: 'jest --coverage',\n },\n {\n id: 'vitest',\n name: 'Vitest',\n category: 'tests',\n languages: ['typescript', 'javascript'],\n alternativeTo: ['jest'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'coverage',\n description: 'Vite-native testing framework',\n command: 'vitest run --coverage',\n },\n {\n id: 'bun-test',\n name: 'Bun Test',\n category: 'tests',\n languages: ['typescript', 'javascript'],\n alternativeTo: ['jest', 'vitest'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'coverage',\n description: 'Bun native test runner',\n command: 'bun test',\n },\n\n // Python testing\n {\n id: 'pytest',\n name: 'Pytest',\n category: 'tests',\n languages: ['python'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'coverage',\n description: 'Python testing framework',\n command: 'pytest --cov',\n },\n\n // Go testing\n {\n id: 'go-test',\n name: 'Go Test',\n category: 'tests',\n languages: ['go'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'coverage',\n description: 'Go test runner',\n command: 'go test -cover',\n },\n\n // Rust testing\n {\n id: 'cargo-test',\n name: 'Cargo Test',\n category: 'tests',\n languages: ['rust'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'coverage',\n description: 'Rust test runner',\n command: 'cargo test',\n },\n\n // ============================================================\n // DEAD CODE - Unused code detection\n // ============================================================\n\n // TypeScript/JavaScript\n {\n id: 'knip',\n name: 'Knip',\n category: 'dead-code',\n languages: ['typescript', 'javascript'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Find unused files, dependencies and exports',\n command: 'knip',\n },\n\n // Python\n {\n id: 'vulture',\n name: 'Vulture',\n category: 'dead-code',\n languages: ['python'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Find dead Python code',\n command: 'vulture',\n },\n\n // ============================================================\n // DOCUMENTATION - Documentation coverage\n // ============================================================\n\n {\n id: 'alexandria',\n name: 'Alexandria',\n category: 'documentation',\n languages: ['typescript', 'javascript'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'binary',\n description: 'Documentation coverage checker',\n command: 'alexandria lint',\n },\n {\n id: 'typedoc',\n name: 'TypeDoc',\n category: 'documentation',\n languages: ['typescript'],\n outputsFileMetrics: false,\n outputsAggregate: true,\n colorScheme: 'coverage',\n description: 'TypeScript documentation generator',\n command: 'typedoc',\n },\n\n // ============================================================\n // SECURITY - Security scanning\n // ============================================================\n\n {\n id: 'npm-audit',\n name: 'npm audit',\n category: 'security',\n languages: ['typescript', 'javascript'],\n outputsFileMetrics: false,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Check for known vulnerabilities in dependencies',\n command: 'npm audit',\n },\n {\n id: 'bandit',\n name: 'Bandit',\n category: 'security',\n languages: ['python'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Python security linter',\n command: 'bandit -r',\n },\n];\n\n/**\n * Category configurations for UI display\n */\nexport const CATEGORY_CONFIGS: CategoryConfig[] = [\n {\n id: 'linting',\n name: 'Linting',\n description: 'Code style and bug detection',\n icon: 'AlertCircle',\n },\n {\n id: 'formatting',\n name: 'Formatting',\n description: 'Code formatting consistency',\n icon: 'AlignLeft',\n },\n {\n id: 'types',\n name: 'Types',\n description: 'Type safety and checking',\n icon: 'FileType',\n },\n {\n id: 'tests',\n name: 'Tests',\n description: 'Test coverage and results',\n icon: 'TestTube',\n },\n {\n id: 'dead-code',\n name: 'Dead Code',\n description: 'Unused code detection',\n icon: 'Trash2',\n invertedScale: true,\n },\n {\n id: 'documentation',\n name: 'Documentation',\n description: 'Documentation coverage',\n icon: 'FileText',\n },\n {\n id: 'security',\n name: 'Security',\n description: 'Security vulnerability scanning',\n icon: 'Shield',\n },\n {\n id: 'complexity',\n name: 'Complexity',\n description: 'Code complexity metrics',\n icon: 'GitBranch',\n },\n];\n\n/**\n * Language configurations for UI display\n */\nexport const LANGUAGE_CONFIGS: LanguageConfig[] = [\n {\n id: 'typescript',\n name: 'TypeScript',\n extensions: ['.ts', '.tsx', '.mts', '.cts'],\n icon: 'TS',\n },\n {\n id: 'javascript',\n name: 'JavaScript',\n extensions: ['.js', '.jsx', '.mjs', '.cjs'],\n icon: 'JS',\n },\n {\n id: 'python',\n name: 'Python',\n extensions: ['.py', '.pyi'],\n icon: 'PY',\n },\n {\n id: 'go',\n name: 'Go',\n extensions: ['.go'],\n icon: 'GO',\n },\n {\n id: 'rust',\n name: 'Rust',\n extensions: ['.rs'],\n icon: 'RS',\n },\n {\n id: 'java',\n name: 'Java',\n extensions: ['.java'],\n icon: 'JV',\n },\n {\n id: 'csharp',\n name: 'C#',\n extensions: ['.cs'],\n icon: 'C#',\n },\n {\n id: 'ruby',\n name: 'Ruby',\n extensions: ['.rb'],\n icon: 'RB',\n },\n {\n id: 'php',\n name: 'PHP',\n extensions: ['.php'],\n icon: 'PHP',\n },\n];\n","import type { LensMetadata, LensCategory, Language, CategoryConfig, LanguageConfig } from './types.js';\nimport { LENS_REGISTRY, CATEGORY_CONFIGS, LANGUAGE_CONFIGS } from './registry.js';\n\n// ============================================================\n// Lens Lookups\n// ============================================================\n\n/**\n * Get lens metadata by ID\n */\nexport function getLensById(id: string): LensMetadata | undefined {\n return LENS_REGISTRY.find((lens) => lens.id === id);\n}\n\n/**\n * Get all lenses in a category\n */\nexport function getLensesByCategory(category: LensCategory): LensMetadata[] {\n return LENS_REGISTRY.filter((lens) => lens.category === category);\n}\n\n/**\n * Get all lenses that support a language\n */\nexport function getLensesByLanguage(language: Language): LensMetadata[] {\n return LENS_REGISTRY.filter((lens) => lens.languages.includes(language));\n}\n\n/**\n * Get lenses that support a category for a specific language\n */\nexport function getLensesByCategoryAndLanguage(\n category: LensCategory,\n language: Language\n): LensMetadata[] {\n return LENS_REGISTRY.filter(\n (lens) => lens.category === category && lens.languages.includes(language)\n );\n}\n\n/**\n * Get the category for a lens ID\n */\nexport function getCategoryForLens(lensId: string): LensCategory | undefined {\n return getLensById(lensId)?.category;\n}\n\n/**\n * Get alternative lenses for a given lens ID\n */\nexport function getAlternatives(lensId: string): LensMetadata[] {\n const lens = getLensById(lensId);\n if (!lens) return [];\n\n // Find lenses that list this one as an alternative\n const listedAsAlternative = LENS_REGISTRY.filter(\n (other) => other.alternativeTo?.includes(lensId)\n );\n\n // Find lenses that this one lists as alternatives\n const thisListsAsAlternative = lens.alternativeTo\n ? LENS_REGISTRY.filter((other) => lens.alternativeTo!.includes(other.id))\n : [];\n\n // Combine and dedupe\n const all = [...listedAsAlternative, ...thisListsAsAlternative];\n return Array.from(new Map(all.map((l) => [l.id, l])).values());\n}\n\n/**\n * Check if two lenses are alternatives to each other\n */\nexport function areLensesAlternatives(lensId1: string, lensId2: string): boolean {\n const lens1 = getLensById(lensId1);\n const lens2 = getLensById(lensId2);\n\n if (!lens1 || !lens2) return false;\n if (lens1.category !== lens2.category) return false;\n\n return (\n lens1.alternativeTo?.includes(lensId2) ||\n lens2.alternativeTo?.includes(lensId1) ||\n false\n );\n}\n\n/**\n * Get all lenses that output file metrics (for File City visualization)\n */\nexport function getLensesWithFileMetrics(): LensMetadata[] {\n return LENS_REGISTRY.filter((lens) => lens.outputsFileMetrics);\n}\n\n/**\n * Get all lenses that output aggregate scores (for Quality Hexagon)\n */\nexport function getLensesWithAggregates(): LensMetadata[] {\n return LENS_REGISTRY.filter((lens) => lens.outputsAggregate);\n}\n\n// ============================================================\n// Color Mode Helpers (for File City)\n// ============================================================\n\n/**\n * Get the appropriate color mode (lens ID) for a category based on which lenses ran\n * Returns the first lens that ran for the category, preferring alternatives in order\n */\nexport function getColorModeForCategory(\n category: LensCategory,\n lensesRan: string[]\n): string | null {\n const lensesInCategory = getLensesByCategory(category);\n\n // Find the first lens that ran\n for (const lensId of lensesRan) {\n if (lensesInCategory.some((lens) => lens.id === lensId)) {\n return lensId;\n }\n }\n\n return null;\n}\n\n/**\n * Get display name for a lens (for UI labels)\n */\nexport function getLensDisplayName(lensId: string): string {\n return getLensById(lensId)?.name ?? lensId;\n}\n\n/**\n * Get color scheme for a lens (for File City layer rendering)\n */\nexport function getLensColorScheme(lensId: string): 'issues' | 'coverage' | 'binary' {\n return getLensById(lensId)?.colorScheme ?? 'issues';\n}\n\n// ============================================================\n// Category Helpers\n// ============================================================\n\n/**\n * Get category configuration\n */\nexport function getCategoryConfig(category: LensCategory): CategoryConfig | undefined {\n return CATEGORY_CONFIGS.find((c) => c.id === category);\n}\n\n/**\n * Get category display name\n */\nexport function getCategoryDisplayName(category: LensCategory): string {\n return getCategoryConfig(category)?.name ?? category;\n}\n\n/**\n * Check if a category uses inverted scale (lower is better)\n */\nexport function isCategoryInverted(category: LensCategory): boolean {\n return getCategoryConfig(category)?.invertedScale ?? false;\n}\n\n// ============================================================\n// Language Helpers\n// ============================================================\n\n/**\n * Get language configuration\n */\nexport function getLanguageConfig(language: Language): LanguageConfig | undefined {\n return LANGUAGE_CONFIGS.find((l) => l.id === language);\n}\n\n/**\n * Detect language from file extension\n */\nexport function detectLanguageFromExtension(extension: string): Language | undefined {\n const normalizedExt = extension.startsWith('.') ? extension : `.${extension}`;\n const config = LANGUAGE_CONFIGS.find((l) =>\n l.extensions.includes(normalizedExt.toLowerCase())\n );\n return config?.id;\n}\n\n/**\n * Get all languages that have lenses in a category\n */\nexport function getLanguagesForCategory(category: LensCategory): Language[] {\n const lenses = getLensesByCategory(category);\n const languages = new Set<Language>();\n for (const lens of lenses) {\n for (const lang of lens.languages) {\n languages.add(lang);\n }\n }\n return Array.from(languages);\n}\n\n// ============================================================\n// Validation Helpers\n// ============================================================\n\n/**\n * Validate that a lens ID exists in the registry\n */\nexport function isValidLensId(lensId: string): boolean {\n return getLensById(lensId) !== undefined;\n}\n\n/**\n * Find lenses that ran for the same category (potential conflicts)\n */\nexport function findCategoryConflicts(\n lensesRan: string[]\n): Array<{ category: LensCategory; lenses: string[] }> {\n const byCategory = new Map<LensCategory, string[]>();\n\n for (const lensId of lensesRan) {\n const category = getCategoryForLens(lensId);\n if (category) {\n const existing = byCategory.get(category) || [];\n existing.push(lensId);\n byCategory.set(category, existing);\n }\n }\n\n const conflicts: Array<{ category: LensCategory; lenses: string[] }> = [];\n for (const [category, lenses] of byCategory) {\n if (lenses.length > 1) {\n conflicts.push({ category, lenses });\n }\n }\n\n return conflicts;\n}\n\n/**\n * Check if all required lenses produced expected outputs\n */\nexport function validateLensOutputs(\n lensesRan: string[],\n fileMetricsProduced: string[],\n aggregatesProduced: string[]\n): Array<{ lensId: string; missing: ('fileMetrics' | 'aggregate')[] }> {\n const issues: Array<{ lensId: string; missing: ('fileMetrics' | 'aggregate')[] }> = [];\n\n for (const lensId of lensesRan) {\n const lens = getLensById(lensId);\n if (!lens) continue;\n\n const missing: ('fileMetrics' | 'aggregate')[] = [];\n\n if (lens.outputsFileMetrics && !fileMetricsProduced.includes(lensId)) {\n missing.push('fileMetrics');\n }\n if (lens.outputsAggregate && !aggregatesProduced.includes(lensId)) {\n missing.push('aggregate');\n }\n\n if (missing.length > 0) {\n issues.push({ lensId, missing });\n }\n }\n\n return issues;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/registry.ts","../src/helpers.ts"],"sourcesContent":["import type { LensMetadata, CategoryConfig, LanguageConfig } from './types.js';\n\n/**\n * Central registry of all quality lenses\n *\n * When adding a new lens:\n * 1. Add it to this registry with complete metadata\n * 2. Implement the lens in @principal-ai/codebase-quality-lenses\n * 3. The UI packages will automatically discover and support it\n */\nexport const LENS_REGISTRY: LensMetadata[] = [\n // ============================================================\n // LINTING - Code style and bug detection\n // ============================================================\n\n // TypeScript/JavaScript linting\n {\n id: 'eslint',\n name: 'ESLint',\n category: 'linting',\n languages: ['typescript', 'javascript'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Pluggable linting utility for JavaScript and TypeScript',\n command: 'eslint',\n },\n {\n id: 'biome-lint',\n name: 'Biome Lint',\n category: 'linting',\n languages: ['typescript', 'javascript'],\n alternativeTo: ['eslint'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Fast linter for JavaScript and TypeScript',\n command: 'biome lint',\n },\n {\n id: 'oxlint',\n name: 'OxLint',\n category: 'linting',\n languages: ['typescript', 'javascript'],\n alternativeTo: ['eslint', 'biome-lint'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Blazing fast JavaScript/TypeScript linter',\n command: 'oxlint',\n },\n\n // Python linting\n {\n id: 'ruff',\n name: 'Ruff',\n category: 'linting',\n languages: ['python'],\n alternativeTo: ['pylint', 'flake8'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Extremely fast Python linter',\n command: 'ruff check',\n },\n {\n id: 'pylint',\n name: 'Pylint',\n category: 'linting',\n languages: ['python'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Python static code analyzer',\n command: 'pylint',\n },\n\n // Go linting\n {\n id: 'golangci-lint',\n name: 'golangci-lint',\n category: 'linting',\n languages: ['go'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Fast linters runner for Go',\n command: 'golangci-lint run',\n },\n\n // Rust linting\n {\n id: 'clippy',\n name: 'Clippy',\n category: 'linting',\n languages: ['rust'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Rust linter',\n command: 'cargo clippy',\n },\n\n // ============================================================\n // FORMATTING - Code formatting\n // ============================================================\n\n // TypeScript/JavaScript formatting\n {\n id: 'prettier',\n name: 'Prettier',\n category: 'formatting',\n languages: ['typescript', 'javascript'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'binary',\n description: 'Opinionated code formatter',\n command: 'prettier --check',\n },\n {\n id: 'biome-format',\n name: 'Biome Format',\n category: 'formatting',\n languages: ['typescript', 'javascript'],\n alternativeTo: ['prettier'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'binary',\n description: 'Fast code formatter for JavaScript and TypeScript',\n command: 'biome format',\n },\n\n // Python formatting\n {\n id: 'black',\n name: 'Black',\n category: 'formatting',\n languages: ['python'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'binary',\n description: 'The uncompromising Python code formatter',\n command: 'black --check',\n },\n {\n id: 'ruff-format',\n name: 'Ruff Format',\n category: 'formatting',\n languages: ['python'],\n alternativeTo: ['black'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'binary',\n description: 'Fast Python formatter (Ruff)',\n command: 'ruff format --check',\n },\n\n // Go formatting\n {\n id: 'gofmt',\n name: 'gofmt',\n category: 'formatting',\n languages: ['go'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'binary',\n description: 'Go code formatter',\n command: 'gofmt -l',\n },\n\n // Rust formatting\n {\n id: 'rustfmt',\n name: 'rustfmt',\n category: 'formatting',\n languages: ['rust'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'binary',\n description: 'Rust code formatter',\n command: 'cargo fmt --check',\n },\n\n // ============================================================\n // TYPES - Type checking\n // ============================================================\n\n // TypeScript\n {\n id: 'typescript',\n name: 'TypeScript',\n category: 'types',\n languages: ['typescript'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'TypeScript type checker',\n command: 'tsc --noEmit',\n },\n\n // Python type checking\n {\n id: 'mypy',\n name: 'MyPy',\n category: 'types',\n languages: ['python'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Static type checker for Python',\n command: 'mypy',\n },\n {\n id: 'pyright',\n name: 'Pyright',\n category: 'types',\n languages: ['python'],\n alternativeTo: ['mypy'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Static type checker for Python',\n command: 'pyright',\n },\n\n // Go type checking (built into compiler)\n {\n id: 'go-vet',\n name: 'Go Vet',\n category: 'types',\n languages: ['go'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Go static analyzer',\n command: 'go vet',\n },\n\n // ============================================================\n // TESTS - Test coverage and results\n // ============================================================\n\n // JavaScript/TypeScript testing\n {\n id: 'jest',\n name: 'Jest',\n category: 'tests',\n languages: ['typescript', 'javascript'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'coverage',\n description: 'JavaScript testing framework',\n command: 'jest --coverage',\n },\n {\n id: 'vitest',\n name: 'Vitest',\n category: 'tests',\n languages: ['typescript', 'javascript'],\n alternativeTo: ['jest'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'coverage',\n description: 'Vite-native testing framework',\n command: 'vitest run --coverage',\n },\n {\n id: 'bun-test',\n name: 'Bun Test',\n category: 'tests',\n languages: ['typescript', 'javascript'],\n alternativeTo: ['jest', 'vitest'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'coverage',\n description: 'Bun native test runner',\n command: 'bun test',\n },\n\n // Python testing\n {\n id: 'pytest',\n name: 'Pytest',\n category: 'tests',\n languages: ['python'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'coverage',\n description: 'Python testing framework',\n command: 'pytest --cov',\n },\n\n // Go testing\n {\n id: 'go-test',\n name: 'Go Test',\n category: 'tests',\n languages: ['go'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'coverage',\n description: 'Go test runner',\n command: 'go test -cover',\n },\n\n // Rust testing\n {\n id: 'cargo-test',\n name: 'Cargo Test',\n category: 'tests',\n languages: ['rust'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'coverage',\n description: 'Rust test runner',\n command: 'cargo test',\n },\n\n // ============================================================\n // DEAD CODE - Unused code detection\n // ============================================================\n\n // TypeScript/JavaScript\n {\n id: 'knip',\n name: 'Knip',\n category: 'dead-code',\n languages: ['typescript', 'javascript'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Find unused files, dependencies and exports',\n command: 'knip',\n },\n\n // Python\n {\n id: 'vulture',\n name: 'Vulture',\n category: 'dead-code',\n languages: ['python'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Find dead Python code',\n command: 'vulture',\n },\n\n // ============================================================\n // DOCUMENTATION - Documentation coverage\n // ============================================================\n\n {\n id: 'alexandria',\n name: 'Alexandria',\n category: 'documentation',\n languages: ['typescript', 'javascript'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'binary',\n description: 'Documentation coverage checker',\n command: 'alexandria lint',\n },\n {\n id: 'typedoc',\n name: 'TypeDoc',\n category: 'documentation',\n languages: ['typescript'],\n outputsFileMetrics: false,\n outputsAggregate: true,\n colorScheme: 'coverage',\n description: 'TypeScript documentation generator',\n command: 'typedoc',\n },\n\n // ============================================================\n // SECURITY - Security scanning\n // ============================================================\n\n {\n id: 'npm-audit',\n name: 'npm audit',\n category: 'security',\n languages: ['typescript', 'javascript'],\n outputsFileMetrics: false,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Check for known vulnerabilities in dependencies',\n command: 'npm audit',\n },\n {\n id: 'bandit',\n name: 'Bandit',\n category: 'security',\n languages: ['python'],\n outputsFileMetrics: true,\n outputsAggregate: true,\n colorScheme: 'issues',\n description: 'Python security linter',\n command: 'bandit -r',\n },\n];\n\n/**\n * Category configurations for UI display\n */\nexport const CATEGORY_CONFIGS: CategoryConfig[] = [\n {\n id: 'linting',\n name: 'Linting',\n description: 'Code style and bug detection',\n icon: 'AlertCircle',\n },\n {\n id: 'formatting',\n name: 'Formatting',\n description: 'Code formatting consistency',\n icon: 'AlignLeft',\n },\n {\n id: 'types',\n name: 'Types',\n description: 'Type safety and checking',\n icon: 'FileType',\n },\n {\n id: 'tests',\n name: 'Tests',\n description: 'Test coverage and results',\n icon: 'TestTube',\n },\n {\n id: 'dead-code',\n name: 'Dead Code',\n description: 'Unused code detection',\n icon: 'Trash2',\n invertedScale: true,\n },\n {\n id: 'documentation',\n name: 'Documentation',\n description: 'Documentation coverage',\n icon: 'FileText',\n },\n {\n id: 'security',\n name: 'Security',\n description: 'Security vulnerability scanning',\n icon: 'Shield',\n },\n {\n id: 'complexity',\n name: 'Complexity',\n description: 'Code complexity metrics',\n icon: 'GitBranch',\n },\n];\n\n/**\n * Language configurations for UI display\n */\nexport const LANGUAGE_CONFIGS: LanguageConfig[] = [\n {\n id: 'typescript',\n name: 'TypeScript',\n extensions: ['.ts', '.tsx', '.mts', '.cts'],\n icon: 'TS',\n },\n {\n id: 'javascript',\n name: 'JavaScript',\n extensions: ['.js', '.jsx', '.mjs', '.cjs'],\n icon: 'JS',\n },\n {\n id: 'python',\n name: 'Python',\n extensions: ['.py', '.pyi'],\n icon: 'PY',\n },\n {\n id: 'go',\n name: 'Go',\n extensions: ['.go'],\n icon: 'GO',\n },\n {\n id: 'rust',\n name: 'Rust',\n extensions: ['.rs'],\n icon: 'RS',\n },\n {\n id: 'java',\n name: 'Java',\n extensions: ['.java'],\n icon: 'JV',\n },\n {\n id: 'csharp',\n name: 'C#',\n extensions: ['.cs'],\n icon: 'C#',\n },\n {\n id: 'ruby',\n name: 'Ruby',\n extensions: ['.rb'],\n icon: 'RB',\n },\n {\n id: 'php',\n name: 'PHP',\n extensions: ['.php'],\n icon: 'PHP',\n },\n];\n","import type { LensMetadata, LensCategory, Language, CategoryConfig, LanguageConfig } from './types.js';\nimport { LENS_REGISTRY, CATEGORY_CONFIGS, LANGUAGE_CONFIGS } from './registry.js';\n\n// ============================================================\n// Lens Lookups\n// ============================================================\n\n/**\n * Get lens metadata by ID\n */\nexport function getLensById(id: string): LensMetadata | undefined {\n return LENS_REGISTRY.find((lens) => lens.id === id);\n}\n\n/**\n * Get all lenses in a category\n */\nexport function getLensesByCategory(category: LensCategory): LensMetadata[] {\n return LENS_REGISTRY.filter((lens) => lens.category === category);\n}\n\n/**\n * Get all lenses that support a language\n */\nexport function getLensesByLanguage(language: Language): LensMetadata[] {\n return LENS_REGISTRY.filter((lens) => lens.languages.includes(language));\n}\n\n/**\n * Get lenses that support a category for a specific language\n */\nexport function getLensesByCategoryAndLanguage(\n category: LensCategory,\n language: Language\n): LensMetadata[] {\n return LENS_REGISTRY.filter(\n (lens) => lens.category === category && lens.languages.includes(language)\n );\n}\n\n/**\n * Get the category for a lens ID\n */\nexport function getCategoryForLens(lensId: string): LensCategory | undefined {\n return getLensById(lensId)?.category;\n}\n\n/**\n * Get alternative lenses for a given lens ID\n */\nexport function getAlternatives(lensId: string): LensMetadata[] {\n const lens = getLensById(lensId);\n if (!lens) return [];\n\n // Find lenses that list this one as an alternative\n const listedAsAlternative = LENS_REGISTRY.filter(\n (other) => other.alternativeTo?.includes(lensId)\n );\n\n // Find lenses that this one lists as alternatives\n const thisListsAsAlternative = lens.alternativeTo\n ? LENS_REGISTRY.filter((other) => lens.alternativeTo!.includes(other.id))\n : [];\n\n // Combine and dedupe\n const all = [...listedAsAlternative, ...thisListsAsAlternative];\n return Array.from(new Map(all.map((l) => [l.id, l])).values());\n}\n\n/**\n * Check if two lenses are alternatives to each other\n */\nexport function areLensesAlternatives(lensId1: string, lensId2: string): boolean {\n const lens1 = getLensById(lensId1);\n const lens2 = getLensById(lensId2);\n\n if (!lens1 || !lens2) return false;\n if (lens1.category !== lens2.category) return false;\n\n return (\n lens1.alternativeTo?.includes(lensId2) ||\n lens2.alternativeTo?.includes(lensId1) ||\n false\n );\n}\n\n/**\n * Get all lenses that output file metrics (for File City visualization)\n */\nexport function getLensesWithFileMetrics(): LensMetadata[] {\n return LENS_REGISTRY.filter((lens) => lens.outputsFileMetrics);\n}\n\n/**\n * Get all lenses that output aggregate scores (for Quality Hexagon)\n */\nexport function getLensesWithAggregates(): LensMetadata[] {\n return LENS_REGISTRY.filter((lens) => lens.outputsAggregate);\n}\n\n// ============================================================\n// Color Mode Helpers (for File City)\n// ============================================================\n\n/**\n * Get the appropriate color mode (lens ID) for a category based on which lenses ran\n * Returns the first lens that ran for the category, preferring alternatives in order\n */\nexport function getColorModeForCategory(\n category: LensCategory,\n lensesRan: string[]\n): string | null {\n const lensesInCategory = getLensesByCategory(category);\n\n // Find the first lens that ran\n for (const lensId of lensesRan) {\n if (lensesInCategory.some((lens) => lens.id === lensId)) {\n return lensId;\n }\n }\n\n return null;\n}\n\n/**\n * Get display name for a lens (for UI labels)\n */\nexport function getLensDisplayName(lensId: string): string {\n return getLensById(lensId)?.name ?? lensId;\n}\n\n/**\n * Get color scheme for a lens (for File City layer rendering)\n */\nexport function getLensColorScheme(lensId: string): 'issues' | 'coverage' | 'binary' {\n return getLensById(lensId)?.colorScheme ?? 'issues';\n}\n\n// ============================================================\n// Category Helpers\n// ============================================================\n\n/**\n * Get category configuration\n */\nexport function getCategoryConfig(category: LensCategory): CategoryConfig | undefined {\n return CATEGORY_CONFIGS.find((c) => c.id === category);\n}\n\n/**\n * Get category display name\n */\nexport function getCategoryDisplayName(category: LensCategory): string {\n return getCategoryConfig(category)?.name ?? category;\n}\n\n/**\n * Check if a category uses inverted scale (lower is better)\n */\nexport function isCategoryInverted(category: LensCategory): boolean {\n return getCategoryConfig(category)?.invertedScale ?? false;\n}\n\n// ============================================================\n// Language Helpers\n// ============================================================\n\n/**\n * Get language configuration\n */\nexport function getLanguageConfig(language: Language): LanguageConfig | undefined {\n return LANGUAGE_CONFIGS.find((l) => l.id === language);\n}\n\n/**\n * Detect language from file extension\n */\nexport function detectLanguageFromExtension(extension: string): Language | undefined {\n const normalizedExt = extension.startsWith('.') ? extension : `.${extension}`;\n const config = LANGUAGE_CONFIGS.find((l) =>\n l.extensions.includes(normalizedExt.toLowerCase())\n );\n return config?.id;\n}\n\n/**\n * Get all languages that have lenses in a category\n */\nexport function getLanguagesForCategory(category: LensCategory): Language[] {\n const lenses = getLensesByCategory(category);\n const languages = new Set<Language>();\n for (const lens of lenses) {\n for (const lang of lens.languages) {\n languages.add(lang);\n }\n }\n return Array.from(languages);\n}\n\n// ============================================================\n// Hexagon Metric Helpers (for Quality Hexagon UI)\n// ============================================================\n\n/**\n * Hexagon metric keys use camelCase (from QualityMetrics interface)\n * These map to LensCategory which uses kebab-case\n */\nexport type HexagonMetricKey =\n | 'linting'\n | 'formatting'\n | 'types'\n | 'tests'\n | 'deadCode'\n | 'documentation';\n\n/**\n * Map hexagon metric keys to registry LensCategory\n */\nconst HEXAGON_METRIC_TO_CATEGORY: Record<HexagonMetricKey, LensCategory> = {\n linting: 'linting',\n formatting: 'formatting',\n types: 'types',\n tests: 'tests',\n deadCode: 'dead-code',\n documentation: 'documentation',\n};\n\n/**\n * Map LensCategory back to hexagon metric keys\n */\nconst CATEGORY_TO_HEXAGON_METRIC: Partial<Record<LensCategory, HexagonMetricKey>> = {\n 'linting': 'linting',\n 'formatting': 'formatting',\n 'types': 'types',\n 'tests': 'tests',\n 'dead-code': 'deadCode',\n 'documentation': 'documentation',\n};\n\n/**\n * Get the LensCategory for a hexagon metric key\n */\nexport function getCategoryForHexagonMetric(metric: HexagonMetricKey): LensCategory {\n return HEXAGON_METRIC_TO_CATEGORY[metric];\n}\n\n/**\n * Get the hexagon metric key for a LensCategory\n */\nexport function getHexagonMetricForCategory(category: LensCategory): HexagonMetricKey | undefined {\n return CATEGORY_TO_HEXAGON_METRIC[category];\n}\n\n/**\n * Check if a lens ID belongs to a hexagon metric\n */\nexport function isLensInHexagonMetric(lensId: string, metric: HexagonMetricKey): boolean {\n const lensCategory = getCategoryForLens(lensId);\n if (!lensCategory) return false;\n return HEXAGON_METRIC_TO_CATEGORY[metric] === lensCategory;\n}\n\n/**\n * Get the color mode for a hexagon metric based on which lenses ran.\n * This is the main entry point for the QualityHexagon panel.\n */\nexport function getColorModeForHexagonMetric(\n metric: HexagonMetricKey,\n lensesRan: string[]\n): string | null {\n const category = HEXAGON_METRIC_TO_CATEGORY[metric];\n return getColorModeForCategory(category, lensesRan);\n}\n\n/**\n * Check if a hexagon metric is configured (has at least one lens that ran)\n */\nexport function isHexagonMetricConfigured(\n metric: HexagonMetricKey,\n lensesRan: string[] | undefined\n): boolean {\n // undefined = old data without lensesRan tracking, assume all configured (backwards compatibility)\n if (lensesRan === undefined) {\n return true;\n }\n // Empty array = new data, explicitly no lenses ran for this package\n if (lensesRan.length === 0) {\n return false;\n }\n return lensesRan.some((lensId) => isLensInHexagonMetric(lensId, metric));\n}\n\n/**\n * Get all hexagon metric keys\n */\nexport function getHexagonMetricKeys(): HexagonMetricKey[] {\n return Object.keys(HEXAGON_METRIC_TO_CATEGORY) as HexagonMetricKey[];\n}\n\n// ============================================================\n// Validation Helpers\n// ============================================================\n\n/**\n * Validate that a lens ID exists in the registry\n */\nexport function isValidLensId(lensId: string): boolean {\n return getLensById(lensId) !== undefined;\n}\n\n/**\n * Find lenses that ran for the same category (potential conflicts)\n */\nexport function findCategoryConflicts(\n lensesRan: string[]\n): Array<{ category: LensCategory; lenses: string[] }> {\n const byCategory = new Map<LensCategory, string[]>();\n\n for (const lensId of lensesRan) {\n const category = getCategoryForLens(lensId);\n if (category) {\n const existing = byCategory.get(category) || [];\n existing.push(lensId);\n byCategory.set(category, existing);\n }\n }\n\n const conflicts: Array<{ category: LensCategory; lenses: string[] }> = [];\n for (const [category, lenses] of byCategory) {\n if (lenses.length > 1) {\n conflicts.push({ category, lenses });\n }\n }\n\n return conflicts;\n}\n\n/**\n * Check if all required lenses produced expected outputs\n */\nexport function validateLensOutputs(\n lensesRan: string[],\n fileMetricsProduced: string[],\n aggregatesProduced: string[]\n): Array<{ lensId: string; missing: ('fileMetrics' | 'aggregate')[] }> {\n const issues: Array<{ lensId: string; missing: ('fileMetrics' | 'aggregate')[] }> = [];\n\n for (const lensId of lensesRan) {\n const lens = getLensById(lensId);\n if (!lens) continue;\n\n const missing: ('fileMetrics' | 'aggregate')[] = [];\n\n if (lens.outputsFileMetrics && !fileMetricsProduced.includes(lensId)) {\n missing.push('fileMetrics');\n }\n if (lens.outputsAggregate && !aggregatesProduced.includes(lensId)) {\n missing.push('aggregate');\n }\n\n if (missing.length > 0) {\n issues.push({ lensId, missing });\n }\n }\n\n return issues;\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@principal-ai/quality-lens-registry",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Centralized registry of quality lens metadata for the Principal AI quality toolchain",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",