UNPKG

@tricoteuses/assemblee

Version:

Retrieve, clean up & handle French Assemblée nationale's open data

134 lines (130 loc) 18.4 kB
import fs from "fs-extra"; import path from "path"; import stream from "stream"; import StreamZip from "node-stream-zip"; import util from "util"; import { walkDir } from "../file_systems.mjs"; import { XMLParser } from "fast-xml-parser"; const pipeline = util.promisify(stream.pipeline); // Function to fetch zip files with retry mechanism async function fetchZipFile(url, zipFilePath, retries = 3) { for (let attempt = 0; attempt < retries; attempt++) { const response = await fetch(url); if (response.ok) { await pipeline(response.body, fs.createWriteStream(zipFilePath)); return; } else if (attempt < retries - 1) { console.warn(`Retrying fetch for ${url}: ${response.statusText}`); } else { console.error(`Failed to fetch ${url} after ${retries} attempts`); throw new Error(`Fetch failed: ${url}`); } } } async function extractZip(zipFilePath, outputDir) { return new Promise((resolve, reject) => { const zip = new StreamZip({ file: zipFilePath, storeEntries: true }); zip.on("ready", () => { zip.extract(null, outputDir, err => { zip.close(); if (err) { reject(err); } else { resolve(); } }); }); }); } function reindentJsonFiles(dataDirOrFilePath) { if (fs.statSync(dataDirOrFilePath).isDirectory()) { for (const dataFileSplitPath of walkDir(dataDirOrFilePath)) { const dataFilePath = path.join(dataDirOrFilePath, ...dataFileSplitPath); if (dataFilePath.endsWith(".json")) { const data = JSON.parse(fs.readFileSync(dataFilePath, { encoding: "utf-8" })); fs.writeFileSync(dataFilePath, JSON.stringify(data, null, 2)); } } } else { const data = JSON.parse(fs.readFileSync(dataDirOrFilePath, { encoding: "utf-8" })); fs.writeFileSync(dataDirOrFilePath, JSON.stringify(data, null, 2)); } } const xmlParser = new XMLParser({ ignoreDeclaration: true, ignoreAttributes: false, ignorePiTags: true, attributeNamePrefix: "", textNodeName: "_", processEntities: false, trimValues: true, stopNodes: ["*.texte", "*.intitule"], parseTagValue: false, parseAttributeValue: false, transformTagName: tagName => tagName === "Para" ? "para" : tagName }); /** * Processes a dataset by fetching, unzipping, and converting files from XML to JSON format. * * @param {any} dataset - The dataset object containing metadata and processing instructions. * @param {string} dataDir - The directory where the dataset files will be stored. * @param {any} options - Options to control the processing behavior, such as fetching and silent mode. * @returns {Promise<void>} A promise that resolves when the dataset processing is complete. */ export async function processDataset(args) { const { dataset, dataDir, options } = args; const zipFilePath = path.join(dataDir, `${dataset.filename}.zip`); const dataDirOrFilePath = path.join(dataDir, dataset.filename); fs.removeSync(dataDirOrFilePath); if (options.fetch) { // Fetch & save ZIP file. if (!options.silent) { console.log(`Loading ${dataset.title}: ${dataset.filename}.zip`); } await fetchZipFile(dataset.url, zipFilePath); } if (!options.silent) { console.log(`Unzipping ${dataset.title}: ${dataset.filename}.zip`); } await extractZip(zipFilePath, dataDir); if (dataset.repairZip !== undefined) { if (!options.silent) { console.log(`Repairing ${dataset.title}: ${dataset.filename}`); } dataset.repairZip(dataset, dataDir); } // Convert xml to JSON. if (dataset.filename.endsWith(".xml")) { for (const dataFileSplitPath of walkDir(dataDirOrFilePath)) { const dataFilePath = path.join(dataDirOrFilePath, ...dataFileSplitPath); if (dataFilePath.endsWith(".xml")) { fs.readFile(dataFilePath, function (err, data) { if (err) return console.error(err); let result = xmlParser.parse(data); const newDataFilePath = dataFilePath.replace(/\.[^.]+$/, ".json"); fs.copy(dataFilePath, newDataFilePath, err => { fs.writeFileSync(newDataFilePath, JSON.stringify(result, null, 2)); if (err) return console.error(err); }); }); } } } // Reindent JSON file. if (!options.silent) { console.log(`Reidenting ${dataset.title}: ${dataset.filename}`); } reindentJsonFiles(dataDirOrFilePath); } //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJmcyIsInBhdGgiLCJzdHJlYW0iLCJTdHJlYW1aaXAiLCJ1dGlsIiwid2Fsa0RpciIsIlhNTFBhcnNlciIsInBpcGVsaW5lIiwicHJvbWlzaWZ5IiwiZmV0Y2haaXBGaWxlIiwidXJsIiwiemlwRmlsZVBhdGgiLCJyZXRyaWVzIiwiYXR0ZW1wdCIsInJlc3BvbnNlIiwiZmV0Y2giLCJvayIsImJvZHkiLCJjcmVhdGVXcml0ZVN0cmVhbSIsImNvbnNvbGUiLCJ3YXJuIiwic3RhdHVzVGV4dCIsImVycm9yIiwiRXJyb3IiLCJleHRyYWN0WmlwIiwib3V0cHV0RGlyIiwiUHJvbWlzZSIsInJlc29sdmUiLCJyZWplY3QiLCJ6aXAiLCJmaWxlIiwic3RvcmVFbnRyaWVzIiwib24iLCJleHRyYWN0IiwiZXJyIiwiY2xvc2UiLCJyZWluZGVudEpzb25GaWxlcyIsImRhdGFEaXJPckZpbGVQYXRoIiwic3RhdFN5bmMiLCJpc0RpcmVjdG9yeSIsImRhdGFGaWxlU3BsaXRQYXRoIiwiZGF0YUZpbGVQYXRoIiwiam9pbiIsImVuZHNXaXRoIiwiZGF0YSIsIkpTT04iLCJwYXJzZSIsInJlYWRGaWxlU3luYyIsImVuY29kaW5nIiwid3JpdGVGaWxlU3luYyIsInN0cmluZ2lmeSIsInhtbFBhcnNlciIsImlnbm9yZURlY2xhcmF0aW9uIiwiaWdub3JlQXR0cmlidXRlcyIsImlnbm9yZVBpVGFncyIsImF0dHJpYnV0ZU5hbWVQcmVmaXgiLCJ0ZXh0Tm9kZU5hbWUiLCJwcm9jZXNzRW50aXRpZXMiLCJ0cmltVmFsdWVzIiwic3RvcE5vZGVzIiwicGFyc2VUYWdWYWx1ZSIsInBhcnNlQXR0cmlidXRlVmFsdWUiLCJ0cmFuc2Zvcm1UYWdOYW1lIiwidGFnTmFtZSIsInByb2Nlc3NEYXRhc2V0IiwiYXJncyIsImRhdGFzZXQiLCJkYXRhRGlyIiwib3B0aW9ucyIsImZpbGVuYW1lIiwicmVtb3ZlU3luYyIsInNpbGVudCIsImxvZyIsInRpdGxlIiwicmVwYWlyWmlwIiwidW5kZWZpbmVkIiwicmVhZEZpbGUiLCJyZXN1bHQiLCJuZXdEYXRhRmlsZVBhdGgiLCJyZXBsYWNlIiwiY29weSJdLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zY3JpcHRzL3Byb2Nlc3Nfb3Blbl9kYXRhc2V0LnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBmcyBmcm9tIFwiZnMtZXh0cmFcIlxuaW1wb3J0IHBhdGggZnJvbSBcInBhdGhcIlxuaW1wb3J0IHN0cmVhbSBmcm9tIFwic3RyZWFtXCJcbmltcG9ydCBTdHJlYW1aaXAgZnJvbSBcIm5vZGUtc3RyZWFtLXppcFwiXG5pbXBvcnQgdXRpbCBmcm9tIFwidXRpbFwiXG5cbmltcG9ydCB7IHdhbGtEaXIgfSBmcm9tIFwiLi4vZmlsZV9zeXN0ZW1zXCJcbmltcG9ydCB7IFhNTFBhcnNlciB9IGZyb20gXCJmYXN0LXhtbC1wYXJzZXJcIlxuXG5jb25zdCBwaXBlbGluZSA9IHV0aWwucHJvbWlzaWZ5KHN0cmVhbS5waXBlbGluZSlcblxuLy8gRnVuY3Rpb24gdG8gZmV0Y2ggemlwIGZpbGVzIHdpdGggcmV0cnkgbWVjaGFuaXNtXG5hc3luYyBmdW5jdGlvbiBmZXRjaFppcEZpbGUoXG4gIHVybDogc3RyaW5nLFxuICB6aXBGaWxlUGF0aDogc3RyaW5nLFxuICByZXRyaWVzID0gMyxcbik6IFByb21pc2U8dm9pZD4ge1xuICBmb3IgKGxldCBhdHRlbXB0ID0gMDsgYXR0ZW1wdCA8IHJldHJpZXM7IGF0dGVtcHQrKykge1xuICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2godXJsKVxuICAgIGlmIChyZXNwb25zZS5vaykge1xuICAgICAgYXdhaXQgcGlwZWxpbmUoXG4gICAgICAgIHJlc3BvbnNlLmJvZHkgYXMgdW5rbm93biBhcyBOb2RlSlMuUmVhZGFibGVTdHJlYW0sXG4gICAgICAgIGZzLmNyZWF0ZVdyaXRlU3RyZWFtKHppcEZpbGVQYXRoKSxcbiAgICAgIClcbiAgICAgIHJldHVyblxuICAgIH0gZWxzZSBpZiAoYXR0ZW1wdCA8IHJldHJpZXMgLSAxKSB7XG4gICAgICBjb25zb2xlLndhcm4oYFJldHJ5aW5nIGZldGNoIGZvciAke3VybH06ICR7cmVzcG9uc2Uuc3RhdHVzVGV4dH1gKVxuICAgIH0gZWxzZSB7XG4gICAgICBjb25zb2xlLmVycm9yKGBGYWlsZWQgdG8gZmV0Y2ggJHt1cmx9IGFmdGVyICR7cmV0cmllc30gYXR0ZW1wdHNgKVxuICAgICAgdGhyb3cgbmV3IEVycm9yKGBGZXRjaCBmYWlsZWQ6ICR7dXJsfWApXG4gICAgfVxuICB9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGV4dHJhY3RaaXAoXG4gIHppcEZpbGVQYXRoOiBzdHJpbmcsXG4gIG91dHB1dERpcjogc3RyaW5nLFxuKTogUHJvbWlzZTx2b2lkPiB7XG4gIHJldHVybiBuZXcgUHJvbWlzZTx2b2lkPigocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgY29uc3QgemlwID0gbmV3IFN0cmVhbVppcCh7XG4gICAgICBmaWxlOiB6aXBGaWxlUGF0aCxcbiAgICAgIHN0b3JlRW50cmllczogdHJ1ZSxcbiAgICB9KVxuXG4gICAgemlwLm9uKFwicmVhZHlcIiwgKCkgPT4ge1xuICAgICAgemlwLmV4dHJhY3QobnVsbCEsIG91dHB1dERpciwgKGVycikgPT4ge1xuICAgICAgICB6aXAuY2xvc2UoKVxuICAgICAgICBpZiAoZXJyKSB7XG4gICAgICAgICAgcmVqZWN0KGVycilcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICByZXNvbHZlKClcbiAgICAgICAgfVxuICAgICAgfSlcbiAgICB9KVxuICB9KVxufVxuXG5mdW5jdGlvbiByZWluZGVudEpzb25GaWxlcyhkYXRhRGlyT3JGaWxlUGF0aDogc3RyaW5nKTogdm9pZCB7XG4gIGlmIChmcy5zdGF0U3luYyhkYXRhRGlyT3JGaWxlUGF0aCkuaXNEaXJlY3RvcnkoKSkge1xuICAgIGZvciAoY29uc3QgZGF0YUZpbGVTcGxpdFBhdGggb2Ygd2Fsa0RpcihkYXRhRGlyT3JGaWxlUGF0aCkpIHtcbiAgICAgIGNvbnN0IGRhdGFGaWxlUGF0aCA9IHBhdGguam9pbihkYXRhRGlyT3JGaWxlUGF0aCwgLi4uZGF0YUZpbGVTcGxpdFBhdGgpXG4gICAgICBpZiAoZGF0YUZpbGVQYXRoLmVuZHNXaXRoKFwiLmpzb25cIikpIHtcbiAgICAgICAgY29uc3QgZGF0YSA9IEpTT04ucGFyc2UoXG4gICAgICAgICAgZnMucmVhZEZpbGVTeW5jKGRhdGFGaWxlUGF0aCwgeyBlbmNvZGluZzogXCJ1dGYtOFwiIH0pLFxuICAgICAgICApXG4gICAgICAgIGZzLndyaXRlRmlsZVN5bmMoZGF0YUZpbGVQYXRoLCBKU09OLnN0cmluZ2lmeShkYXRhLCBudWxsLCAyKSlcbiAgICAgIH1cbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgY29uc3QgZGF0YSA9IEpTT04ucGFyc2UoXG4gICAgICBmcy5yZWFkRmlsZVN5bmMoZGF0YURpck9yRmlsZVBhdGgsIHsgZW5jb2Rpbmc6IFwidXRmLThcIiB9KSxcbiAgICApXG4gICAgZnMud3JpdGVGaWxlU3luYyhkYXRhRGlyT3JGaWxlUGF0aCwgSlNPTi5zdHJpbmdpZnkoZGF0YSwgbnVsbCwgMikpXG4gIH1cbn1cblxudHlwZSBQcm9jZXNzRGF0YXNldEFyZ3VtZW50cyA9IHtcbiAgZGF0YXNldDogYW55XG4gIGRhdGFEaXI6IHN0cmluZ1xuICBvcHRpb25zOiBhbnlcbn1cblxuY29uc3QgeG1sUGFyc2VyID0gbmV3IFhNTFBhcnNlcih7XG4gIGlnbm9yZURlY2xhcmF0aW9uOiB0cnVlLFxuICBpZ25vcmVBdHRyaWJ1dGVzOiBmYWxzZSxcbiAgaWdub3JlUGlUYWdzOiB0cnVlLFxuICBhdHRyaWJ1dGVOYW1lUHJlZml4OiBcIlwiLFxuICB0ZXh0Tm9kZU5hbWU6IFwiX1wiLFxuICBwcm9jZXNzRW50aXRpZXM6IGZhbHNlLFxuICB0cmltVmFsdWVzOiB0cnVlLFxuICBzdG9wTm9kZXM6IFtcIioudGV4dGVcIiwgXCIqLmludGl0dWxlXCJdLFxuICBwYXJzZVRhZ1ZhbHVlOiBmYWxzZSxcbiAgcGFyc2VBdHRyaWJ1dGVWYWx1ZTogZmFsc2UsXG4gIHRyYW5zZm9ybVRhZ05hbWU6ICh0YWdOYW1lOiBzdHJpbmcpID0+XG4gICAgdGFnTmFtZSA9PT0gXCJQYXJhXCIgPyBcInBhcmFcIiA6IHRhZ05hbWUsXG59KVxuXG4vKipcbiAqIFByb2Nlc3NlcyBhIGRhdGFzZXQgYnkgZmV0Y2hpbmcsIHVuemlwcGluZywgYW5kIGNvbnZlcnRpbmcgZmlsZXMgZnJvbSBYTUwgdG8gSlNPTiBmb3JtYXQuXG4gKlxuICogQHBhcmFtIHthbnl9IGRhdGFzZXQgLSBUaGUgZGF0YXNldCBvYmplY3QgY29udGFpbmluZyBtZXRhZGF0YSBhbmQgcHJvY2Vzc2luZyBpbnN0cnVjdGlvbnMuXG4gKiBAcGFyYW0ge3N0cmluZ30gZGF0YURpciAtIFRoZSBkaXJlY3Rvcnkgd2hlcmUgdGhlIGRhdGFzZXQgZmlsZXMgd2lsbCBiZSBzdG9yZWQuXG4gKiBAcGFyYW0ge2FueX0gb3B0aW9ucyAtIE9wdGlvbnMgdG8gY29udHJvbCB0aGUgcHJvY2Vzc2luZyBiZWhhdmlvciwgc3VjaCBhcyBmZXRjaGluZyBhbmQgc2lsZW50IG1vZGUuXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2hlbiB0aGUgZGF0YXNldCBwcm9jZXNzaW5nIGlzIGNvbXBsZXRlLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcHJvY2Vzc0RhdGFzZXQoXG4gIGFyZ3M6IFByb2Nlc3NEYXRhc2V0QXJndW1lbnRzLFxuKTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IHsgZGF0YXNldCwgZGF0YURpciwgb3B0aW9ucyB9ID0gYXJnc1xuICBjb25zdCB6aXBGaWxlUGF0aCA9IHBhdGguam9pbihkYXRhRGlyLCBgJHtkYXRhc2V0LmZpbGVuYW1lfS56aXBgKVxuICBjb25zdCBkYXRhRGlyT3JGaWxlUGF0aCA9IHBhdGguam9pbihkYXRhRGlyLCBkYXRhc2V0LmZpbGVuYW1lKVxuICBmcy5yZW1vdmVTeW5jKGRhdGFEaXJPckZpbGVQYXRoKVxuXG4gIGlmIChvcHRpb25zLmZldGNoKSB7XG4gICAgLy8gRmV0Y2ggJiBzYXZlIFpJUCBmaWxlLlxuICAgIGlmICghb3B0aW9ucy5zaWxlbnQpIHtcbiAgICAgIGNvbnNvbGUubG9nKGBMb2FkaW5nICR7ZGF0YXNldC50aXRsZX06ICR7ZGF0YXNldC5maWxlbmFtZX0uemlwYClcbiAgICB9XG4gICAgYXdhaXQgZmV0Y2haaXBGaWxlKGRhdGFzZXQudXJsLCB6aXBGaWxlUGF0aClcbiAgfVxuICBpZiAoIW9wdGlvbnMuc2lsZW50KSB7XG4gICAgY29uc29sZS5sb2coYFVuemlwcGluZyAke2RhdGFzZXQudGl0bGV9OiAke2RhdGFzZXQuZmlsZW5hbWV9LnppcGApXG4gIH1cbiAgYXdhaXQgZXh0cmFjdFppcCh6aXBGaWxlUGF0aCwgZGF0YURpcilcblxuICBpZiAoZGF0YXNldC5yZXBhaXJaaXAgIT09IHVuZGVmaW5lZCkge1xuICAgIGlmICghb3B0aW9ucy5zaWxlbnQpIHtcbiAgICAgIGNvbnNvbGUubG9nKGBSZXBhaXJpbmcgJHtkYXRhc2V0LnRpdGxlfTogJHtkYXRhc2V0LmZpbGVuYW1lfWApXG4gICAgfVxuICAgIGRhdGFzZXQucmVwYWlyWmlwKGRhdGFzZXQsIGRhdGFEaXIpXG4gIH1cblxuICAvLyBDb252ZXJ0IHhtbCB0byBKU09OLlxuICBpZiAoZGF0YXNldC5maWxlbmFtZS5lbmRzV2l0aChcIi54bWxcIikpIHtcbiAgICBmb3IgKGNvbnN0IGRhdGFGaWxlU3BsaXRQYXRoIG9mIHdhbGtEaXIoZGF0YURpck9yRmlsZVBhdGgpKSB7XG4gICAgICBjb25zdCBkYXRhRmlsZVBhdGggPSBwYXRoLmpvaW4oZGF0YURpck9yRmlsZVBhdGgsIC4uLmRhdGFGaWxlU3BsaXRQYXRoKVxuICAgICAgaWYgKGRhdGFGaWxlUGF0aC5lbmRzV2l0aChcIi54bWxcIikpIHtcbiAgICAgICAgZnMucmVhZEZpbGUoZGF0YUZpbGVQYXRoLCBmdW5jdGlvbiAoZXJyLCBkYXRhKSB7XG4gICAgICAgICAgaWYgKGVycikgcmV0dXJuIGNvbnNvbGUuZXJyb3IoZXJyKVxuICAgICAgICAgIGxldCByZXN1bHQgPSB4bWxQYXJzZXIucGFyc2UoZGF0YSlcbiAgICAgICAgICBjb25zdCBuZXdEYXRhRmlsZVBhdGggPSBkYXRhRmlsZVBhdGgucmVwbGFjZSgvXFwuW14uXSskLywgXCIuanNvblwiKVxuICAgICAgICAgIGZzLmNvcHkoZGF0YUZpbGVQYXRoLCBuZXdEYXRhRmlsZVBhdGgsIChlcnIpID0+IHtcbiAgICAgICAgICAgIGZzLndyaXRlRmlsZVN5bmMobmV3RGF0YUZpbGVQYXRoLCBKU09OLnN0cmluZ2lmeShyZXN1bHQsIG51bGwsIDIpKVxuICAgICAgICAgICAgaWYgKGVycikgcmV0dXJuIGNvbnNvbGUuZXJyb3IoZXJyKVxuICAgICAgICAgIH0pXG4gICAgICAgIH0pXG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLy8gUmVpbmRlbnQgSlNPTiBmaWxlLlxuICBpZiAoIW9wdGlvbnMuc2lsZW50KSB7XG4gICAgY29uc29sZS5sb2coYFJlaWRlbnRpbmcgJHtkYXRhc2V0LnRpdGxlfTogJHtkYXRhc2V0LmZpbGVuYW1lfWApXG4gIH1cbiAgcmVpbmRlbnRKc29uRmlsZXMoZGF0YURpck9yRmlsZVBhdGgpXG59XG4iXSwibWFwcGluZ3MiOiJBQUFBLE9BQU9BLEVBQUUsTUFBTSxVQUFVO0FBQ3pCLE9BQU9DLElBQUksTUFBTSxNQUFNO0FBQ3ZCLE9BQU9DLE1BQU0sTUFBTSxRQUFRO0FBQzNCLE9BQU9DLFNBQVMsTUFBTSxpQkFBaUI7QUFDdkMsT0FBT0MsSUFBSSxNQUFNLE1BQU07QUFBQSxTQUVkQyxPQUFPO0FBQ2hCLFNBQVNDLFNBQVMsUUFBUSxpQkFBaUI7QUFFM0MsTUFBTUMsUUFBUSxHQUFHSCxJQUFJLENBQUNJLFNBQVMsQ0FBQ04sTUFBTSxDQUFDSyxRQUFRLENBQUM7O0FBRWhEO0FBQ0EsZUFBZUUsWUFBWUEsQ0FDekJDLEdBQVcsRUFDWEMsV0FBbUIsRUFDbkJDLE9BQU8sR0FBRyxDQUFDLEVB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