Ajoute un script d'import d'images Wikimedia
This commit is contained in:
163
tools/lib/bundles.js
Normal file
163
tools/lib/bundles.js
Normal file
@@ -0,0 +1,163 @@
|
||||
const fs = require("node:fs");
|
||||
const fsPromises = require("node:fs/promises");
|
||||
const path = require("node:path");
|
||||
const readline = require("node:readline/promises");
|
||||
const { stdin, stdout } = require("node:process");
|
||||
|
||||
/**
|
||||
* Normalise une entrée utilisateur vers le dossier du bundle.
|
||||
* @param {string} input Chemin saisi par l'utilisateur.
|
||||
* @returns {string} Chemin absolu du bundle.
|
||||
*/
|
||||
function resolveBundlePath(input) {
|
||||
if (typeof input !== "string" || !input.trim()) {
|
||||
throw new Error("Le chemin du bundle est vide.");
|
||||
}
|
||||
|
||||
const resolved = path.resolve(input);
|
||||
if (resolved.toLowerCase().endsWith(`${path.sep}index.md`)) {
|
||||
return path.dirname(resolved);
|
||||
}
|
||||
return resolved;
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie qu'un dossier correspond bien à un bundle Hugo.
|
||||
* @param {string} bundleDir Chemin absolu du bundle.
|
||||
*/
|
||||
function ensureBundleExists(bundleDir) {
|
||||
if (!fs.existsSync(bundleDir)) {
|
||||
throw new Error(`Le bundle ${bundleDir} est introuvable.`);
|
||||
}
|
||||
|
||||
const stats = fs.statSync(bundleDir);
|
||||
if (!stats.isDirectory()) {
|
||||
throw new Error(`Le bundle ${bundleDir} n'est pas un dossier.`);
|
||||
}
|
||||
|
||||
const indexPath = path.join(bundleDir, "index.md");
|
||||
if (!fs.existsSync(indexPath)) {
|
||||
throw new Error(`Le bundle ${bundleDir} ne contient pas index.md.`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pose une question simple à l'utilisateur.
|
||||
* @param {string} query Texte affiché dans le terminal.
|
||||
* @returns {Promise<string>} Réponse nettoyée.
|
||||
*/
|
||||
async function askQuestion(query) {
|
||||
const rl = readline.createInterface({ input: stdin, output: stdout });
|
||||
const answer = await rl.question(query);
|
||||
rl.close();
|
||||
return answer.trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* Cherche le bundle modifié le plus récemment sous un répertoire racine.
|
||||
* @param {string} rootDir Racine à parcourir.
|
||||
* @returns {Promise<string|null>} Chemin absolu du dernier bundle trouvé.
|
||||
*/
|
||||
async function findLatestBundle(rootDir) {
|
||||
let latestPath = null;
|
||||
let latestTime = 0;
|
||||
|
||||
await walk(rootDir);
|
||||
|
||||
return latestPath;
|
||||
|
||||
/**
|
||||
* Parcourt récursivement l'arborescence et conserve le bundle le plus récent.
|
||||
* @param {string} currentDir Dossier en cours d'analyse.
|
||||
*/
|
||||
async function walk(currentDir) {
|
||||
const entries = await fsPromises.readdir(currentDir, { withFileTypes: true });
|
||||
let hasIndex = false;
|
||||
|
||||
for (const entry of entries) {
|
||||
if (entry.isFile() && entry.name === "index.md") {
|
||||
hasIndex = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasIndex) {
|
||||
const stats = await fsPromises.stat(currentDir);
|
||||
if (stats.mtimeMs > latestTime) {
|
||||
latestTime = stats.mtimeMs;
|
||||
latestPath = currentDir;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
for (const entry of entries) {
|
||||
if (!entry.isDirectory()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const childDir = path.join(currentDir, entry.name);
|
||||
await walk(childDir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Résout le bundle cible à partir d'un chemin manuel ou du dernier bundle trouvé.
|
||||
* @param {string|null|undefined} manualPath Chemin optionnel fourni en argument.
|
||||
* @param {{ contentDir: string, prompts?: { confirmLatest: Function, manualPath: string } }} options Options de résolution.
|
||||
* @returns {Promise<string>} Chemin absolu du bundle retenu.
|
||||
*/
|
||||
async function promptForBundlePath(manualPath, options) {
|
||||
let contentDir = path.resolve("content");
|
||||
if (options && typeof options.contentDir === "string" && options.contentDir.trim()) {
|
||||
contentDir = path.resolve(options.contentDir);
|
||||
}
|
||||
|
||||
const defaultPrompts = {
|
||||
confirmLatest(latest) {
|
||||
return `Use latest bundle found: ${latest}? (Y/n) `;
|
||||
},
|
||||
manualPath: "Enter the relative path to your bundle: ",
|
||||
};
|
||||
let prompts = defaultPrompts;
|
||||
|
||||
if (options && options.prompts && typeof options.prompts === "object") {
|
||||
prompts = {
|
||||
confirmLatest: defaultPrompts.confirmLatest,
|
||||
manualPath: defaultPrompts.manualPath,
|
||||
};
|
||||
|
||||
if (typeof options.prompts.confirmLatest === "function") {
|
||||
prompts.confirmLatest = options.prompts.confirmLatest;
|
||||
}
|
||||
|
||||
if (typeof options.prompts.manualPath === "string" && options.prompts.manualPath.trim()) {
|
||||
prompts.manualPath = options.prompts.manualPath;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof manualPath === "string" && manualPath.trim()) {
|
||||
return resolveBundlePath(manualPath);
|
||||
}
|
||||
|
||||
const latest = await findLatestBundle(contentDir);
|
||||
if (!latest) {
|
||||
throw new Error("Aucun bundle n'a été trouvé sous content/.");
|
||||
}
|
||||
|
||||
const confirm = await askQuestion(prompts.confirmLatest(latest));
|
||||
if (confirm.toLowerCase() === "n") {
|
||||
const inputPath = await askQuestion(prompts.manualPath);
|
||||
return resolveBundlePath(inputPath);
|
||||
}
|
||||
|
||||
return latest;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
resolveBundlePath,
|
||||
ensureBundleExists,
|
||||
askQuestion,
|
||||
findLatestBundle,
|
||||
promptForBundlePath,
|
||||
};
|
||||
Reference in New Issue
Block a user