cidr-tools 11.0.10 → 11.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/index.d.ts +26 -24
  2. package/dist/index.js +311 -331
  3. package/package.json +12 -11
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ //#region index.d.ts
1
2
  type IPv4Address = string;
2
3
  type IPv6Address = string;
3
4
  type IPv4CIDR = string;
@@ -6,38 +7,39 @@ type Network = IPv4Address | IPv4CIDR | IPv6Address | IPv6CIDR;
6
7
  type Networks = Network | Array<Network>;
7
8
  type ValidIpVersion = 4 | 6;
8
9
  type ParsedCidr = {
9
- cidr: string;
10
- ip: string;
11
- version: ValidIpVersion;
12
- prefix: string;
13
- prefixPresent: boolean;
14
- start: bigint;
15
- end: bigint;
10
+ cidr: string;
11
+ ip: string;
12
+ version: ValidIpVersion;
13
+ prefix: string;
14
+ prefixPresent: boolean;
15
+ start: bigint;
16
+ end: bigint;
16
17
  };
17
18
  type NormalizeOpts = {
18
- compress?: boolean;
19
- hexify?: boolean;
19
+ compress?: boolean;
20
+ hexify?: boolean;
20
21
  };
21
22
  /** Returns a string or array (depending on input) with a normalized representation. Will not include a prefix on single IPs. Will set network address to the start of the network. */
22
- export declare function normalizeCidr<T extends Network | Array<Network>>(cidr: T, opts?: NormalizeOpts): T;
23
+ declare function normalizeCidr<T extends Network | Array<Network>>(cidr: T, opts?: NormalizeOpts): T;
23
24
  /** Returns a `parsed` Object which is used internally by this module. It can be used to test whether the passed network is IPv4 or IPv6 or to work with the BigInts directly. */
24
- export declare function parseCidr(str: Network): ParsedCidr;
25
+ declare function parseCidr(str: Network): ParsedCidr;
25
26
  /** Returns an array of merged networks */
26
- export declare function mergeCidr(nets: Networks): Array<Network>;
27
+ declare function mergeCidr(nets: Networks): Array<Network>;
27
28
  /** Returns an array of merged remaining networks of the subtraction of `excludeNetworks` from `baseNetworks`. */
28
- export declare function excludeCidr(base: Networks, excl: Networks): Array<Network>;
29
- export declare function expandCidr(nets: Networks): Generator<Network>;
29
+ declare function excludeCidr(base: Networks, excl: Networks): Array<Network>;
30
+ declare function expandCidr(nets: Networks): Generator<Network>;
30
31
  /** Returns a boolean that indicates if `networksA` overlap (intersect) with `networksB`. */
31
- export declare function overlapCidr(a: Networks, b: Networks): boolean;
32
+ declare function overlapCidr(a: Networks, b: Networks): boolean;
32
33
  /** Returns a boolean that indicates whether `networksA` fully contain all `networksB`. */
33
- export declare function containsCidr(a: Networks, b: Networks): boolean;
34
+ declare function containsCidr(a: Networks, b: Networks): boolean;
34
35
  declare const _default: {
35
- mergeCidr: typeof mergeCidr;
36
- excludeCidr: typeof excludeCidr;
37
- expandCidr: typeof expandCidr;
38
- overlapCidr: typeof overlapCidr;
39
- containsCidr: typeof containsCidr;
40
- normalizeCidr: typeof normalizeCidr;
41
- parseCidr: typeof parseCidr;
36
+ mergeCidr: typeof mergeCidr;
37
+ excludeCidr: typeof excludeCidr;
38
+ expandCidr: typeof expandCidr;
39
+ overlapCidr: typeof overlapCidr;
40
+ containsCidr: typeof containsCidr;
41
+ normalizeCidr: typeof normalizeCidr;
42
+ parseCidr: typeof parseCidr;
42
43
  };
