Skip to content
Open
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
97 changes: 97 additions & 0 deletions library/src/actions/cidr/cidr.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import { IPV4_REGEX, IPV6_REGEX } from '../../regex.ts';
import type {
BaseIssue,
BaseValidation,
ErrorMessage,
} from '../../types/index.ts';
import { _addIssue } from '../../utils/index.ts';

/**
* Validates a [CIDR](https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing)
* string: an IPv4 or IPv6 address followed by a `/` and a prefix length in
* range (0-32 for IPv4, 0-128 for IPv6). See issue #342.
*/
function isCidr(value: string): boolean {
const slash = value.lastIndexOf('/');
if (slash < 0) return false;
const ip = value.slice(0, slash);
const prefix = value.slice(slash + 1);
if (!/^\d{1,3}$/.test(prefix)) return false;
const n = Number(prefix);
if (IPV4_REGEX.test(ip)) {
return n >= 0 && n <= 32;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: Library formatting CI will reject this new file because it lacks a final newline. End the file with LF so Prettier's check passes.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At library/src/actions/cidr/cidr.ts, line 23:

<comment>Library formatting CI will reject this new file because it lacks a final newline. End the file with LF so Prettier's check passes.</comment>

<file context>
@@ -0,0 +1,97 @@
+  const n = Number(prefix);
+  if (IPV4_REGEX.test(ip)) {
+    return n >= 0 && n <= 32;
+  }
+  if (IPV6_REGEX.test(ip)) {
+    return n >= 0 && n <= 128;
</file context>
Suggested change
}
}

if (IPV6_REGEX.test(ip)) {
return n >= 0 && n <= 128;
}
return false;
}

/**
* CIDR issue interface.
*/
export interface CidrIssue<TInput extends string>
extends BaseIssue<TInput> {
readonly kind: 'validation';
readonly type: 'cidr';
readonly expected: null;
readonly received: `"${string}"`;
readonly requirement: (input: string) => boolean;
}

/**
* CIDR action interface.
*/
export interface CidrAction<
TInput extends string,
TMessage extends ErrorMessage<CidrIssue<TInput>> | undefined,
> extends BaseValidation<TInput, TInput, CidrIssue<TInput>> {
readonly type: 'cidr';
readonly reference: typeof cidr;
readonly expects: null;
readonly requirement: (input: string) => boolean;
readonly message: TMessage;
}

/**
* Creates a [CIDR](https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing)
* validation action that accepts both IPv4 (`192.168.1.0/24`) and IPv6
* (`2001:db8::/32`) CIDR notation. The prefix length must be in range (0-32 for
* IPv4, 0-128 for IPv6). See issue #342.
*
* @returns A CIDR action.
*/
export function cidr<TInput extends string>(): CidrAction<TInput, undefined>;

/**
* Creates a CIDR validation action.
*
* @param message The error message.
*
* @returns A CIDR action.
*/
export function cidr<
TInput extends string,
const TMessage extends ErrorMessage<CidrIssue<TInput>> | undefined,
>(message: TMessage): CidrAction<TInput, TMessage>;

// @__NO_SIDE_EFFECTS__
export function cidr(
message?: ErrorMessage<CidrIssue<string>>,
): CidrAction<string, ErrorMessage<CidrIssue<string>> | undefined> {
return {
kind: 'validation',
type: 'cidr',
reference: cidr,
async: false,
expects: null,
requirement: isCidr,
message,
'~run'(dataset, config) {
if (dataset.typed && !this.requirement(dataset.value)) {
_addIssue(this, 'CIDR', dataset, config);
}
return dataset;
},
};
}
1 change: 1 addition & 0 deletions library/src/actions/cidr/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './cidr.ts';
1 change: 1 addition & 0 deletions library/src/actions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export * from './imei/index.ts';
export * from './includes/index.ts';
export * from './integer/index.ts';
export * from './ip/index.ts';
export * from './cidr/index.ts';
export * from './ipv4/index.ts';
export * from './ipv6/index.ts';
export * from './isbn/index.ts';
Expand Down