@technobuddha/library
Version:
A large library of useful functions
252 lines • 10.8 kB
JavaScript
/* eslint-disable unicorn/better-regex */
/* eslint-disable require-unicode-regexp */
/* eslint-disable no-control-regex */
import { re } from "./re.js";
//#region ipV4
/**
* Validate an IPv4 segment.
* @internal
*/
const IPV4_SEG = /(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])/;
/**
* validate an IPv4 address
* @group RegExp
* @category Constants
* @example
* ```typescript
* ipV4.test('192.168.1.1'); // true
* ipV4.test('255.255.255.255'); // true
* ipV4.test('256.0.0.1'); // false
* ipV4.test('abc.def.ghi.jkl'); // false
* ```
*/
export const ipV4 = re `^${IPV4_SEG}\.${IPV4_SEG}\.${IPV4_SEG}\.${IPV4_SEG}$`;
//#endregion
//#region ipV4Local
/**
* Validate a private network 10.x.x.x address.
* @internal
*/
const IPV4_NET10 = re `^0?10[.]${IPV4_SEG}`;
/**
* Validate a private network 172.16.x.x - 172.31.x.x address.
* @internal
*/
const IPV4_NET172 = /^172[.]0?(?:1[6-9]|2[0-9]|3[0-1])/;
/**
* Validate a private network 192.168.x.x address.
* @internal
*/
const IPV4_NET192 = /^192[.]168$/;
/**
* determine if Ipv4 address is local
* @group RegExp
* @category Constants
* @example
* ```typescript
* ipV4Local.test('192.168.1.1'); // true
* ipV4Local.test('10.0.0.1'); // true
* ipV4Local.test('172.16.0.1'); // true
* ipV4Local.test('8.8.8.8'); // false
* ipV4Local.test('256.0.0.1'); // false
* ```
*/
export const ipV4Local = re `^(?:${IPV4_NET10}|${IPV4_NET172}|${IPV4_NET192})[.]${IPV4_SEG}[.]${IPV4_SEG}$`;
//#endregion
//#region isoDate
//cspell:ignore ZONEPLUG, ZONEMINUS, ZONEPLUS, ZONEHOUR, ZONEMINUTE
/**
* Validate a year component in a date string.
* @internal
*/
const ISO_YEAR = /^[0-9]{4}$/;
/**
* Validate a month component in a date string.
* @internal
*/
const ISO_MONTH = /^(?:0[1-9]|1[0-2])$/;
/**
* Validate a day component in a date string.
* @internal
*/
const ISO_DAY = /^(?:3[0-1]|[1-2][0-9]|0[1-9])$/;
/**
* Validate an hour component in a time string.
* @internal
*/
const ISO_HOUR = /^(?:2[0-3]|[0-1][0-9])$/;
/**
* Validate a minute component in a time string.
* @internal
*/
const ISO_MINUTE = /^[0-5][0-9]$/;
/**
* Validate a second component in a time string.
* @internal
*/
const ISO_SECOND = ISO_MINUTE;
/**
* Validate a fractional second component in a time string.
* @internal
*/
const ISO_FRACTION = /^[0-9]+$/;
/**
* Validate a positive timezone offset hour.
* @internal
*/
const ISO_ZONEPLUS = /^[+](?:1[0-4]|0[0-9])$/;
/**
* Validate a negative timezone offset hour.
* @internal
*/
const ISO_ZONEMINUS = /^[-](?:1[0-2]|0[0-9])$/;
/**
* Validate a timezone offset hour.
* @internal
*/
const ISO_ZONEHOUR = re `^${ISO_ZONEPLUS}|${ISO_ZONEMINUS}$`;
/**
* Validate a timezone offset minute.
* @internal
*/
const ISO_ZONEMINUTE = /^[0-5][0-9]$/;
/**
* Validate a timezone offset minute.
* @internal
*/
const ISO_TIMEZONE = re `^(?:(?:${ISO_ZONEHOUR}(?::${ISO_ZONEMINUTE})?)|Z)$`;
/**
* Validate a ISO formatted date
* @group RegExp
* @category Constants
* @example
* ```typescript
* isoDate.test('2023-08-29T12:34:56Z'); // true
* isoDate.test('2023-08-29T12:34:56.789+02:00'); // true
* isoDate.test('2023-08-29T12:34'); // true
* isoDate.test('2023-08-29'); // false
* isoDate.test('not-a-date'); // false
* ```
*/
export const isoDate = re `^${ISO_YEAR}-${ISO_MONTH}-${ISO_DAY}T${ISO_HOUR}:${ISO_MINUTE}(?::${ISO_SECOND}(?:[.]${ISO_FRACTION})?)?${ISO_TIMEZONE}$`;
//#endregion
//#region numeric
/**
* Validate a valid number
* @group RegExp
* @category Constants
* @example
* ```typescript
* numeric.test('123'); // true
* numeric.test('-123.45'); // true
* numeric.test('1.23e4'); // true
* numeric.test('Infinity'); // true
* numeric.test('NaN'); // true
* numeric.test('abc'); // false
* numeric.test(''); // false
* ```
*/
export const numeric = /^((?:NaN|[+-]?(?:(?:\d+|\d*[.]\d+)(?:[Ee][+-]?\d+)?|[+-]?Infinity)))$/;
// TODO [>2.1]: enhance numeric regex to support hexadecimal and binary literals
// TODO [>2.1]: Add isNumeric function, but with a different name
//#endregion numeric
//#region domain
/**
* Regular expression to match a valid hostname label ending with a dot.
* @internal
*/
const DOMAIN_HOST = /^(?!-)[a-zA-Z0-9-]{1,63}(?<!-)[.]$/;
/**
* Regular expression to match a valid top-level domain (TLD).
* @internal
*/
const DOMAIN_TLD = /^[a-z]{2,}$/;
/**
* Regular expression for matching a domain name composed of a host and a top-level domain (TLD).
* @group RegExp
* @category Constants
* @example
* ```typescript
* domain.test('example.com'); // true
* domain.test('sub.example.co'); // true
* domain.test('invalid_domain'); // false
* ```
*/
export const domain = re `^${DOMAIN_HOST}+${DOMAIN_TLD}$`;
// TODO [>2.1]: enable punycode support
//#endregion
//#region email
// cspell:ignore EMAILGLYPH, EMAILQUOTE, EMAILESCAPE, EMAILADDRESS
/**
* Regular expression matching a single valid character for the local part of an email address.
* @internal
*/
const EMAIL_GLYPH = /[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]/;
/**
* Characters allowed within a quoted string in the local part of an email address.
* @internal
*/
const EMAIL_QUOTE = /[\u0001-\u0008\u000b\u000c\u000e-\u001f\u0021\u0023-\u005b\u005d-\u007f]/;
/**
* Matches a backslash followed by any ASCII character except line feed and carriage return.
* @internal
*/
const EMAIL_ESCAPE = /\\[\u0001-\u0009\u000b\u000c\u000e-\u007f]/;
/**
* Validate the local part of an email address.
* @internal
*/
const EMAIL_ADDRESS = re `(?:${EMAIL_GLYPH}+(?:[.]${EMAIL_GLYPH}+)*|"(?:${EMAIL_QUOTE}|${EMAIL_ESCAPE})*")`;
/**
* validate an valid email address
* @group RegExp
* @category Constants
* @example
* ```typescript
* email.test('user@example.com'); // true
* email.test('user@sub.example.co'); // true
* email.test('invalid@domain'); // false
* email.test('not-an-email'); // false
* ```
*/
export const email = re `${EMAIL_ADDRESS}@(?:\[${ipV4}\]|${domain})$`;
//#endregion
//#region trimEquivalent
/**
* Regular expression that matches any whitespace character, including standard spaces,
* non-breaking spaces (`\u00A0`), and zero-width no-break spaces (`\uFEFF`).
* Useful for trimming or identifying whitespace-equivalent characters in strings.
* @group RegExp
* @category Constants
*/
export const trimEquivalent = /[\s\uFEFF\u00A0]/u;
//#endregion
//#region ANSI Escape Sequences
// Valid string terminator sequences are BEL, ESC\, and 0x9c (String Terminator))
/**
* Matches ANSI terminator: Bell (BEL), String Terminator (ST), ESC\\
* @internal
*/
const ANSI_ST = re `\u0007|\u001b\u005c|\u009c`;
/**
* OSC sequences only: ESC ] ... ST (non-greedy until the first ST)
* @internal
*/
const ANSI_OSC = re `\u001B\][\s\S]*?${ANSI_ST}`;
/**
* CSI and related: ESC/C1, optional intermediates, optional params (supports ; and :) then final byte
* @internal
*/
const ANSI_CSI = re `[\u001B\u009B][\[\]()#;?]*(?:\d{1,4}(?:[;:]\d{0,4})*)?[\dA-PR-TZcf-nq-uy=><~]`;
/**
* Regular expression that matches ANSI escape sequences, including OSC (Operating System Command)
* and CSI (Control Sequence Introducer) patterns. Useful for stripping or identifying ANSI codes
* in strings, such as those used for terminal text formatting.
*
* @see https://en.wikipedia.org/wiki/ANSI_escape_code
* @group RegExp
* @category Constants
*/
export const ansiEscapes = re('g') `${ANSI_OSC}|${ANSI_CSI}`;
//#endregion
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVnZXhwLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3JlZ2V4cC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSx5Q0FBeUM7QUFDekMsMkNBQTJDO0FBQzNDLHFDQUFxQztBQUNyQyxPQUFPLEVBQUUsRUFBRSxFQUFFLE1BQU0sU0FBUyxDQUFDO0FBRTdCLGNBQWM7QUFDZDs7O0dBR0c7QUFDSCxNQUFNLFFBQVEsR0FBRyxrREFBa0QsQ0FBQztBQUVwRTs7Ozs7Ozs7Ozs7R0FXRztBQUNILE1BQU0sQ0FBQyxNQUFNLElBQUksR0FBRyxFQUFFLENBQUEsSUFBSSxRQUFRLEtBQUssUUFBUSxLQUFLLFFBQVEsS0FBSyxRQUFRLEdBQUcsQ0FBQztBQUM3RSxZQUFZO0FBQ1osbUJBQW1CO0FBQ25COzs7R0FHRztBQUNILE1BQU0sVUFBVSxHQUFHLEVBQUUsQ0FBQSxXQUFXLFFBQVEsRUFBRSxDQUFDO0FBRTNDOzs7R0FHRztBQUNILE1BQU0sV0FBVyxHQUFHLG1DQUFtQyxDQUFDO0FBRXhEOzs7R0FHRztBQUNILE1BQU0sV0FBVyxHQUFHLGFBQWEsQ0FBQztBQUVsQzs7Ozs7Ozs7Ozs7O0dBWUc7QUFDSCxNQUFNLENBQUMsTUFBTSxTQUFTLEdBQUcsRUFBRSxDQUFBLE9BQU8sVUFBVSxJQUFJLFdBQVcsSUFBSSxXQUFXLE9BQU8sUUFBUSxNQUFNLFFBQVEsR0FBRyxDQUFDO0FBQzNHLFlBQVk7QUFDWixpQkFBaUI7QUFDakIsbUVBQW1FO0FBQ25FOzs7R0FHRztBQUNILE1BQU0sUUFBUSxHQUFHLFlBQVksQ0FBQztBQUU5Qjs7O0dBR0c7QUFDSCxNQUFNLFNBQVMsR0FBRyxxQkFBcUIsQ0FBQztBQUV4Qzs7O0dBR0c7QUFDSCxNQUFNLE9BQU8sR0FBRyxnQ0FBZ0MsQ0FBQztBQUVqRDs7O0dBR0c7QUFDSCxNQUFNLFFBQVEsR0FBRyx5QkFBeUIsQ0FBQztBQUUzQzs7O0dBR0c7QUFDSCxNQUFNLFVBQVUsR0FBRyxjQUFjLENBQUM7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