npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@ban-team/formatter-bal

v0.1.1

Published

Permet de formatter les fichier BAL, avant leurs publication sur l'api-depot

Readme

formatter-bal

Outil de mise en forme des fichiers BAL (Base Adresses Locales) avant publication sur l'api-depot.

Installation

yarn install
yarn build

Utilisation

En ligne de commande

./exe formatter-bal path/to/input.csv

Le 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 TypeScript

Transformations 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 (bisB, terT) ; commence par un chiffre : chaîne entière en majuscule (2B2B) |

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_adresse au format @c:{id} @v:{id} @a:{id} décodé pour extraire id_ban_commune, id_ban_toponyme, id_ban_adresse
  • Noms localisés (toponyme_bre, commune_nom_eu, etc.) collectés dynamiquement et conservés dans Record<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 + #99999 pour 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 de cle_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 :

  1. Calcul de la clé de voie 99999 sur le nom du lieudit
  2. Si aucune voie 99999 explicite n'existe avec ce nom → création d'une voie sans adresse synthétique
  3. Centroïde géographique calculé en moyennant les coordonnées (lat/long et x/y) de toutes les positions référençant ce lieudit
  4. Si une voie 99999 existe déjà (ligne explicite dans le fichier d'entrée) et que position_sans_adresse est absente → injection du centroïde comme position_sans_adresse

Phase 4 — Récupération des données BAN (src/ban/index.ts)

  • GET /api/lookup/{codeInsee} → lookup de la commune, retourne typeComposition (bal ou assemblage) et withBanId (booléen)
  • GET /api/district/cog/{codeInsee} → récupération de l'id_ban_commune
  • GET /ban/communes/{codeCommune}/download/csv-bal/adresses → CSV de référence BAN parsé via le même pipeline (Phases 1-3) pour construire un treeBAN de 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échargementassignMissingIds (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 :

  1. Même valeur de numero (entier)
  2. Même suffixe normalisé
  3. 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_adresse BAN
  • Numéro absent → conservation de l'id_ban_adresse issu 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_commune
  • GET 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 |