mirror of
https://github.com/siteboon/claudecodeui.git
synced 2026-06-21 16:41:57 +08:00
87 lines
2.8 KiB
TypeScript
87 lines
2.8 KiB
TypeScript
export function decodeHtmlEntities(text: string) {
|
|
if (!text) return text;
|
|
return text
|
|
.replace(/</g, '<')
|
|
.replace(/>/g, '>')
|
|
.replace(/"/g, '"')
|
|
.replace(/'/g, "'")
|
|
.replace(/&/g, '&');
|
|
}
|
|
|
|
export function normalizeInlineCodeFences(text: string) {
|
|
if (!text || typeof text !== 'string') return text;
|
|
try {
|
|
return text.replace(/```[ \t]*([^\n\r]+?)[ \t]*```/g, '`$1`');
|
|
} catch {
|
|
return text;
|
|
}
|
|
}
|
|
|
|
export function unescapeWithMathProtection(text: string) {
|
|
if (!text || typeof text !== 'string') return text;
|
|
|
|
const mathBlocks: string[] = [];
|
|
const placeholderPrefix = '__MATH_BLOCK_';
|
|
const placeholderSuffix = '__';
|
|
|
|
let processedText = text.replace(/\$\$([\s\S]*?)\$\$|\$([^\$\n]+?)\$/g, (match) => {
|
|
const index = mathBlocks.length;
|
|
mathBlocks.push(match);
|
|
return `${placeholderPrefix}${index}${placeholderSuffix}`;
|
|
});
|
|
|
|
processedText = processedText.replace(/\\n/g, '\n').replace(/\\t/g, '\t').replace(/\\r/g, '\r');
|
|
|
|
processedText = processedText.replace(
|
|
new RegExp(`${placeholderPrefix}(\\d+)${placeholderSuffix}`, 'g'),
|
|
(match, index) => {
|
|
return mathBlocks[parseInt(index, 10)];
|
|
},
|
|
);
|
|
|
|
return processedText;
|
|
}
|
|
|
|
export function escapeRegExp(value: string) {
|
|
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
}
|
|
|
|
export function formatUsageLimitText(text: string) {
|
|
try {
|
|
if (typeof text !== 'string') return text;
|
|
return text.replace(/Claude AI usage limit reached\|(\d{10,13})/g, (match, ts) => {
|
|
let timestampMs = parseInt(ts, 10);
|
|
if (!Number.isFinite(timestampMs)) return match;
|
|
if (timestampMs < 1e12) timestampMs *= 1000;
|
|
const reset = new Date(timestampMs);
|
|
|
|
const timeStr = new Intl.DateTimeFormat(undefined, {
|
|
hour: '2-digit',
|
|
minute: '2-digit',
|
|
hour12: false,
|
|
}).format(reset);
|
|
|
|
const offsetMinutesLocal = -reset.getTimezoneOffset();
|
|
const sign = offsetMinutesLocal >= 0 ? '+' : '-';
|
|
const abs = Math.abs(offsetMinutesLocal);
|
|
const offH = Math.floor(abs / 60);
|
|
const offM = abs % 60;
|
|
const gmt = `GMT${sign}${offH}${offM ? ':' + String(offM).padStart(2, '0') : ''}`;
|
|
const tzId = Intl.DateTimeFormat().resolvedOptions().timeZone || '';
|
|
const cityRaw = tzId.split('/').pop() || '';
|
|
const city = cityRaw
|
|
.replace(/_/g, ' ')
|
|
.toLowerCase()
|
|
.replace(/\b\w/g, (char) => char.toUpperCase());
|
|
const tzHuman = city ? `${gmt} (${city})` : gmt;
|
|
|
|
const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
|
|
const dateReadable = `${reset.getDate()} ${months[reset.getMonth()]} ${reset.getFullYear()}`;
|
|
|
|
return `Claude usage limit reached. Your limit will reset at **${timeStr} ${tzHuman}** - ${dateReadable}`;
|
|
});
|
|
} catch {
|
|
return text;
|
|
}
|
|
}
|