UNPKG

rwanda-geo

Version:

Complete, typed, and lightweight dataset of Rwanda's administrative divisions - 5 provinces, 30 districts, 416 sectors, 2,148 cells, and 14,837 villages. Server-side only package for Node.js, Next.js, and backend applications.

820 lines (811 loc) 26.4 kB
import { gunzipSync, brotliDecompressSync } from 'zlib'; import { existsSync, readFileSync } from 'fs'; import { join, dirname } from 'path'; import { fileURLToPath } from 'url'; var __defProp = Object.defineProperty; var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, { get: (a, b) => (typeof require !== "undefined" ? require : a)[b] }) : x)(function(x) { if (typeof require !== "undefined") return require.apply(this, arguments); throw Error('Dynamic require of "' + x + '" is not supported'); }); var __glob = (map) => (path) => { var fn = map[path]; if (fn) return fn(); throw new Error("Module not found in bundle: " + path); }; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; // src/types.ts var types_exports = {}; __export(types_exports, { AdminLevel: () => AdminLevel }); var AdminLevel = /* @__PURE__ */ ((AdminLevel2) => { AdminLevel2["PROVINCE"] = "province"; AdminLevel2["DISTRICT"] = "district"; AdminLevel2["SECTOR"] = "sector"; AdminLevel2["CELL"] = "cell"; AdminLevel2["VILLAGE"] = "village"; return AdminLevel2; })(AdminLevel || {}); // src/helpers.ts var helpers_exports = {}; __export(helpers_exports, { clearDataCache: () => clearDataCache, fuzzySearchByName: () => fuzzySearchByName, getAllCells: () => getAllCells, getAllDescendants: () => getAllDescendants, getAllDistricts: () => getAllDistricts, getAllProvinces: () => getAllProvinces, getAllSectors: () => getAllSectors, getAllVillages: () => getAllVillages, getAvailableData: () => getAvailableData, getByCode: () => getByCode, getByLevel: () => getByLevel, getCacheStats: () => getCacheStats, getCellsBySector: () => getCellsBySector, getChildren: () => getChildren, getCodeLevel: () => getCodeLevel, getCounts: () => getCounts, getDirectChildren: () => getDirectChildren, getDistrictsByProvince: () => getDistrictsByProvince, getFullHierarchy: () => getFullHierarchy, getHierarchy: () => getHierarchy, getSectorsByDistrict: () => getSectorsByDistrict, getSiblings: () => getSiblings, getSuggestions: () => getSuggestions, getSummary: () => getSummary, getVillagesByCell: () => getVillagesByCell, isValidCode: () => isValidCode, preloadData: () => preloadData, searchByName: () => searchByName, searchByPartialCode: () => searchByPartialCode, searchBySlug: () => searchBySlug, validateCodeFormat: () => validateCodeFormat, validateHierarchyIntegrity: () => validateHierarchyIntegrity, validateParentChildRelationship: () => validateParentChildRelationship, validateUnitProperties: () => validateUnitProperties }); // require("../data-embedded/**/*.js") in src/utils/modern-loader.ts var globRequire_data_embedded_js = __glob({ "../data-embedded/cells.js": () => __require("./cells-4NHYTI5Y.js"), "../data-embedded/districts.js": () => __require("./districts-34ZRBVRA.js"), "../data-embedded/provinces.js": () => __require("./provinces-Q5623OUW.js"), "../data-embedded/sectors.js": () => __require("./sectors-WZGCUJRQ.js"), "../data-embedded/villages.js": () => __require("./villages-DTZJ6K5C.js") }); // src/utils/modern-loader.ts var dataCache = /* @__PURE__ */ new Map(); function decompressBuffer(buffer) { try { return brotliDecompressSync(buffer).toString("utf8"); } catch { return gunzipSync(buffer).toString("utf8"); } } function loadEmbeddedData(filename) { if (dataCache.has(filename)) { return dataCache.get(filename); } let data; try { const dataModule = globRequire_data_embedded_js(`../data-embedded/${filename}.js`); const base64Data = dataModule.default || dataModule; const buffer = Buffer.from(base64Data, "base64"); const decompressed = decompressBuffer(buffer); data = JSON.parse(decompressed); dataCache.set(filename, data); return data; } catch { console.warn(`Embedded data not available for ${filename}, falling back to file system loader`); return loadLegacyData(filename); } } function loadLegacyData(filename) { try { const { readFileSync: readFileSync3, existsSync: existsSync3 } = __require("fs"); const { join: join3, dirname: dirname3 } = __require("path"); let packageRoot; try { const packageJsonPath = __require.resolve("rwanda-geo/package.json"); packageRoot = dirname3(packageJsonPath); } catch { const currentDir = __dirname; const srcIndex = currentDir.indexOf("/src/"); packageRoot = srcIndex !== -1 ? currentDir.substring(0, srcIndex) : process.cwd(); } const paths = [ join3(packageRoot, "dist/data", `${filename}.json.gz`), join3(packageRoot, "src/data", `${filename}.json.gz`), join3(packageRoot, "dist/data", `${filename}.json`), join3(packageRoot, "src/data", `${filename}.json`) ]; for (const path of paths) { try { if (existsSync3(path)) { if (path.endsWith(".gz")) { const gzipped = readFileSync3(path); const decompressed = decompressBuffer(gzipped); const data = JSON.parse(decompressed); dataCache.set(filename, data); return data; } else { const content = readFileSync3(path, "utf8"); const data = JSON.parse(content); dataCache.set(filename, data); return data; } } } catch { continue; } } throw new Error(`Failed to load ${filename} from any location`); } catch (error) { throw new Error(`Failed to load ${filename}: ${error instanceof Error ? error.message : "Unknown error"}`); } } var dataCache2 = /* @__PURE__ */ new Map(); function decompressBuffer2(buffer) { try { return brotliDecompressSync(buffer).toString("utf8"); } catch { return gunzipSync(buffer).toString("utf8"); } } function getPackageRoot() { try { const packageJsonPath = __require.resolve("rwanda-geo/package.json"); return dirname(packageJsonPath); } catch (error) { const currentDir = __dirname; const srcIndex = currentDir.indexOf("/src/"); if (srcIndex !== -1) { return currentDir.substring(0, srcIndex); } let currentDir2 = process.cwd(); while (currentDir2 !== dirname(currentDir2)) { if (existsSync(join(currentDir2, "package.json"))) { if (existsSync(join(currentDir2, "dist", "data", "provinces.json.gz"))) { return currentDir2; } } currentDir2 = dirname(currentDir2); } throw new Error(`Could not determine package root. This package must be properly installed or run from its own directory. Error: ${error instanceof Error ? error.message : "Unknown error"}`); } } function lazyLoadGzippedJson(filename) { if (dataCache2.has(filename)) { return dataCache2.get(filename); } const packageRoot = getPackageRoot(); const paths = [ join(packageRoot, "dist/data", `${filename}.json.gz`), // Production (published package) join(packageRoot, "src/data", `${filename}.json.gz`), // Development join(packageRoot, "dist/data", `${filename}.json`), // Production fallback join(packageRoot, "src/data", `${filename}.json`) // Development fallback ]; for (const path of paths) { try { if (existsSync(path)) { if (path.endsWith(".gz")) { const gzipped = readFileSync(path); const decompressed = decompressBuffer2(gzipped); const data = JSON.parse(decompressed); dataCache2.set(filename, data); return data; } else { const content = readFileSync(path, "utf8"); const data = JSON.parse(content); dataCache2.set(filename, data); return data; } } } catch { continue; } } throw new Error(`Failed to load ${filename}.json.gz or ${filename}.json from package directory: ${packageRoot}. Tried paths: ${paths.join(", ")}`); } function preloadData(filenames) { filenames.forEach((filename) => { if (!dataCache2.has(filename)) { try { lazyLoadGzippedJson(filename); } catch (error) { console.warn(`Failed to preload ${filename}:`, error instanceof Error ? error.message : "Unknown error"); } } }); } function clearDataCache() { dataCache2.clear(); } function getCacheStats() { return { size: dataCache2.size, keys: Array.from(dataCache2.keys()) }; } // src/helpers.ts var PROVINCE_LANGUAGE_MAP = { "Kigali City": { en: "Kigali City", rw: "Umujyi wa Kigali" }, "Southern Province": { en: "Southern Province", rw: "Amajyepfo" }, "Western Province": { en: "Western Province", rw: "Iburengerazuba" }, "Northern Province": { en: "Northern Province", rw: "Amajyaruguru" }, "Eastern Province": { en: "Eastern Province", rw: "Iburasirazuba" } }; var PROVINCE_SLUG_MAP = { "Kigali City": { en: "kigali-city", rw: "umujyi-wa-kigali" }, "Southern Province": { en: "southern-province", rw: "amajyepfo" }, "Western Province": { en: "western-province", rw: "iburengerazuba" }, "Northern Province": { en: "northern-province", rw: "amajyaruguru" }, "Eastern Province": { en: "eastern-province", rw: "iburasirazuba" } }; function getTranslatedProvinceName(originalName, language = "en") { const mapping = PROVINCE_LANGUAGE_MAP[originalName]; const result = mapping ? mapping[language] : originalName; return result; } function getTranslatedProvinceSlug(originalName, language = "en") { const mapping = PROVINCE_SLUG_MAP[originalName]; return mapping ? mapping[language] : originalName.toLowerCase().replace(/\s+/g, "-"); } function getProvincesData() { try { return loadEmbeddedData("provinces"); } catch (error) { console.warn("Warning: Could not load provinces data:", error instanceof Error ? error.message : "Unknown error"); return []; } } function getDistrictsData() { try { return loadEmbeddedData("districts"); } catch (error) { console.warn("Warning: Could not load districts data:", error instanceof Error ? error.message : "Unknown error"); return []; } } function getSectorsData() { try { return loadEmbeddedData("sectors"); } catch (error) { console.warn("Warning: Could not load sectors data:", error instanceof Error ? error.message : "Unknown error"); return []; } } function getCellsData() { try { return loadEmbeddedData("cells"); } catch (error) { console.warn("Warning: Could not load cells data:", error instanceof Error ? error.message : "Unknown error"); return []; } } function getVillagesData() { try { return loadEmbeddedData("villages"); } catch (error) { console.warn("Warning: Could not load villages data:", error instanceof Error ? error.message : "Unknown error"); return []; } } var allUnitsMap = null; function getAllUnitsMap() { if (!allUnitsMap) { allUnitsMap = /* @__PURE__ */ new Map(); try { getProvincesData().forEach((province) => allUnitsMap.set(province.code, province)); } catch (error) { console.warn("Warning: Could not load provinces data:", error instanceof Error ? error.message : "Unknown error"); } try { getDistrictsData().forEach((district) => allUnitsMap.set(district.code, district)); } catch (error) { console.warn("Warning: Could not load districts data:", error instanceof Error ? error.message : "Unknown error"); } try { getSectorsData().forEach((sector) => allUnitsMap.set(sector.code, sector)); } catch (error) { console.warn("Warning: Could not load sectors data:", error instanceof Error ? error.message : "Unknown error"); } try { getCellsData().forEach((cell) => allUnitsMap.set(cell.code, cell)); } catch (error) { console.warn("Warning: Could not load cells data:", error instanceof Error ? error.message : "Unknown error"); } try { getVillagesData().forEach((village) => allUnitsMap.set(village.code, village)); } catch (error) { console.warn("Warning: Could not load villages data:", error instanceof Error ? error.message : "Unknown error"); } } return allUnitsMap; } function getAllProvinces(options) { try { const provinces = getProvincesData(); const language = options?.language || "en"; if (language === "en") { return [...provinces]; } if (language === "rw") { return provinces.map((province) => ({ ...province, name: getTranslatedProvinceName(province.name, "rw"), slug: getTranslatedProvinceSlug(province.name, "rw") })); } return [...provinces]; } catch (error) { console.warn("Warning: Could not load provinces data:", error instanceof Error ? error.message : "Unknown error"); return []; } } function getAllDistricts() { try { return [...getDistrictsData()]; } catch (error) { console.warn("Warning: Could not load districts data:", error instanceof Error ? error.message : "Unknown error"); return []; } } function getAllSectors() { try { return [...getSectorsData()]; } catch (error) { console.warn("Warning: Could not load sectors data:", error instanceof Error ? error.message : "Unknown error"); return []; } } function getAllCells() { try { return [...getCellsData()]; } catch (error) { console.warn("Warning: Could not load cells data:", error instanceof Error ? error.message : "Unknown error"); return []; } } function getAllVillages() { try { return [...getVillagesData()]; } catch (error) { console.warn("Warning: Could not load villages data:", error instanceof Error ? error.message : "Unknown error"); return []; } } function getDistrictsByProvince(provinceCode) { return getDistrictsData().filter((district) => district.parentCode === provinceCode); } function getSectorsByDistrict(districtCode) { return getSectorsData().filter((sector) => sector.parentCode === districtCode); } function getCellsBySector(sectorCode) { return getCellsData().filter((cell) => cell.parentCode === sectorCode); } function getVillagesByCell(cellCode) { return getVillagesData().filter((village) => village.parentCode === cellCode); } function getByCode(code) { return getAllUnitsMap().get(code); } function getHierarchy(code) { const unit = getByCode(code); if (!unit) { return []; } const hierarchy = [unit]; let currentUnit = unit; while (currentUnit.parentCode) { const parent = getByCode(currentUnit.parentCode); if (parent) { hierarchy.unshift(parent); currentUnit = parent; } else { break; } } return hierarchy; } function getChildren(parentCode) { return Array.from(getAllUnitsMap().values()).filter((unit) => unit.parentCode === parentCode); } function searchByName(name) { const searchTerm = name.toLowerCase(); return Array.from(getAllUnitsMap().values()).filter( (unit) => unit.name.toLowerCase().includes(searchTerm) ); } function searchBySlug(slug) { const searchTerm = slug.toLowerCase(); return Array.from(getAllUnitsMap().values()).filter( (unit) => unit.slug.toLowerCase().includes(searchTerm) ); } function getByLevel(level) { switch (level) { case "province": return getAllProvinces(); case "district": return getAllDistricts(); case "sector": return getAllSectors(); case "cell": return getAllCells(); case "village": return getAllVillages(); default: return []; } } function getCounts() { const provinces = getProvincesData(); const districts = getDistrictsData(); const sectors = getSectorsData(); const cells = getCellsData(); const villages = getVillagesData(); return { provinces: provinces.length, districts: districts.length, sectors: sectors.length, cells: cells.length, villages: villages.length, total: provinces.length + districts.length + sectors.length + cells.length + villages.length }; } function isValidCode(code) { return getAllUnitsMap().has(code); } function getCodeLevel(code) { if (!isValidCode(code)) return void 0; if (code.startsWith("RW-") && code.length === 5 && code.match(/^RW-\d{2}$/)) return "province"; if (code.startsWith("RW-D-")) return "district"; if (code.startsWith("RW-S-")) return "sector"; if (code.startsWith("RW-C-")) return "cell"; if (code.startsWith("RW-V-")) return "village"; return void 0; } function getSummary() { const provinces = getProvincesData(); const districts = getDistrictsData(); const sectors = getSectorsData(); const cells = getCellsData(); const villages = getVillagesData(); return { provinces: provinces.length, districts: districts.length, sectors: sectors.length, cells: cells.length, villages: villages.length }; } function getFullHierarchy(code) { return getHierarchy(code); } function getDirectChildren(parentCode) { return getChildren(parentCode); } function getSiblings(code) { const unit = getByCode(code); if (!unit || !unit.parentCode) return []; return getChildren(unit.parentCode).filter((sibling) => sibling.code !== code); } function getAllDescendants(parentCode) { const descendants = []; const queue = [parentCode]; while (queue.length > 0) { const currentCode = queue.shift(); const children = getChildren(currentCode); children.forEach((child) => { descendants.push(child); queue.push(child.code); }); } return descendants; } function levenshteinDistance(str1, str2) { const matrix = Array(str2.length + 1).fill(null).map(() => Array(str1.length + 1).fill(null)); for (let i = 0; i <= str1.length; i++) matrix[0][i] = i; for (let j = 0; j <= str2.length; j++) matrix[j][0] = j; for (let j = 1; j <= str2.length; j++) { for (let i = 1; i <= str1.length; i++) { const indicator = str1[i - 1] === str2[j - 1] ? 0 : 1; matrix[j][i] = Math.min( matrix[j][i - 1] + 1, // deletion matrix[j - 1][i] + 1, // insertion matrix[j - 1][i - 1] + indicator // substitution ); } } return matrix[str2.length][str1.length]; } function fuzzySearchByName(query, threshold = 3, limit = 10) { const searchTerm = query.toLowerCase(); const results = []; getAllUnitsMap().forEach((unit) => { const distance = levenshteinDistance(searchTerm, unit.name.toLowerCase()); if (distance <= threshold) { results.push({ unit, score: 1 - distance / Math.max(searchTerm.length, unit.name.length) }); } }); return results.sort((a, b) => b.score - a.score).slice(0, limit); } function searchByPartialCode(partialCode, limit = 20) { const searchTerm = partialCode.toUpperCase(); const results = []; getAllUnitsMap().forEach((unit) => { if (unit.code.includes(searchTerm)) { results.push(unit); } }); return results.slice(0, limit); } function getSuggestions(query, limit = 10) { const searchTerm = query.toLowerCase(); const suggestions = []; getAllUnitsMap().forEach((unit) => { if (unit.name.toLowerCase() === searchTerm) { suggestions.push({ unit, type: "exact", matchField: "name" }); } else if (unit.code.toLowerCase() === searchTerm) { suggestions.push({ unit, type: "exact", matchField: "code" }); } else if (unit.slug.toLowerCase() === searchTerm) { suggestions.push({ unit, type: "exact", matchField: "slug" }); } else if (unit.name.toLowerCase().includes(searchTerm)) { suggestions.push({ unit, type: "partial", matchField: "name" }); } else if (unit.code.toLowerCase().includes(searchTerm)) { suggestions.push({ unit, type: "partial", matchField: "code" }); } else if (unit.slug.toLowerCase().includes(searchTerm)) { suggestions.push({ unit, type: "partial", matchField: "slug" }); } else { const nameDistance = levenshteinDistance(searchTerm, unit.name.toLowerCase()); if (nameDistance <= 3) { suggestions.push({ unit, type: "fuzzy", matchField: "name" }); } } }); const typePriority = { exact: 3, partial: 2, fuzzy: 1 }; return suggestions.sort((a, b) => { const priorityDiff = typePriority[b.type] - typePriority[a.type]; if (priorityDiff !== 0) return priorityDiff; return a.unit.name.localeCompare(b.unit.name); }).slice(0, limit); } function validateParentChildRelationship(parentCode, childCode) { const parent = getByCode(parentCode); const child = getByCode(childCode); if (!parent) { return { isValid: false, error: `Parent code '${parentCode}' not found` }; } if (!child) { return { isValid: false, error: `Child code '${childCode}' not found` }; } const parentLevel = getCodeLevel(parentCode); const childLevel = getCodeLevel(childCode); if (!parentLevel || !childLevel) { return { isValid: false, error: "Invalid code format" }; } if (child.parentCode !== parentCode) { return { isValid: false, error: `Child '${childCode}' does not have parent '${parentCode}'`, parentLevel, childLevel }; } return { isValid: true, parentLevel, childLevel }; } function validateCodeFormat(code) { const level = getCodeLevel(code); if (!level) { return { isValid: false, error: "Invalid code format", format: "Expected: RW-XX, RW-D-XX, RW-S-XXX, RW-C-XXXX, or RW-V-XXXXX" }; } return { isValid: true, level }; } function validateHierarchyIntegrity() { const issues = []; const allUnits = Array.from(getAllUnitsMap().values()); const totalUnits = allUnits.length; let orphanedUnits = 0; let invalidParents = 0; let circularReferences = 0; let missingUnits = 0; allUnits.forEach((unit) => { if (unit.parentCode && !getByCode(unit.parentCode)) { issues.push({ type: "orphaned", message: `Unit '${unit.code}' has missing parent '${unit.parentCode}'`, code: unit.code }); orphanedUnits++; } if (unit.parentCode) { const parent = getByCode(unit.parentCode); if (parent) { const validation = validateParentChildRelationship(unit.parentCode, unit.code); if (!validation.isValid) { issues.push({ type: "invalid_parent", message: validation.error || "Invalid parent-child relationship", code: unit.code }); invalidParents++; } } } }); return { isValid: issues.length === 0, issues, summary: { totalUnits, orphanedUnits, invalidParents, circularReferences, missingUnits } }; } function validateUnitProperties(unit) { const issues = []; if (!unit.code || typeof unit.code !== "string") { issues.push("Missing or invalid code"); } if (!unit.name || typeof unit.name !== "string") { issues.push("Missing or invalid name"); } if (!unit.slug || typeof unit.slug !== "string") { issues.push("Missing or invalid slug"); } const codeValidation = validateCodeFormat(unit.code); if (!codeValidation.isValid) { issues.push(`Invalid code format: ${codeValidation.error}`); } return { isValid: issues.length === 0, issues }; } function getAvailableData() { return { provinces: (() => { try { getProvincesData(); return true; } catch { return false; } })(), districts: (() => { try { getDistrictsData(); return true; } catch { return false; } })(), sectors: (() => { try { getSectorsData(); return true; } catch { return false; } })(), cells: (() => { try { getCellsData(); return true; } catch { return false; } })(), villages: (() => { try { getVillagesData(); return true; } catch { return false; } })() }; } function getModuleDir() { if (typeof __dirname !== "undefined") { return __dirname; } else { return dirname(fileURLToPath(import.meta.url)); } } function getDataPaths(filename) { const moduleDir = getModuleDir(); return [ // Production: dist/data (when running from dist/index.js) join(moduleDir, "data", `${filename}.json.gz`), join(moduleDir, "data", `${filename}.json`), // Development: src/data (when running from src/index.ts) join(moduleDir, "../src/data", `${filename}.json.gz`), join(moduleDir, "../src/data", `${filename}.json`) ]; } function loadGzippedJson(filename) { const paths = getDataPaths(filename); for (const path of paths) { try { if (existsSync(path)) { if (path.endsWith(".gz")) { const gzipped = readFileSync(path); const decompressed = gunzipSync(gzipped); return JSON.parse(decompressed.toString("utf8")); } else { const content = readFileSync(path, "utf8"); return JSON.parse(content); } } } catch { continue; } } throw new Error(`Failed to load ${filename}.json.gz or ${filename}.json from any of the expected locations: ${paths.join(", ")}`); } function loadGzippedJsonSafe(filename) { try { return loadGzippedJson(filename); } catch (error) { console.warn(`Warning: Failed to load ${filename}.json.gz:`, error instanceof Error ? error.message : "Unknown error"); return null; } } // src/index.ts var index_default = { ...helpers_exports, ...types_exports, loadGzippedJson, loadGzippedJsonSafe }; export { AdminLevel, clearDataCache, index_default as default, fuzzySearchByName, getAllCells, getAllDescendants, getAllDistricts, getAllProvinces, getAllSectors, getAllVillages, getAvailableData, getByCode, getByLevel, getCacheStats, getCellsBySector, getChildren, getCodeLevel, getCounts, getDirectChildren, getDistrictsByProvince, getFullHierarchy, getHierarchy, getSectorsByDistrict, getSiblings, getSuggestions, getSummary, getVillagesByCell, isValidCode, loadGzippedJson, loadGzippedJsonSafe, preloadData, searchByName, searchByPartialCode, searchBySlug, validateCodeFormat, validateHierarchyIntegrity, validateParentChildRelationship, validateUnitProperties };