Files
IPSExtractor/services/desktop_app/electron/folderIndex.cjs
T

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,
};