const fs = require("fs/promises"); const path = require("path"); async function collectMarkdownFiles(rootDir, { skipIndex = true } = {}) { const entries = await fs.readdir(rootDir, { withFileTypes: true }); const files = []; for (const entry of entries) { const fullPath = path.join(rootDir, entry.name); if (entry.isDirectory()) { const nested = await collectMarkdownFiles(fullPath, { skipIndex }); files.push(...nested); continue; } if (!entry.isFile()) continue; if (!entry.name.toLowerCase().endsWith(".md")) continue; if (skipIndex && entry.name === "_index.md") continue; files.push(fullPath); } return files; } async function collectSectionIndexDirs(rootDir) { const sections = new Set(); async function walk(dir) { let entries; try { entries = await fs.readdir(dir, { withFileTypes: true }); } catch (error) { console.error(`Skipping section scan for ${dir}: ${error.message}`); return; } let hasIndex = false; for (const entry of entries) { if (entry.isFile() && entry.name.toLowerCase() === "_index.md") { hasIndex = true; break; } } if (hasIndex) { sections.add(path.resolve(dir)); } for (const entry of entries) { if (entry.isDirectory()) { await walk(path.join(dir, entry.name)); } } } await walk(rootDir); return sections; } async function resolveMarkdownTargets(inputs, { rootDir = process.cwd(), skipIndex = true } = {}) { if (!inputs || inputs.length === 0) { return collectMarkdownFiles(rootDir, { skipIndex }); } const targets = new Set(); for (const input of inputs) { const resolved = path.resolve(input); try { const stat = await fs.stat(resolved); if (stat.isDirectory()) { const nested = await collectMarkdownFiles(resolved, { skipIndex }); nested.forEach((file) => targets.add(file)); continue; } if (stat.isFile()) { const lower = resolved.toLowerCase(); if (!lower.endsWith(".md")) continue; if (skipIndex && path.basename(resolved) === "_index.md") continue; targets.add(resolved); } } catch (error) { console.error(`Skipping ${input}: ${error.message}`); } } return Array.from(targets); } async function collectBundles(rootDir) { const bundles = []; await walk(rootDir, rootDir, bundles); bundles.sort((a, b) => a.relativePath.localeCompare(b.relativePath)); return bundles; } async function walk(rootDir, currentDir, bucket) { let entries; try { entries = await fs.readdir(currentDir, { withFileTypes: true }); } catch (error) { console.warn(`⚠️ Lecture impossible de ${currentDir}: ${error.message}`); return; } let hasIndex = false; for (const entry of entries) { if (entry.isFile() && entry.name === "index.md") { hasIndex = true; break; } } if (hasIndex) { const relative = path.relative(rootDir, currentDir); const parts = relative.split(path.sep).filter(Boolean); const slug = parts[parts.length - 1] || path.basename(currentDir); bucket.push({ dir: currentDir, indexPath: path.join(currentDir, "index.md"), relativePath: parts.join("/"), parts, slug, }); } for (const entry of entries) { if (!entry.isDirectory()) continue; if (entry.name === ".git" || entry.name === "node_modules") continue; await walk(rootDir, path.join(currentDir, entry.name), bucket); } } module.exports = { collectMarkdownFiles, collectSectionIndexDirs, resolveMarkdownTargets, collectBundles, };