@ban-team/formatter-bal
v0.1.1
Published
Permet de formatter les fichier BAL, avant leurs publication sur l'api-depot
Keywords
Readme
formatter-bal
Outil de mise en forme des fichiers BAL (Base Adresses Locales) avant publication sur l'api-depot.
Installation
yarn install
yarn buildUtilisation
En ligne de commande
./exe formatter-bal path/to/input.csvLe fichier de sortie est écrit dans le répertoire courant sous la forme bal_YYYYMMDD_HHMMSS.csv.
En tant que bibliothèque
import { formatterBAL } from "@ban-team/formatter-bal";
import { readFileSync } from "fs";
const balBuffer = readFileSync("input.csv");
const enrichedBuffer = await formatterBAL(balBuffer);
if (enrichedBuffer) {
// enrichedBuffer est un Buffer CSV encodé UTF-8 avec les IDs BAN assignés
}Scripts disponibles
| Commande | Description |
| ------------ | ----------------------------------------- |
| yarn build | Compile le projet TypeScript vers dist/ |
| yarn test | Lance les tests Jest |
Pipeline de traitement
Fichier CSV (Buffer)
↓
Détection encodage + parsing CSV (papaparse)
↓
Construction de l'arbre BalTree (Voie → Numéro → Position[])
↓
Récupération id_ban_commune + CSV de référence BAN
↓
Calcul et propagation des IDs BAN (ou génération UUIDs)
↓
Sérialisation vers CSV UTF-8 (Buffer)Structure du projet
src/
├── index.ts # Point d'entrée principal (formatterBAL)
├── parse/ # Détection d'encodage et parsing CSV
├── tree/ # Construction de l'arbre d'adresses
├── ban/ # Appels à l'API BAN
├── compute_ids/ # Logique d'assignation des identifiants
├── serialize/ # Sérialisation vers CSV
├── commands/ # Handler CLI (yargs)
└── types/ # Définitions de types TypeScriptTransformations appliquées au fichier BAL
Détail exhaustif de chaque opération effectuée sur le fichier d'entrée, phase par phase.
Phase 1 — Parsing du fichier (src/parse/index.ts)
Détection d'encodage (chardet), rejet des binaires (file-type), BOM supprimé, délimiteur CSV auto-détecté (, \t ;).
Phase 2 — Normalisation des champs (src/tree/parse-row.ts)
| Champ | Traitement |
| ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| numero | parseInt(10) ; ligne entièrement ignorée si non parseable |
| x, y, long, lat | parseFloat ; accepte , comme séparateur décimal |
| date_der_maj | 9 formats tentés successivement (ISO YYYY-MM-DD, dd/MM/yy, dd/MM/yyyy, yyyy/MM/dd, dd-MM-yyyy, dd MM yyyy, yyyy MM dd, d LLLL yyyy avec locale fr, yyyy-MM-dd HH:mm) ; invalide → undefined |
| certification_commune | "1" ou "true" → true ; sinon → undefined |
| position (type enum) | Suppression des diacritiques + normalisation espaces + lowercase ; invalide → undefined |
| cad_parcelles | Split par \| → tableau de chaînes |
| suffixe | Commence par une lettre : première lettre en majuscule (bis → B, ter → T) ; commence par un chiffre : chaîne entière en majuscule (2B → 2B) |
Compatibilité multi-versions :
- BAL 1.4 :
voie_nom→ renommétoponyme;voie_nom_*→ renommétoponyme_*(BAL 1.5 prioritaire en cas de conflit) - BAL 1.3 :
uid_adresseau format@c:{id} @v:{id} @a:{id}décodé pour extraireid_ban_commune,id_ban_toponyme,id_ban_adresse - Noms localisés (
toponyme_bre,commune_nom_eu, etc.) collectés dynamiquement et conservés dansRecord<string, string>
Phase 3 — Construction de l'arbre (src/tree/index.ts)
Clés de l'arbre :
- Clé de voie :
normalize(toponyme)(via@ban-team/adresses-util) +@{commune_deleguee_insee}si présent +#99999pour les voies sans numéro - Clé de numéro :
${numero}#${suffixeNormalisé}(ex:5#bis) - Code INSEE : priorité au champ
commune_insee, sinon au premier segment decle_interop
Création automatique des voies 99999 (buildLieuditVoies())
Tous les numéros portant un lieudit_complement_nom donnent lieu à la synthèse automatique d'un toponyme sans adresse :
- Calcul de la clé de voie 99999 sur le nom du lieudit
- Si aucune voie 99999 explicite n'existe avec ce nom → création d'une voie sans adresse synthétique
- Centroïde géographique calculé en moyennant les coordonnées (
lat/longetx/y) de toutes les positions référençant ce lieudit - Si une voie 99999 existe déjà (ligne explicite dans le fichier d'entrée) et que
position_sans_adresseest absente → injection du centroïde commeposition_sans_adresse
Phase 4 — Récupération des données BAN (src/ban/index.ts)
GET /api/lookup/{codeInsee}→ lookup de la commune, retournetypeComposition(balouassemblage) etwithBanId(booléen)GET /api/district/cog/{codeInsee}→ récupération de l'id_ban_communeGET /ban/communes/{codeCommune}/download/csv-bal/adresses→ CSV de référence BAN parsé via le même pipeline (Phases 1-3) pour construire untreeBANde comparaison — conditionnel selon le résultat du lookup (voir ci-dessous)- En cas d'indisponibilité de l'API → passage en mode fallback UUID (Phase 5C)
Conditions de téléchargement du CSV de référence BAN
Le CSV de référence BAN n'est téléchargé (et computeIds n'est exécuté) que si l'une des deux conditions suivantes est remplie :
| typeComposition | withBanId | Comportement |
| ----------------- | ----------- | ------------------------------------------------------------------------ |
| bal | true | Téléchargement du CSV BAN + computeIds (réutilisation des IDs stables) |
| assemblage | — | Téléchargement du CSV BAN + computeIds (réutilisation des IDs stables) |
| bal | false | Pas de téléchargement → assignMissingIds (nouveaux UUIDs) |
Cas typeComposition === "bal" et withBanId === false : la commune est encore sur l'ancien socle BAN, dont les identifiants ne sont pas stables (mauvais IDs). Dans ce cas, le CSV de référence BAN n'est pas consulté et de nouveaux UUIDs sont assignés à toutes les entités de la BAL en entrée qui n'en possèdent pas. Ce comportement est sûr car la BAN ne bloque pas l'initialisation de nouveaux identifiants lors du passage sur le nouveau socle.
Phase 5 — Calcul et propagation des identifiants BAN (src/compute_ids/index.ts)
Pour chaque voie du fichier BAL, les stratégies suivantes sont tentées dans l'ordre :
5A — Correspondance exacte de nom
Recherche de treeBAN.voies[clé normalisée]. Si trouvée : réutilisation de l'id_ban_toponyme BAN.
5B — Voie renommée
Si aucune correspondance exacte, parcours de toutes les voies BAN pour trouver une voie dont ≥ 80 % des numéros sont retrouvés dans la voie BAL via isSameNumero().
Un numéro est considéré identique si les trois conditions suivantes sont réunies :
- Même valeur de
numero(entier) - Même
suffixenormalisé - Distance ≤ 10 mètres entre les premières positions géographiques :
- Coordonnées WGS84 → formule haversine (R = 6 371 km)
- Coordonnées Lambert 93 → distance euclidienne
- Aucune coordonnée des deux côtés → considéré comme match
Si une voie renommée est détectée : réutilisation de l'id_ban_toponyme de la voie BAN d'origine.
5C — Nouvelle voie
Conservation de l'id_ban_toponyme existant (issu du fichier d'entrée ou extrait de uid_adresse) ; génération d'un UUID si absent.
Propagation des id_ban_adresse
Pour chaque numéro dans les cas 5A et 5B :
- Numéro retrouvé dans BAN via
isSameNumero()→ réutilisation de l'id_ban_adresseBAN - Numéro absent → conservation de l'
id_ban_adresseissu du fichier d'entrée si présent, sinon génération d'un UUID
Fallback (BAN indisponible) — assignMissingIds() : complète uniquement les champs manquants par des UUIDs, sans jamais écraser les IDs existants.
Phase 6 — Sérialisation (src/serialize/index.ts)
Une ligne par position pour les voies numérotées, une ligne par voie pour les 99999. Reformatages standards (date_der_maj, certification_commune, cad_parcelles), champs undefined omis, sortie UTF-8.
API BAN utilisée
GET https://plateforme.adresse.data.gouv.fr/api/district/cog/{codeInsee}— Récupération de l'id_ban_communeGET https://plateforme.adresse.data.gouv.fr/ban/communes/{codeCommune}/download/csv-bal/adresses— Téléchargement du CSV de référence BAL
Dépendances principales
| Package | Rôle |
| ------------------------- | ---------------------------------- |
| @ban-team/adresses-util | Normalisation des noms de voies |
| chardet + iconv-lite | Détection et conversion d'encodage |
| papaparse | Parsing et génération de CSV |
| date-fns | Parsing de dates |
| yargs | Interface CLI |
