daedalOS/scripts/searchIndex.js
2023-12-23 14:20:03 -08:00

134 lines
2.9 KiB
JavaScript

const {
existsSync,
readdirSync,
readFileSync,
statSync,
writeFileSync,
mkdirSync,
} = require("fs");
const { basename, extname, join } = require("path");
const { parse } = require("ini");
const lunr = require("lunr");
const PUBLIC_PATH = "public";
const SEARCH_EXTENSIONS = require("./searchExtensions.json");
const IGNORE_FILES = new Set([
"desktop.ini",
"favicon.ico",
"fs.9p.json",
"preload.json",
"robots.txt",
"search.lunr.json",
"sitemap.xml",
]);
const IGNORE_PATHS = [
".index",
"Program Files",
"System",
"Users/Public/Icons",
"Users/Public/Pictures/Blog",
];
const indexData = [];
const normalizePath = (path) =>
path.replace(/\\/g, "/").replace(PUBLIC_PATH, "");
const normalizeText = (text) =>
text.replace(/\r?\n|\r/g, " ").replace(/<\/?[^>]+(>|$)/g, "");
const keyPathMap = {};
const keyPathMapper = (path) =>
(keyPathMap[path] ||= Object.keys(keyPathMap).length);
const createSearchIndex = (path) => {
const directoryContents = readdirSync(path);
const normalizedPath = normalizePath(path);
if (normalizedPath) {
const name = basename(path);
indexData.push({
name,
path: keyPathMapper(normalizedPath),
text: normalizeText(
[
name,
...directoryContents.filter(
(entry) => !statSync(join(path, entry)).isDirectory()
),
].join(" ")
),
});
}
directoryContents.forEach((entry) => {
if (
IGNORE_PATHS.some((ignoredPath) =>
path.startsWith(join(PUBLIC_PATH, ignoredPath))
)
) {
return;
}
const fullPath = join(path, entry);
const stats = statSync(fullPath);
if (stats.isDirectory()) {
createSearchIndex(fullPath);
} else if (
!IGNORE_FILES.has(entry) &&
!SEARCH_EXTENSIONS.ignore.includes(extname(entry).toLowerCase())
) {
const keyPath = normalizePath(fullPath);
if (extname(entry).toLowerCase() === ".url") {
const {
InternetShortcut: { URL: url = "" },
} = parse(readFileSync(fullPath).toString());
if (url.length > 1 && url.startsWith("/")) {
return;
}
}
const name = basename(keyPath, extname(keyPath));
indexData.push({
name,
path: keyPathMapper(keyPath),
text: SEARCH_EXTENSIONS.index.includes(extname(entry).toLowerCase())
? `${name} ${normalizeText(readFileSync(fullPath, "utf8"))}`
: name,
});
}
});
};
createSearchIndex(PUBLIC_PATH);
const searchIndex = lunr(function () {
this.ref("path");
this.field("name");
this.field("text");
indexData.forEach((doc) => this.add(doc));
});
if (!existsSync(join(PUBLIC_PATH, ".index"))) {
mkdirSync(join(PUBLIC_PATH, ".index"));
}
const searchJson = searchIndex.toJSON();
searchJson.paths = Object.keys(keyPathMap);
writeFileSync(
join(PUBLIC_PATH, ".index/search.lunr.json"),
JSON.stringify(searchJson),
{
flag: "w",
}
);