Functional Weave
Code in Rust

net.ip-classify@1.0.0

impl/typescript.ts

1,780 bytes · the TypeScript implementation · view raw

Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.

import { cidrContains } from "./net_cidr.ts";  ← from net.cidr ^1.0.0 · built alongside by fune
import { isIpv4 } from "./net_ipv4.ts";  ← from net.ipv4 ^1.0.0 · built alongside by fune
import { formatIpv6, isIpv6, parseIpv6 } from "./net_ipv6.ts";  ← from net.ipv6 ^1.0.0 · built alongside by fune
import { SPECIAL_BLOCKS } from "./net_ip_classify_data.ts";  ← this capability’s own data, compiled from data/special-purpose.json into the same file by fune build
import { type IpCategory, type IpClassification } from "./net_ip_classify_types.ts";

/**
 * Which special-purpose block an address is in, from the IANA IPv4 and IPv6
 * Special-Purpose Address Registries (RFC 6890) plus the multicast ranges.
 * The most specific block wins: 192.0.0.9 is Port Control Protocol Anycast
 * (globally reachable), not the /24 of IETF assignments around it (not).
 * An address in no block is "global".
 */
export function classifyIp(address: string): IpClassification {
  let version: number;
  let canonical: string;
  if (isIpv4(address)) {
    version = 4;
    canonical = address;
  } else if (isIpv6(address)) {
    version = 6;
    canonical = formatIpv6(parseIpv6(address));
  } else {
    throw new Error(`"${String(address)}" is not an IPv4 or IPv6 address`);
  }
  let best: (typeof SPECIAL_BLOCKS)[number] | null = null;
  let bestPrefix = -1;
  for (const row of SPECIAL_BLOCKS) {
    if (row.block.includes(":") !== (version === 6)) continue;
    if (!cidrContains(row.block, canonical)) continue;
    const prefix = Number(row.block.slice(row.block.indexOf("/") + 1));
    if (prefix > bestPrefix) {
      best = row;
      bestPrefix = prefix;
    }
  }
  if (best === null) {
    return { address: canonical, version, category: "global", name: "Global unicast", block: null, rfc: null, globallyReachable: true };
  }
  return {
    address: canonical,
    version,
    category: best.category as IpCategory,
    name: best.name,
    block: best.block,
    rfc: best.rfc,
    globallyReachable: best.globallyReachable,
  };
}