add tests and failsafe for values true and false

This commit is contained in:
Tykayn 2025-05-13 23:59:21 +02:00 committed by tykayn
parent 5b0271716c
commit cb6075fc61
10 changed files with 376 additions and 230 deletions

View file

@ -38,7 +38,15 @@ let listOfBooleanKeys = [
"gratuit", "gratuit",
"paiement_acte", "paiement_acte",
"paiement_cb", "paiement_cb",
"cable_t2_attache" "cable_t2_attache",
"paiement_acte",
"paiement_cb",
"cable_t2_attache",
"socket:typee",
"socket:type2_combo",
"socket:chademo",
"socket:type2",
"socket:type2_cable",
] ]
let irve_max_output = 401 // limite de kW de puissance pour une borne de recharge publique let irve_max_output = 401 // limite de kW de puissance pour une borne de recharge publique

View file

@ -12,8 +12,13 @@
* --outname=nom_fichier : Alias pour --output-file * --outname=nom_fichier : Alias pour --output-file
* --testingConfig : Active le mode test avec la configuration mappingTest * --testingConfig : Active le mode test avec la configuration mappingTest
*/ */
import fetch from 'node-fetch';
import * as fs from 'fs'
import mapping_engine from './mappings/engine'
import MappingConfigType, { BoundingBoxCoordinatesType, FeatureCollection } from "./mappings/mapping-config.type";
import utils from './mappings/utils'
import config from './config'
/** /**
* Mesure de l'utilisation de la RAM * Mesure de l'utilisation de la RAM
*/ */
@ -42,12 +47,6 @@ process.on('exit', () => {
}); });
import * as fs from 'fs'
import mapping_engine from './mappings/engine'
import MappingConfigType, { BoundingBoxCoordinatesType, FeatureCollection } from "./mappings/mapping-config.type";
import utils from './mappings/utils'
import config from './config'
@ -125,29 +124,6 @@ if (mini_arguments['wget']) {
async function replaceFile(sourceFilePathGeoJson: string, url: string) {
const response = await fetch(url)
if (!response.ok) {
throw new Error(`Erreur lors du téléchargement: ${response.status} ${response.statusText}`)
}
// afficher la taille du fichier téléchargé
const contentLength = response.headers.get('content-length')
const data = await response.text()
if (contentLength) {
const sizeInMB = (parseInt(contentLength) / (1024 * 1024)).toFixed(2)
console.log(`Taille du fichier téléchargé: ${sizeInMB} Mo`)
} else {
// mesurer la taille des données
const sizeInMB = (data.length / (1024 * 1024)).toFixed(2)
console.log(`Taille des données: ${sizeInMB} Mo`)
}
fs.writeFileSync(sourceFilePathGeoJson, data)
console.log('fichier téléchargé avec succès:', sourceFilePathGeoJson)
}
let filterZipCode = new RegExp(`^${filterDepartment}`) let filterZipCode = new RegExp(`^${filterDepartment}`)
let filterZipCodeAdresse = new RegExp(` ${filterDepartment}`) let filterZipCodeAdresse = new RegExp(` ${filterDepartment}`)
@ -281,7 +257,6 @@ function convertDataFromSource(sourceFilePath: string, mapping: MappingConfigTyp
let remove_original_key = false; let remove_original_key = false;
// fix des jeux de données qui ne sont pas des geojson // fix des jeux de données qui ne sont pas des geojson
let properties_list: any = [] let properties_list: any = []
if (feature_point.geo_point_2d) { if (feature_point.geo_point_2d) {
@ -362,8 +337,6 @@ function convertDataFromSource(sourceFilePath: string, mapping: MappingConfigTyp
debugLog('pas de filtre sur les coordonnées bounding box') debugLog('pas de filtre sur les coordonnées bounding box')
} }
// TODO add filter offset max
// filter points depending on zipcode // filter points depending on zipcode
if (regex_filter_test_result) { if (regex_filter_test_result) {
feature_points_after_filter.push(feature_point) feature_points_after_filter.push(feature_point)
@ -385,13 +358,9 @@ function convertDataFromSource(sourceFilePath: string, mapping: MappingConfigTyp
debugLog('convert : work on 1 point') debugLog('convert : work on 1 point')
let mapped_point: any = {} let mapped_point: any = {}
if (use_mapping_engine) { // if (use_mapping_engine) {
mapped_point = Mapping_engine.mapElementFromConf(feature_point) mapped_point = Mapping_engine.mapElementFromConf(feature_point)
debugLog('mapped_point', mapped_point) debugLog('mapped_point', mapped_point)
} else {
debugLog('convert :using simple converter on feature point', feature_point)
mapped_point = mapElementFromConfSimple(feature_point, mapping)
}
if (mapped_point) { if (mapped_point) {
converted_geo_json.features.push(mapped_point) converted_geo_json.features.push(mapped_point)
debugLog('convert : added one point to converted_geo_json') debugLog('convert : added one point to converted_geo_json')
@ -435,104 +404,50 @@ function convertDataFromSource(sourceFilePath: string, mapping: MappingConfigTyp
}) })
} }
/**
* retuns the converted element from mapping config if present, null otherwise
*/
function mapElementFromConfSimple(featurePoint: any, mappingConfig: any) {
let mappingKeys = Object.keys(mappingConfig)
let featurePointPropertiesKeys = Object.keys(featurePoint.properties)
debugLog('keys', mappingKeys, featurePointPropertiesKeys)
let newProperties: any = defaultPropertiesOfPoint
// reinit properties of current point
let basePoint = Object.create(featurePoint)
basePoint.type = featurePoint.type
basePoint.geometry = featurePoint.geometry
basePoint.properties = newProperties
// apply new properties if found in mapping config
featurePointPropertiesKeys.forEach((pointKeyName: string) => {
if (mappingKeys.indexOf(pointKeyName) !== -1) {
// debugLog('found element', pointKeyName, '=>', mappingConfig[pointKeyName], 'value : ', featurePoint.properties[pointKeyName])
let convertedValue: any = ''
if (utils.isBooleanKey(pointKeyName)) {
let copyOfValue: any = '' + featurePoint.properties[pointKeyName]
if (typeof copyOfValue === typeof Object && copyOfValue.key_converted) {
copyOfValue = copyOfValue.key_converted
}
convertedValue = copyOfValue.toLowerCase() == 'true' ? 'yes' : 'no'
} else {
convertedValue = featurePoint.properties[pointKeyName]
}
if (convertedValue) {
let convertedKey: any = mappingConfig[pointKeyName]
newProperties[convertedKey] = convertedValue
}
}
})
debugLog('basePoint', basePoint)
return basePoint
}
function setMappingConfigFromName(engine_conf_choice: string) { function setMappingConfigFromName(engine_conf_choice: string) {
console.log('------- geojson source', sourceFilePathGeoJson) console.log('------- geojson source', sourceFilePathGeoJson)
console.log('------- conversion engine', engine_conf_choice) console.log('------- conversion engine', engine_conf_choice)
if (use_mapping_engine) {
debugLog(' - using mapping engine')
debugLog(' - pointCounterMax', pointCounterMax)
if (osmoseFormat) { debugLog(' - pointCounterMax', pointCounterMax)
Mapping_engine.setConfig(config.allowed_configs.mappingConfigIRVEFromOsmose)
} else { if (osmoseFormat) {
Mapping_engine.setConfig(config.allowed_configs.mappingConfigIRVEFromOsmose)
if (engine_conf_choice !== default_engine_conf_choice && Object.keys(config.allowed_configs).indexOf("mappingIssy2Roues") !== -1) {
Mapping_engine.setConfig(config.allowed_configs[engine_conf_choice])
} else {
console.error('mauvais paramètre de Mapping_engine: ' + engine_conf_choice, '.\n Veuillez en sélectionner un parmi ceux autorisés avec l option --engine-config=MaConfigQuiVaBien parmi ceux ci :', Object.keys(config.allowed_configs))
return
}
}
let currentMappingConfig = Mapping_engine.getConfig() as MappingConfigType;
// si on a wget et que le mapping config a une source, on récupère la source définie dans le mapping config
if (wget) {
// console.log('wget enabled', currentMappingConfig.source)
// let geojson_path = currentMappingConfig.source.geojson_path
// let filename = sourceFilePathGeoJson.split('/').pop()
// télécharger le fichier source depuis l'url du mapping config
if (currentMappingConfig.source.geojson_path) {
console.log('téléchargement du fichier source depuis', currentMappingConfig.source.geojson_path)
console.log('la documentation de la ressource est disponible sur ', currentMappingConfig.source.url)
try {
replaceFile(sourceFilePathGeoJson, currentMappingConfig.source.geojson_path)
convertDataFromSource(sourceFilePathGeoJson, currentMappingConfig, pointCounterMax, boundingBoxCoordinates)
} catch (error) {
console.error('Erreur lors du téléchargement du fichier source:', error)
process.exit(1)
}
} else {
console.log('wget enabled, but no geojson_path found in mapping config', currentMappingConfig.source)
}
} else {
convertDataFromSource(sourceFilePathGeoJson, currentMappingConfig, pointCounterMax, boundingBoxCoordinates)
}
} else { } else {
console.log(' ------ on utilise mappingConfigIRVE_simple') if (engine_conf_choice !== default_engine_conf_choice && Object.keys(config.allowed_configs).indexOf("mappingIssy2Roues") !== -1) {
let mappingConfigIRVE = config.allowed_configs.mappingConfigIRVE_simple Mapping_engine.setConfig(config.allowed_configs[engine_conf_choice])
convertDataFromSource(sourceFilePathGeoJson, mappingConfigIRVE, pointCounterMax, boundingBoxCoordinates) } else {
console.error('mauvais paramètre de Mapping_engine: ' + engine_conf_choice, '.\n Veuillez en sélectionner un parmi ceux autorisés avec l option --engine-config=MaConfigQuiVaBien parmi ceux ci :', Object.keys(config.allowed_configs))
return
}
}
let currentMappingConfig = Mapping_engine.getConfig() as MappingConfigType;
// si on a wget et que le mapping config a une source, on récupère la source définie dans le mapping config
if (wget) {
console.log('wget enabled')
// télécharger le fichier source depuis l'url du mapping config
if (currentMappingConfig.source.geojson_path) {
console.log('téléchargement du fichier source depuis', currentMappingConfig.source.geojson_path)
console.log('la documentation de la ressource est disponible sur ', currentMappingConfig.source.url)
try {
utils.replaceFile(sourceFilePathGeoJson, currentMappingConfig.source.geojson_path)
convertDataFromSource(sourceFilePathGeoJson, currentMappingConfig, pointCounterMax, boundingBoxCoordinates)
} catch (error) {
console.error('Erreur lors du téléchargement du fichier source:', error)
process.exit(1)
}
} else {
console.log('wget enabled, but no geojson_path found in mapping config', currentMappingConfig.source)
}
}
else {
convertDataFromSource(sourceFilePathGeoJson, currentMappingConfig, pointCounterMax, boundingBoxCoordinates)
} }
} }

152
docs/website/index.html Normal file
View file

@ -0,0 +1,152 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Wololo - Convertisseur de données vers OSM</title>
<style>
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
line-height: 1.6;
max-width: 1000px;
margin: 0 auto;
padding: 20px;
background-color: #f5f5f5;
}
.container {
background-color: white;
padding: 30px;
border-radius: 10px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
}
h1 {
color: #2c3e50;
text-align: center;
margin-bottom: 30px;
}
.mapping-config {
margin: 20px 0;
padding: 20px;
border: 1px solid #e0e0e0;
border-radius: 5px;
}
.mapping-config h2 {
color: #3498db;
display: flex;
align-items: center;
gap: 10px;
}
.mapping-config i {
font-size: 24px;
}
.contact {
text-align: center;
margin-top: 40px;
padding: 20px;
background-color: #f8f9fa;
border-radius: 5px;
}
.sources {
margin: 30px 0;
}
a {
color: #3498db;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
</style>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
</head>
<body>
<div class="container">
<h1>🌍 Wololo - Convertisseur de données vers OpenStreetMap</h1>
<p>Wololo est un outil de conversion de données qui permet de transformer différents formats de données en tags
OpenStreetMap. Il facilite l'import de données provenant de diverses sources vers la base de données OSM.</p>
<h2><i class="fas fa-cogs"></i> Configurations de mapping disponibles</h2>
<div class="mapping-config">
<h2>⚡ IRVE (Bornes de recharge)</h2>
<p>Configuration pour la conversion des données de bornes de recharge électrique.</p>
</div>
<div class="mapping-config">
<h2>🚲 Stationnements vélos</h2>
<p>Configuration pour la conversion des données de stationnements vélos.</p>
</div>
<div class="mapping-config">
<h2>🗄️ Osmose</h2>
<p>Configuration pour la conversion des données issues d'Osmose.</p>
</div>
<div class="mapping-config">
<h2>🏛️ Musées</h2>
<p>Configuration pour la conversion des données de musées et lieux culturels.</p>
</div>
<div class="mapping-config">
<h2>🪧 Plaques commémoratives</h2>
<p>Configuration pour la conversion des données de plaques commémoratives et historiques.</p>
</div>
<div class="mapping-config">
<h2>🌳 Arbres</h2>
<p>Configuration pour la conversion des données d'arbres et d'espaces verts.</p>
</div>
<div class="mapping-config">
<h2>🚦 Panneaux de signalisation routière</h2>
<p>Configuration pour la conversion des données de panneaux de signalisation et de sécurité routière.</p>
</div>
<div class="mapping-config">
<h2>♻️ Points d'apport volontaire</h2>
<p>Configuration pour la conversion des données de points de collecte et de recyclage.</p>
</div>
<div class="mapping-config">
<h2>🦸 Demandez Angela</h2>
<p>Configuration pour la conversion des lieux partenaires du dispositif "Demandez Angela" contre le harcèlement.
</p>
</div>
<div class="mapping-config">
<h2>🎥 Appareils de surveillance</h2>
<p>Configuration pour la conversion des données de caméras et dispositifs de surveillance.</p>
</div>
<div class="mapping-config">
<h2>🏥 Lieux de soin</h2>
<p>Configuration pour la conversion des données de centres de santé, hôpitaux et lieux de soin.</p>
</div>
<div class="sources">
<h2><i class="fas fa-code-branch"></i> Sources du projet</h2>
<p>Le code source de Wololo est disponible sur GitHub : <a href="https://github.com/osm-fr/osmose-to-osm"
target="_blank">osmose-to-osm</a></p>
</div>
<div class="contact">
<h2><i class="fas fa-envelope"></i> Contact</h2>
<p>Pour toute question ou suggestion, n'hésitez pas à me contacter :</p>
<a href="mailto:contact+wololo@cipherbliss.com">contact+wololo@cipherbliss.com</a>
</div>
</div>
</body>
</html>

View file

@ -29,7 +29,7 @@ const MappingIRVE: MappingConfigType = {
enable_properties_filter: true, enable_properties_filter: true,
// filter_points_older_than_year: 2024, // filter_points_older_than_year: 2024,
// filter_points_by_year_property: 'date_mise_en_service', // filter_points_by_year_property: 'date_mise_en_service',
// filter_points_lesser_than_NkW: 50 // ne pas sortir les points qui ont moins de ce nombre de puissance nominale // filter_points_lesser_than_NkW: 20 // ne pas sortir les points qui ont moins de ce nombre de puissance nominale
// add only geojson points who are found having this regex in the zipcode properties // add only geojson points who are found having this regex in the zipcode properties
// properties: { // properties: {
// consolidated_code_postal: '^[76|27]' // consolidated_code_postal: '^[76|27]'
@ -50,7 +50,12 @@ const MappingIRVE: MappingConfigType = {
"gratuit", "gratuit",
"paiement_acte", "paiement_acte",
"paiement_cb", "paiement_cb",
"cable_t2_attache" "cable_t2_attache",
"socket:typee",
"socket:type2_combo",
"socket:chademo",
"socket:type2",
"socket:type2_cable",
], ],
tags: { tags: {
// ******* nombres // ******* nombres
@ -90,12 +95,12 @@ const MappingIRVE: MappingConfigType = {
paiement_acte: paiement_acte:
{ {
key_converted: 'authentication:none', key_converted: 'authentication:none',
convert_to_boolean_value: true, // convertit en yes ou no convert_to_boolean_value: true,
}, },
reservation: { reservation: {
key_converted: 'reservation', key_converted: 'reservation',
convert_to_boolean_value: true, // convertit en yes ou no convert_to_boolean_value: true,
}, },
// observations: 'note', // observations: 'note',
nom_station: 'description', nom_station: 'description',
@ -116,27 +121,21 @@ const MappingIRVE: MappingConfigType = {
, ,
prise_type_ef: { prise_type_ef: {
key_converted: 'socket:typee', key_converted: 'socket:typee',
ignore_if_falsy: true, keep_only_truthy_yes_or_no_without_enum: true,
convert_to_boolean_value: true,
keep_only_max_in_enum: true,
}, },
prise_type_2: { prise_type_2: {
key_converted: 'socket:type2', key_converted: 'socket:type2',
ignore_if_falsy: true, // on convertit en yes ou no, sans enum, et on ne garde que si on obtient "yes"
convert_to_boolean_value: true, keep_only_truthy_yes_or_no_without_enum: true,
keep_only_max_in_enum: true,
}, },
prise_type_combo_ccs: { prise_type_combo_ccs: {
key_converted: 'socket:type2_combo', key_converted: 'socket:type2_combo',
ignore_if_falsy: true, keep_only_truthy_yes_or_no_without_enum: true,
convert_to_boolean_value: true,
keep_only_max_in_enum: true,
}, },
prise_type_chademo: { prise_type_chademo: {
key_converted: 'socket:chademo', key_converted: 'socket:chademo',
ignore_if_falsy: true, keep_only_truthy_yes_or_no_without_enum: true,
convert_to_boolean_value: true,
keep_only_max_in_enum: true,
}, },
// ******** champs plus complexes // ******** champs plus complexes
horaires: 'opening_hours', // déjà au bon format, enfin, en général. vérifier avec le validateur josm. horaires: 'opening_hours', // déjà au bon format, enfin, en général. vérifier avec le validateur josm.
@ -149,9 +148,7 @@ const MappingIRVE: MappingConfigType = {
accessibilite_pmr: { accessibilite_pmr: {
key_converted: "wheelchair", key_converted: "wheelchair",
conditional_values: { conditional_values: {
"Accessibilité inconnue": {
ignore_this_data: true, // ne pas ajouter de tag si la valeur est égale à Accessibilité inconnue.
},
"Accessible mais non réservé PMR": { "Accessible mais non réservé PMR": {
value_converted: "yes" value_converted: "yes"
}, },

View file

@ -53,15 +53,6 @@ export default class MappingEngine {
return geoJSONConvertedPoint return geoJSONConvertedPoint
} }
/**
* TODO convert to mapping config property to transform_truthy
* @param pointKeyName
* @returns {boolean}
*/
isBooleanKey(pointKeyName: string): boolean {
return config.listOfBooleanKeys.indexOf(pointKeyName) !== -1
}
/** /**
* filter: reduce number of features * filter: reduce number of features
@ -174,8 +165,6 @@ export default class MappingEngine {
} }
// console.log('mapElementFromConf: ============= keys mappingKeys:', featurePointPropertiesKeys.length, mappingKeys)
let newProperties = { ...this.mapping_config.default_properties_of_point } let newProperties = { ...this.mapping_config.default_properties_of_point }
@ -185,23 +174,17 @@ export default class MappingEngine {
basePoint.geometry = featurePoint.geometry basePoint.geometry = featurePoint.geometry
basePoint.properties = { ...this.mapping_config.default_properties_of_point } basePoint.properties = { ...this.mapping_config.default_properties_of_point }
// apply new properties if found in mapping config // apply new properties if found in mapping config
featurePointPropertiesKeys.forEach(pointKeyName => { featurePointPropertiesKeys.forEach(pointKeyName => {
// if (featurePointPropertiesKeys.indexOf(pointKeyName) !== -1) {
this.convertProperty({ this.convertProperty({
pointKeyName, mappingKeys, featurePoint, newProperties pointKeyName, mappingKeys, featurePoint, newProperties
}) })
// }
}) })
basePoint.properties = newProperties basePoint.properties = newProperties
// debugLog('mapElementFromConf: basePoint', basePoint)
return basePoint return basePoint
} }
@ -245,7 +228,7 @@ export default class MappingEngine {
let remove_original_key = false; let remove_original_key = false;
debugLog('tags_to_ignore_if_value_is', this.mapping_config.tags_to_ignore_if_value_is) debugLog('tags_to_ignore_if_value_is', this.mapping_config.tags_to_ignore_if_value_is)
if (this.mapping_config.tags_to_ignore_if_value_is && this.mapping_config.tags_to_ignore_if_value_is.length && this.mapping_config.tags_to_ignore_if_value_is?.indexOf(originalValue) !== -1) { if (this.mapping_config.tags_to_ignore_if_value_is && this.mapping_config.tags_to_ignore_if_value_is.length && this.mapping_config.tags_to_ignore_if_value_is?.indexOf(originalValue) !== -1) {
debugLog('(x) => ignore', originalValue, ' in ', pointKeyName) console.log('(x) => ignore', originalValue, ' in ', pointKeyName)
remove_original_key = true; remove_original_key = true;
} }
@ -353,13 +336,44 @@ export default class MappingEngine {
/** /**
* conversion booléenne * conversion booléenne
*/ */
if (mappingValueObject.keep_only_truthy_yes_or_no_without_enum) {
if (originalValue.indexOf(";") === -1 && custom_utils.truthyValues.indexOf(originalValue) !== -1) {
convertedValue = 'yes'
} else {
remove_original_key = true
}
}
if (mappingValueObject.convert_to_boolean_value) { if (mappingValueObject.convert_to_boolean_value) {
debugLog('convertProperty: is boolean_value_conversion')
// debugLog('convertProperty: is boolean_value_conversion')
convertedValue = custom_utils.convertToYesOrNo(originalValue) convertedValue = custom_utils.convertToYesOrNo(originalValue)
// if (pointKeyName === 'prise_type_2') {
// console.log('convertProperty: is boolean_value_conversion', pointKeyName, keyConvertedFromMapping, originalValue, '=>', convertedValue)
// newProperties[keyConvertedFromMapping] = convertedValue
// }
// console.log('convertProperty: is boolean_value_conversion', pointKeyName, keyConvertedFromMapping, originalValue, '=>', convertedValue)
if (configObject.ignore_if_falsy && !custom_utils.convertToBoolean(originalValue)) {
return newProperties
}
if (configObject.ignore_if_truthy && custom_utils.convertToBoolean(originalValue)) {
return newProperties
}
} else { } else {
debugLog('convertProperty: is NOT having boolean_value_conversion', mappingValueObject) debugLog('convertProperty: is NOT having boolean_value_conversion', mappingValueObject)
} }
if (configObject.invert_boolean_value) {
convertedValue = !custom_utils.convertToBoolean(originalValue) ? 'yes' : 'no'
debugLog('invert boolean', convertedValue, originalValue)
}
// gestion des puissances de bornes // gestion des puissances de bornes
@ -381,13 +395,10 @@ export default class MappingEngine {
}) })
} }
if (configObject.invert_boolean_value) {
convertedValue = !custom_utils.convertToBoolean(originalValue) ? 'yes' : 'no'
debugLog('invert boolean', convertedValue, originalValue)
}
if (configObject.remove_stars) { if (configObject.remove_stars) {
// Remplace toutes les occurrences de * de manière greedy // Remplace toutes les occurrences de * de manière greedy
convertedValue = originalValue.replaceAll('*', '') convertedValue = originalValue.replace('*', '')
debugLog('remove_stars', convertedValue, originalValue) debugLog('remove_stars', convertedValue, originalValue)
} }
@ -409,7 +420,9 @@ export default class MappingEngine {
if (configObject.remove_original_key) { if (configObject.remove_original_key) {
remove_original_key = true remove_original_key = true
} }
if (configObject.ignore_if_falsy && !custom_utils.convertToBoolean(originalValue)) {
if (configObject.ignore_if_falsy && (false === custom_utils.convertToBoolean(originalValue))) {
remove_original_key = true remove_original_key = true
} }
if (configObject.ignore_if_truthy && custom_utils.convertToBoolean(originalValue)) { if (configObject.ignore_if_truthy && custom_utils.convertToBoolean(originalValue)) {
@ -423,11 +436,16 @@ export default class MappingEngine {
} }
let conditionalConfig: any = '' let conditionalConfig: any = ''
// console.log('/////////// configObject.ignore_if_falsy', configObject.ignore_if_falsy, "converti en booléen", custom_utils.convertToBoolean(originalValue), "remove?", remove_original_key)
/** /**
* config pour une clé * config pour une clé
* nous pouvons renseigner une string ou un objet décrivant les transformations à réaliser * nous pouvons renseigner une string ou un objet décrivant les transformations à réaliser
*/ */
if (configObject.conditional_values) {
if (!remove_original_key && configObject.conditional_values) {
// convert numbers from json to string to compare them correctly // convert numbers from json to string to compare them correctly
originalValue = '' + originalValue originalValue = '' + originalValue
@ -440,13 +458,14 @@ export default class MappingEngine {
// sauf si on a activé l'option allow_unspecified_conditional_values dans la MappingConfigType // sauf si on a activé l'option allow_unspecified_conditional_values dans la MappingConfigType
if (!this.mapping_config.allow_unspecified_conditional_values && foundValue === -1) { if (!this.mapping_config.allow_unspecified_conditional_values && foundValue === -1) {
// console.log('(x) => ignore', originalValue, ' in ', pointKeyName) // console.log('!!!!!!!!!! (x) => ignore', originalValue, ' in ', pointKeyName, 'on vire ', keyConvertedFromMapping)
remove_original_key = true remove_original_key = true
} }
if (!remove_original_key) { if (!remove_original_key) {
// console.log('-------- on garde la valeur', originalValue, ' dans ', pointKeyName)
if (foundValue !== -1) { if (foundValue !== -1) {
debugLog('found condition', foundValue) debugLog('found condition', foundValue)
@ -462,48 +481,47 @@ export default class MappingEngine {
remove_original_key = true; remove_original_key = true;
} }
let lowerKey = (originalValue + '').toLowerCase()
if (conditionalConfig.truthy_value) { if (conditionalConfig.truthy_value) {
// convertir la valeur, si elle est truthy, la transformer en ce que donne la propriété truthy_value // convertir la valeur, si elle est truthy, la transformer en ce que donne la propriété truthy_value
// exemple: le jeu de données dit que la colonne cable_t2_attache vaut "True", mais on veut le convertir en "1". // exemple: le jeu de données dit que la colonne cable_t2_attache vaut "True", mais on veut le convertir en "1".
// on met donc truthy_value: '1' // on met donc truthy_value: '1'
if (custom_utils.truthyValues.indexOf(originalValue) !== -1) { if (custom_utils.truthyValues.indexOf(lowerKey) !== -1) {
convertedValue = conditionalConfig.truthy_value convertedValue = conditionalConfig.truthy_value
} }
} }
if (conditionalConfig.falsy_value) { if (conditionalConfig.falsy_value) {
if (custom_utils.falsyValues.indexOf(originalValue) !== -1) { if (custom_utils.falsyValues.indexOf(lowerKey) !== -1) {
convertedValue = conditionalConfig.falsy_value convertedValue = conditionalConfig.falsy_value
} }
} }
// use the value converted // use the value converted
else if (conditionalConfig.value_converted) { if (conditionalConfig.value_converted) {
convertedValue = conditionalConfig.value_converted convertedValue = conditionalConfig.value_converted
} }
} }
// console.log('convertedValue =>', convertedValue)
if (conditionalConfig?.tags_to_add) {
debugLog('on ajoute des tags', conditionalConfig.tags_to_add)
// on peut définir un ensemble de tags à rajouter
let tagKeys = Object.keys(conditionalConfig.tags_to_add)
debugLog('conditionnalConfig.tags_to_add', conditionalConfig.tags_to_add)
tagKeys.forEach((index: any) => {
debugLog('key', index)
debugLog('value', conditionalConfig.tags_to_add[index])
newProperties[index] = conditionalConfig.tags_to_add[index]
})
}
}
}
// console.log('convertedValue =>', convertedValue)
if (conditionalConfig?.tags_to_add) {
debugLog('on ajoute des tags', conditionalConfig.tags_to_add)
// on peut définir un ensemble de tags à rajouter
let tagKeys = Object.keys(conditionalConfig.tags_to_add)
debugLog('conditionnalConfig.tags_to_add', conditionalConfig.tags_to_add)
tagKeys.forEach((index: any) => {
debugLog('key', index)
debugLog('value', conditionalConfig.tags_to_add[index])
newProperties[index] = conditionalConfig.tags_to_add[index]
})
}
} else { } else {
debugLog('no conditional values', configObject) debugLog('no conditional values', configObject)
} }
// console.log('conditionnalConfig', conditionnalConfig, convertedValue)
debugLog('convertProperty: convertedValue ==========> {', newKey, ':', convertedValue, '}') debugLog('convertProperty: convertedValue ==========> {', newKey, ':', convertedValue, '}')
debugLog(' =============== remove_original_key', newKey, remove_original_key) debugLog(' =============== remove_original_key', newKey, remove_original_key)
@ -514,21 +532,32 @@ export default class MappingEngine {
keysOfConfigObject = Object.keys(configObject) keysOfConfigObject = Object.keys(configObject)
debugLog('keysOfConfigObject', keysOfConfigObject) debugLog('keysOfConfigObject', keysOfConfigObject)
hasKeyIgnoreThisData = (keysOfConfigObject.indexOf('ignore_this_data') !== -1) hasKeyIgnoreThisData = (keysOfConfigObject.indexOf('ignore_this_data') !== -1)
// console.log('-------- hasKeyIgnoreThisData', hasKeyIgnoreThisData)
} }
debugLog('remove_original_key && newKey && convertedValue && hasKeyIgnoreThisData', remove_original_key, newKey, convertedValue, hasKeyIgnoreThisData) debugLog('remove_original_key && newKey && convertedValue && hasKeyIgnoreThisData', remove_original_key, newKey, convertedValue, hasKeyIgnoreThisData)
// console.log('newKey && convertedValue && !hasKeyIgnoreThisData', newKey && convertedValue && !hasKeyIgnoreThisData, newKey, convertedValue, !hasKeyIgnoreThisData) // console.log('newKey && convertedValue && !hasKeyIgnoreThisData', newKey && convertedValue && !hasKeyIgnoreThisData, newKey, convertedValue, !hasKeyIgnoreThisData)
if (remove_original_key) {
delete newProperties[pointKeyName]; // failsafe for boolean values, OSM never returns true or false
if (convertedValue == 'true') {
convertedValue = 'yes'
} }
if (newKey && convertedValue && !hasKeyIgnoreThisData if (convertedValue == 'false') {
convertedValue = 'no'
}
if (newKey && convertedValue && !hasKeyIgnoreThisData && !remove_original_key
) { ) {
debugLog('convertedValue', convertedValue) debugLog('convertedValue', convertedValue)
debugLog('convertProperty: added', newKey, (`${convertedValue}`).trim()) debugLog('convertProperty: added', newKey, (`${convertedValue}`).trim())
newProperties[newKey] = (`${convertedValue}`).trim() newProperties[newKey] = (`${convertedValue}`).trim()
} }
if (remove_original_key) {
// console.log('remove_original_key', pointKeyName, originalValue, '=>', convertedValue)
delete newProperties[pointKeyName];
}
} }
else { else {
@ -539,8 +568,6 @@ export default class MappingEngine {
} }
} }
// console.log('pointKeyName', pointKeyName)
return newProperties; return newProperties;
} }

View file

@ -80,6 +80,7 @@ export interface FeaturePropertyMappingConfigType {
conditional_values?: ConditionnalValuesConfigType, conditional_values?: ConditionnalValuesConfigType,
transform_function?: Function, transform_function?: Function,
keep_only_max_in_enum?: boolean, keep_only_max_in_enum?: boolean,
keep_only_truthy_yes_or_no_without_enum?: boolean,
[key: string]: any, [key: string]: any,
} }

View file

@ -1,4 +1,5 @@
import * as fs from 'node:fs' import * as fs from 'node:fs'
import fetch from 'node-fetch';
let show_debug = 0 let show_debug = 0
// show_debug = 1 // show_debug = 1
@ -18,8 +19,8 @@ function debugLog(...args: any[]) {
} }
} }
const truthyValues = [true, 'true', 'True', 'TRUE', '1', 'yes', 1] const truthyValues = [true, 'true', '1', 'yes', 1]
const falsyValues = [false, 'false', 'False', 'FALSE', '0', 'no', 0] const falsyValues = [false, 'false', '0', 'no', 0]
let listOfBooleanKeys = [ let listOfBooleanKeys = [
"prise_type_ef", "prise_type_ef",
@ -39,10 +40,10 @@ function boolToAddable(someBooleanValue: boolean) {
function isTruthyValue(someValue: string) { function isTruthyValue(someValue: string) {
let convertedValue; let convertedValue;
if (truthyValues.indexOf(someValue) !== -1) { if (truthyValues.indexOf(someValue + ''.toLowerCase()) !== -1) {
convertedValue = true convertedValue = true
} }
if (falsyValues.indexOf(someValue) !== -1) { if (falsyValues.indexOf(someValue + ''.toLowerCase()) !== -1) {
convertedValue = false convertedValue = false
} }
return convertedValue return convertedValue
@ -138,39 +139,35 @@ function truncate_enums_to_limit(str: string, limit: number = 255) {
} }
function convertToBoolean(originalValue: any): boolean { function convertToBoolean(originalValue: any): boolean {
if (truthyValues.indexOf(originalValue) !== -1) { if (truthyValues.indexOf(originalValue + ''.toLowerCase()) !== -1) {
return true; return true;
} }
if (falsyValues.indexOf(originalValue) !== -1) { if (falsyValues.indexOf(originalValue + ''.toLowerCase()) !== -1) {
return false; return false;
} }
return false; // valeur par défaut return false; // valeur par défaut
} }
function convertToYesOrNo(originalValue: any) { function convertToYesOrNo(originalValue: any): string {
let intermediateValue = '' + originalValue let intermediateValue = '' + originalValue
let isEnumeration = false;
let convertedValue = ''; let convertedValue = '';
// handle lists with ; as separator // handle lists with ; as separator
if (intermediateValue.includes(';')) {
isEnumeration = true;
intermediateValue = intermediateValue.split(';')[0]
}
// on ne peut pas conclure ce que l'on doit garder avec une liste // on ne peut pas conclure ce que l'on doit garder avec une liste
if (isEnumeration) { if (intermediateValue.indexOf(';') !== -1) {
return '' return ''
} }
intermediateValue = intermediateValue.split(';')[0]
debugLog('convertProperty: ==========> original value', originalValue, intermediateValue) debugLog('convertProperty: ==========> original value', originalValue, intermediateValue)
if (truthyValues.indexOf(originalValue) !== -1) { if (truthyValues.indexOf((originalValue + '').toLowerCase()) !== -1) {
convertedValue = 'yes' return 'yes'
} else { } else {
debugLog('convertProperty: ==========> !!! NOT in truthy values', originalValue) debugLog('convertProperty: ==========> !!! NOT in truthy values', originalValue)
} }
if (falsyValues.indexOf(originalValue) !== -1) { if (falsyValues.indexOf((originalValue + '').toLowerCase()) !== -1) {
convertedValue = 'no' return 'no'
} else { } else {
debugLog('convertProperty: ==========> !!! NOT in falsy values', originalValue) debugLog('convertProperty: ==========> !!! NOT in falsy values', originalValue)
} }
@ -178,6 +175,30 @@ function convertToYesOrNo(originalValue: any) {
return convertedValue; return convertedValue;
} }
async function replaceFile(sourceFilePathGeoJson: string, url: string) {
const response = await fetch(url)
if (!response.ok) {
throw new Error(`Erreur lors du téléchargement: ${response.status} ${response.statusText}`)
}
// afficher la taille du fichier téléchargé
const contentLength = response.headers.get('content-length')
const data = await response.text()
if (contentLength) {
const sizeInMB = (parseInt(contentLength) / (1024 * 1024)).toFixed(2)
console.log(`Taille du fichier téléchargé: ${sizeInMB} Mo`)
} else {
// mesurer la taille des données
const sizeInMB = (data.length / (1024 * 1024)).toFixed(2)
console.log(`Taille des données: ${sizeInMB} Mo`)
}
fs.writeFileSync(sourceFilePathGeoJson, data)
console.log('fichier téléchargé avec succès:', sourceFilePathGeoJson)
}
export default { export default {
// debug tools // debug tools
debugLog, debugLog,
@ -198,4 +219,5 @@ export default {
prefix_phone_fr_only, prefix_phone_fr_only,
// file tools // file tools
writeFile, writeFile,
replaceFile,
} }

View file

@ -70,6 +70,10 @@ export const mappingBoolean: MappingConfigType = {
consolidated_is_lon_lat_correct: { consolidated_is_lon_lat_correct: {
convert_to_boolean_value: true, convert_to_boolean_value: true,
}, },
prise_type_chademo: {
key_converted: 'socket:chademo',
convert_to_boolean_value: true,
},
}, },
add_not_mapped_tags_too: false, add_not_mapped_tags_too: false,
source: { source: {

View file

@ -21,6 +21,26 @@
"osm_id": 1234567890, "osm_id": 1234567890,
"non_spécifié": "non spécifié" "non_spécifié": "non spécifié"
} }
},
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [
4.822159,
45.635079
]
},
"properties": {
"boolean_enum": "True;false",
"boolean_simple": "True",
"boolean_simple_false": "False",
"boolean_simple_false_uppercase": "FALSE",
"boolean_simple_true": "TRUE",
"boolean_simple_one": "1",
"boolean_simple_zero": "0",
"id": "0000002"
}
} }
] ]
} }

