cadastre-cli
Version:
CLI to query French cadastre
116 lines (100 loc) • 4.19 kB
JavaScript
const zlib = require('zlib');
const request = require('request');
const terminalLink = require('terminal-link');
const inquirer = require('inquirer');
inquirer.registerPrompt('autocomplete', require('inquirer-autocomplete-prompt'));
const chalk = require('chalk');
let sections = new Map();
let selectedSection = '';
let selectedParcelle = '';
function extractBetweenChars(str, char1, char2) {
return mySubString = str.substring(
str.lastIndexOf(char1) + 1,
str.lastIndexOf(char2));
}
function setInDoubleMapSection(parcelle) {
const properties = parcelle.properties;
parcelle.geometry.coordinates = parcelle.geometry.coordinates[0].map(point => [point[1], point[0]])
let section = sections.get(properties.section);
if (!section) {
sections.set(properties.section, new Map());
section = sections.get(properties.section);
}
section.set(properties.numero, parcelle);
}
const includes = (str1, str2) => {
if (str1 === str2) return true;
if (!str1 || !str2) return true;
return str1.toLowerCase().includes(str2.toLowerCase());
}
const searchSection = async (_, search) => {
if (search === '?') return ['?'];
const result = Array.from(sections.keys()).filter(section => includes(section, search));
if (!search) return ['?', ...result];
return result;
}
const searchParcelleSectionUnknown = (search) => {
return Array.from(sections.values()).map(section => {
return Array.from(section.values())
.filter(parcelle => parcelle.properties.numero == search)
.map(parcelle => {
const properties = parcelle.properties;
return `${properties.numero} (${properties.section}) - ${properties.contenance} m²`;
})
}).flat();
}
const searchParcelle = async (_, search) => {
if (!search) return [];
if (selectedSection === '?') {
return searchParcelleSectionUnknown(search);
}
return Array.from(sections.get(selectedSection).keys()).filter(section => section.startsWith(search));
}
const getSelectedParcelle = () => {
if (selectedSection !== '?') return sections.get(selectedSection).get(selectedParcelle);
// selectedParcelle : _numeroParcelle_ (_numeroSection_) _superficie_ m²
const parcelle = selectedParcelle.split(' ')[0];
const section = extractBetweenChars(selectedParcelle, '(', ')');
return sections.get(section).get(parcelle);
}
async function getParcelles(codeCommune) {
sections = new Map();
const sectionsRes = await requestGzip(`https://cadastre.data.gouv.fr/bundler/cadastre-etalab/communes/${codeCommune}/geojson/parcelles`);
sectionsRes.features.map(setInDoubleMapSection);
}
function requestGzip(url) {
return new Promise((resolve, reject) => {
request(url, {encoding: null}, function(err, response, body){
zlib.gunzip(body, function(err, dezipped) {
if (err) reject(err);
resolve(JSON.parse(dezipped.toString()));
});
});
});
}
exports.selectParcelle = async (codeCommune) => {
await getParcelles(codeCommune);
selectedSection = (await inquirer.prompt({
type: 'autocomplete',
name: 'section',
message: 'Saisir une section dans la commune (ou ?)',
source: searchSection
})).section;
console.log(selectedSection);
selectedParcelle = (await inquirer.prompt({
type: 'autocomplete',
name: 'parcelle',
message: 'Saisir un numero de parcelle',
source: searchParcelle
})).parcelle;
return getSelectedParcelle();
}
exports.printParcelle = (parcelle) => {
const coords = parcelle.geometry.coordinates[0];
const geoportailMap = `https://www.geoportail.gouv.fr/carte?c=${coords[1]},${coords[0]}&z=19&l0=ORTHOIMAGERY.ORTHOPHOTOS::GEOPORTAIL:OGC:WMTS(1)&l1=GEOGRAPHICALGRIDSYSTEMS.MAPS.SCAN25TOUR.CV::GEOPORTAIL:OGC:WMTS(1)&l2=CADASTRALPARCELS.PARCELS::GEOPORTAIL:OGC:WMTS(1)&permalink=yes`;
const googleMap = `https://www.google.com/maps/search/${coords[0]},${coords[1]}`;
console.log('📐 ' + chalk.yellow(parcelle.properties.contenance + ' m²'));
console.log('📌 ' + chalk.yellow(coords[0] + ', ' + coords[1]));
console.log('🗺 ' + chalk.blue(terminalLink('Geoportail', geoportailMap)));
console.log('🗺 ' + chalk.blue(terminalLink('Google Maps', googleMap)));
}