Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added isFreightContainerID validator #2144

Merged
merged 7 commits into from
Feb 8, 2023
Merged
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
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ Validator | Description
**isEthereumAddress(str)** | check if the string is an [Ethereum][Ethereum] address. Does not validate address checksums.
**isFloat(str [, options])** | check if the string is a float.<br/><br/>`options` is an object which can contain the keys `min`, `max`, `gt`, and/or `lt` to validate the float is within boundaries (e.g. `{ min: 7.22, max: 9.55 }`) it also has `locale` as an option.<br/><br/>`min` and `max` are equivalent to 'greater or equal' and 'less or equal', respectively while `gt` and `lt` are their strict counterparts.<br/><br/>`locale` determines the decimal separator and is one of `['ar', 'ar-AE', 'ar-BH', 'ar-DZ', 'ar-EG', 'ar-IQ', 'ar-JO', 'ar-KW', 'ar-LB', 'ar-LY', 'ar-MA', 'ar-QA', 'ar-QM', 'ar-SA', 'ar-SD', 'ar-SY', 'ar-TN', 'ar-YE', 'bg-BG', 'cs-CZ', 'da-DK', 'de-DE', 'en-AU', 'en-GB', 'en-HK', 'en-IN', 'en-NZ', 'en-US', 'en-ZA', 'en-ZM', 'es-ES', 'fr-CA', 'fr-FR', 'hu-HU', 'it-IT', 'nb-NO', 'nl-NL', 'nn-NO', 'pl-PL', 'pt-BR', 'pt-PT', 'ru-RU', 'sl-SI', 'sr-RS', 'sr-RS@latin', 'sv-SE', 'tr-TR', 'uk-UA']`. Locale list is `validator.isFloatLocales`.
**isFQDN(str [, options])** | check if the string is a fully qualified domain name (e.g. domain.com).<br/><br/>`options` is an object which defaults to `{ require_tld: true, allow_underscores: false, allow_trailing_dot: false, allow_numeric_tld: false, allow_wildcard: false, ignore_max_length: false }`. If `allow_wildcard` is set to true, the validator will allow domain starting with `*.` (e.g. `*.example.com` or `*.shop.example.com`).
**isFreightContainerID(str)** | alias for `isISO6346`, check if the string is a valid [ISO 6346](https://en.wikipedia.org/wiki/ISO_6346) shipping container identification.
**isFullWidth(str)** | check if the string contains any full-width chars.
**isHalfWidth(str)** | check if the string contains any half-width chars.
**isHash(str, algorithm)** | check if the string is a hash of type algorithm.<br/><br/>Algorithm is one of `['crc32', 'crc32b', 'md4', 'md5', 'ripemd128', 'ripemd160', 'sha1', 'sha256', 'sha384', 'sha512', 'tiger128', 'tiger160', 'tiger192']`.
Expand All @@ -129,6 +130,7 @@ Validator | Description
**isIPRange(str [, version])** | check if the string is an IP Range (version 4 or 6).
**isISBN(str [, options])** | check if the string is an [ISBN][ISBN].<br/><br/>`options` is an object that has no default.<br/>**Options:**<br/>`version`: ISBN version to compare to. Accepted values are '10' and '13'. If none provided, both will be tested.
**isISIN(str)** | check if the string is an [ISIN][ISIN] (stock/security identifier).
**isISO6346(str)** | check if the string is a valid [ISO 6346](https://en.wikipedia.org/wiki/ISO_6346) shipping container identification.
**isISO6391(str)** | check if the string is a valid [ISO 639-1][ISO 639-1] language code.
**isISO8601(str [, options])** | check if the string is a valid [ISO 8601][ISO 8601] date. <br/>`options` is an object which defaults to `{ strict: false, strictSeparator: false }`. If `strict` is true, date strings with invalid dates like `2009-02-29` will be invalid. If `strictSeparator` is true, date strings with date and time separated by anything other than a T will be invalid.
**isISO31661Alpha2(str)** | check if the string is a valid [ISO 3166-1 alpha-2][ISO 3166-1 alpha-2] officially assigned country code.
Expand Down
3 changes: 3 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ import isCurrency from './lib/isCurrency';

import isBtcAddress from './lib/isBtcAddress';

import { isISO6346, isFreightContainerID } from './lib/isISO6346';
import isISO6391 from './lib/isISO6391';
import isISO8601 from './lib/isISO8601';
import isRFC3339 from './lib/isRFC3339';
Expand Down Expand Up @@ -199,6 +200,8 @@ const validator = {
isEthereumAddress,
isCurrency,
isBtcAddress,
isISO6346,
isFreightContainerID,
isISO6391,
isISO8601,
isRFC3339,
Expand Down
37 changes: 37 additions & 0 deletions src/lib/isISO6346.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import assertString from './util/assertString';

// https://en.wikipedia.org/wiki/ISO_6346
// according to ISO6346 standard, checksum digit is mandatory for freight container but recommended
// for other container types (J and Z)
const isISO6346Str = /^[A-Z]{3}(U[0-9]{7})|([J,Z][0-9]{6,7})$/;
const isDigit = /^[0-9]$/;

export function isISO6346(str) {
assertString(str);

str = str.toUpperCase();

if (!isISO6346Str.test(str)) return false;

if (str.length === 11) {
let sum = 0;
for (let i = 0; i < str.length - 1; i++) {
if (!isDigit.test(str[i])) {
let convertedCode;
const letterCode = str.charCodeAt(i) - 55;
if (letterCode < 11) convertedCode = letterCode;
else if (letterCode >= 11 && letterCode <= 20) convertedCode = 12 + (letterCode % 11);
else if (letterCode >= 21 && letterCode <= 30) convertedCode = 23 + (letterCode % 21);
else convertedCode = 34 + (letterCode % 31);
sum += convertedCode * (2 ** i);
} else sum += str[i] * (2 ** i);
}

const checkSumDigit = sum % 11;
return Number(str[str.length - 1]) === checkSumDigit;
}

return true;
}

export const isFreightContainerID = isISO6346;
52 changes: 52 additions & 0 deletions test/validators.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11946,6 +11946,58 @@ describe('Validators', () => {
});
});


it('should validate ISO6346 shipping containerID', () => {
test({
validator: 'isISO6346',
valid: [
'HLXU2008419',
'TGHU7599330',
'ECMU4657496',
'MEDU6246078',
'YMLU2809976',
'MRKU0046221',
'EMCU3811879',
'OOLU8643084',
'HJCU1922713',
'QJRZ123456',
],
invalid: [
'OOLU1922713',
'HJCU1922413',
'FCUI985619',
'ECMJ4657496',
'TBJA7176445',
'AFFU5962593',
],
});
});
it('should validate ISO6346 shipping containerID', () => {
test({
validator: 'isFreightContainerID',
valid: [
'HLXU2008419',
'TGHU7599330',
'ECMU4657496',
'MEDU6246078',
'YMLU2809976',
'MRKU0046221',
'EMCU3811879',
'OOLU8643084',
'HJCU1922713',
'QJRZ123456',
],
invalid: [
'OOLU1922713',
'HJCU1922413',
'FCUI985619',
'ECMJ4657496',
'TBJA7176445',
'AFFU5962593',
],
});
});

// EU-UK valid numbers sourced from https://ec.europa.eu/taxation_customs/tin/specs/FS-TIN%20Algorithms-Public.docx or constructed by @tplessas.
it('should validate taxID', () => {
test({
Expand Down