/** * Static import of URT Taxonomy data */ import urtData from './urt-codes.json'; import type { URTTaxonomy } from './types'; export const taxonomy = urtData as URTTaxonomy; /** * Get subcode count for a category */ export function getSubcodeCount(categoryKey: string): number { const domainKey = categoryKey[0]; const domain = taxonomy.domains[domainKey]; if (!domain) return 0; const category = domain.categories[categoryKey]; if (!category) return 0; return Object.keys(category.subcodes).length; } /** * Get subcode count for a domain */ export function getDomainSubcodeCount(domainKey: string): number { return taxonomy.indices.subcodes_by_domain[domainKey] || 0; } /** * Get category count for a domain */ export function getDomainCategoryCount(domainKey: string): number { const domain = taxonomy.domains[domainKey]; if (!domain) return 0; return Object.keys(domain.categories).length; } /** * Search taxonomy codes by text */ export function searchTaxonomy(query: string): { domains: string[]; categories: string[]; subcodes: string[]; } { const normalizedQuery = query.toLowerCase().trim(); if (!normalizedQuery) { return { domains: [], categories: [], subcodes: [] }; } const matchedDomains: string[] = []; const matchedCategories: string[] = []; const matchedSubcodes: string[] = []; for (const [domainKey, domain] of Object.entries(taxonomy.domains)) { const domainMatches = domainKey.toLowerCase().includes(normalizedQuery) || domain.name.toLowerCase().includes(normalizedQuery) || domain.description.toLowerCase().includes(normalizedQuery); if (domainMatches) { matchedDomains.push(domainKey); } for (const [categoryKey, category] of Object.entries(domain.categories)) { const categoryMatches = categoryKey.toLowerCase().includes(normalizedQuery) || category.name.toLowerCase().includes(normalizedQuery) || category.definition.toLowerCase().includes(normalizedQuery); if (categoryMatches) { matchedCategories.push(categoryKey); } for (const [subcodeKey, subcode] of Object.entries(category.subcodes)) { const subcodeMatches = subcodeKey.toLowerCase().includes(normalizedQuery) || subcode.name.toLowerCase().includes(normalizedQuery) || subcode.definition.toLowerCase().includes(normalizedQuery) || subcode.positive_example.toLowerCase().includes(normalizedQuery) || subcode.negative_example.toLowerCase().includes(normalizedQuery); if (subcodeMatches) { matchedSubcodes.push(subcodeKey); } } } } return { domains: matchedDomains, categories: matchedCategories, subcodes: matchedSubcodes, }; } /** * Get parent domain and category for a subcode */ export function getSubcodeContext(subcodeKey: string): { domainKey: string; categoryKey: string; } | null { // Parse subcode key like "O1.01" -> domain "O", category "O1" const match = subcodeKey.match(/^([OPJEAVR])(\d)/); if (!match) return null; const domainKey = match[1]; const categoryKey = `${match[1]}${match[2]}`; return { domainKey, categoryKey }; } /** * Get parent domain for a category */ export function getCategoryDomain(categoryKey: string): string | null { const match = categoryKey.match(/^([OPJEAVR])/); return match ? match[1] : null; } /** * Get subcode definition by subcode key (e.g., "J1.04" -> "Meeting scheduled times") */ export function getSubcodeDefinition(subcodeKey: string): string | null { const context = getSubcodeContext(subcodeKey); if (!context) return null; const domain = taxonomy.domains[context.domainKey]; if (!domain) return null; const category = domain.categories[context.categoryKey]; if (!category) return null; const subcode = category.subcodes[subcodeKey]; return subcode?.definition || null; }