43
- export default _default;
44
+ //#endregion
45
+ export { containsCidr, _default as default, excludeCidr, expandCidr, mergeCidr, normalizeCidr, overlapCidr, parseCidr };
package/dist/index.js CHANGED
@@ -1,362 +1,342 @@
1
- import { parseIp, stringifyIp, normalizeIp } from "ip-bigint";
2
- const bits = { 4: 32, 6: 128 };
1
+ import { normalizeIp, parseIp, stringifyIp } from "ip-bigint";
2
+
3
+ //#region index.ts
4
+ const bits = {
5
+ 4: 32,
6
+ 6: 128
7
+ };
3
8
  function uniq(arr) {
4
- const set = new Set(arr);
5
- return set.size === arr.length ? arr : Array.from(set);
9
+ const set = new Set(arr);
10
+ return set.size === arr.length ? arr : Array.from(set);
6
11
  }
7
12
  function doNormalize(cidr, { compress = true, hexify = false } = {}) {
8
- const { start, end, prefix, version, prefixPresent } = parseCidr(cidr);
9
- if (start !== end || prefixPresent) {
10
- const ip = normalizeIp(stringifyIp({ number: start, version }), { compress, hexify });
11
- return `${ip}/${prefix}`;
12
- } else {
13
- return normalizeIp(cidr, { compress, hexify });
14
- }
13
+ const { start, end, prefix, version, prefixPresent } = parseCidr(cidr);
14
+ if (start !== end || prefixPresent) return `${normalizeIp(stringifyIp({
15
+ number: start,
16
+ version
17
+ }), {
18
+ compress,
19
+ hexify
20
+ })}/${prefix}`;
21
+ else return normalizeIp(cidr, {
22
+ compress,
23
+ hexify
24
+ });
15
25
  }
26
+ /** Returns a string or array (depending on input) with a normalized representation. Will not include a prefix on single IPs. Will set network address to the start of the network. */
16
27
  function normalizeCidr(cidr, opts) {
17
- if (Array.isArray(cidr)) {
18
- return cidr.map((entry) => normalizeCidr(entry, opts));
19
- } else {
20
- return doNormalize(cidr, opts);
21
- }
28
+ if (Array.isArray(cidr)) return cidr.map((entry) => normalizeCidr(entry, opts));
29
+ else return doNormalize(cidr, opts);
22
30
  }
31
+ /** Returns a `parsed` Object which is used internally by this module. It can be used to test whether the passed network is IPv4 or IPv6 or to work with the BigInts directly. */
23
32
  function parseCidr(str) {
24
- const parsed = /* @__PURE__ */ Object.create(null);
25
- const slashIndex = str.indexOf("/");
26
- let ipPart;
27
- let prefix;
28
- if (slashIndex !== -1) {
29
- ipPart = str.substring(0, slashIndex);
30
- prefix = str.substring(slashIndex + 1);
31
- if (!/^[0-9]+$/.test(prefix)) {
32
- throw new Error(`Network is not a CIDR or IP: "${str}"`);
33
- }
34
- parsed.prefixPresent = true;
35
- } else {
36
- ipPart = str;
37
- parsed.prefixPresent = false;
38
- prefix = "";
39
- }
40
- const { number, version, ipv4mapped, scopeid } = parseIp(ipPart);
41
- if (!version) {
42
- throw new Error(`Network is not a CIDR or IP: "${str}"`);
43
- }
44
- if (!parsed.prefixPresent) {
45
- prefix = String(bits[version]);
46
- }
47
- parsed.version = version;
48
- parsed.ip = stringifyIp({ number, version, ipv4mapped, scopeid });
49
- parsed.cidr = `${parsed.ip}/${prefix}`;
50
- parsed.prefix = prefix;
51
- const numBits = bits[version];
52
- const hostBits = numBits - Number(prefix);
53
- const mask = hostBits > 0 ? (1n << BigInt(hostBits)) - 1n : 0n;
54
- parsed.start = number & ~mask;
55
- parsed.end = number | mask;
56
- return parsed;
33
+ const parsed = Object.create(null);
34
+ const slashIndex = str.indexOf("/");
35
+ let ipPart;
36
+ let prefix;
37
+ if (slashIndex !== -1) {
38
+ ipPart = str.substring(0, slashIndex);
39
+ prefix = str.substring(slashIndex + 1);
40
+ if (!/^[0-9]+$/.test(prefix)) throw new Error(`Network is not a CIDR or IP: "${str}"`);
41
+ parsed.prefixPresent = true;
42
+ } else {
43
+ ipPart = str;
44
+ parsed.prefixPresent = false;
45
+ prefix = "";
46
+ }
47
+ const { number, version, ipv4mapped, scopeid } = parseIp(ipPart);
48
+ if (!version) throw new Error(`Network is not a CIDR or IP: "${str}"`);
49
+ if (!parsed.prefixPresent) prefix = String(bits[version]);
50
+ parsed.version = version;
51
+ parsed.ip = stringifyIp({
52
+ number,
53
+ version,
54
+ ipv4mapped,
55
+ scopeid
56
+ });
57
+ parsed.cidr = `${parsed.ip}/${prefix}`;
58
+ parsed.prefix = prefix;
59
+ const hostBits = bits[version] - Number(prefix);
60
+ const mask = hostBits > 0 ? (1n << BigInt(hostBits)) - 1n : 0n;
61
+ parsed.start = number & ~mask;
62
+ parsed.end = number | mask;
63
+ return parsed;
57
64
  }
