Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 11 additions & 7 deletions src/IPAddress.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,27 @@
import {IPv4, IPv6} from "./index.js";

/**
* An IP address
* An IP address.
*/
export abstract class IPAddress {
/**
* The integer representation of the IP address
* The integer representation of the IP address.
*/
public readonly value: bigint;

/**
* Create new IP address instance
* Creates a new IP address instance.
*
* @param value The integer representation of the IP address.
* @deprecated This class will be sealed in v2.0.0 and should not be extended by public API users.
*/
protected constructor(value: bigint) {
this.value = value;
}

/**
* Create IP address from string
* Creates an IP address from a string.
*
* @throws {@link !RangeError} If provided string is not a valid IPv4 or IPv6 address
*/
public static fromString(str: string): IPv4 | IPv6 {
Expand All @@ -42,19 +46,19 @@ export abstract class IPAddress {
}

/**
* Get IP address binary representation
* Gets the IP address binary representation.
*/
public abstract binary(): ArrayBufferView;

/**
* Check if the given addresses are equal
* Checks if the given addresses are equal.
*/
public equals(other: IPAddress): boolean {
return other instanceof this.constructor && other.value === this.value;
}

/**
* Format IP address as string
* Formats the IP address as string.
*/
public abstract toString(): string;
}
37 changes: 28 additions & 9 deletions src/IPv4.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright © 2024 Cloudnode OÜ
* Copyright © 2024–2025 Cloudnode OÜ
*
* This file is part of @cldn/ip.
*
Expand All @@ -17,18 +17,33 @@
import {IPAddress} from "./index.js";

/**
* An IPv4 address
* An IPv4 address.
*/
export class IPv4 extends IPAddress {
/**
* Regular expression for testing IPv4 addresses in string form.
*/
public static regex = /^(?:(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)$/;

/**
* Bit length of IPv4 addresses.
*/
public static bitLength = 32;

/**
* Create new IPv4 address instance
* @throws {@link !TypeError} If
* Creates a new IPv4 address instance.
*
* @param value A 32-bit unsigned big integer.
* @throws {@link !TypeError} If provided value is not a 32-bit unsigned integer.
*/
public constructor(value: bigint);

/**
* Creates a new IPv4 address instance.
*
* @param value A 32-bit unsigned number.
* @throws {@link !TypeError} If provided value is not a 32-bit unsigned integer.
*/
public constructor(value: number);

public constructor(value: number | bigint) {
Expand All @@ -39,8 +54,10 @@ export class IPv4 extends IPAddress {
}

/**
* Create an IPv4 address instance from octets
* @throws {@link !RangeError} If provided octets are not 4
* Creates an IPv4 address instance from octets.
*
* @param octets A typed array of 4 octets.
* @throws {@link !RangeError} If provided octets are not 4.
*/
public static fromBinary(octets: Uint8Array): IPv4 {
if (octets.length !== 4) throw new RangeError("Expected 4 octets, got " + octets.length);
Expand All @@ -56,8 +73,10 @@ export class IPv4 extends IPAddress {
}

/**
* Create an IPv4 address instance from string
* @throws {@link !RangeError} If provided string is not a valid IPv4 address
* Creates an IPv4 address instance from a string.
*
* @param str A string representation of an IPv4 address.
* @throws {@link !RangeError} If provided string is not a valid IPv4 address.
*/
public static override fromString(str: string): IPv4 {
const octets = str.split(".", 4).map(octet => Number.parseInt(octet, 10));
Expand All @@ -68,7 +87,7 @@ export class IPv4 extends IPAddress {
}

/**
* Get the 4 octets of the IPv4 address
* Gets the 4 octets of the IPv4 address.
*/
public override binary(): Uint8Array {
return new Uint8Array([
Expand Down
33 changes: 20 additions & 13 deletions src/IPv6.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright © 2024 Cloudnode OÜ
* Copyright © 2024–2025 Cloudnode OÜ
*
* This file is part of @cldn/ip.
*
Expand All @@ -17,13 +17,16 @@
import {IPAddress, IPv4, Subnet} from "./index.js";

/**
* An IPv6 address
* An IPv6 address.
*/
export class IPv6 extends IPAddress {
public static bitLength = 128;

/**
* Create new IPv6 address instance
* Creates a new IPv6 address instance.
*
* @param value A 128-bit unsigned big integer.
* @throws {@link !TypeError} If provided value is not a 128-bit unsigned integer.
*/
public constructor(value: bigint) {
if (value < 0n || value > ((1n << BigInt(IPv6.bitLength)) - 1n))
Expand All @@ -32,8 +35,10 @@ export class IPv6 extends IPAddress {
}

/**
* Create an IPv6 address instance from hextets
* @throws {@link !RangeError} If provided hextets are not 8
* Creates an IPv6 address instance from hextets.
*
* @param hextets A typed array of 8 hextets.
* @throws {@link !RangeError} If provided hextets are not 8.
*/
public static fromBinary(hextets: Uint16Array): IPv6 {
if (hextets.length !== 8) throw new RangeError("Expected 8 hextets, got " + hextets.length);
Expand All @@ -51,8 +56,10 @@ export class IPv6 extends IPAddress {
}

/**
* Create an IPv6 address instance from string
* @throws {@link !RangeError} If provided string is not a valid IPv6 address
* Creates an IPv6 address instance from a string.
*
* @param str A string representation of an IPv6 address.
* @throws {@link !RangeError} If provided string is not a valid IPv6 address.
*/
public static override fromString(str: string): IPv6 {
const parts = str.split("::", 2);
Expand All @@ -77,7 +84,7 @@ export class IPv6 extends IPAddress {
}

/**
* Parse string hextet into unsigned 16-bit integer
* Parses a string hextet into unsigned 16-bit integer.
* @internal
*/
private static parseHextet(hextet: string): number | number[] {
Expand All @@ -92,7 +99,7 @@ export class IPv6 extends IPAddress {
}

/**
* Get the 8 hextets of the IPv6 address
* Gets the 8 hextets of the IPv6 address
*/
public binary(): Uint16Array {
return new Uint16Array([
Expand All @@ -108,16 +115,16 @@ export class IPv6 extends IPAddress {
}

/**
* Check whether this is an IPv4-mapped IPv6 address.
* Only works for `::ffff:0:0/96`
* Checks whether this is an IPv4-mapped IPv6 address. Only works for `::ffff:0:0/96`.
*/
public hasMappedIPv4(): boolean {
return Subnet.IPV4_MAPPED_IPV6.has(this);
}

/**
* Get the IPv4-mapped IPv6 address.
* Returns the last 32 bits as an IPv4 address.
* Gets the IPv4-mapped IPv6 address.
*
* @returns An IPv4 address from the least significant 32 bits of this IPv6 address.
* @see {@link IPv6#hasMappedIPv4}
*/
public getMappedIPv4(): IPv4 {
Expand Down
31 changes: 18 additions & 13 deletions src/Network.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright © 2024 Cloudnode OÜ
* Copyright © 2024–2025 Cloudnode OÜ
*
* This file is part of @cldn/ip.
*
Expand All @@ -17,11 +17,11 @@
import {IPv4, IPv6, Subnet} from "./index.js"

/**
* A network that can contain multiple subnets
* A network that can contain multiple subnets.
*/
export class Network {
/**
* Reserved subnets
* A network of reserved subnets. This network does not contain publicly routable IP addresses.
*/
public static readonly BOGON = new Network([
// IPv4
Expand Down Expand Up @@ -58,53 +58,58 @@ export class Network {
readonly #subnets: Map<string, Subnet<IPv4 | IPv6>> = new Map();

/**
* Create new network
* @param [subnets] Initial subnets to add to this network
* Creates a new network.
*
* @param [subnets] Initial subnets to add to this network.
*/
public constructor(subnets?: Iterable<Subnet<IPv4 | IPv6>>) {
if (subnets) for (const subnet of subnets) this.add(subnet);
}

/**
* Add a subnet to this network
* Adds a subnet to this network.
*/
public add(subnet: Subnet<IPv4 | IPv6>): void {
this.#subnets.set(subnet.toString(), subnet);
}

/**
* Remove a subnet from this network
* @param cidr CIDR notation of the subnet to remove
* Removes a subnet from this network.
*
* @param cidr CIDR notation of the subnet to remove.
*/
public remove(cidr: string): void {
this.#subnets.delete(Subnet.fromCIDR(cidr).toString());
}

/**
* Check if subnet is in this network
* @param cidr CIDR notation of the subnet to check
* Checks if a subnet is in this network.
*
* @param cidr CIDR notation of the subnet to check.
*/
public hasSubnet(cidr: string): boolean {
return this.#subnets.has(Subnet.fromCIDR(cidr).toString());
}

/**
* Get all subnets in this network mapped to their CIDR notation
* Gets all subnets in this network mapped to their CIDR notation.
*/
public subnets(): ReadonlyMap<string, Subnet<IPv4 | IPv6>> {
return this.#subnets;
}

/**
* Check if an IP address is in this network
* Checks if an IP address is in this network.
*
* @param address IP address to check.
*/
public has(address: IPv4 | IPv6): boolean {
for (const subnet of this.#subnets.values()) if (subnet.has(address)) return true;
return false;
}

/**
* Get the number of addresses in this network
* Gets the number of addresses in this network.
*/
public size(): bigint {
let size = 0n;
Expand Down
Loading