UNPKG

vitepress-theme-async

Version:

<h1 align="center">vitepress-theme-async</h1>

273 lines (269 loc) 8.59 kB
// plugin/page.ts import fs from "node:fs"; import path from "node:path"; import matter from "gray-matter"; // utils/shared.ts var dataPath = (data, paths) => { const keys = paths.split("."); if (!isObject(data)) return; const len = keys.length; for (let index = 0; index < len; index++) { const key = keys[index]; if (!isObject(data[key]) && index < len - 1) { return; } else { data = data[key]; } } return data; }; var groupBy = (data, path2, convert) => { const map = /* @__PURE__ */ new Map(); convert = convert ?? ((key) => key); const setMap = (key) => { const id = convert(key); if (map.has(id)) { map.set(id, map.get(id) + 1); } else { map.set(id, 1); } }; data.forEach((item) => { const val = dataPath(item, path2); if ((val ?? "") !== "") { if (Array.isArray(val)) { for (let index = 0; index < val.length; index++) { setMap(val[index]); } } else { setMap(val); } } else { setMap(""); } }); return Array.from(map); }; var parseArgs = (orderby) => { const result = []; if (typeof orderby === "string") { const arr = orderby.split(" "); for (let i = 0, len = arr.length; i < len; i++) { const key = arr[i]; switch (key[0]) { case "+": result.push([key.slice(1), 1]); break; case "-": result.push([key.slice(1), -1]); break; default: result.push([key, 1]); } } } else { result.push( ...Object.keys(orderby).map((key) => { return [key, orderby[key]]; }) ); } return result; }; var sortBy = (data, orderby) => { const sort = parseArgs(orderby); const len = sort.length; return data.sort((a, b) => { for (let index = 0; index < len; index++) { const [key, order] = sort[index]; if (a[key] === b[key]) { continue; } else { return order > 0 ? a[key] - b[key] : b[key] - a[key]; } } return 0; }); }; var joinPath = (base, ...paths) => `${base}/${paths.join("/")}`.replace(/\/+/g, "/"); var isString = (value) => Object.prototype.toString.call(value) === "[object String]"; var isObject = (val) => Object.prototype.toString.call(val) === "[object Object]"; var formatDate = (d, fmt = "yyyy-MM-dd HH:mm:ss") => { if (!(d instanceof Date)) { if (isString(d)) { d = d.replace(/-/gs, "/"); } d = d ? new Date(d) : /* @__PURE__ */ new Date(); } const o = { "M+": d.getMonth() + 1, "(d|D)+": d.getDate(), "(h|H)+": d.getHours(), "m+": d.getMinutes(), "s+": d.getSeconds(), "q+": Math.floor((d.getMonth() + 3) / 3), S: d.getMilliseconds() }; if (/((Y|y)+)/.test(fmt)) { fmt = fmt.replace(RegExp.$1, (d.getFullYear() + "").substring(4 - RegExp.$1.length)); } for (const k in o) { if (new RegExp("(" + k + ")").test(fmt)) { const val = o[k].toString(); fmt = fmt.replace(RegExp.$1, RegExp.$1.length === 1 ? val : ("00" + val).substring(val.length)); } } return fmt; }; // utils/node/index.ts import { spawnSync } from "node:child_process"; function getFileBirthTime(url) { try { const infoStr = spawnSync("git", ["log", '--pretty="%ci"', url]).stdout?.toString().replace(/["']/g, "").trim(); const timeList = infoStr.split("\n").filter((item) => Boolean(item.trim())); if (timeList.length > 0) { return new Date(timeList.pop()).getTime(); } } catch (error) { return void 0; } } // plugin/page.ts import { normalizePath } from "vite"; var cache = /* @__PURE__ */ new Map(); var getFiles = (dir) => { let results = []; const files = fs.readdirSync(dir); for (const file of files) { const filePath = path.join(dir, file); const stat = fs.statSync(filePath); if (stat && stat.isDirectory()) { if (file !== "node_modules" && file !== "dist") { results = results.concat(getFiles(filePath)); } } else { if (/\.md$/.test(file)) { results.push(path.resolve(filePath)); } } } return results; }; var getMeta = (files, timeZone) => { const raw = []; for (const file of files) { const { mtimeMs: timestamp, birthtimeMs } = fs.statSync(file); const cached = cache.get(file); if (cached && timestamp === cached.timestamp) { raw.push(cached.data); continue; } const fileContent = fs.readFileSync(file, "utf-8"); const { data: meta } = matter(fileContent); timeZone = timeZone ?? 8; if (!meta.date) { meta.date = getFileBirthTime(file); if (!meta.date) { meta.date = birthtimeMs; } } else { meta.date = (/* @__PURE__ */ new Date(`${new Date(meta.date).toUTCString()}+${timeZone}`)).getTime(); } meta.tags = typeof meta.tags === "string" ? [meta.tags] : meta.tags || []; meta.categories = typeof meta.categories === "string" ? [meta.categories.trim()] : meta.categories || []; raw.push(meta); cache.set(file, { data: meta, timestamp }); } return raw; }; var generatePages = (len, pageSize, paramKey, otherPageName, fitstPageName) => { otherPageName = otherPageName.replace(/^\//, ""); fitstPageName = fitstPageName.replace(/^\//, ""); const count = Math.ceil(len / pageSize); return new Array(count).fill(null).map((_, i) => { return i === 0 ? { params: { [paramKey]: fitstPageName, index: fitstPageName } } : { params: { [paramKey]: joinPath(otherPageName, (i + 1).toString()), index: joinPath(otherPageName, (i + 1).toString()) } }; }); }; var generatePagesByType = async (files, config, pageType, processFn) => { const raw = getMeta(files, config.themeConfig?.timeZone || 8); const pageSize = (pageType === "index" ? config.themeConfig?.indexGenerator?.perPage : config.themeConfig?.archiveGenerator?.perPage) || 10; const type = pageType; const paramKey = pageType; const baseName = config.themeConfig?.page?.[pageType] || pageType; const basePageName = baseName.replace(/(\/index$|^index$)/, ""); let firstPageName = baseName; if (/\/$/.test(firstPageName) || firstPageName === "") { firstPageName = joinPath(firstPageName, "index"); } const len = ["index", "archives"].includes(pageType) ? files.length : raw.filter((item) => item[type].length).length; const defpage = generatePages(len, pageSize, paramKey, joinPath(basePageName, "page"), firstPageName); if (processFn) { const childPage = processFn(raw, config).map(([key, val]) => { const childrFirstName = joinPath(basePageName, key); const childOtherName = joinPath(childrFirstName, "page"); return generatePages(val, pageSize, paramKey, childOtherName, childrFirstName); }).flat(1); defpage.push(...childPage); } return [...defpage]; }; var pageIndex = async (files, config, pageType) => { return generatePagesByType(files, config, pageType); }; var tagPageIndex = async (files, config, pageType) => { const processFn = (raw) => sortBy(groupBy(raw, "tags"), { 1: -1 }); return generatePagesByType(files, config, pageType, processFn); }; var categoriePageIndex = async (files, config, pageType) => { const processFn = (raw) => sortBy(groupBy(raw, "categories"), { 1: -1 }); return generatePagesByType(files, config, pageType, processFn); }; var archivePageIndex = async (files, config, pageType) => { const processFn = (raw) => sortBy( groupBy(raw, "date", (date) => formatDate(date, config.themeConfig?.archiveGenerator?.dateFmt || "YYYY")), { 0: -1 } ); return generatePagesByType(files, config, pageType, processFn); }; var dynamicPages = async (config, pageType, root) => { if (!root) { const argv = process.argv.slice(2); const command = argv[0]; const dir = argv[command ? 1 : 0] || process.cwd(); root = normalizePath(path.resolve(dir)); } const srcDir = normalizePath(path.resolve(root, config.srcDir || ".")); const files = getFiles(normalizePath(`${srcDir}/${config.themeConfig?.postDir ?? "posts"}`)); let paths = []; switch (pageType) { case "index": paths = await pageIndex(files, config, pageType); break; case "tags": paths = await tagPageIndex(files, config, pageType); break; case "archives": paths = await archivePageIndex(files, config, pageType); break; case "categories": paths = await categoriePageIndex(files, config, pageType); break; default: break; } return paths; }; export { dynamicPages };