58
65
  function parseCidrLean(str) {
59
- const slashIndex = str.indexOf("/");
60
- let ipPart;
61
- let prefixNum;
62
- if (slashIndex !== -1) {
63
- ipPart = str.substring(0, slashIndex);
64
- const prefixStr = str.substring(slashIndex + 1);
65
- if (!/^[0-9]+$/.test(prefixStr)) {
66
- throw new Error(`Network is not a CIDR or IP: "${str}"`);
67
- }
68
- prefixNum = Number(prefixStr);
69
- } else {
70
- ipPart = str;
71
- prefixNum = -1;
72
- }
73
- const { number, version } = parseIp(ipPart);
74
- if (!version) {
75
- throw new Error(`Network is not a CIDR or IP: "${str}"`);
76
- }
77
- if (prefixNum === -1) {
78
- prefixNum = bits[version];
79
- }
80
- const numBits = bits[version];
81
- const hostBits = numBits - prefixNum;
82
- const mask = hostBits > 0 ? (1n << BigInt(hostBits)) - 1n : 0n;
83
- return {
84
- start: number & ~mask,
85
- end: number | mask,
86
- version
87
- };
88
- }
89
- function excludeNetsParts(a, b) {
90
- if (a.start > b.end || a.end < b.start) {
91
- return [a];
92
- }
93
- if (a.start === b.start && a.end === b.end) {
94
- return [];
95
- }
96
- if (a.start > b.start && a.end < b.end) {
97
- return [];
98
- }
99
- const parts = [];
100
- if (a.start < b.start && a.end <= b.end) {
101
- parts.push({ start: a.start, end: b.start - 1n });
102
- }
103
- if (a.start >= b.start && a.end > b.end) {
104
- parts.push({ start: b.end + 1n, end: a.end });
105
- }
106
- if (a.start < b.start && a.end > b.end) {
107
- parts.push(
108
- { start: a.start, end: b.start - 1n },
109
- { start: b.end + 1n, end: a.end }
110
- );
111
- }
112
- const remaining = [];
113
- for (const part of parts) {
114
- subparts(part, remaining);
115
- }
116
- return remaining;
66
+ const slashIndex = str.indexOf("/");
67
+ let ipPart;
68
+ let prefixNum;
69
+ if (slashIndex !== -1) {
70
+ ipPart = str.substring(0, slashIndex);
71
+ const prefixStr = str.substring(slashIndex + 1);
72
+ if (!/^[0-9]+$/.test(prefixStr)) throw new Error(`Network is not a CIDR or IP: "${str}"`);
73
+ prefixNum = Number(prefixStr);
74
+ } else {
75
+ ipPart = str;
76
+ prefixNum = -1;
77
+ }
78
+ const { number, version } = parseIp(ipPart);
79
+ if (!version) throw new Error(`Network is not a CIDR or IP: "${str}"`);
80
+ if (prefixNum === -1) prefixNum = bits[version];
81
+ const hostBits = bits[version] - prefixNum;
82
+ const mask = hostBits > 0 ? (1n << BigInt(hostBits)) - 1n : 0n;
83
+ return {
84
+ start: number & ~mask,
85
+ end: number | mask,
86
+ version
87
+ };
117
88
  }
