first-commit
Some checks failed
CI Pipeline / build (push) Failing after 3m23s

This commit is contained in:
2025-08-27 14:05:33 +08:00
commit 9e1b8bdc9d
5159 changed files with 1081326 additions and 0 deletions

View File

@@ -0,0 +1,33 @@
// adapted from https://stackoverflow.com/a/46432113/11613622
export class LRUCache {
max;
cache;
constructor(max = 10) {
this.max = max;
this.cache = new Map();
}
get(key) {
let item = this.cache.get(key);
if (item !== undefined) {
// refresh key
this.cache.delete(key);
this.cache.set(key, item);
}
return item;
}
set(key, val) {
// refresh key
if (this.cache.has(key))
this.cache.delete(key);
// evict oldest
else if (this.cache.size === this.max)
this.cache.delete(this.first());
this.cache.set(key, val);
}
first() {
return this.cache.keys().next().value;
}
clear() {
this.cache.clear();
}
}

View File

@@ -0,0 +1,89 @@
import { isActive } from '../../shared';
import { ensureStartingSlash } from './utils';
/**
* Get the `Sidebar` from sidebar option. This method will ensure to get correct
* sidebar config from `MultiSideBarConfig` with various path combinations such
* as matching `guide/` and `/guide/`. If no matching config was found, it will
* return empty array.
*/
export function getSidebar(_sidebar, path) {
if (Array.isArray(_sidebar))
return addBase(_sidebar);
if (_sidebar == null)
return [];
path = ensureStartingSlash(path);
const dir = Object.keys(_sidebar)
.sort((a, b) => {
return b.split('/').length - a.split('/').length;
})
.find((dir) => {
// make sure the multi sidebar key starts with slash too
return path.startsWith(ensureStartingSlash(dir));
});
const sidebar = dir ? _sidebar[dir] : [];
return Array.isArray(sidebar)
? addBase(sidebar)
: addBase(sidebar.items, sidebar.base);
}
/**
* Get or generate sidebar group from the given sidebar items.
*/
export function getSidebarGroups(sidebar) {
const groups = [];
let lastGroupIndex = 0;
for (const index in sidebar) {
const item = sidebar[index];
if (item.items) {
lastGroupIndex = groups.push(item);
continue;
}
if (!groups[lastGroupIndex]) {
groups.push({ items: [] });
}
groups[lastGroupIndex].items.push(item);
}
return groups;
}
export function getFlatSideBarLinks(sidebar) {
const links = [];
function recursivelyExtractLinks(items) {
for (const item of items) {
if (item.text && item.link) {
links.push({
text: item.text,
link: item.link,
docFooterText: item.docFooterText
});
}
if (item.items) {
recursivelyExtractLinks(item.items);
}
}
}
recursivelyExtractLinks(sidebar);
return links;
}
/**
* Check if the given sidebar item contains any active link.
*/
export function hasActiveLink(path, items) {
if (Array.isArray(items)) {
return items.some((item) => hasActiveLink(path, item));
}
return isActive(path, items.link)
? true
: items.items
? hasActiveLink(path, items.items)
: false;
}
function addBase(items, _base) {
return [...items].map((_item) => {
const item = { ..._item };
const base = item.base || _base;
if (base && item.link)
item.link = base + item.link;
if (item.items)
item.items = addBase(item.items, base);
return item;
});
}

View File

@@ -0,0 +1,49 @@
import { useData } from '../composables/data';
/**
* @param themeObject Can be an object with `translations` and `locales` properties
*/
export function createSearchTranslate(defaultTranslations) {
const { localeIndex, theme } = useData();
function translate(key) {
const keyPath = key.split('.');
const themeObject = theme.value.search?.options;
const isObject = themeObject && typeof themeObject === 'object';
const locales = (isObject && themeObject.locales?.[localeIndex.value]?.translations) ||
null;
const translations = (isObject && themeObject.translations) || null;
let localeResult = locales;
let translationResult = translations;
let defaultResult = defaultTranslations;
const lastKey = keyPath.pop();
for (const k of keyPath) {
let fallbackResult = null;
const foundInFallback = defaultResult?.[k];
if (foundInFallback) {
fallbackResult = defaultResult = foundInFallback;
}
const foundInTranslation = translationResult?.[k];
if (foundInTranslation) {
fallbackResult = translationResult = foundInTranslation;
}
const foundInLocale = localeResult?.[k];
if (foundInLocale) {
fallbackResult = localeResult = foundInLocale;
}
// Put fallback into unresolved results
if (!foundInFallback) {
defaultResult = fallbackResult;
}
if (!foundInTranslation) {
translationResult = fallbackResult;
}
if (!foundInLocale) {
localeResult = fallbackResult;
}
}
return (localeResult?.[lastKey] ??
translationResult?.[lastKey] ??
defaultResult?.[lastKey] ??
'');
}
return translate;
}

View File

@@ -0,0 +1,33 @@
import { withBase } from 'vitepress';
import { isExternal, treatAsHtml } from '../../shared';
import { useData } from '../composables/data';
export function throttleAndDebounce(fn, delay) {
let timeoutId;
let called = false;
return () => {
if (timeoutId)
clearTimeout(timeoutId);
if (!called) {
fn();
(called = true) && setTimeout(() => (called = false), delay);
}
else
timeoutId = setTimeout(fn, delay);
};
}
export function ensureStartingSlash(path) {
return path.startsWith('/') ? path : `/${path}`;
}
export function normalizeLink(url) {
const { pathname, search, hash, protocol } = new URL(url, 'http://a.com');
if (isExternal(url) ||
url.startsWith('#') ||
!protocol.startsWith('http') ||
!treatAsHtml(pathname))
return url;
const { site } = useData();
const normalizedPath = pathname.endsWith('/') || pathname.endsWith('.html')
? url
: url.replace(/(?:(^\.+)\/)?.*$/, `$1${pathname.replace(/(\.md)?$/, site.value.cleanUrls ? '' : '.html')}${search}${hash}`);
return withBase(normalizedPath);
}