@badrap/ipv46
Advanced tools
Comparing version 2.1.2 to 2.2.0
@@ -10,2 +10,3 @@ export declare class IPv4 { | ||
cidr(bits: number): IPRange; | ||
_cidrBits(last: IPv4): number | undefined; | ||
_next(): IPv4 | null; | ||
@@ -22,2 +23,3 @@ } | ||
cidr(bits: number): IPRange; | ||
_cidrBits(last: IPv6): number | undefined; | ||
_next(): IPv6 | null; | ||
@@ -38,2 +40,3 @@ } | ||
ips(): Iterable<IP>; | ||
toString(): string; | ||
} |
@@ -51,2 +51,5 @@ "use strict"; | ||
} | ||
_cidrBits(last) { | ||
return cidrBits(this._bytes, last._bytes, 8); | ||
} | ||
_next() { | ||
@@ -185,2 +188,5 @@ const bytes = this._bytes.slice(); | ||
} | ||
_cidrBits(last) { | ||
return cidrBits(this._words, last._words, 16); | ||
} | ||
_next() { | ||
@@ -222,2 +228,42 @@ const words = this._words.slice(); | ||
}; | ||
function cidrBits(array1, array2, bitsPerItem) { | ||
// Find the longest run of equal items from the start of the array. | ||
let commonItems = 0; | ||
for (let i = 0; i < array1.length; i++) { | ||
if (array1[i] !== array2[i]) { | ||
break; | ||
} | ||
commonItems++; | ||
} | ||
// Skip the rest if the arrays are completely equal. | ||
if (commonItems === array1.length) { | ||
return commonItems * bitsPerItem; | ||
} | ||
// Find the longest run of equal most significant bits from the | ||
// first item that is not equal between array1 and array2. | ||
let commonBits = 0; | ||
for (let i = 0; i < bitsPerItem; i++) { | ||
const mask = 1 << (bitsPerItem - i - 1); | ||
if ((array1[commonItems] & mask) !== (array2[commonItems] & mask)) { | ||
break; | ||
} | ||
commonBits++; | ||
} | ||
// Check that all the remaining bits are all zeroes in array1 | ||
// and all ones in array2. | ||
for (let i = commonBits; i < bitsPerItem; i++) { | ||
const mask = 1 << (bitsPerItem - i - 1); | ||
if ((array1[commonItems] & mask) !== 0 || | ||
(array2[commonItems] & mask) === 0) { | ||
return undefined; | ||
} | ||
} | ||
const allOnes = bitsPerItem === 8 ? 0xff : 0xffff; | ||
for (let i = commonItems + 1; i < array1.length; i++) { | ||
if (array1[i] !== 0 || array2[i] !== allOnes) { | ||
return undefined; | ||
} | ||
} | ||
return commonItems * bitsPerItem + commonBits; | ||
} | ||
function mask(array, bits, bitsPerItem, bitValue) { | ||
@@ -297,4 +343,25 @@ const itemMask = (1 << bitsPerItem) - 1; | ||
} | ||
toString() { | ||
let bits; | ||
let maxBits; | ||
if (this.first.version === 4) { | ||
bits = this.first._cidrBits(this.last); | ||
maxBits = 32; | ||
} | ||
else { | ||
bits = this.first._cidrBits(this.last); | ||
maxBits = 128; | ||
} | ||
if (bits === undefined) { | ||
return this.first.toString() + "-" + this.last.toString(); | ||
} | ||
else if (bits === maxBits) { | ||
return this.first.toString(); | ||
} | ||
else { | ||
return this.first.toString() + "/" + bits; | ||
} | ||
} | ||
} | ||
exports.IPRange = IPRange; | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "@badrap/ipv46", | ||
"version": "2.1.2", | ||
"version": "2.2.0", | ||
"description": "Parse, format and compare IPv4/6 addresses", | ||
@@ -8,6 +8,7 @@ "main": "./dist/cjs/index.js", | ||
"exports": { | ||
"bun": "./src/index.ts", | ||
"node": { | ||
"module": "./dist/mjs/index.mjs", | ||
"import": "./dist/mjs/index.mjs", | ||
"require": "./dist/cjs/index.js" | ||
"module": "./dist/node-mjs/index.mjs", | ||
"import": "./dist/node-cjs/index.esm.mjs", | ||
"require": "./dist/node-cjs/index.js" | ||
}, | ||
@@ -20,21 +21,29 @@ "default": "./dist/mjs/index.mjs" | ||
"license": "MIT", | ||
"publishConfig": { | ||
"provenance": true | ||
}, | ||
"scripts": { | ||
"lint": "eslint --ignore-path .gitignore --max-warnings 0 --ext=.js,.ts .", | ||
"lint": "eslint --max-warnings 0 .", | ||
"typecheck": "tsc --skipLibCheck --noEmit", | ||
"test": "vitest run", | ||
"build": "rm -rf dist/* && npm run build:cjs && npm run build:mjs", | ||
"build:cjs": "tsc -p ./tsconfig.build.json --target es2015 --module commonjs --outDir ./dist/cjs", | ||
"build:mjs": "tsc -p ./tsconfig.build.json --target es2015 --module es2015 --outDir ./dist/mjs && mv ./dist/mjs/index.js ./dist/mjs/index.mjs && mv ./dist/mjs/index.d.ts ./dist/mjs/index.d.mts", | ||
"prepack": "npm run build" | ||
"build": "rm -rf dist/* && npm run build:cjs && npm run build:mjs && npm run build:node-mjs && npm run build:node-cjs", | ||
"build:cjs": "tsc -p ./tsconfig.cjs.json --outDir ./dist/cjs", | ||
"build:node-cjs": "tsc -p ./tsconfig.cjs.json --target es2021 --outDir ./dist/node-cjs", | ||
"build:mjs": "tsc -p ./tsconfig.esm.json --outDir ./dist/mjs && mv ./dist/mjs/index.js ./dist/mjs/index.mjs && mv ./dist/mjs/index.d.ts ./dist/mjs/index.d.mts", | ||
"build:node-mjs": "tsc -p ./tsconfig.esm.json --target es2021 --outDir ./dist/node-mjs && mv ./dist/node-mjs/index.js ./dist/node-mjs/index.mjs && mv ./dist/node-mjs/index.d.ts ./dist/node-mjs/index.d.mts", | ||
"changeset": "changeset", | ||
"bump": "changeset version && sed --in-place \"s/\\\"version\\\": \\\".*\\\"/\\\"version\\\": \\\"$(sed -n 's/^\\s*\\\"version\\\": \\\"\\([^\\\"/]*\\)\\\".*/\\1/p' package.json)\\\"/\" jsr.json", | ||
"release": "npm run build && changeset publish && jsr publish" | ||
}, | ||
"devDependencies": { | ||
"@typescript-eslint/eslint-plugin": "^6.2.1", | ||
"@typescript-eslint/parser": "^6.2.1", | ||
"eslint": "^8.46.0", | ||
"eslint-config-prettier": "^9.0.0", | ||
"eslint-plugin-prettier": "^5.0.0", | ||
"prettier": "^3.0.1", | ||
"ts-expect": "^1.3.0", | ||
"typescript": "^5.1.6", | ||
"vitest": "^0.34.1" | ||
"@changesets/changelog-github": "^0.5.0", | ||
"@changesets/cli": "^2.27.9", | ||
"@typescript-eslint/eslint-plugin": "^8.9.0", | ||
"@typescript-eslint/parser": "^8.9.0", | ||
"eslint": "^8.57.0", | ||
"eslint-config-prettier": "^9.1.0", | ||
"eslint-plugin-prettier": "^5.2.1", | ||
"prettier": "^3.3.3", | ||
"typescript": "^5.6.3", | ||
"vitest": "^2.1.3" | ||
}, | ||
@@ -41,0 +50,0 @@ "keywords": [ |
@@ -1,5 +0,8 @@ | ||
# ipv4 | ||
# ipv46 [![CI](https://github.com/badrap/ipv46/actions/workflows/ci.yml/badge.svg)](https://github.com/badrap/ipv46/actions/workflows/ci.yml) [![npm](https://img.shields.io/npm/v/@badrap/ipv46.svg)](https://www.npmjs.com/package/@badrap/ipv46) [![JSR](https://jsr.io/badges/@badrap/ipv46)](https://jsr.io/@badrap/ipv46) | ||
**ipv46** is a small JavaScript library for parsing, formatting and sorting IPv4/6 addresses. It works on both Node.js and browser environments. | ||
> [!NOTE] | ||
> While this package is still evolving, we're currently not accepting any new feature requests or suggestions. Please use the issue tracker for bug reports and security concerns, which we highly value and welcome. Thank you for your understanding ❤️ | ||
## Installation | ||
@@ -23,5 +26,5 @@ | ||
```js | ||
IP.parse("192.0.2.1"); // IPv4 { ... } | ||
IP.parse("2001:db8::1"); // IPv6 { ... } | ||
IP.parse("non-address"); // null | ||
IP.parse("192.0.2.1"); // IPv4 { ... } | ||
IP.parse("2001:db8::1"); // IPv6 { ... } | ||
IP.parse("non-address"); // null | ||
``` | ||
@@ -32,3 +35,3 @@ | ||
```js | ||
IP.parse("2001:db8::192.0.2.1"); // IPv6 { ... } | ||
IP.parse("2001:db8::192.0.2.1"); // IPv6 { ... } | ||
``` | ||
@@ -41,4 +44,4 @@ | ||
```js | ||
IP.parse("192.0.2.1").version; // 4 | ||
IP.parse("2001:db8::1").version; // 6 | ||
IP.parse("192.0.2.1").version; // 4 | ||
IP.parse("2001:db8::1").version; // 6 | ||
``` | ||
@@ -51,5 +54,5 @@ | ||
```js | ||
IP.parse("192.0.2.1").toString(); // '192.0.2.1' | ||
IP.parse("2001:db8::1").toString(); // '2001:db8::1' | ||
IP.parse("2001:db8::192.0.2.1").toString(); // '2001:db8::c000:201' | ||
IP.parse("192.0.2.1").toString(); // '192.0.2.1' | ||
IP.parse("2001:db8::1").toString(); // '2001:db8::1' | ||
IP.parse("2001:db8::192.0.2.1").toString(); // '2001:db8::c000:201' | ||
``` | ||
@@ -60,6 +63,7 @@ | ||
Compare and sort addresses. **IP.cmp(a, b)** returns: | ||
* **-1** if **a** is sorted before **b** | ||
* **0** if **a** equals **b** | ||
* **1** otherwise | ||
- **-1** if **a** is sorted before **b** | ||
- **0** if **a** equals **b** | ||
- **1** otherwise | ||
```js | ||
@@ -69,5 +73,5 @@ const a = IP.parse("192.0.2.1"); | ||
IP.cmp(a, a); // 0 | ||
IP.cmp(a, b); // -1 | ||
IP.cmp(b, a); // 1 | ||
IP.cmp(a, a); // 0 | ||
IP.cmp(a, b); // -1 | ||
IP.cmp(b, a); // 1 | ||
``` | ||
@@ -81,3 +85,3 @@ | ||
IP.cmp(ipv4, ipv6); // -1 | ||
IP.cmp(ipv4, ipv6); // -1 | ||
``` | ||
@@ -90,5 +94,5 @@ | ||
const a = IP.parse("2001:0db8::1"); | ||
const b = IP.parse("2001:0db8:0000::0001") | ||
const b = IP.parse("2001:0db8:0000::0001"); | ||
IP.cmp(a, b); // 0 | ||
IP.cmp(a, b); // 0 | ||
``` | ||
@@ -100,6 +104,6 @@ | ||
const a = IP.parse("2001:0db8::2"); | ||
const b = IP.parse("2001:0db8::1") | ||
const b = IP.parse("2001:0db8::1"); | ||
const c = IP.parse("2001:0db8::") | ||
[a, b, c].sort(IP.cmp); // [c, b, a] | ||
[(a, b, c)].sort(IP.cmp); // [c, b, a] | ||
``` |
@@ -59,2 +59,6 @@ function cmpSameLengthArrays<T>(left: T[], right: T[]): number { | ||
_cidrBits(last: IPv4): number | undefined { | ||
return cidrBits(this._bytes, last._bytes, 8); | ||
} | ||
_next(): IPv4 | null { | ||
@@ -212,2 +216,6 @@ const bytes = this._bytes.slice(); | ||
_cidrBits(last: IPv6): number | undefined { | ||
return cidrBits(this._words, last._words, 16); | ||
} | ||
_next(): IPv6 | null { | ||
@@ -250,6 +258,56 @@ const words = this._words.slice(); | ||
function cidrBits<T extends number[]>( | ||
array1: T, | ||
array2: T, | ||
bitsPerItem: 8 | 16, | ||
): number | undefined { | ||
// Find the longest run of equal items from the start of the array. | ||
let commonItems = 0; | ||
for (let i = 0; i < array1.length; i++) { | ||
if (array1[i] !== array2[i]) { | ||
break; | ||
} | ||
commonItems++; | ||
} | ||
// Skip the rest if the arrays are completely equal. | ||
if (commonItems === array1.length) { | ||
return commonItems * bitsPerItem; | ||
} | ||
// Find the longest run of equal most significant bits from the | ||
// first item that is not equal between array1 and array2. | ||
let commonBits = 0; | ||
for (let i = 0; i < bitsPerItem; i++) { | ||
const mask = 1 << (bitsPerItem - i - 1); | ||
if ((array1[commonItems] & mask) !== (array2[commonItems] & mask)) { | ||
break; | ||
} | ||
commonBits++; | ||
} | ||
// Check that all the remaining bits are all zeroes in array1 | ||
// and all ones in array2. | ||
for (let i = commonBits; i < bitsPerItem; i++) { | ||
const mask = 1 << (bitsPerItem - i - 1); | ||
if ( | ||
(array1[commonItems] & mask) !== 0 || | ||
(array2[commonItems] & mask) === 0 | ||
) { | ||
return undefined; | ||
} | ||
} | ||
const allOnes = bitsPerItem === 8 ? 0xff : 0xffff; | ||
for (let i = commonItems + 1; i < array1.length; i++) { | ||
if (array1[i] !== 0 || array2[i] !== allOnes) { | ||
return undefined; | ||
} | ||
} | ||
return commonItems * bitsPerItem + commonBits; | ||
} | ||
function mask<T extends number[]>( | ||
array: T, | ||
bits: number, | ||
bitsPerItem: number, | ||
bitsPerItem: 8 | 16, | ||
bitValue: 0 | 1, | ||
@@ -338,2 +396,22 @@ ): T { | ||
} | ||
toString(): string { | ||
let bits: number | undefined; | ||
let maxBits: number; | ||
if (this.first.version === 4) { | ||
bits = this.first._cidrBits(this.last as IPv4); | ||
maxBits = 32; | ||
} else { | ||
bits = this.first._cidrBits(this.last as IPv6); | ||
maxBits = 128; | ||
} | ||
if (bits === undefined) { | ||
return this.first.toString() + "-" + this.last.toString(); | ||
} else if (bits === maxBits) { | ||
return this.first.toString(); | ||
} else { | ||
return this.first.toString() + "/" + bits; | ||
} | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
115070
16
1882
101
10