UNPKG

locutus

Version:

Locutus other languages' standard libraries to JavaScript for fun and educational purposes

106 lines (105 loc) 3.32 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ParseIP = ParseIP; function ParseIP(value) { // discuss at: https://locutus.io/golang/net/ParseIP/ // parity verified: Go 1.23 // original by: Kevin van Zonneveld (https://kvz.io) // note 1: Parses IPv4/IPv6 textual addresses and returns a normalized string or null when invalid. // note 2: IPv6 output is normalized to lowercase but not fully canonicalized. // example 1: ParseIP('127.0.0.1') // returns 1: '127.0.0.1' // example 2: ParseIP('2001:DB8::1') // returns 2: '2001:db8::1' // example 3: ParseIP('999.1.2.3') // returns 3: null const input = String(value); const ipv4 = parseIPv4(input); if (ipv4) { return ipv4.join('.'); } if (isValidIPv6(input)) { return input.toLowerCase(); } return null; } function parseIPv4(value) { const parts = value.split('.'); if (parts.length !== 4) { return null; } const bytes = []; for (const part of parts) { if (!/^\d+$/.test(part)) { return null; } if (part.length > 1 && part.startsWith('0')) { return null; } const n = Number(part); if (!Number.isInteger(n) || n < 0 || n > 255) { return null; } bytes.push(n); } return [bytes[0] ?? 0, bytes[1] ?? 0, bytes[2] ?? 0, bytes[3] ?? 0]; } function isValidIPv6(value) { if (value === '' || value.includes('[') || value.includes(']') || value.includes('%')) { return false; } const doubleColonParts = value.split('::'); if (doubleColonParts.length > 2) { return false; } const hasCompression = doubleColonParts.length === 2; const left = doubleColonParts[0] ?? ''; const right = doubleColonParts[1] ?? ''; const leftGroups = left === '' ? [] : left.split(':'); const rightGroups = right === '' ? [] : right.split(':'); if (leftGroups.some((group) => group === '') || rightGroups.some((group) => group === '')) { return false; } let groupCount = 0; for (let i = 0; i < leftGroups.length; i++) { const group = leftGroups[i] ?? ''; if (group.includes('.')) { if (i !== leftGroups.length - 1 || rightGroups.length > 0) { return false; } if (!parseIPv4(group)) { return false; } groupCount += 2; continue; } if (!isValidHextet(group)) { return false; } groupCount += 1; } for (let i = 0; i < rightGroups.length; i++) { const group = rightGroups[i] ?? ''; if (group.includes('.')) { if (i !== rightGroups.length - 1) { return false; } if (!parseIPv4(group)) { return false; } groupCount += 2; continue; } if (!isValidHextet(group)) { return false; } groupCount += 1; } if (hasCompression) { return groupCount < 8; } return groupCount === 8; } function isValidHextet(value) { return /^[0-9a-fA-F]{1,4}$/.test(value); }