118
89
  function biggestPowerOfTwo(num) {
119
- if (num === 0n) return 0n;
120
- let b = 0n;
121
- let n = num >> 1n;
122
- while (n > 0n) {
123
- b++;
124
- n >>= 1n;
125
- }
126
- return 1n << b;
90
+ if (num === 0n) return 0n;
91
+ return 1n << BigInt(num.toString(2).length - 1);
127
92
  }
128
93
  function subparts(part, output) {
129
- if (!output) output = [];
130
- if (part.end < part.start) {
131
- return output;
132
- }
133
- if (part.end === part.start) {
134
- output.push(part);
135
- return output;
136
- }
137
- if (part.end - part.start === 1n) {
138
- if (part.end % 2n === 0n) {
139
- output.push({ start: part.start, end: part.start }, { start: part.end, end: part.end });
140
- } else {
141
- output.push({ start: part.start, end: part.end });
142
- }
143
- return output;
144
- }
145
- const size = diff(part.end, part.start);
146
- let biggest = biggestPowerOfTwo(size);
147
- let start;
148
- let end;
149
- if (size === biggest && part.start % biggest === 0n) {
150
- output.push(part);
151
- return output;
152
- } else if (part.start % biggest === 0n) {
153
- start = part.start;
154
- end = start + biggest - 1n;
155
- } else {
156
- start = part.end / biggest * biggest;
157
- if (start + biggest - 1n > part.end) {
158
- start = (part.end / biggest - 1n) * biggest;
159
- while (start < part.start) {
160
- biggest /= 2n;
161
- start = (part.end / biggest - 1n) * biggest;
162
- }
163
- end = start + biggest - 1n;
164
- } else {
165
- start = part.end / biggest * biggest;
166
- end = start + biggest - 1n;
167
- }
168
- }
169
- if (start !== part.start) {
170
- subparts({ start: part.start, end: start - 1n }, output);
171
- }
172
- output.push({ start, end });
173
- if (end !== part.end) {
174
- subparts({ start: end + 1n, end: part.end }, output);
175
- }
176
- return output;
94
+ if (!output) output = [];
95
+ if (part.end < part.start) return output;
96
+ if (part.end === part.start) {
97
+ output.push(part);
98
+ return output;
99
+ }
100
+ if (part.end - part.start === 1n) {
101
+ if (part.end % 2n === 0n) output.push({
102
+ start: part.start,
103
+ end: part.start
104
+ }, {
105
+ start: part.end,
106
+ end: part.end
107
+ });
108
+ else output.push({
109
+ start: part.start,
110
+ end: part.end
111
+ });
112
+ return output;
113
+ }
114
+ const size = diff(part.end, part.start);
115
+ let biggest = biggestPowerOfTwo(size);
116
+ let start;
117
+ let end;
118
+ if (size === biggest && part.start % biggest === 0n) {
119
+ output.push(part);
120
+ return output;
121
+ } else if (part.start % biggest === 0n) {
122
+ start = part.start;
123
+ end = start + biggest - 1n;
124
+ } else {
125
+ start = part.end / biggest * biggest;
126
+ if (start + biggest - 1n > part.end) {
127
+ start = (part.end / biggest - 1n) * biggest;
128
+ while (start < part.start) {
129
+ biggest /= 2n;
130
+ start = (part.end / biggest - 1n) * biggest;
131
+ }
132
+ end = start + biggest - 1n;
133
+ } else {
134
+ start = part.end / biggest * biggest;
135
+ end = start + biggest - 1n;
136
+ }
137
+ }
138
+ if (start !== part.start) subparts({
139
+ start: part.start,
140
+ end: start - 1n
141
+ }, output);
142
+ output.push({
143
+ start,
144
+ end
145
+ });
146
+ if (end !== part.end) subparts({
147
+ start: end + 1n,
148
+ end: part.end
149
+ }, output);
150
+ return output;
177
151
  }
178
152
  function diff(a, b) {
179
- return a + 1n - b;
153
+ return a + 1n - b;
180
154
  }
