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
30 changes: 15 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,21 +66,21 @@ Validate is a standard Deno module for validating string.
* [x] isMultibyte
* [x] isNumeric
* [x] isOctal
* [ ] isPassportNumber
* [ ] isPort
* [ ] isPostalCode
* [ ] isRFC3339
* [ ] isRgbColor
* [ ] isSemVer
* [ ] isSlug
* [ ] isSurrogatePair
* [ ] isSvg
* [ ] isTaxID
* [ ] isURL
* [ ] isUUID
* [ ] isUppercase
* [ ] isVariableWidth
* [ ] isWhitelisted
* [x] isPassportNumber
* [x] isPort
* [x] isPostalCode
* [x] isRFC3339
* [x] isRgbColor
* [x] isSemVer
* [x] isSlug
* [x] isSurrogatePair
* [x] isSvg
* [x] isTaxID
* [x] isUppercase
* [x] isURL
* [x] isUUID
* [x] isVariableWidth
* [x] isWhitelisted

## 🔧 How to use

Expand Down
115 changes: 115 additions & 0 deletions src/libs/isPassportNumber.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
// @ts-ignore allowing typedoc to build
import assertString from '../utils/assertString.ts';

type CountryCode =
| 'AM'
| 'AR'
| 'AT'
| 'AU'
| 'BE'
| 'BG'
| 'CA'
| 'CH'
| 'CN'
| 'CY'
| 'CZ'
| 'DE'
| 'DK'
| 'DZ'
| 'EE'
| 'ES'
| 'FI'
| 'FR'
| 'GB'
| 'GR'
| 'HR'
| 'HU'
| 'IE'
| 'IN'
| 'IS'
| 'IT'
| 'JP'
| 'KR'
| 'LT'
| 'LU'
| 'LV'
| 'MT'
| 'NL'
| 'PO'
| 'PT'
| 'RO'
| 'SE'
| 'SL'
| 'SK'
| 'TR'
| 'UA'
| 'US';

/**
* Reference:
* https://en.wikipedia.org/ -- Wikipedia
* https://docs.microsoft.com/en-us/microsoft-365/compliance/eu-passport-number -- EU Passport Number
* https://countrycode.org/ -- Country Codes
*/
const passportRegexByCountryCode = {
AM: /^[A-Z]{2}\d{7}$/, // ARMENIA
AR: /^[A-Z]{3}\d{6}$/, // ARGENTINA
AT: /^[A-Z]\d{7}$/, // AUSTRIA
AU: /^[A-Z]\d{7}$/, // AUSTRALIA
BE: /^[A-Z]{2}\d{6}$/, // BELGIUM
BG: /^\d{9}$/, // BULGARIA
CA: /^[A-Z]{2}\d{6}$/, // CANADA
CH: /^[A-Z]\d{7}$/, // SWITZERLAND
CN: /^[GE]\d{8}$/, // CHINA [G=Ordinary, E=Electronic] followed by 8-digits
CY: /^[A-Z](\d{6}|\d{8})$/, // CYPRUS
CZ: /^\d{8}$/, // CZECH REPUBLIC
DE: /^[CFGHJKLMNPRTVWXYZ0-9]{9}$/, // GERMANY
DK: /^\d{9}$/, // DENMARK
DZ: /^\d{9}$/, // ALGERIA
EE: /^([A-Z]\d{7}|[A-Z]{2}\d{7})$/, // ESTONIA (K followed by 7-digits), e-passports have 2 UPPERCASE followed by 7 digits
ES: /^[A-Z0-9]{2}([A-Z0-9]?)\d{6}$/, // SPAIN
FI: /^[A-Z]{2}\d{7}$/, // FINLAND
FR: /^\d{2}[A-Z]{2}\d{5}$/, // FRANCE
GB: /^\d{9}$/, // UNITED KINGDOM
GR: /^[A-Z]{2}\d{7}$/, // GREECE
HR: /^\d{9}$/, // CROATIA
HU: /^[A-Z]{2}(\d{6}|\d{7})$/, // HUNGARY
IE: /^[A-Z0-9]{2}\d{7}$/, // IRELAND
IN: /^[A-Z]{1}-?\d{7}$/, // INDIA
IS: /^(A)\d{7}$/, // ICELAND
IT: /^[A-Z0-9]{2}\d{7}$/, // ITALY
JP: /^[A-Z]{2}\d{7}$/, // JAPAN
KR: /^[MS]\d{8}$/, // SOUTH KOREA, REPUBLIC OF KOREA, [S=PS Passports, M=PM Passports]
LT: /^[A-Z0-9]{8}$/, // LITHUANIA
LU: /^[A-Z0-9]{8}$/, // LUXEMBURG
LV: /^[A-Z0-9]{2}\d{7}$/, // LATVIA
MT: /^\d{7}$/, // MALTA
NL: /^[A-Z]{2}[A-Z0-9]{6}\d$/, // NETHERLANDS
PO: /^[A-Z]{2}\d{7}$/, // POLAND
PT: /^[A-Z]\d{6}$/, // PORTUGAL
RO: /^\d{8,9}$/, // ROMANIA
SE: /^\d{8}$/, // SWEDEN
SL: /^(P)[A-Z]\d{7}$/, // SLOVANIA
SK: /^[0-9A-Z]\d{7}$/, // SLOVAKIA
TR: /^[A-Z]\d{8}$/, // TURKEY
UA: /^[A-Z]{2}\d{6}$/, // UKRAINE
US: /^\d{9}$/, // UNITED STATES
};
/**
* Check if str is a valid passport number
* relative to provided ISO Country Code.
*
* @param {string} str
* @param {string} countryCode
* @return {boolean}
*/
export const isPassportNumber = (str: string, countryCode: CountryCode) => {
assertString(str);
/** Remove All Whitespaces, Convert to UPPERCASE */
const normalizedStr = str.replace(/\s/g, '').toUpperCase();

return (
countryCode.toUpperCase() in passportRegexByCountryCode &&
passportRegexByCountryCode[countryCode].test(normalizedStr)
);
};
6 changes: 6 additions & 0 deletions src/libs/isPort.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// @ts-ignore allowing typedoc to build
import { isInt } from './isInt.ts';

