cidr-regex 7.0.1 → 7.1.0

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.
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # cidr-regex
2
2
  [![](https://img.shields.io/npm/v/cidr-regex.svg?style=flat)](https://www.npmjs.org/package/cidr-regex) [![](https://img.shields.io/npm/dm/cidr-regex.svg)](https://www.npmjs.org/package/cidr-regex) [![](https://packagephobia.com/badge?p=cidr-regex)](https://packagephobia.com/result?p=cidr-regex) [![](https://depx.co/api/badge/cidr-regex)](https://depx.co/pkg/cidr-regex)
3
3
 
4
- > Regular expression for matching IP addresses in CIDR notation
4
+ > Regular expression for matching IP addresses in CIDR notation and bare IP addresses
5
5
 
6
6
  ## Usage
7
7
 
@@ -26,9 +26,22 @@ cidrRegex.v6({exact: true}).test("1:2:3:4:5:6:7:8/64");
26
26
  // Extract CIDRs from string
27
27
  "foo 192.168.0.1/24 bar 1:2:3:4:5:6:7:8/64 baz".match(cidrRegex());
28
28
  //=> ["192.168.0.1/24", "1:2:3:4:5:6:7:8/64"]
29
+
30
+ // Is a bare IP address?
31
+ cidrRegex({exact: true, prefix: "none"}).test("192.168.0.1");
32
+ //=> true
33
+
34
+ // Is either?
35
+ cidrRegex({exact: true, prefix: "optional"}).test("192.168.0.1");
36
+ //=> true
37
+ cidrRegex({exact: true, prefix: "optional"}).test("192.168.0.1/24");
38
+ //=> true
29
39
  ```
30
40
 
31
41
  ## API
42
+
43
+ All three functions match CIDR notation by default. The `prefix` option switches them to bare IP addresses or to either.
44
+
32
45
  ### cidrRegex(options?: CidrRegexOptions)
33
46
 
34
47
  Returns a regex for matching both IPv4 and IPv6 CIDR IP addresses.
@@ -46,6 +59,7 @@ Returns a regex for matching IPv6 CIDR IP addresses.
46
59
  The options object has the following properties:
47
60
 
48
61
  - `exact` *boolean*: Only match an exact string. Useful with `RegExp#test()` to check if a string is a CIDR IP address. Default: false.
62
+ - `prefix` *string*: Whether a `/prefix` must follow the address. `"required"` matches only CIDR, `"optional"` matches CIDR and bare IP addresses, `"none"` matches only bare IP addresses. Default: `"required"`.
49
63
 
50
64
  ## Related
51
65
 
package/dist/index.d.ts CHANGED
@@ -1,27 +1,28 @@
1
1
  //#region index.d.ts
2
2
  type CidrRegexOptions = {
3
3
  /**
4
- Only match an exact string. Useful with `RegExp#test()` to check if a string is an IP address. *(`false` matches any IP address in a string)*
5
- @defaultValue false
6
- */
4
+ Only match an exact string. Useful with `RegExp#test()` to check if a string is an IP address. *(`false` matches any IP address in a string)*
5
+
6
+ @defaultValue false
7
+ */
7
8
  readonly exact?: boolean;
9
+ /**
10
+ Whether a `/prefix` must follow the address. `"required"` matches only CIDR, `"optional"` matches both,
11
+ `"none"` matches only bare IP addresses. Combined with `exact: false`, `"none"` matches the address part
12
+ inside a CIDR, so `1.2.3.4/24` yields `1.2.3.4`.
13
+
14
+ @defaultValue "required"
15
+ */
16
+ readonly prefix?: "required" | "optional" | "none";
8
17
  };
9
- declare const cidrRegex: {
10
- ({
11
- exact
12
- }?: CidrRegexOptions): RegExp;
13
- v4: ({
14
- exact
15
- }?: CidrRegexOptions) => RegExp;
16
- v6: ({
17
- exact
18
- }?: CidrRegexOptions) => RegExp;
19
- };
20
- declare const v4: ({
21
- exact
22
- }?: CidrRegexOptions) => RegExp;
23
- declare const v6: ({
24
- exact
25
- }?: CidrRegexOptions) => RegExp;
18
+ declare function cidrRegex(opts?: CidrRegexOptions): RegExp;
19
+ declare namespace cidrRegex {
20
+ var _a: (opts?: CidrRegexOptions) => RegExp;
21
+ export { _a as v4 };
22
+ export var _b: (opts?: CidrRegexOptions) => RegExp;
23
+ export { _b as v6 };
24
+ }
25
+ declare const v4: (opts?: CidrRegexOptions) => RegExp;
26
+ declare const v6: (opts?: CidrRegexOptions) => RegExp;
26
27
  //#endregion
27
28
  export { CidrRegexOptions, cidrRegex as default, v4, v6 };
package/dist/index.js CHANGED
@@ -2,23 +2,41 @@
2
2
  const octet = "(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)";
3
3
  const v4dotted = `${octet}(?:\\.${octet}){3}`;
4
4
  const hex = "[\\dA-Fa-f]{1,4}";
5
- const scopeIdRe = "(?:%[^\\s%/\\0]+)?";
6
- const v4src = `${v4dotted}/(?:3[0-2]|[12]?\\d)`;
7
- const v6src = `(?:(?:${hex}:){7}(?:${hex}|:)|(?:${hex}:){6}(?:${v4dotted}|:${hex}|:)|(?:${hex}:){5}(?::${v4dotted}|(?::${hex}){1,2}|:)|(?:${hex}:){4}(?:(?::${hex})?:${v4dotted}|(?::${hex}){1,3}|:)|(?:${hex}:){3}(?:(?::${hex}){0,2}:${v4dotted}|(?::${hex}){1,4}|:)|(?:${hex}:){2}(?:(?::${hex}){0,3}:${v4dotted}|(?::${hex}){1,5}|:)|${hex}:(?:(?::${hex}){0,4}:${v4dotted}|(?::${hex}){1,6}|:)|:(?:(?::${hex}){0,5}:${v4dotted}|(?::${hex}){1,7}|:))${scopeIdRe}/(?:12[0-8]|1[01]\\d|[1-9]?\\d)`;
8
- const v6srcFast = `(?=[\\dA-Fa-f:])${v6src}`;
9
- const v4exact = new RegExp(`^${v4src}$`);
10
- const v6exact = new RegExp(`^${v6src}$`);
11
- const v46exact = new RegExp(`^(?:${v4src}|${v6src})$`);
12
- const v4global = new RegExp(v4src, "g");
13
- const v6global = new RegExp(v6srcFast, "g");
14
- const v46global = new RegExp(`${v4src}|${v6srcFast}`, "g");
15
- function resetRegex(re) {
16
- re.lastIndex = 0;
5
+ const v6addr = `(?:(?:${hex}:){7}(?:${hex}|:)|(?:${hex}:){6}(?:${v4dotted}|:${hex}|:)|(?:${hex}:){5}(?::${v4dotted}|(?::${hex}){1,2}|:)|(?:${hex}:){4}(?:(?::${hex})?:${v4dotted}|(?::${hex}){1,3}|:)|(?:${hex}:){3}(?:(?::${hex}){0,2}:${v4dotted}|(?::${hex}){1,4}|:)|(?:${hex}:){2}(?:(?::${hex}){0,3}:${v4dotted}|(?::${hex}){1,5}|:)|${hex}:(?:(?::${hex}){0,4}:${v4dotted}|(?::${hex}){1,6}|:)|:(?:(?::${hex}){0,5}:${v4dotted}|(?::${hex}){1,7}|:))(?:%[^\\s%/\\0]+)?`;
6
+ const v6fast = "(?=[\\dA-Fa-f:])";
7
+ const suffixes = (range) => [
8
+ range,
9
+ `(?:${range})?`,
10
+ ""
11
+ ];
12
+ const v4suffixes = suffixes("/(?:3[0-2]|[12]?\\d)");
13
+ const v6suffixes = suffixes("/(?:12[0-8]|1[01]\\d|[1-9]?\\d)");
14
+ const V4 = 0;
15
+ const V6 = 1;
16
+ const V46 = 2;
17
+ const cache = new Array(18);
18
+ function regexFor(family, { exact, prefix = "required" }) {
19
+ const mode = prefix === "required" ? 0 : prefix === "optional" ? 1 : 2;
20
+ const index = family * 6 + mode * 2 + (exact ? 1 : 0);
21
+ let re = cache[index];
22
+ if (!re) {
23
+ const v4src = v4dotted + v4suffixes[mode];
24
+ const v6src = v6addr + v6suffixes[mode];
25
+ if (exact) {
26
+ const body = family === V4 ? v4src : family === V6 ? v6src : `(?:${v4src}|${v6src})`;
27
+ re = cache[index] = new RegExp(`^${body}$`);
28
+ } else {
29
+ const v6fastSrc = v6fast + v6src;
30
+ const body = family === V4 ? v4src : family === V6 ? v6fastSrc : `${v4src}|${v6fastSrc}`;
31
+ re = cache[index] = new RegExp(body, "g");
32
+ }
33
+ }
34
+ if (!exact) re.lastIndex = 0;
17
35
  return re;
18
36
  }
19
- const cidrRegex = ({ exact } = {}) => exact ? v46exact : resetRegex(v46global);
20
- const v4 = cidrRegex.v4 = ({ exact } = {}) => exact ? v4exact : resetRegex(v4global);
21
- const v6 = cidrRegex.v6 = ({ exact } = {}) => exact ? v6exact : resetRegex(v6global);
37
+ const cidrRegex = (opts = {}) => regexFor(V46, opts);
38
+ const v4 = cidrRegex.v4 = (opts = {}) => regexFor(V4, opts);
39
+ const v6 = cidrRegex.v6 = (opts = {}) => regexFor(V6, opts);
22
40
 
23
41
  //#endregion
24
42
  export { cidrRegex as default, v4, v6 };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "cidr-regex",
3
- "version": "7.0.1",
4
- "description": "Regular expression for matching IP addresses in CIDR notation",
3
+ "version": "7.1.0",
4
+ "description": "Regular expression for matching IP addresses in CIDR notation and bare IP addresses",
5
5
  "author": "silverwind <me@silverwind.io>",
6
6
  "contributors": [
7
7
  "Felipe Apostol <flipjs.io@gmail.com> (http://flipjs.io/)"
@@ -36,19 +36,19 @@
36
36
  "node": ">=22"
37
37
  },
38
38
  "devDependencies": {
39
- "@types/node": "25.7.0",
40
- "@typescript/native-preview": "7.0.0-dev.20260512.1",
41
- "eslint": "10.3.0",
42
- "eslint-config-silverwind": "133.0.1",
39
+ "@types/node": "26.2.0",
40
+ "@typescript/native-preview": "7.0.0-dev.20260707.2",
41
+ "eslint": "10.8.1",
42
+ "eslint-config-silverwind": "144.0.2",
43
43
  "jest-extended": "7.0.0",
44
- "tsdown": "0.22.0",
45
- "tsdown-config-silverwind": "3.0.1",
44
+ "tsdown": "0.22.14",
45
+ "tsdown-config-silverwind": "4.0.3",
46
46
  "typescript": "6.0.3",
47
- "typescript-config-silverwind": "18.0.0",
48
- "updates": "17.16.10",
49
- "updates-config-silverwind": "4.0.0",
50
- "versions": "15.0.3",
51
- "vitest": "4.1.6",
52
- "vitest-config-silverwind": "11.3.4"
47
+ "typescript-config-silverwind": "20.0.3",
48
+ "updates": "18.0.1",
49
+ "updates-config-silverwind": "4.0.5",
50
+ "versions": "15.3.4",
51
+ "vitest": "4.1.11",
52
+ "vitest-config-silverwind": "11.6.0"
53
53
  }
54
54
  }