-
Notifications
You must be signed in to change notification settings - Fork 62
Expand file tree
/
Copy pathgrouped-entry-normalization.ts
More file actions
148 lines (124 loc) · 4.45 KB
/
Copy pathgrouped-entry-normalization.ts
File metadata and controls
148 lines (124 loc) · 4.45 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
import type { QuotaToastEntry } from "./entries.js";
export type GroupedRenderTarget = "toast" | "quota";
export type NormalizedGroupedQuotaEntry = QuotaToastEntry & {
group: string;
};
export type QuotaEntryGroup = {
group: string;
entries: NormalizedGroupedQuotaEntry[];
};
type RankedGroupedQuotaEntry = {
entry: NormalizedGroupedQuotaEntry;
originalIndex: number;
rank: number | null;
};
function trimOptional(value?: string): string | undefined {
const trimmed = value?.trim();
return trimmed ? trimmed : undefined;
}
function normalizeDurationText(value?: string): string | undefined {
const trimmed = trimOptional(value);
return trimmed?.replace(/:+$/u, "").trim().toLowerCase();
}
function looksLikeGoogleModel(name: string): boolean {
const lower = name.toLowerCase();
return lower === "claude" || lower === "g3pro" || lower === "g3flash" || lower === "g3image" || lower === "gpt-oss";
}
function getGoogleFallbackMeta(name: string): { group: string; label: string } | undefined {
const match = name.match(/^(.+?)\s*\((.+)\)\s*$/);
if (!match) return undefined;
const model = match[1]!.trim();
const account = match[2]!.trim();
if (!looksLikeGoogleModel(model) || !account) return undefined;
return {
group: `Google Antigravity (${account})`,
label: `${model}:`,
};
}
function getDurationRankFromText(value?: string): number | null {
const text = normalizeDurationText(value);
if (!text) return null;
if (/\b(?:rpm|per minute|minute|minutes)\b/u.test(text)) return 1;
if (/\b(?:rolling|5h|5 h|5-hour|5 hour|five-hour|five hour)\b/u.test(text)) return 300;
if (/\b(?:hourly|1h|1 h|1-hour|1 hour|hour)\b/u.test(text)) return 60;
if (/\b(?:7d|7 d|7-day|7 day|weekly|week)\b/u.test(text)) return 10080;
if (/\b(?:daily|1d|1 d|1-day|1 day|day)\b/u.test(text)) return 1440;
if (/\b(?:monthly|month)\b/u.test(text)) return 43200;
if (/\b(?:yearly|annual|annually|year)\b/u.test(text)) return 525600;
return null;
}
function getDurationRank(entry: NormalizedGroupedQuotaEntry): number | null {
return entry.label ? getDurationRankFromText(entry.label) : getDurationRankFromText(entry.name);
}
function normalizeGroupedQuotaEntry(
entry: QuotaToastEntry,
target: GroupedRenderTarget,
): NormalizedGroupedQuotaEntry {
const group = trimOptional(entry.group);
const label = trimOptional(entry.label);
const right = trimOptional(entry.right);
const normalized = {
...entry,
...(label ? { label } : {}),
...(right ? { right } : {}),
};
if (group) {
return { ...normalized, group };
}
const googleFallback = getGoogleFallbackMeta(entry.name);
if (googleFallback) {
return {
...normalized,
group: googleFallback.group,
...(label || target === "quota" ? { label: label ?? googleFallback.label } : {}),
};
}
return {
...normalized,
group: entry.name.trim(),
...(target === "quota" ? { label: label ?? "Status:" } : {}),
};
}
export function groupQuotaEntries(
entries: QuotaToastEntry[],
target: GroupedRenderTarget,
): QuotaEntryGroup[] {
const groupOrder: string[] = [];
const groupedEntries = new Map<string, RankedGroupedQuotaEntry[]>();
for (const [originalIndex, entry] of entries.entries()) {
const normalizedEntry = normalizeGroupedQuotaEntry(entry, target);
const rankedEntry: RankedGroupedQuotaEntry = {
entry: normalizedEntry,
originalIndex,
rank: getDurationRank(normalizedEntry),
};
const existing = groupedEntries.get(normalizedEntry.group);
if (existing) {
existing.push(rankedEntry);
continue;
}
groupOrder.push(normalizedEntry.group);
groupedEntries.set(normalizedEntry.group, [rankedEntry]);
}
return groupOrder.map((group) => {
const rankedEntries = groupedEntries.get(group) ?? [];
const entries = rankedEntries
.slice()
.sort((left, right) => {
if (left.rank !== null && right.rank !== null && left.rank !== right.rank) {
return left.rank - right.rank;
}
if (left.rank !== null && right.rank === null) return -1;
if (left.rank === null && right.rank !== null) return 1;
return left.originalIndex - right.originalIndex;
})
.map(({ entry }) => entry);
return { group, entries };
});
}
export function normalizeGroupedQuotaEntries(
entries: QuotaToastEntry[],
target: GroupedRenderTarget,
): NormalizedGroupedQuotaEntry[] {
return groupQuotaEntries(entries, target).flatMap((group) => group.entries);
}