export const isPort = (str: string) => {
return isInt(str, { min: 0, max: 65535 });
};
140 changes: 140 additions & 0 deletions src/libs/isPostalCode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
// @ts-ignore allowing typedoc to build
import assertString from '../utils/assertString.ts';

// common patterns
const threeDigit = /^\d{3}$/;
const fourDigit = /^\d{4}$/;
const fiveDigit = /^\d{5}$/;
const sixDigit = /^\d{6}$/;

type PostalCode =
| 'AD'
| 'AT'
| 'AU'
| 'BE'
| 'BG'
| 'BR'
| 'CA'
| 'CH'
| 'CZ'
| 'DE'
| 'DK'
| 'DZ'
| 'EE'
| 'ES'
| 'FI'
| 'FR'
| 'GB'
| 'GR'
| 'HR'
| 'HU'
| 'ID'
| 'IE'
| 'IL'
| 'IN'
| 'IS'
| 'IT'
| 'JP'
| 'KE'
| 'LI'
| 'LT'
| 'LU'
| 'LV'
| 'MX'
| 'MT'
| 'NL'
| 'NO'
| 'NP'
| 'NZ'
| 'PL'
| 'PR'
| 'PT'
| 'RO'
| 'RU'
| 'SA'
| 'SE'
| 'SI'
| 'SK'
| 'TN'
| 'TW'
| 'UA'
| 'US'
| 'ZA'
| 'ZM'
| 'any';

const patterns = {
AD: /^AD\d{3}$/,
AT: fourDigit,
AU: fourDigit,
BE: fourDigit,
BG: fourDigit,
BR: /^\d{5}-\d{3}$/,
CA: /^[ABCEGHJKLMNPRSTVXY]\d[ABCEGHJ-NPRSTV-Z][\s\-]?\d[ABCEGHJ-NPRSTV-Z]\d$/i,
CH: fourDigit,
CZ: /^\d{3}\s?\d{2}$/,
DE: fiveDigit,
DK: fourDigit,
DZ: fiveDigit,
EE: fiveDigit,
ES: /^(5[0-2]{1}|[0-4]{1}\d{1})\d{3}$/,
FI: fiveDigit,
FR: /^\d{2}\s?\d{3}$/,
GB: /^(gir\s?0aa|[a-z]{1,2}\d[\da-z]?\s?(\d[a-z]{2})?)$/i,
GR: /^\d{3}\s?\d{2}$/,
HR: /^([1-5]\d{4}$)/,
HU: fourDigit,
ID: fiveDigit,
IE: /^(?!.*(?:o))[A-z]\d[\dw]\s\w{4}$/i,
IL: /^(\d{5}|\d{7})$/,
IN: /^((?!10|29|35|54|55|65|66|86|87|88|89)[1-9][0-9]{5})$/,
IS: threeDigit,
IT: fiveDigit,
JP: /^\d{3}\-\d{4}$/,
KE: fiveDigit,
LI: /^(948[5-9]|949[0-7])$/,
LT: /^LT\-\d{5}$/,
LU: fourDigit,
LV: /^LV\-\d{4}$/,
MX: fiveDigit,
MT: /^[A-Za-z]{3}\s{0,1}\d{4}$/,
NL: /^\d{4}\s?[a-z]{2}$/i,
NO: fourDigit,
NP: /^(10|21|22|32|33|34|44|45|56|57)\d{3}$|^(977)$/i,
NZ: fourDigit,
PL: /^\d{2}\-\d{3}$/,
PR: /^00[679]\d{2}([ -]\d{4})?$/,
PT: /^\d{4}\-\d{3}?$/,
RO: sixDigit,
RU: sixDigit,
SA: fiveDigit,
SE: /^[1-9]\d{2}\s?\d{2}$/,
SI: fourDigit,
SK: /^\d{3}\s?\d{2}$/,
TN: fourDigit,
TW: /^\d{3}(\d{2})?$/,
UA: fiveDigit,
US: /^\d{5}(-\d{4})?$/,
ZA: fourDigit,
ZM: fiveDigit,
};

