Files
EvoBGP/web/src/lib/sort-prefixes.ts
T
Denozordec c263fd5c7e
CI / changes (push) Successful in 7s
CI / openapi (push) Has been skipped
CI / web (push) Successful in 29s
CI / go (push) Has been skipped
CI / docker-web (push) Successful in 1m22s
CI / docker-bird (push) Has been skipped
CI / bird2 (push) Has been skipped
CI / docker-go (push) Has been skipped
refactor: improve code consistency and formatting across components
- Standardized formatting in various Svelte components for better readability.
- Updated README.md and .prettierrc for consistent styling and improved documentation.
- Refactored class attributes in UI components to enhance clarity and maintainability.
- Adjusted layout files to ensure proper alignment and spacing in the application interface.
2026-05-20 00:37:00 +07:00

116 lines
3.8 KiB
TypeScript

import type { RevisionPrefix } from '$lib/api/types.js';
export function prefixStringFromItem(p: string | RevisionPrefix): string {
if (typeof p === 'string') return p;
return p.prefix ?? '';
}
function parseIPv4Octets(addr: string): [number, number, number, number] | null {
const m = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(addr);
if (!m) return null;
const o = [m[1], m[2], m[3], m[4]].map((x) => parseInt(x, 10));
if (o.some((n) => !Number.isFinite(n) || n < 0 || n > 255)) return null;
return [o[0], o[1], o[2], o[3]];
}
/** 8 групп по 16 бит + длина префикса (или null, если не распознали). */
function parseIPv6(addrPart: string): { words: number[]; pl: number } | null {
if (!addrPart.includes(':')) return null;
const zone = addrPart.indexOf('%');
if (zone >= 0) addrPart = addrPart.slice(0, zone);
const parts = addrPart.split('::');
if (parts.length > 2) return null;
const parseGroup = (h: string) => parseInt(h, 16);
if (parts.length === 1) {
const g = parts[0].split(':').filter(Boolean);
if (g.length === 8) {
return { words: g.map(parseGroup), pl: 128 };
}
// IPv4-хвост: x:x:x:x:x:x:a.b.c.d (6 групп + IPv4)
if (g.length === 7 && g[6].includes('.')) {
const o = parseIPv4Octets(g[6]);
if (!o) return null;
const w = g.slice(0, 6).map(parseGroup);
w.push((o[0] << 8) | o[1], (o[2] << 8) | o[3]);
return { words: w, pl: 128 };
}
return null;
}
const left = parts[0] ? parts[0].split(':').filter(Boolean) : [];
const right = parts[1] ? parts[1].split(':').filter(Boolean) : [];
const lastR = right[right.length - 1];
if (lastR && lastR.includes('.')) {
const o = parseIPv4Octets(lastR);
if (!o) return null;
const rWords = right.slice(0, -1).map(parseGroup);
rWords.push((o[0] << 8) | o[1], (o[2] << 8) | o[3]);
const missing = 8 - left.length - rWords.length;
if (missing < 0) return null;
return { words: [...left.map(parseGroup), ...Array(missing).fill(0), ...rWords], pl: 128 };
}
const missing = 8 - left.length - right.length;
if (missing < 0) return null;
return {
words: [...left.map(parseGroup), ...Array(missing).fill(0), ...right.map(parseGroup)],
pl: 128
};
}
type SortKey =
| { t: 0; v4: [number, number, number, number]; pl: number }
| { t: 1; v6: number[]; pl: number }
| { t: 2; s: string };
function sortKeyForCidr(s: string): SortKey {
const slash = s.indexOf('/');
const addr = slash >= 0 ? s.slice(0, slash) : s;
const plStr = slash >= 0 ? s.slice(slash + 1) : '';
const plNum = plStr ? parseInt(plStr, 10) : NaN;
const v4 = parseIPv4Octets(addr);
if (v4 && !addr.includes(':')) {
const pl = Number.isFinite(plNum) ? plNum : 32;
return { t: 0, v4, pl };
}
const v6 = parseIPv6(addr);
if (v6) {
const pl = Number.isFinite(plNum) ? plNum : v6.pl;
return { t: 1, v6: v6.words, pl };
}
return { t: 2, s: s.toLowerCase() };
}
function compareKeys(a: SortKey, b: SortKey): number {
if (a.t !== b.t) return a.t - b.t;
if (a.t === 2 && b.t === 2) {
return a.s.localeCompare(b.s, 'en', { numeric: true, sensitivity: 'base' });
}
if (a.t === 0 && b.t === 0) {
for (let i = 0; i < 4; i++) {
if (a.v4[i] !== b.v4[i]) return a.v4[i] - b.v4[i];
}
return a.pl - b.pl;
}
if (a.t === 1 && b.t === 1) {
for (let i = 0; i < 8; i++) {
if (a.v6[i] !== b.v6[i]) return a.v6[i] - b.v6[i];
}
return a.pl - b.pl;
}
return 0;
}
/** Сортировка CIDR и прочих строк префиксов (as:, домены и т.д.) для отображения. */
export function sortPrefixStrings(strings: string[]): string[] {
return [...strings].sort((a, b) => compareKeys(sortKeyForCidr(a), sortKeyForCidr(b)));
}
export function sortRevisionDiffItems(items: (string | RevisionPrefix)[]): string[] {
return sortPrefixStrings(items.map(prefixStringFromItem));
}