181
155
  function formatPart(part, version) {
182
- const ip = normalizeIp(stringifyIp({ number: part.start, version }));
183
- const size = diff(part.end, part.start);
184
- let hostBits = 0;
185
- let s = size >> 1n;
186
- while (s > 0n) {
187
- s >>= 1n;
188
- hostBits++;
189
- }
190
- const prefix = bits[version] - hostBits;
191
- return `${ip}/${prefix}`;
156
+ const ip = stringifyIp({
157
+ number: part.start,
158
+ version
159
+ });
160
+ const size = diff(part.end, part.start);
161
+ const hostBits = size <= 1n ? 0 : size.toString(2).length - 1;
162
+ return `${ip}/${bits[version] - hostBits}`;
192
163
  }
193
- function mapNets(nets) {
194
- const maps = { 4: /* @__PURE__ */ new Map(), 6: /* @__PURE__ */ new Map() };
195
- for (const { start, end, version } of nets) {
196
- let startEntry = maps[version].get(start);
197
- if (!startEntry) {
198
- startEntry = { start: 0, end: 0 };
199
- maps[version].set(start, startEntry);
200
- }
201
- let endEntry = maps[version].get(end);
202
- if (!endEntry) {
203
- endEntry = { start: 0, end: 0 };
204
- maps[version].set(end, endEntry);
205
- }
206
- startEntry.start += 1;
207
- endEntry.end += 1;
208
- }
209
- return maps;
164
+ function mergeIntervalsRaw(nets) {
165
+ if (nets.length === 0) return [];
166
+ const sorted = nets.slice().sort((a, b) => a.start > b.start ? 1 : a.start < b.start ? -1 : a.end > b.end ? 1 : a.end < b.end ? -1 : 0);
167
+ const merged = [];
168
+ let curStart = sorted[0].start;
169
+ let curEnd = sorted[0].end;
170
+ for (let i = 1; i < sorted.length; i++) {
171
+ const { start, end } = sorted[i];
172
+ if (start <= curEnd + 1n) {
173
+ if (end > curEnd) curEnd = end;
174
+ } else {
175
+ merged.push({
176
+ start: curStart,
177
+ end: curEnd
178
+ });
179
+ curStart = start;
180
+ curEnd = end;
181
+ }
182
+ }
183
+ merged.push({
184
+ start: curStart,
185
+ end: curEnd
186
+ });
187
+ return merged;
210
188
  }
211
- function doMerge(maps) {
212
- let start = null;
213
- let end = null;
214
- const numbers = Array.from(maps.keys()).sort((a, b) => a > b ? 1 : a < b ? -1 : 0);
215
- let depth = 0;
216
- const merged = [];
217
- for (const [index2, number] of numbers.entries()) {
218
- const marker = maps.get(number);
219
- if (start === null && marker.start) start = number;
220
- if (marker.end) end = number;
221
- if (start === null) continue;
222
- if (marker.start) depth += marker.start;
223
- if (marker.end) depth -= marker.end;
224
- const next = numbers[index2 + 1];
225
- if (marker.end && depth === 0 && next !== void 0 && next - number > 1n) {
226
- subparts({ start, end }, merged);
227
- start = null;
228
- end = null;
229
- } else if (index2 === numbers.length - 1) {
230
- subparts({ start, end }, merged);
231
- }
232
- }
233
- return merged;
189
+ function mergeIntervals(nets) {
190
+ const merged = [];
191
+ for (const part of mergeIntervalsRaw(nets)) subparts(part, merged);
192
+ return merged;
234
193
  }
194
+ function subtractSorted(bases, excls) {
195
+ if (excls.length === 0) return bases;
196
+ if (bases.length === 0) return [];
197
+ const result = [];
198
+ let j = 0;
199
+ for (const base of bases) {
200
+ let start = base.start;
201
+ const end = base.end;
202
+ while (j < excls.length && excls[j].end < start) j++;
203
+ let k = j;
204
+ while (k < excls.length && excls[k].start <= end && start <= end) {
205
+ if (excls[k].start > start) result.push({
206
+ start,
207
+ end: excls[k].start - 1n
208
+ });
209
+ start = excls[k].end + 1n;
210
+ k++;
211
+ }
212
+ if (start <= end) result.push({
213
+ start,
214
+ end
215
+ });
216
+ }
217
+ return result;
218
+ }
219
+ /** Returns an array of merged networks */
235
220
  function mergeCidr(nets) {
236
- const arr = uniq(Array.isArray(nets) ? nets : [nets]).map(parseCidrLean);
237
- const maps = mapNets(arr);
238
- const merged = [];
239
- for (const v of [4, 6]) {
240
- for (const part of doMerge(maps[v])) {
241
- merged.push(formatPart(part, v));
242
- }
243
- }
244
- return merged;
221
+ const arr = uniq(Array.isArray(nets) ? nets : [nets]).map(parseCidrLean);
222
+ const byVersion = {
223
+ 4: [],
224
+ 6: []
225
+ };
226
+ for (const n of arr) byVersion[n.version].push(n);
227
+ const merged = [];
228
+ for (const v of [4, 6]) for (const part of mergeIntervals(byVersion[v])) merged.push(formatPart(part, v));
229
+ return merged;
245
230
  }
231
+ /** Returns an array of merged remaining networks of the subtraction of `excludeNetworks` from `baseNetworks`. */
246
232
  function excludeCidr(base, excl) {
247
- const baseArr = uniq(Array.isArray(base) ? base : [base]).map(parseCidrLean);
248
- const exclArr = uniq(Array.isArray(excl) ? excl : [excl]).map(parseCidrLean);
249
- const baseMaps = mapNets(baseArr);
250
- const exclMaps = mapNets(exclArr);
251
- const bases = { 4: [], 6: [] };
252
- const excls = { 4: [], 6: [] };
253
- for (const v of [4, 6]) {
254
- bases[v] = doMerge(baseMaps[v]);
255
- excls[v] = doMerge(exclMaps[v]);
256
- }
257
- for (const v of [4, 6]) {
258
- for (const exclPart of excls[v]) {
259
- const newBases = [];
260
- for (const basePart of bases[v]) {
261
- for (const part of excludeNetsParts(basePart, exclPart)) {
262
- newBases.push(part);
263
- }
264
- }
265
- bases[v] = newBases;
266
- }
267
- }
268
- const result = [];
269
- for (const v of [4, 6]) {
270
- for (const part of bases[v]) {
271
- result.push(formatPart(part, v));
272
- }
273
- }
274
- return result;
233
+ const baseArr = uniq(Array.isArray(base) ? base : [base]).map(parseCidrLean);
234
+ const exclArr = uniq(Array.isArray(excl) ? excl : [excl]).map(parseCidrLean);
235
+ const baseByVersion = {
236
+ 4: [],
237
+ 6: []
238
+ };
239
+ const exclByVersion = {
240
+ 4: [],
241
+ 6: []
242
+ };
243
+ for (const n of baseArr) baseByVersion[n.version].push(n);
244
+ for (const n of exclArr) exclByVersion[n.version].push(n);
245
+ const result = [];
246
+ for (const v of [4, 6]) {
247
+ const remaining = subtractSorted(mergeIntervalsRaw(baseByVersion[v]), mergeIntervalsRaw(exclByVersion[v]));
248
+ for (const part of remaining) {
249
+ const aligned = subparts(part);
250
+ for (const p of aligned) result.push(formatPart(p, v));
251
+ }
252
+ }
253
+ return result;
275
254
  }
276
255
  function* expandCidr(nets) {
277
- const arr = uniq(Array.isArray(nets) ? nets : [nets]);
278
- for (const net of mergeCidr(arr)) {
279
- const { start, end, version } = parseCidrLean(net);
280
- for (let number = start; number <= end; number++) {
281
- yield normalizeIp(stringifyIp({ number, version }));
282
- }
283
- }
256
+ const arr = uniq(Array.isArray(nets) ? nets : [nets]);
257
+ for (const net of mergeCidr(arr)) {
258
+ const { start, end, version } = parseCidrLean(net);
259
+ for (let number = start; number <= end; number++) yield normalizeIp(stringifyIp({
260
+ number,
261
+ version
262
+ }));
263
+ }
284
264
  }
265
+ /** Returns a boolean that indicates if `networksA` overlap (intersect) with `networksB`. */
285
266
  function overlapCidr(a, b) {
286
- const aNets = uniq(Array.isArray(a) ? a : [a]).map(parseCidrLean);
287
- const bNets = uniq(Array.isArray(b) ? b : [b]).map(parseCidrLean);
288
- const aByVersion = { 4: [], 6: [] };
289
- const bByVersion = { 4: [], 6: [] };
290
- for (const n of aNets) aByVersion[n.version].push(n);
291
- for (const n of bNets) bByVersion[n.version].push(n);
292
- for (const v of [4, 6]) {
293
- const aVer = aByVersion[v].sort((x, y) => x.start > y.start ? 1 : x.start < y.start ? -1 : 0);
294
- const bVer = bByVersion[v].sort((x, y) => x.start > y.start ? 1 : x.start < y.start ? -1 : 0);
295
- let i = 0, j = 0;
296
- while (i < aVer.length && j < bVer.length) {
297
- const aNet = aVer[i];
298
- const bNet = bVer[j];
299
- if (aNet.start <= bNet.end && bNet.start <= aNet.end) return true;
300
- if (aNet.end < bNet.end) i++;
301
- else j++;
302
- }
303
- }
304
- return false;
267
+ const aNets = uniq(Array.isArray(a) ? a : [a]).map(parseCidrLean);
268
+ const bNets = uniq(Array.isArray(b) ? b : [b]).map(parseCidrLean);
269
+ const aByVersion = {
270
+ 4: [],
271
+ 6: []
272
+ };
273
+ const bByVersion = {
274
+ 4: [],
275
+ 6: []
276
+ };
277
+ for (const n of aNets) aByVersion[n.version].push(n);
278
+ for (const n of bNets) bByVersion[n.version].push(n);
279
+ for (const v of [4, 6]) {
280
+ const aVer = aByVersion[v].sort((x, y) => x.start > y.start ? 1 : x.start < y.start ? -1 : 0);
281
+ const bVer = bByVersion[v].sort((x, y) => x.start > y.start ? 1 : x.start < y.start ? -1 : 0);
282
+ let i = 0, j = 0;
283
+ while (i < aVer.length && j < bVer.length) {
284
+ const aNet = aVer[i];
285
+ const bNet = bVer[j];
286
+ if (aNet.start <= bNet.end && bNet.start <= aNet.end) return true;
287
+ if (aNet.end < bNet.end) i++;
288
+ else j++;
289
+ }
290
+ }
291
+ return false;
305
292
  }
293
+ /** Returns a boolean that indicates whether `networksA` fully contain all `networksB`. */
306
294
  function containsCidr(a, b) {
307
- const aNets = uniq(Array.isArray(a) ? a : [a]).map(parseCidrLean);
308
- const bNets = uniq(Array.isArray(b) ? b : [b]).map(parseCidrLean);
309
- const aByVersion = { 4: [], 6: [] };
310
- const bByVersion = { 4: [], 6: [] };
311
- for (const n of aNets) aByVersion[n.version].push(n);
312
- for (const n of bNets) bByVersion[n.version].push(n);
313
- for (const v of [4, 6]) {
314
- const containers = aByVersion[v].sort((x, y) => x.start > y.start ? 1 : x.start < y.start ? -1 : 0);
315
- const targets = bByVersion[v];
316
- if (targets.length === 0) continue;
317
- if (containers.length === 0) return false;
318
- const maxEnd = new Array(containers.length);
319
- maxEnd[0] = containers[0].end;
320
- for (let i = 1; i < containers.length; i++) {
321
- if (containers[i].end > maxEnd[i - 1]) {
322
- maxEnd[i] = containers[i].end;
323
- } else {
324
- maxEnd[i] = maxEnd[i - 1];
325
- }
326
- }
327
- for (const target of targets) {
328
- let lo = 0, hi = containers.length - 1;
329
- let idx = -1;
330
- while (lo <= hi) {
331
- const mid = lo + hi >> 1;
332
- if (containers[mid].start <= target.start) {
333
- idx = mid;
334
- lo = mid + 1;
335
- } else {
336
- hi = mid - 1;
337
- }
338
- }
339
- if (idx < 0 || maxEnd[idx] < target.end) return false;
340
- }
341
- }
342
- return true;
295
+ const aNets = uniq(Array.isArray(a) ? a : [a]).map(parseCidrLean);
296
+ const bNets = uniq(Array.isArray(b) ? b : [b]).map(parseCidrLean);
297
+ const aByVersion = {
298
+ 4: [],
299
+ 6: []
300
+ };
301
+ const bByVersion = {
302
+ 4: [],
303
+ 6: []
304
+ };
305
+ for (const n of aNets) aByVersion[n.version].push(n);
306
+ for (const n of bNets) bByVersion[n.version].push(n);
307
+ for (const v of [4, 6]) {
308
+ const containers = aByVersion[v].sort((x, y) => x.start > y.start ? 1 : x.start < y.start ? -1 : 0);
309
+ const targets = bByVersion[v];
310
+ if (targets.length === 0) continue;
311
+ if (containers.length === 0) return false;
312
+ const maxEnd = new Array(containers.length);
313
+ maxEnd[0] = containers[0].end;
314
+ for (let i = 1; i < containers.length; i++) if (containers[i].end > maxEnd[i - 1]) maxEnd[i] = containers[i].end;
315
+ else maxEnd[i] = maxEnd[i - 1];
316
+ for (const target of targets) {
317
+ let lo = 0, hi = containers.length - 1;
318
+ let idx = -1;
319
+ while (lo <= hi) {
320
+ const mid = lo + hi >> 1;
321
+ if (containers[mid].start <= target.start) {
322
+ idx = mid;
323
+ lo = mid + 1;
324
+ } else hi = mid - 1;
325
+ }
326
+ if (idx < 0 || maxEnd[idx] < target.end) return false;
327
+ }
328
+ }
329
+ return true;
343
330
  }
344
- const index = {
345
- mergeCidr,
346
- excludeCidr,
347
- expandCidr,
348
- overlapCidr,
349
- containsCidr,
350
- normalizeCidr,
351
- parseCidr
352
- };
353
- export {
354
- containsCidr,
355
- index as default,
356
- excludeCidr,
357
- expandCidr,
358
- mergeCidr,
359
- normalizeCidr,
360
- overlapCidr,
361
- parseCidr
331
+ var cidr_tools_default = {
332
+ mergeCidr,
333
+ excludeCidr,
334
+ expandCidr,
335
+ overlapCidr,
336
+ containsCidr,
337
+ normalizeCidr,
338
+ parseCidr
362
339
  };
340
+
341
+ //#endregion
342
+ export { containsCidr, cidr_tools_default as default, excludeCidr, expandCidr, mergeCidr, normalizeCidr, overlapCidr, parseCidr };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cidr-tools",
3
- "version": "11.0.10",
3
+ "version": "11.0.11",
4
4
  "author": "silverwind <me@silverwind.io>",
5
5
  "description": "Tools to work with IPv4 and IPv6 CIDR",
6
6
  "repository": "silverwind/cidr-tools",
@@ -17,21 +17,22 @@
17
17
  "node": ">=18"
18
18
  },
19
19
  "dependencies": {
20
- "ip-bigint": "^8.2.6"
20
+ "ip-bigint": "^8.2.7"
21
21
  },
22
22
  "devDependencies": {
23
- "@typescript/native-preview": "7.0.0-dev.20260202.1",
24
- "eslint": "9.39.2",
25
- "eslint-config-silverwind": "120.1.2",
23
+ "@types/node": "25.3.0",
24
+ "@typescript/native-preview": "7.0.0-dev.20260224.1",
25
+ "eslint": "9.39.3",
26
+ "eslint-config-silverwind": "121.1.3",
26
27
  "jest-extended": "7.0.0",
28
+ "tsdown": "0.20.3",
29
+ "tsdown-config-silverwind": "1.7.5",
27
30
  "typescript": "5.9.3",
28
- "typescript-config-silverwind": "14.0.0",
29
- "updates": "17.1.0",
31
+ "typescript-config-silverwind": "15.0.0",
32
+ "updates": "17.6.2",
30
33
  "updates-config-silverwind": "1.0.3",
31
- "versions": "14.1.0",
32
- "vite": "7.3.1",
33
- "vite-config-silverwind": "6.0.9",
34
+ "versions": "14.2.0",
34
35
  "vitest": "4.0.18",
35
- "vitest-config-silverwind": "10.6.1"
36
+ "vitest-config-silverwind": "10.6.3"
36
37
  }
37
38
  }