export const isPostalCode = (str: string, locale: PostalCode) => {
assertString(str);
if (locale in patterns) {
return (patterns as any)[locale].test(str);
} else if (locale === 'any') {
for (const key in patterns) {
// https://github.com/gotwarlost/istanbul/blob/master/ignoring-code-for-coverage.md#ignoring-code-for-coverage-purposes
// istanbul ignore else
if (patterns.hasOwnProperty(key)) {
const pattern = (patterns as any)[key];
if (pattern.test(str)) {
return true;
}
}
}
return false;
}
throw new Error(`Invalid locale '${locale}'`);
};
26 changes: 26 additions & 0 deletions src/libs/isRFC3339.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// @ts-ignore allowing typedoc to build
import assertString from '../utils/assertString.ts';

/* Based on https://tools.ietf.org/html/rfc3339#section-5.6 */
const dateFullYear = /[0-9]{4}/;
const dateMonth = /(0[1-9]|1[0-2])/;
const dateMDay = /([12]\d|0[1-9]|3[01])/;
const timeHour = /([01][0-9]|2[0-3])/;
const timeMinute = /[0-5][0-9]/;
const timeSecond = /([0-5][0-9]|60)/;
const timeSecFrac = /(\.[0-9]+)?/;
const timeNumOffset = new RegExp(`[-+]${timeHour.source}:${timeMinute.source}`);
const timeOffset = new RegExp(`([zZ]|${timeNumOffset.source})`);
const partialTime = new RegExp(
`${timeHour.source}:${timeMinute.source}:${timeSecond.source}${timeSecFrac.source}`
);
const fullDate = new RegExp(
`${dateFullYear.source}-${dateMonth.source}-${dateMDay.source}`
);
const fullTime = new RegExp(`${partialTime.source}${timeOffset.source}`);
const rfc3339 = new RegExp(`${fullDate.source}[ tT]${fullTime.source}`);

export const isRFC3339 = (str: string) => {
assertString(str);
return rfc3339.test(str);
};
22 changes: 22 additions & 0 deletions src/libs/isRgbColor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// @ts-ignore allowing typedoc to build
import assertString from '../utils/assertString.ts';

const rgbColor = /^rgb\((([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]),){2}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\)$/;
const rgbaColor = /^rgba\((([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]),){3}(0?\.\d|1(\.0)?|0(\.0)?)\)$/;
const rgbColorPercent = /^rgb\((([0-9]%|[1-9][0-9]%|100%),){2}([0-9]%|[1-9][0-9]%|100%)\)/;
const rgbaColorPercent = /^rgba\((([0-9]%|[1-9][0-9]%|100%),){3}(0?\.\d|1(\.0)?|0(\.0)?)\)/;

export const isRgbColor = (str: string, includePercentValues = true) => {
assertString(str);

if (!includePercentValues) {
return rgbColor.test(str) || rgbaColor.test(str);
}

return (
rgbColor.test(str) ||
rgbaColor.test(str) ||
rgbColorPercent.test(str) ||
rgbaColorPercent.test(str)
);
};
22 changes: 22 additions & 0 deletions src/libs/isSemVer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// @ts-ignore allowing typedoc to build
import multilineRegexp from '../utils/multilineRegex.ts';
// @ts-ignore allowing typedoc to build
import assertString from '../utils/assertString.ts';

/**
* Regular Expression to match
* semantic versioning (SemVer)
* built from multi-line, multi-parts regexp
* Reference: https://semver.org/
*/
const semanticVersioningRegex = multilineRegexp([
'^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)',
'(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))',
'?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$',
]);

export const isSemVer = (str: string) => {
assertString(str);

return semanticVersioningRegex.test(str);
};
9 changes: 9 additions & 0 deletions src/libs/isSlug.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// @ts-ignore allowing typedoc to build
import assertString from '../utils/assertString.ts';

const charsetRegex = /^[^\s-_](?!.*?[-_]{2,})([a-z0-9-\\]{1,})[^\s]*[^-_\s]$/;

export const isSlug = (str: string) => {
assertString(str);
return charsetRegex.test(str);
};
9 changes: 9 additions & 0 deletions src/libs/isSurrogatePair.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// @ts-ignore allowing typedoc to build
import assertString from '../utils/assertString.ts';

const surrogatePair = /[\uD800-\uDBFF][\uDC00-\uDFFF]/;

export const isSurrogatePair = (str: string) => {
assertString(str);
return surrogatePair.test(str);
};
Loading