126 lines
3.7 KiB
JavaScript
126 lines
3.7 KiB
JavaScript
const fs = require("node:fs/promises");
|
|
const path = require("node:path");
|
|
|
|
const ALLOWED_DOC_EXTS = new Set([".pdf", ".tif", ".tiff"]);
|
|
|
|
function matchesPattern(filename, pattern) {
|
|
if (!filename || !pattern) return false;
|
|
const fname = filename.toLowerCase();
|
|
const pat = pattern.toLowerCase().trim();
|
|
const ext = path.extname(fname);
|
|
if (!ALLOWED_DOC_EXTS.has(ext)) return false;
|
|
|
|
const hasWildcards = pat.includes("*") || pat.includes("?");
|
|
if (hasWildcards) {
|
|
const pExt = path.extname(pat);
|
|
if (ALLOWED_DOC_EXTS.has(pExt)) {
|
|
return fnmatch(fname, pat);
|
|
}
|
|
const stem = path.basename(fname, ext);
|
|
return fnmatch(stem, pat);
|
|
}
|
|
return fname.includes(pat);
|
|
}
|
|
|
|
function fnmatch(name, pattern) {
|
|
const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".");
|
|
return new RegExp(`^${escaped}$`, "i").test(name);
|
|
}
|
|
|
|
async function listDirSafe(dirPath) {
|
|
try {
|
|
return await fs.readdir(dirPath, { withFileTypes: true });
|
|
} catch {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
async function statSize(filePath) {
|
|
try {
|
|
const stat = await fs.stat(filePath);
|
|
return stat.size;
|
|
} catch {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
async function findFirstMatchingFile(files, keyword) {
|
|
const sorted = [...files].sort((a, b) => a.localeCompare(b, undefined, { numeric: true }));
|
|
if (!keyword) {
|
|
return sorted.find((name) => ALLOWED_DOC_EXTS.has(path.extname(name).toLowerCase())) || null;
|
|
}
|
|
return sorted.find((name) => matchesPattern(name, keyword)) || null;
|
|
}
|
|
|
|
async function indexRadicados(rootPath, docTypes) {
|
|
const entries = [];
|
|
const radicadoDirs = (await listDirSafe(rootPath))
|
|
.filter((entry) => entry.isDirectory())
|
|
.map((entry) => entry.name)
|
|
.sort((a, b) => a.localeCompare(b, undefined, { numeric: true }));
|
|
|
|
for (const radicado of radicadoDirs) {
|
|
const radPath = path.join(rootPath, radicado);
|
|
const files = (await listDirSafe(radPath))
|
|
.filter((entry) => entry.isFile())
|
|
.map((entry) => entry.name);
|
|
|
|
for (const docType of docTypes) {
|
|
const name = String(docType.name || "").trim();
|
|
const keyword = String(docType.keyword || "").trim();
|
|
if (!name || !keyword) continue;
|
|
const match = await findFirstMatchingFile(files, keyword);
|
|
if (!match) continue;
|
|
const localPath = path.join(radPath, match);
|
|
entries.push({
|
|
radicado,
|
|
filename: match,
|
|
docType: name,
|
|
localPath,
|
|
size: await statSize(localPath),
|
|
});
|
|
}
|
|
}
|
|
return entries;
|
|
}
|
|
|
|
async function indexGeneral(rootPath, keywords) {
|
|
const entries = [];
|
|
const normalizedKeywords = (keywords || [])
|
|
.map((item) => String(item || "").trim())
|
|
.filter(Boolean);
|
|
const files = (await listDirSafe(rootPath))
|
|
.filter((entry) => entry.isFile())
|
|
.map((entry) => entry.name)
|
|
.filter((name) => ALLOWED_DOC_EXTS.has(path.extname(name).toLowerCase()))
|
|
.sort((a, b) => a.localeCompare(b, undefined, { numeric: true }));
|
|
|
|
for (const filename of files) {
|
|
if (normalizedKeywords.length > 0 && !normalizedKeywords.some((kw) => matchesPattern(filename, kw))) {
|
|
continue;
|
|
}
|
|
const localPath = path.join(rootPath, filename);
|
|
entries.push({
|
|
radicado: path.basename(filename, path.extname(filename)),
|
|
filename,
|
|
localPath,
|
|
size: await statSize(localPath),
|
|
});
|
|
}
|
|
return entries;
|
|
}
|
|
|
|
async function indexFolder(rootPath, structureMode, docTypes, keywords) {
|
|
const mode = structureMode === "general" ? "general" : "radicados";
|
|
if (mode === "general") {
|
|
return indexGeneral(rootPath, keywords);
|
|
}
|
|
return indexRadicados(rootPath, docTypes || []);
|
|
}
|
|
|
|
module.exports = {
|
|
indexFolder,
|
|
matchesPattern,
|
|
ALLOWED_DOC_EXTS,
|
|
};
|