Compare commits

..
2 Commits
Author SHA1 Message Date
ztimson 54aaa58990 Added everyNested to walk nested objects/arrays
Build / Publish Docs (push) Successful in 31s
Build / Build NPM Project (push) Successful in 36s
Build / Tag Version (push) Successful in 7s
2026-10-08 11:28:05 -04:00
ztimson 59b03d5b51 isReserved IPv6 support
Build / Publish Docs (push) Successful in 1m31s
Build / Build NPM Project (push) Successful in 1m37s
Build / Tag Version (push) Successful in 7s
2026-10-08 10:01:03 -04:00
3 changed files with 15 additions and 6 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@ztimson/utils", "name": "@ztimson/utils",
"version": "0.30.9", "version": "0.30.11",
"description": "Utility library", "description": "Utility library",
"author": "Zak Timson", "author": "Zak Timson",
"license": "MIT", "license": "MIT",
+5 -5
View File
@@ -48,12 +48,12 @@ export function reservedIp(ip: string): boolean {
* @returns {null | 'Invalid' | 'Host' | 'Loopback' | 'Private (Class A)' | 'Private (Class B)' | 'Link-Local' | 'IETF Protocol Assignments' | 'Documentation (TEST-NET-1)' | 'Benchmarking' | 'Documentation (TEST-NET-2)' | 'Documentation (TEST-NET-3)' | 'Multicast' | 'Reserved (Class E)'} null if public, class name if reserved * @returns {null | 'Invalid' | 'Host' | 'Loopback' | 'Private (Class A)' | 'Private (Class B)' | 'Link-Local' | 'IETF Protocol Assignments' | 'Documentation (TEST-NET-1)' | 'Benchmarking' | 'Documentation (TEST-NET-2)' | 'Documentation (TEST-NET-3)' | 'Multicast' | 'Reserved (Class E)'} null if public, class name if reserved
*/ */
export function isReserved(ip: string): null | 'Invalid' | 'Host' | 'Loopback' | 'Private (Class A)' | 'Private (Class B)' | 'Link-Local' | 'IETF Protocol Assignments' | 'Documentation (TEST-NET-1)' | 'Benchmarking' | 'Documentation (TEST-NET-2)' | 'Documentation (TEST-NET-3)' | 'Multicast' | 'Reserved (Class E)' { export function isReserved(ip: string): null | 'Invalid' | 'Host' | 'Loopback' | 'Private (Class A)' | 'Private (Class B)' | 'Link-Local' | 'IETF Protocol Assignments' | 'Documentation (TEST-NET-1)' | 'Benchmarking' | 'Documentation (TEST-NET-2)' | 'Documentation (TEST-NET-3)' | 'Multicast' | 'Reserved (Class E)' {
const ipToNumber = (ip: string) => { const ipToNumber = (ip: string) => ip.split('.').reduce((acc: number, octet: string) => (acc << 8) + parseInt(octet, 10), 0) >>> 0;
return ip.split('.').reduce((acc: number, octet: string) => (acc << 8) + parseInt(octet, 10), 0) >>> 0;
};
const ipNum = ipToNumber(ip); const ipv4 = ip.includes(':') ? ipV6ToV4(ip) : ip;
if (ipNum === null) return 'Invalid'; if(ipv4 === null || !ipv4.includes('.')) return 'Invalid';
const ipNum = ipToNumber(ipv4);
if(ipNum === null) return 'Invalid';
const reserved = [ const reserved = [
{ name: "Host", start: ipToNumber("0.0.0.0"), end: ipToNumber("0.255.255.255") }, { name: "Host", start: ipToNumber("0.0.0.0"), end: ipToNumber("0.255.255.255") },
+9
View File
@@ -165,6 +165,15 @@ export function encodeQuery(data: any): string {
).join('&'); ).join('&');
} }
/** Recursively walks obj/arrays, calling cb(dotPath, value) for every leaf+branch prop */
export function everyNested(obj: any, cb: (key: string, value: any) => void, prefix = ''){
Object.entries(obj).forEach(([k, v]) => {
const key = prefix ? `${prefix}.${k}` : k;
cb(key, v);
if (v && typeof v === 'object') everyNested(v, cb, key);
});
}
/** /**
* Recursively flatten a nested object, while maintaining key structure * Recursively flatten a nested object, while maintaining key structure
* *