View file

@ -83,19 +83,19 @@ describe('convert boolean keys', () => {
expect(mapped_point.properties).toStrictEqual({ consolidated_is_lon_lat_correct: 'yes' }) expect(mapped_point.properties).toStrictEqual({ consolidated_is_lon_lat_correct: 'yes' })
}) })
// test('ignore one value if it is truthy', () => { test('no result with enum transform', () => {
// let Mapping_engine = new MappingEngine(mappings.mappingIgnoreTruthy) // on ne doit rien garder en cas d'énumération dans une propriété censée être booléenne si elle est une énumération
// Mapping_engine.setConfig(mappings.mappingIgnoreTruthy) expect(utils.convertToYesOrNo("True;FALSE")).toStrictEqual('')
// let feature_to_test = testingGeoJson.features[0] })
// let mapped_point = Mapping_engine.mapElementFromConf(feature_to_test)
// expect(mapped_point.properties).toStrictEqual({}) test('no result with simple transform', () => {
// }) expect(utils.convertToYesOrNo("1")).toStrictEqual('yes')
// test('ignore one value if it is falsy', () => { })
// let Mapping_engine = new MappingEngine(mappings.mappingIgnoreFalsy)
// let feature_to_test = testingGeoJson.features[0] test('no result with simple transform', () => {
// let mapped_point = Mapping_engine.mapElementFromConf(feature_to_test) expect(utils.convertToYesOrNo("False")).toStrictEqual('no')
// expect(mapped_point.properties).toStrictEqual({}) })
// })
}) })
describe('ignore points having osm id', () => { describe('ignore points having osm id', () => {