/** * propose_mapping_from_data.ts * Examine un jeu de données GeoJSON et propose des tags à mettre dans une config * comme celle dans mappings/converters/configIRVE.ts * * Exemple de lancement: * npx ts-node propose_mapping_from_data.ts mon_fichier.geojson */ import * as fs from 'fs'; import * as path from 'path'; interface GeoJSONFeature { type: string; geometry: any; properties: Record; } interface GeoJSONData { type: string; features: GeoJSONFeature[]; } /** * Vérifie les arguments de la ligne de commande */ function checkArguments(): string { if (process.argv.length < 3) { console.error("Usage: npx ts-node propose_mapping_from_data.ts "); process.exit(1); } return process.argv[2]; } /** * Charge et parse le fichier GeoJSON */ function loadGeoJSONFile(filePath: string): GeoJSONData { try { const fileContent = fs.readFileSync(filePath, 'utf8'); const data = JSON.parse(fileContent); // Vérifie que le fichier est bien un GeoJSON avec des features if (!data.features || !Array.isArray(data.features)) { console.error("Le fichier ne semble pas être un GeoJSON valide avec des features"); process.exit(1); } return data; } catch (error) { console.error(`Erreur lors du chargement du fichier: ${error}`); process.exit(1); } } /** * Extrait toutes les propriétés uniques des features */ function extractProperties(data: GeoJSONData): Set { const properties: Set = new Set(); for (const feature of data.features) { if (feature.properties) { Object.keys(feature.properties).forEach(key => properties.add(key)); } } return properties; } /** * Compte les occurrences des différentes valeurs pour chaque propriété */ function countPropertyValues(data: GeoJSONData): Record> { const valuesCounts: Record> = {}; // Initialiser le comptage pour chaque propriété for (const feature of data.features) { if (feature.properties) { Object.entries(feature.properties).forEach(([key, value]) => { // Convertir la valeur en chaîne pour pouvoir la compter const stringValue = String(value); // Initialiser le compteur pour cette propriété si nécessaire if (!valuesCounts[key]) { valuesCounts[key] = {}; } // Incrémenter le compteur pour cette valeur valuesCounts[key][stringValue] = (valuesCounts[key][stringValue] || 0) + 1; }); } } return valuesCounts; } /** * Crée les mappings suggérés pour les propriétés */ function createMappingSuggestions(properties: Set): Record { const defaults: Record = {}; properties.forEach(prop => { // Cherche les propriétés liées au web ou au téléphone if (prop.toLowerCase().includes('web') || prop.toLowerCase().includes('site') || prop.toLowerCase().includes('url')) { defaults[prop] = 'contact:website'; } else if (prop.toLowerCase().includes('telephone') || prop.toLowerCase().includes('téléphone') || prop.toLowerCase().includes('phone')) { defaults[prop] = 'contact:phone'; } else if (prop.toLowerCase().includes('nom') || prop.toLowerCase().includes('name')) { defaults[prop] = 'name'; } else if (prop.toLowerCase().includes('adresse') || prop.toLowerCase().includes('address')) { defaults[prop] = 'addr:full'; } else if (prop.toLowerCase().includes('id') || prop.toLowerCase().includes('ref')) { defaults[prop] = 'ref'; } else { defaults[prop] = ''; } }); return defaults; } /** * Affiche les statistiques des valeurs pour chaque propriété */ function displayPropertyValueStats(valuesCounts: Record>): void { console.log('\n=== Statistiques des valeurs par propriété ==='); Object.entries(valuesCounts).forEach(([prop, values]) => { const totalValues = Object.values(values).reduce((sum, count) => sum + count, 0); const uniqueValues = Object.keys(values).length; console.log(`\nPropriété: ${prop}`); console.log(`- Total d'occurrences: ${totalValues}`); console.log(`- Valeurs uniques: ${uniqueValues}`); // Si trop de valeurs uniques, n'afficher que les plus fréquentes if (uniqueValues > 10) { console.log('- Top 5 des valeurs les plus fréquentes:'); const sortedValues = Object.entries(values) .sort((a, b) => b[1] - a[1]) .slice(0, 5); sortedValues.forEach(([value, count]) => { // Tronquer les valeurs très longues const displayValue = value.length > 50 ? value.substring(0, 47) + '...' : value; console.log(` "${displayValue}": ${count} occurrences (${Math.round(count / totalValues * 100)}%)`); }); console.log(` ... et ${uniqueValues - 5} autres valeurs`); } else { console.log('- Toutes les valeurs:'); Object.entries(values) .sort((a, b) => b[1] - a[1]) .forEach(([value, count]) => { // Tronquer les valeurs très longues const displayValue = value.length > 50 ? value.substring(0, 47) + '...' : value; console.log(` "${displayValue}": ${count} occurrences (${Math.round(count / totalValues * 100)}%)`); }); } }); console.log('\n=== Fin des statistiques ===\n'); } /** * Fonction principale */ function main(): void { const filePath = checkArguments(); const data = loadGeoJSONFile(filePath); console.log(`\nFichier GeoJSON chargé: ${filePath}`); console.log(`Nombre de features: ${data.features.length}`); const properties = extractProperties(data); const valuesCounts = countPropertyValues(data); displayPropertyValueStats(valuesCounts); const mappingSuggestions = createMappingSuggestions(properties); console.log('Suggestions de mapping OSM:'); console.log(JSON.stringify(mappingSuggestions, null, 2)); console.log(`Nombre de propriétés uniques: ${properties.size}`); } // Exécution du programme main();