112 lines
9.5 KiB
JavaScript
112 lines
9.5 KiB
JavaScript
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
|
|
import { resolve, join, dirname } from 'path';
|
|
import { fileURLToPath } from 'url';
|
|
const _filename = fileURLToPath(import.meta.url);
|
|
const _dirname = dirname(_filename);
|
|
/**
|
|
* Returns a list of directories to search for GADM cache files, in order of priority.
|
|
*/
|
|
export function getCacheDirs() {
|
|
const dirs = [];
|
|
if (process.env.GADM_CACHE)
|
|
dirs.push(resolve(process.env.GADM_CACHE));
|
|
dirs.push(resolve(process.cwd(), 'cache/gadm'));
|
|
dirs.push(resolve(_dirname, '../cache/gadm'));
|
|
return [...new Set(dirs)];
|
|
}
|
|
/**
|
|
* Normalizes a value into a safe filename-friendly string.
|
|
*/
|
|
export function safeId(id) {
|
|
return id.replace(/[^a-zA-Z0-9\.\-_]/g, '_').substring(0, 50);
|
|
}
|
|
/**
|
|
* Read from the GADM JSON cache.
|
|
*/
|
|
export async function readGadmCache(key, countryCode, externalCache) {
|
|
if (externalCache) {
|
|
try {
|
|
const cached = await externalCache.get(key);
|
|
if (cached)
|
|
return cached;
|
|
}
|
|
catch { /* ignore */ }
|
|
}
|
|
const dirs = getCacheDirs();
|
|
for (const dir of dirs) {
|
|
const paths = [];
|
|
if (countryCode) {
|
|
paths.push(join(dir, countryCode, `${key}.json`));
|
|
}
|
|
paths.push(join(dir, `${key}.json`));
|
|
// Special handling for boundary fallbacks (C++ parity)
|
|
if (key.startsWith('boundary_') && countryCode) {
|
|
const parts = key.split('_');
|
|
const level = parts[parts.length - 1];
|
|
if (level) {
|
|
paths.push(join(dir, countryCode, `boundary_${countryCode}_${level}.json`));
|
|
paths.push(join(dir, `boundary_${countryCode}_${level}.json`));
|
|
}
|
|
}
|
|
for (const p of paths) {
|
|
if (existsSync(p)) {
|
|
try {
|
|
const raw = JSON.parse(readFileSync(p, 'utf-8'));
|
|
// Filter C++ full-country file if we were looking for a specific sub-region
|
|
if (p.includes(`boundary_${countryCode}_`) && !p.includes(key) && raw.features) {
|
|
const originalId = key.replace('boundary_', '').replace(/_\d+$/, '');
|
|
const gidPrefix = originalId.includes('.') ? originalId + '.' : null;
|
|
if (gidPrefix) {
|
|
const filteredFeatures = raw.features.filter((f) => f.code && f.code.startsWith(originalId) // using originalId directly covers both exact and sub-regions
|
|
);
|
|
if (filteredFeatures.length === 0)
|
|
continue;
|
|
// Rehydrate the boundary format
|
|
return {
|
|
type: 'FeatureCollection',
|
|
features: filteredFeatures.map((f) => {
|
|
const { geometry, code, name, ...enrichment } = f;
|
|
return {
|
|
type: 'Feature',
|
|
properties: { name, code, ...enrichment },
|
|
geometry
|
|
};
|
|
})
|
|
};
|
|
}
|
|
}
|
|
return raw;
|
|
}
|
|
catch (e) {
|
|
console.warn(`[gadm-cache] Failed to read cache from ${p}:`, e);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
/**
|
|
* Write to the primary GADM JSON cache.
|
|
*/
|
|
export async function writeGadmCache(key, data, countryCode, externalCache) {
|
|
if (externalCache) {
|
|
try {
|
|
await externalCache.set(key, data);
|
|
return;
|
|
}
|
|
catch { /* ignore */ }
|
|
}
|
|
const primaryDir = getCacheDirs()[0];
|
|
const targetDir = countryCode ? join(primaryDir, countryCode) : primaryDir;
|
|
const targetFile = join(targetDir, `${key}.json`);
|
|
try {
|
|
if (!existsSync(targetDir)) {
|
|
mkdirSync(targetDir, { recursive: true });
|
|
}
|
|
writeFileSync(targetFile, JSON.stringify(data));
|
|
}
|
|
catch (e) {
|
|
console.warn(`[gadm-cache] Failed to write cache to ${targetFile}:`, e);
|
|
}
|
|
}
|
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2FjaGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvY2FjaGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxZQUFZLEVBQUUsYUFBYSxFQUFFLFNBQVMsRUFBRSxNQUFNLElBQUksQ0FBQztBQUN4RSxPQUFPLEVBQUUsT0FBTyxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDOUMsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLEtBQUssQ0FBQztBQUVwQyxNQUFNLFNBQVMsR0FBRyxhQUFhLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztBQUNqRCxNQUFNLFFBQVEsR0FBRyxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUM7QUFPcEM7O0dBRUc7QUFDSCxNQUFNLFVBQVUsWUFBWTtJQUN4QixNQUFNLElBQUksR0FBRyxFQUFFLENBQUM7SUFDaEIsSUFBSSxPQUFPLENBQUMsR0FBRyxDQUFDLFVBQVU7UUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUM7SUFDdkUsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLEdBQUcsRUFBRSxFQUFFLFlBQVksQ0FBQyxDQUFDLENBQUM7SUFDaEQsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsUUFBUSxFQUFFLGVBQWUsQ0FBQyxDQUFDLENBQUM7SUFDOUMsT0FBTyxDQUFDLEdBQUcsSUFBSSxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztBQUM5QixDQUFDO0FBRUQ7O0dBRUc7QUFDSCxNQUFNLFVBQVUsTUFBTSxDQUFDLEVBQVU7SUFDN0IsT0FBTyxFQUFFLENBQUMsT0FBTyxDQUFDLG9CQUFvQixFQUFFLEdBQUcsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFD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
|