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",
"paiement_acte",
"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

View file

@ -12,8 +12,13 @@
* --outname=nom_fichier : Alias pour --output-file
* --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
*/
@ -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 filterZipCodeAdresse = new RegExp(` ${filterDepartment}`)
@ -281,7 +257,6 @@ function convertDataFromSource(sourceFilePath: string, mapping: MappingConfigTyp
let remove_original_key = false;
// fix des jeux de données qui ne sont pas des geojson
let properties_list: any = []
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')
}
// TODO add filter offset max
// filter points depending on zipcode
if (regex_filter_test_result) {
feature_points_after_filter.push(feature_point)
@ -385,13 +358,9 @@ function convertDataFromSource(sourceFilePath: string, mapping: MappingConfigTyp
debugLog('convert : work on 1 point')
let mapped_point: any = {}
if (use_mapping_engine) {
mapped_point = Mapping_engine.mapElementFromConf(feature_point)
debugLog('mapped_point', mapped_point)
} else {
debugLog('convert :using simple converter on feature point', feature_point)
mapped_point = mapElementFromConfSimple(feature_point, mapping)
}
// if (use_mapping_engine) {
mapped_point = Mapping_engine.mapElementFromConf(feature_point)
debugLog('mapped_point', mapped_point)
if (mapped_point) {
converted_geo_json.features.push(mapped_point)
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) {
console.log('------- geojson source', sourceFilePathGeoJson)
console.log('------- conversion engine', engine_conf_choice)
if (use_mapping_engine) {
debugLog(' - using mapping engine')
debugLog(' - pointCounterMax', pointCounterMax)
if (osmoseFormat) {
Mapping_engine.setConfig(config.allowed_configs.mappingConfigIRVEFromOsmose)
debugLog(' - pointCounterMax', pointCounterMax)
} else {
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)
}
if (osmoseFormat) {
Mapping_engine.setConfig(config.allowed_configs.mappingConfigIRVEFromOsmose)
} else {
console.log(' ------ on utilise mappingConfigIRVE_simple')
let mappingConfigIRVE = config.allowed_configs.mappingConfigIRVE_simple
convertDataFromSource(sourceFilePathGeoJson, mappingConfigIRVE, pointCounterMax, boundingBoxCoordinates)
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')
// 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,
// filter_points_older_than_year: 2024,
// 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
// properties: {
// consolidated_code_postal: '^[76|27]'
@ -50,7 +50,12 @@ const MappingIRVE: MappingConfigType = {
"gratuit",
"paiement_acte",
"paiement_cb",
"cable_t2_attache"
"cable_t2_attache",
"socket:typee",
"socket:type2_combo",
"socket:chademo",
"socket:type2",
"socket:type2_cable",
],
tags: {
// ******* nombres
@ -90,12 +95,12 @@ const MappingIRVE: MappingConfigType = {
paiement_acte:
{
key_converted: 'authentication:none',
convert_to_boolean_value: true, // convertit en yes ou no
convert_to_boolean_value: true,
},
reservation: {
key_converted: 'reservation',
convert_to_boolean_value: true, // convertit en yes ou no
convert_to_boolean_value: true,
},
// observations: 'note',
nom_station: 'description',
@ -116,27 +121,21 @@ const MappingIRVE: MappingConfigType = {
,
prise_type_ef: {
key_converted: 'socket:typee',
ignore_if_falsy: true,
convert_to_boolean_value: true,
keep_only_max_in_enum: true,
keep_only_truthy_yes_or_no_without_enum: true,
},
prise_type_2: {
key_converted: 'socket:type2',
ignore_if_falsy: true,
convert_to_boolean_value: true,
keep_only_max_in_enum: true,
// on convertit en yes ou no, sans enum, et on ne garde que si on obtient "yes"
keep_only_truthy_yes_or_no_without_enum: true,
},
prise_type_combo_ccs: {
key_converted: 'socket:type2_combo',
ignore_if_falsy: true,
convert_to_boolean_value: true,
keep_only_max_in_enum: true,
keep_only_truthy_yes_or_no_without_enum: true,
},
prise_type_chademo: {
key_converted: 'socket:chademo',
ignore_if_falsy: true,
convert_to_boolean_value: true,
keep_only_max_in_enum: true,
keep_only_truthy_yes_or_no_without_enum: true,
},
// ******** champs plus complexes
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: {
key_converted: "wheelchair",
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": {
value_converted: "yes"
},

View file

@ -53,15 +53,6 @@ export default class MappingEngine {
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
@ -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 }
@ -185,23 +174,17 @@ export default class MappingEngine {
basePoint.geometry = featurePoint.geometry
basePoint.properties = { ...this.mapping_config.default_properties_of_point }
// apply new properties if found in mapping config
featurePointPropertiesKeys.forEach(pointKeyName => {
// if (featurePointPropertiesKeys.indexOf(pointKeyName) !== -1) {
this.convertProperty({
pointKeyName, mappingKeys, featurePoint, newProperties
})
// }
})
basePoint.properties = newProperties
// debugLog('mapElementFromConf: basePoint', basePoint)
return basePoint
}
@ -245,7 +228,7 @@ export default class MappingEngine {
let remove_original_key = false;
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) {
debugLog('(x) => ignore', originalValue, ' in ', pointKeyName)
console.log('(x) => ignore', originalValue, ' in ', pointKeyName)
remove_original_key = true;
}
@ -353,13 +336,44 @@ export default class MappingEngine {
/**
* 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) {
debugLog('convertProperty: is boolean_value_conversion')
// debugLog('convertProperty: is boolean_value_conversion')
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 {
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
@ -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) {
// Remplace toutes les occurrences de * de manière greedy
convertedValue = originalValue.replaceAll('*', '')
convertedValue = originalValue.replace('*', '')
debugLog('remove_stars', convertedValue, originalValue)
}
@ -409,7 +420,9 @@ export default class MappingEngine {
if (configObject.remove_original_key) {
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
}
if (configObject.ignore_if_truthy && custom_utils.convertToBoolean(originalValue)) {
@ -423,11 +436,16 @@ export default class MappingEngine {
}
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é
* 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
originalValue = '' + originalValue
@ -440,13 +458,14 @@ export default class MappingEngine {
// sauf si on a activé l'option allow_unspecified_conditional_values dans la MappingConfigType
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
}
if (!remove_original_key) {
// console.log('-------- on garde la valeur', originalValue, ' dans ', pointKeyName)
if (foundValue !== -1) {
debugLog('found condition', foundValue)
@ -462,48 +481,47 @@ export default class MappingEngine {
remove_original_key = true;
}
let lowerKey = (originalValue + '').toLowerCase()
if (conditionalConfig.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".
// on met donc truthy_value: '1'
if (custom_utils.truthyValues.indexOf(originalValue) !== -1) {
if (custom_utils.truthyValues.indexOf(lowerKey) !== -1) {
convertedValue = conditionalConfig.truthy_value
}
}
if (conditionalConfig.falsy_value) {
if (custom_utils.falsyValues.indexOf(originalValue) !== -1) {
if (custom_utils.falsyValues.indexOf(lowerKey) !== -1) {
convertedValue = conditionalConfig.falsy_value
}
}
// use the value converted
else if (conditionalConfig.value_converted) {
if (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 {
debugLog('no conditional values', configObject)
}
// console.log('conditionnalConfig', conditionnalConfig, convertedValue)
debugLog('convertProperty: convertedValue ==========> {', newKey, ':', convertedValue, '}')
debugLog(' =============== remove_original_key', newKey, remove_original_key)
@ -514,21 +532,32 @@ export default class MappingEngine {
keysOfConfigObject = Object.keys(configObject)
debugLog('keysOfConfigObject', keysOfConfigObject)
hasKeyIgnoreThisData = (keysOfConfigObject.indexOf('ignore_this_data') !== -1)
// console.log('-------- hasKeyIgnoreThisData', 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)
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('convertProperty: added', newKey, (`${convertedValue}`).trim())
newProperties[newKey] = (`${convertedValue}`).trim()
}
if (remove_original_key) {
// console.log('remove_original_key', pointKeyName, originalValue, '=>', convertedValue)
delete newProperties[pointKeyName];
}
}
else {
@ -539,8 +568,6 @@ export default class MappingEngine {
}
}
// console.log('pointKeyName', pointKeyName)
return newProperties;
}

View file

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

View file

@ -1,4 +1,5 @@
import * as fs from 'node:fs'
import fetch from 'node-fetch';
let show_debug = 0
// show_debug = 1
@ -18,8 +19,8 @@ function debugLog(...args: any[]) {
}
}
const truthyValues = [true, 'true', 'True', 'TRUE', '1', 'yes', 1]
const falsyValues = [false, 'false', 'False', 'FALSE', '0', 'no', 0]
const truthyValues = [true, 'true', '1', 'yes', 1]
const falsyValues = [false, 'false', '0', 'no', 0]
let listOfBooleanKeys = [
"prise_type_ef",
@ -39,10 +40,10 @@ function boolToAddable(someBooleanValue: boolean) {
function isTruthyValue(someValue: string) {
let convertedValue;
if (truthyValues.indexOf(someValue) !== -1) {
if (truthyValues.indexOf(someValue + ''.toLowerCase()) !== -1) {
convertedValue = true
}
if (falsyValues.indexOf(someValue) !== -1) {
if (falsyValues.indexOf(someValue + ''.toLowerCase()) !== -1) {
convertedValue = false
}
return convertedValue
@ -138,39 +139,35 @@ function truncate_enums_to_limit(str: string, limit: number = 255) {
}
function convertToBoolean(originalValue: any): boolean {
if (truthyValues.indexOf(originalValue) !== -1) {
if (truthyValues.indexOf(originalValue + ''.toLowerCase()) !== -1) {
return true;
}
if (falsyValues.indexOf(originalValue) !== -1) {
if (falsyValues.indexOf(originalValue + ''.toLowerCase()) !== -1) {
return false;
}
return false; // valeur par défaut
}
function convertToYesOrNo(originalValue: any) {
function convertToYesOrNo(originalValue: any): string {
let intermediateValue = '' + originalValue
let isEnumeration = false;
let convertedValue = '';
// 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
if (isEnumeration) {
if (intermediateValue.indexOf(';') !== -1) {
return ''
}
intermediateValue = intermediateValue.split(';')[0]
debugLog('convertProperty: ==========> original value', originalValue, intermediateValue)
if (truthyValues.indexOf(originalValue) !== -1) {
convertedValue = 'yes'
if (truthyValues.indexOf((originalValue + '').toLowerCase()) !== -1) {
return 'yes'
} else {
debugLog('convertProperty: ==========> !!! NOT in truthy values', originalValue)
}
if (falsyValues.indexOf(originalValue) !== -1) {
convertedValue = 'no'
if (falsyValues.indexOf((originalValue + '').toLowerCase()) !== -1) {
return 'no'
} else {
debugLog('convertProperty: ==========> !!! NOT in falsy values', originalValue)
}
@ -178,6 +175,30 @@ function convertToYesOrNo(originalValue: any) {
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 {
// debug tools
debugLog,
@ -198,4 +219,5 @@ export default {
prefix_phone_fr_only,
// file tools
writeFile,
replaceFile,
}

View file

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

View file

@ -21,6 +21,26 @@
"osm_id": 1234567890,
"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' })
})
// test('ignore one value if it is truthy', () => {
// let Mapping_engine = new MappingEngine(mappings.mappingIgnoreTruthy)
// Mapping_engine.setConfig(mappings.mappingIgnoreTruthy)
// let feature_to_test = testingGeoJson.features[0]
// let mapped_point = Mapping_engine.mapElementFromConf(feature_to_test)
// expect(mapped_point.properties).toStrictEqual({})
// })
// test('ignore one value if it is falsy', () => {
// let Mapping_engine = new MappingEngine(mappings.mappingIgnoreFalsy)
// 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 enum transform', () => {
// 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
expect(utils.convertToYesOrNo("True;FALSE")).toStrictEqual('')
})
test('no result with simple transform', () => {
expect(utils.convertToYesOrNo("1")).toStrictEqual('yes')
})
test('no result with simple transform', () => {
expect(utils.convertToYesOrNo("False")).toStrictEqual('no')
})
})
describe('ignore points having osm id', () => {