import { readFileSync } from 'fs';
import { join } from 'path';
export interface NACECode {
code: string;
description: string;
fullCodePath: string;
}
export class NACEUtils {
private static naceData: NACECode[] | null = null;
private static loadNACEData(): NACECode[] {
if (!this.naceData) {
try {
const dataPath = join(__dirname, '..', 'data', 'nace-codes.json');
const rawData = readFileSync(dataPath, 'utf-8');
this.naceData = JSON.parse(rawData) as NACECode[];
} catch (error) {
console.error('Failed to load NACE data:', error);
this.naceData = [];
}
}
return this.naceData;
}
/**
* Get all NACE codes that match a hierarchical filter
* @param parentCode The parent code to filter by (e.g., "01.1" will match all codes starting with "01 / 01.1")
* @returns Array of matching NACE codes
*/
static getHierarchicalCodes(parentCode: string): NACECode[] {
const naceData = this.loadNACEData();
// Find the full path for the parent code
const parentEntry = naceData.find(item => item.code === parentCode);
if (!parentEntry) {
return [];
}
const parentPath = parentEntry.fullCodePath;
// Return all codes that have this parent in their path
return naceData.filter(item =>
item.fullCodePath.startsWith(parentPath) &&
item.code !== parentCode
);
}
/**
* Get all child codes for a given NACE code (including the code itself)
* @param parentCode The parent NACE code
* @returns Array of all codes in the hierarchy (including parent)
*/
static getAllChildCodes(parentCode: string): string[] {
const naceData = this.loadNACEData();
// Find the full path for the parent code
const parentEntry = naceData.find(item => item.code === parentCode);
if (!parentEntry) {
return [parentCode]; // Return original code if not found in our data
}
const parentPath = parentEntry.fullCodePath;
// Return all codes that have this parent in their path, including the parent itself
const matchingCodes = naceData
.filter(item => item.fullCodePath.startsWith(parentPath))
.map(item => item.code);
// Always include the parent code itself
if (!matchingCodes.includes(parentCode)) {
matchingCodes.push(parentCode);
}
return matchingCodes;
}
/**
* Search NACE codes by text description
* @param searchText Text to search for in descriptions
* @returns Array of matching NACE codes
*/
static searchNACECodes(searchText: string): NACECode[] {
const naceData = this.loadNACEData();
const lowerSearchText = searchText.toLowerCase();
return naceData.filter(item =>
item.description.toLowerCase().includes(lowerSearchText) ||
item.code.toLowerCase().includes(lowerSearchText)
);
}
/**
* Get NACE code by exact code
* @param code The NACE code to look up
* @returns The NACE code entry or null if not found
*/
static getNACEByCode(code: string): NACECode | null {
const naceData = this.loadNACEData();
return naceData.find(item => item.code === code) || null;
}
/**
* Get all NACE codes
* @returns Array of all NACE codes
*/
static getAllNACECodes(): NACECode[] {
return this.loadNACEData();
}
/**
* Expand industry codes to include all hierarchical children
* @param industryCodes Array of industry codes to expand
* @returns Array of all codes including hierarchical children
*/
static expandIndustryCodes(industryCodes: string[]): string[] {
const expandedCodes: string[] = [];
for (const code of industryCodes) {
const childCodes = this.getAllChildCodes(code);
expandedCodes.push(...childCodes);
}
// Remove duplicates while preserving order
return [...new Set(expandedCodes)];
}
}