stringzy 3.0.0 → 4.0.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/.prettierignore +4 -0
- package/.prettierrc +7 -0
- package/CONTRIBUTING.md +41 -29
- package/README.md +397 -160
- package/dist/analyzing/characterCount.d.ts +19 -0
- package/dist/analyzing/characterCount.js +21 -2
- package/dist/analyzing/characterFrequency.d.ts +19 -0
- package/dist/analyzing/characterFrequency.js +22 -3
- package/dist/analyzing/complexity.d.ts +33 -0
- package/dist/analyzing/complexity.js +35 -2
- package/dist/analyzing/index.d.ts +18 -12
- package/dist/analyzing/index.js +10 -2
- package/dist/analyzing/patternCount.d.ts +10 -0
- package/dist/analyzing/patternCount.js +52 -0
- package/dist/analyzing/stringSimilarity.js +1 -1
- package/dist/analyzing/vowelConsonantCount.d.ts +22 -0
- package/dist/analyzing/vowelConsonantCount.js +38 -0
- package/dist/analyzing/wordCount.d.ts +22 -0
- package/dist/analyzing/wordCount.js +24 -2
- package/dist/formatting/capitalize.d.ts +21 -0
- package/dist/formatting/capitalize.js +22 -1
- package/dist/formatting/index.d.ts +6 -6
- package/dist/formatting/number.d.ts +23 -0
- package/dist/formatting/number.js +24 -1
- package/dist/formatting/phone.d.ts +23 -0
- package/dist/formatting/phone.js +23 -0
- package/dist/index.d.ts +9 -4
- package/dist/tests/analyzing/patternCount.test.d.ts +1 -0
- package/dist/tests/analyzing/patternCount.test.js +34 -0
- package/dist/tests/analyzing/readingDuration.test.js +12 -12
- package/dist/tests/analyzing/vowelConsonantCount.test.d.ts +1 -0
- package/dist/tests/analyzing/vowelConsonantCount.test.js +25 -0
- package/dist/tests/transformations/numberToText.test.d.ts +1 -0
- package/dist/tests/transformations/numberToText.test.js +60 -0
- package/dist/tests/transformations/splitChunks.test.d.ts +1 -0
- package/dist/tests/transformations/splitChunks.test.js +31 -0
- package/dist/tests/validations/isCoordinates.test.d.ts +1 -0
- package/dist/tests/validations/isCoordinates.test.js +18 -0
- package/dist/tests/validations/isEmail.smtpUTF8.test.d.ts +1 -0
- package/dist/tests/validations/isEmail.smtpUTF8.test.js +16 -0
- package/dist/tests/validations/isEmail.test.js +56 -6
- package/dist/tests/validations/isHexColor.test.js +21 -21
- package/dist/tests/validations/isPalindrome.test.d.ts +1 -0
- package/dist/tests/validations/isPalindrome.test.js +39 -0
- package/dist/tests/validations/isTypeOf.test.d.ts +1 -0
- package/dist/tests/validations/isTypeOf.test.js +28 -0
- package/dist/transformations/camelCase.d.ts +24 -0
- package/dist/transformations/camelCase.js +24 -0
- package/dist/transformations/capitalizeWords.d.ts +21 -0
- package/dist/transformations/capitalizeWords.js +23 -2
- package/dist/transformations/constantCase.d.ts +26 -0
- package/dist/transformations/constantCase.js +26 -0
- package/dist/transformations/escapeHTML.d.ts +23 -0
- package/dist/transformations/escapeHTML.js +24 -2
- package/dist/transformations/index.d.ts +3 -0
- package/dist/transformations/index.js +6 -2
- package/dist/transformations/initials.d.ts +27 -0
- package/dist/transformations/initials.js +38 -8
- package/dist/transformations/kebabCase.d.ts +26 -0
- package/dist/transformations/kebabCase.js +26 -0
- package/dist/transformations/maskSegment.js +4 -6
- package/dist/transformations/numberToText/helpers.d.ts +10 -0
- package/dist/transformations/numberToText/helpers.js +31 -0
- package/dist/transformations/numberToText/implementation_EN.d.ts +10 -0
- package/dist/transformations/numberToText/implementation_EN.js +45 -0
- package/dist/transformations/numberToText/implementation_PL.d.ts +10 -0
- package/dist/transformations/numberToText/implementation_PL.js +79 -0
- package/dist/transformations/numberToText/main.d.ts +19 -0
- package/dist/transformations/numberToText/main.js +67 -0
- package/dist/transformations/numberToText/types.d.ts +3 -0
- package/dist/transformations/numberToText/types.js +82 -0
- package/dist/transformations/pascalCase.d.ts +25 -0
- package/dist/transformations/pascalCase.js +25 -0
- package/dist/transformations/removeDuplicates.d.ts +21 -0
- package/dist/transformations/removeDuplicates.js +25 -4
- package/dist/transformations/removeSpecialChars.d.ts +22 -0
- package/dist/transformations/removeSpecialChars.js +26 -4
- package/dist/transformations/removeWords.d.ts +27 -0
- package/dist/transformations/removeWords.js +31 -4
- package/dist/transformations/snakeCase.d.ts +26 -0
- package/dist/transformations/snakeCase.js +26 -0
- package/dist/transformations/splitChunks.d.ts +8 -0
- package/dist/transformations/splitChunks.js +24 -0
- package/dist/transformations/titleCase.d.ts +25 -0
- package/dist/transformations/titleCase.js +25 -0
- package/dist/transformations/toSlug.d.ts +24 -0
- package/dist/transformations/toSlug.js +28 -4
- package/dist/transformations/truncateText.d.ts +25 -0
- package/dist/transformations/truncateText.js +28 -3
- package/dist/validations/index.d.ts +6 -0
- package/dist/validations/index.js +10 -2
- package/dist/validations/isCoordinates.d.ts +8 -0
- package/dist/validations/isCoordinates.js +19 -0
- package/dist/validations/isDate.d.ts +1 -1
- package/dist/validations/isDate.js +6 -8
- package/dist/validations/isEmail.d.ts +13 -1
- package/dist/validations/isEmail.js +176 -3
- package/dist/validations/isEmpty.d.ts +9 -0
- package/dist/validations/isEmpty.js +9 -0
- package/dist/validations/isHexColor.js +1 -1
- package/dist/validations/isIPv4.d.ts +21 -0
- package/dist/validations/isIPv4.js +22 -2
- package/dist/validations/isPalindrome.d.ts +10 -0
- package/dist/validations/isPalindrome.js +21 -0
- package/dist/validations/isSlug.d.ts +27 -0
- package/dist/validations/isSlug.js +27 -0
- package/dist/validations/isTypeOf.d.ts +9 -0
- package/dist/validations/isTypeOf.js +30 -0
- package/dist/validations/isURL.d.ts +21 -0
- package/dist/validations/isURL.js +21 -0
- package/package.json +5 -3
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export { isCoordinates } from './isCoordinates';
|
|
1
2
|
export { isDate } from './isDate';
|
|
2
3
|
export { isEmail } from './isEmail';
|
|
3
4
|
export { isEmpty } from './isEmpty';
|
|
@@ -5,6 +6,8 @@ export { isSlug } from './isSlug';
|
|
|
5
6
|
export { isURL } from './isURL';
|
|
6
7
|
export { isIPv4 } from './isIPv4';
|
|
7
8
|
export { isHexColor } from './isHexColor';
|
|
9
|
+
export { isPalindrome } from './isPalindrome';
|
|
10
|
+
import { isCoordinates } from './isCoordinates';
|
|
8
11
|
import { isDate } from './isDate';
|
|
9
12
|
import { isEmail } from './isEmail';
|
|
10
13
|
import { isEmpty } from './isEmpty';
|
|
@@ -12,7 +15,9 @@ import { isSlug } from './isSlug';
|
|
|
12
15
|
import { isURL } from './isURL';
|
|
13
16
|
import { isIPv4 } from './isIPv4';
|
|
14
17
|
import { isHexColor } from './isHexColor';
|
|
18
|
+
import { isPalindrome } from './isPalindrome';
|
|
15
19
|
export declare const validations: {
|
|
20
|
+
isCoordinates: typeof isCoordinates;
|
|
16
21
|
isDate: typeof isDate;
|
|
17
22
|
isEmail: typeof isEmail;
|
|
18
23
|
isEmpty: typeof isEmpty;
|
|
@@ -20,4 +25,5 @@ export declare const validations: {
|
|
|
20
25
|
isURL: typeof isURL;
|
|
21
26
|
isIPv4: typeof isIPv4;
|
|
22
27
|
isHexColor: typeof isHexColor;
|
|
28
|
+
isPalindrome: typeof isPalindrome;
|
|
23
29
|
};
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.validations = exports.isHexColor = exports.isIPv4 = exports.isURL = exports.isSlug = exports.isEmpty = exports.isEmail = exports.isDate = void 0;
|
|
3
|
+
exports.validations = exports.isPalindrome = exports.isHexColor = exports.isIPv4 = exports.isURL = exports.isSlug = exports.isEmpty = exports.isEmail = exports.isDate = exports.isCoordinates = void 0;
|
|
4
|
+
var isCoordinates_1 = require("./isCoordinates");
|
|
5
|
+
Object.defineProperty(exports, "isCoordinates", { enumerable: true, get: function () { return isCoordinates_1.isCoordinates; } });
|
|
4
6
|
var isDate_1 = require("./isDate");
|
|
5
7
|
Object.defineProperty(exports, "isDate", { enumerable: true, get: function () { return isDate_1.isDate; } });
|
|
6
8
|
var isEmail_1 = require("./isEmail");
|
|
@@ -15,6 +17,9 @@ var isIPv4_1 = require("./isIPv4");
|
|
|
15
17
|
Object.defineProperty(exports, "isIPv4", { enumerable: true, get: function () { return isIPv4_1.isIPv4; } });
|
|
16
18
|
var isHexColor_1 = require("./isHexColor");
|
|
17
19
|
Object.defineProperty(exports, "isHexColor", { enumerable: true, get: function () { return isHexColor_1.isHexColor; } });
|
|
20
|
+
var isPalindrome_1 = require("./isPalindrome");
|
|
21
|
+
Object.defineProperty(exports, "isPalindrome", { enumerable: true, get: function () { return isPalindrome_1.isPalindrome; } });
|
|
22
|
+
const isCoordinates_2 = require("./isCoordinates");
|
|
18
23
|
const isDate_2 = require("./isDate");
|
|
19
24
|
const isEmail_2 = require("./isEmail");
|
|
20
25
|
const isEmpty_2 = require("./isEmpty");
|
|
@@ -22,12 +27,15 @@ const isSlug_2 = require("./isSlug");
|
|
|
22
27
|
const isURL_2 = require("./isURL");
|
|
23
28
|
const isIPv4_2 = require("./isIPv4");
|
|
24
29
|
const isHexColor_2 = require("./isHexColor");
|
|
30
|
+
const isPalindrome_2 = require("./isPalindrome");
|
|
25
31
|
exports.validations = {
|
|
32
|
+
isCoordinates: isCoordinates_2.isCoordinates,
|
|
26
33
|
isDate: isDate_2.isDate,
|
|
27
34
|
isEmail: isEmail_2.isEmail,
|
|
28
35
|
isEmpty: isEmpty_2.isEmpty,
|
|
29
36
|
isSlug: isSlug_2.isSlug,
|
|
30
37
|
isURL: isURL_2.isURL,
|
|
31
38
|
isIPv4: isIPv4_2.isIPv4,
|
|
32
|
-
isHexColor: isHexColor_2.isHexColor
|
|
39
|
+
isHexColor: isHexColor_2.isHexColor,
|
|
40
|
+
isPalindrome: isPalindrome_2.isPalindrome
|
|
33
41
|
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks if given latitude and longitude are valid coordinates.
|
|
3
|
+
*
|
|
4
|
+
* @param {number} lat - The latitude to check.
|
|
5
|
+
* @param {number} long - The longitude to check.
|
|
6
|
+
* @returns {boolean} True if both latitude and longitude are valid, false otherwise.
|
|
7
|
+
*/
|
|
8
|
+
export declare function isCoordinates(lat: number, long: number): boolean;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Checks if given latitude and longitude are valid coordinates.
|
|
4
|
+
*
|
|
5
|
+
* @param {number} lat - The latitude to check.
|
|
6
|
+
* @param {number} long - The longitude to check.
|
|
7
|
+
* @returns {boolean} True if both latitude and longitude are valid, false otherwise.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.isCoordinates = isCoordinates;
|
|
11
|
+
function isCoordinates(lat, long) {
|
|
12
|
+
return isLatitude(lat) && isLongitude(long);
|
|
13
|
+
}
|
|
14
|
+
function isLatitude(num) {
|
|
15
|
+
return Number.isFinite(num) && Math.abs(num) <= 90;
|
|
16
|
+
}
|
|
17
|
+
function isLongitude(num) {
|
|
18
|
+
return Number.isFinite(num) && Math.abs(num) <= 180;
|
|
19
|
+
}
|
|
@@ -4,7 +4,7 @@ export declare enum DateFormats {
|
|
|
4
4
|
DDMMYYYY = "DDMMYYYY"
|
|
5
5
|
}
|
|
6
6
|
declare const VALID_SEPARATORS: readonly [".", "-", "/"];
|
|
7
|
-
type ValidSeparators = typeof VALID_SEPARATORS[number];
|
|
7
|
+
type ValidSeparators = (typeof VALID_SEPARATORS)[number];
|
|
8
8
|
/**
|
|
9
9
|
* Takes a date and a format and returns whether or not the date matches the specified format.
|
|
10
10
|
* Optionally takes a separator that can be used instead of the default hyphen.
|
|
@@ -19,7 +19,7 @@ const VALID_SEPARATORS = ['.', '-', '/'];
|
|
|
19
19
|
* @example 01-01-00 -> False
|
|
20
20
|
*/
|
|
21
21
|
function isDate(input, format, separator = '-') {
|
|
22
|
-
if (typeof input !==
|
|
22
|
+
if (typeof input !== 'string')
|
|
23
23
|
return false;
|
|
24
24
|
if (input.length !== 10)
|
|
25
25
|
return false;
|
|
@@ -31,22 +31,22 @@ function isDate(input, format, separator = '-') {
|
|
|
31
31
|
// Format: YYYY-MM-DD
|
|
32
32
|
format: DateFormats.YYYYMMDD,
|
|
33
33
|
regex: new RegExp(`^\\d{4}${separator}\\d{2}${separator}\\d{2}$`),
|
|
34
|
-
order: [
|
|
34
|
+
order: ['Y', 'M', 'D'],
|
|
35
35
|
},
|
|
36
36
|
{
|
|
37
37
|
// Format: MM-DD-YYYY
|
|
38
38
|
format: DateFormats.MMDDYYYY,
|
|
39
39
|
regex: new RegExp(`^\d{2}${separator}\d{2}${separator}\d{4}$/`),
|
|
40
|
-
order: [
|
|
40
|
+
order: ['M', 'D', 'Y'],
|
|
41
41
|
},
|
|
42
42
|
{
|
|
43
43
|
// Format: DD-MM-YYYY
|
|
44
44
|
format: DateFormats.DDMMYYYY,
|
|
45
45
|
regex: new RegExp(`^\d{2}${separator}\d{2}${separator}\d{4}$`),
|
|
46
|
-
order: [
|
|
46
|
+
order: ['D', 'M', 'Y'],
|
|
47
47
|
},
|
|
48
48
|
];
|
|
49
|
-
const targetFormat = formats.find(f => f.format === format);
|
|
49
|
+
const targetFormat = formats.find((f) => f.format === format);
|
|
50
50
|
const parts = input.split(separator).map(Number);
|
|
51
51
|
const dateParts = {};
|
|
52
52
|
targetFormat === null || targetFormat === void 0 ? void 0 : targetFormat.order.forEach((k, i) => {
|
|
@@ -56,8 +56,6 @@ function isDate(input, format, separator = '-') {
|
|
|
56
56
|
const checkDate = new Date(Y, M - 1, D); // Months are 0 indexed
|
|
57
57
|
if (checkDate.toString() === 'Invalid Date')
|
|
58
58
|
return false;
|
|
59
|
-
const isValid = checkDate.getFullYear() === Y &&
|
|
60
|
-
checkDate.getMonth() === M - 1 &&
|
|
61
|
-
checkDate.getDate() === D;
|
|
59
|
+
const isValid = checkDate.getFullYear() === Y && checkDate.getMonth() === M - 1 && checkDate.getDate() === D;
|
|
62
60
|
return isValid;
|
|
63
61
|
}
|
|
@@ -1 +1,13 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Checks if a given string is a valid email address.
|
|
3
|
+
*
|
|
4
|
+
* Uses a regular expression to verify the format: it must contain
|
|
5
|
+
* one "@" symbol, no spaces, and at least one dot after the "@"
|
|
6
|
+
* (e.g., "example@domain.com").
|
|
7
|
+
*
|
|
8
|
+
* @param {string} str - The string to be checked.
|
|
9
|
+
* @returns {boolean} True if the string is a valid email address, false otherwise.
|
|
10
|
+
*/
|
|
11
|
+
export declare function isEmail(str: string, opts?: {
|
|
12
|
+
smtpUTF8?: boolean;
|
|
13
|
+
}): boolean;
|
|
@@ -1,7 +1,180 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Checks if a given string is a valid email address.
|
|
4
|
+
*
|
|
5
|
+
* Uses a regular expression to verify the format: it must contain
|
|
6
|
+
* one "@" symbol, no spaces, and at least one dot after the "@"
|
|
7
|
+
* (e.g., "example@domain.com").
|
|
8
|
+
*
|
|
9
|
+
* @param {string} str - The string to be checked.
|
|
10
|
+
* @returns {boolean} True if the string is a valid email address, false otherwise.
|
|
11
|
+
*/
|
|
2
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
13
|
exports.isEmail = isEmail;
|
|
4
|
-
function isEmail(str) {
|
|
5
|
-
|
|
6
|
-
|
|
14
|
+
function isEmail(str, opts) {
|
|
15
|
+
if (typeof str !== 'string')
|
|
16
|
+
return false;
|
|
17
|
+
if (!str)
|
|
18
|
+
return false;
|
|
19
|
+
// Enable SMTPUTF8 by default; set opts.smtpUTF8=false to enforce ASCII-only
|
|
20
|
+
const smtpUTF8 = (opts === null || opts === void 0 ? void 0 : opts.smtpUTF8) !== false;
|
|
21
|
+
// Quick overall length guard
|
|
22
|
+
if (str.length > 254)
|
|
23
|
+
return false;
|
|
24
|
+
// Find the separator '@' by scanning from right to left and skipping those inside quotes
|
|
25
|
+
let inQuote = false;
|
|
26
|
+
let atIndex = -1;
|
|
27
|
+
for (let i = str.length - 1; i >= 0; i--) {
|
|
28
|
+
const ch = str[i];
|
|
29
|
+
if (ch === '"') {
|
|
30
|
+
// toggle quote state if this quote is not escaped by a backslash
|
|
31
|
+
const prev = str[i - 1];
|
|
32
|
+
if (prev !== '\\')
|
|
33
|
+
inQuote = !inQuote;
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
if (ch === '@' && !inQuote) {
|
|
37
|
+
atIndex = i;
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (inQuote)
|
|
42
|
+
return false; // unbalanced quotes
|
|
43
|
+
if (atIndex <= 0 || atIndex === str.length - 1)
|
|
44
|
+
return false;
|
|
45
|
+
const local = str.slice(0, atIndex);
|
|
46
|
+
const domain = str.slice(atIndex + 1);
|
|
47
|
+
// Local-part length limit (64 octets)
|
|
48
|
+
if (local.length > 64)
|
|
49
|
+
return false;
|
|
50
|
+
// Validate local part as dot-separated of atoms or quoted-strings
|
|
51
|
+
// Validate local with a robust FSM that supports nested unescaped quotes inside quoted strings
|
|
52
|
+
const isAsciiAtext = (ch) => /[A-Za-z0-9!#$%&'*+\/=?^_`{|}~-]/.test(ch);
|
|
53
|
+
const isUnicodeAtext = (ch) => {
|
|
54
|
+
if (!smtpUTF8)
|
|
55
|
+
return false;
|
|
56
|
+
// Disallow obvious separators and specials used by the parser
|
|
57
|
+
if (ch === '.' || ch === ' ' || ch === '"' || ch === '\\' || ch === '@')
|
|
58
|
+
return false;
|
|
59
|
+
// Disallow whitespace/control
|
|
60
|
+
if (/\s/u.test(ch))
|
|
61
|
+
return false;
|
|
62
|
+
// Allow Unicode Letters, Marks, Numbers and Symbols (e.g., emoji)
|
|
63
|
+
return /[\p{L}\p{N}\p{M}\p{S}]/u.test(ch);
|
|
64
|
+
};
|
|
65
|
+
let lastWasDot = false; // disallow consecutive or leading/trailing dots anywhere
|
|
66
|
+
let inQ = false; // inside a quoted token
|
|
67
|
+
let qDepth = 0; // quote nesting depth (>=1 when inside outer quotes)
|
|
68
|
+
let escQ = false; // backslash escape inside quotes
|
|
69
|
+
let needDotAfterQuoted = false; // require a dot right after a quoted token if not at end
|
|
70
|
+
for (let i = 0; i < local.length; i++) {
|
|
71
|
+
const c = local[i];
|
|
72
|
+
// If we just closed a quoted token, the very next char must be a dot
|
|
73
|
+
if (!inQ && needDotAfterQuoted) {
|
|
74
|
+
if (c !== '.')
|
|
75
|
+
return false;
|
|
76
|
+
needDotAfterQuoted = false;
|
|
77
|
+
lastWasDot = true;
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
if (inQ) {
|
|
81
|
+
if (escQ) {
|
|
82
|
+
// After a backslash, allow any non-newline character (broader under SMTPUTF8)
|
|
83
|
+
if (/\r|\n/.test(c))
|
|
84
|
+
return false;
|
|
85
|
+
escQ = false;
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
if (c === '\\') {
|
|
89
|
+
escQ = true;
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
if (c === '"') {
|
|
93
|
+
// Support nested unescaped quotes within a quoted token.
|
|
94
|
+
// Only close the quoted token when depth returns to 0 and we're at end-of-local
|
|
95
|
+
// or the next character is a dot (separator between tokens).
|
|
96
|
+
if (qDepth > 1) {
|
|
97
|
+
qDepth -= 1;
|
|
98
|
+
lastWasDot = false;
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
// qDepth === 1: decide whether to close or to start nesting
|
|
102
|
+
if (i + 1 === local.length || local[i + 1] === '.') {
|
|
103
|
+
// this quote closes the quoted token
|
|
104
|
+
inQ = false;
|
|
105
|
+
qDepth = 0;
|
|
106
|
+
// require a dot if not at end
|
|
107
|
+
if (i + 1 < local.length)
|
|
108
|
+
needDotAfterQuoted = true;
|
|
109
|
+
lastWasDot = false;
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
// start a nested quote level
|
|
114
|
+
qDepth += 1; // becomes 2
|
|
115
|
+
lastWasDot = false;
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
// Inside quotes: allow ASCII VCHAR and space by default; with SMTPUTF8 allow any char except control newlines
|
|
120
|
+
if (smtpUTF8) {
|
|
121
|
+
if (/\r|\n/.test(c))
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
const code = c.charCodeAt(0);
|
|
126
|
+
if (code < 0x20 || code > 0x7E)
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
// Dots inside quoted string are allowed freely
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
// outside quotes
|
|
133
|
+
if (c === '"') {
|
|
134
|
+
// quotes can only start at token boundaries (start or right after a dot)
|
|
135
|
+
if (i > 0 && !lastWasDot)
|
|
136
|
+
return false;
|
|
137
|
+
inQ = true;
|
|
138
|
+
qDepth = 1;
|
|
139
|
+
escQ = false;
|
|
140
|
+
lastWasDot = false;
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
if (c === '.') {
|
|
144
|
+
if (i === 0 || lastWasDot)
|
|
145
|
+
return false; // leading or consecutive dot
|
|
146
|
+
lastWasDot = true;
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
if (c === ' ')
|
|
150
|
+
return false; // no spaces outside quotes
|
|
151
|
+
// must be atext outside quotes
|
|
152
|
+
if (!(isAsciiAtext(c) || isUnicodeAtext(c)))
|
|
153
|
+
return false;
|
|
154
|
+
lastWasDot = false;
|
|
155
|
+
}
|
|
156
|
+
if (inQ || qDepth !== 0 || escQ)
|
|
157
|
+
return false; // unbalanced quotes or dangling escape
|
|
158
|
+
if (lastWasDot)
|
|
159
|
+
return false; // trailing dot
|
|
160
|
+
// Validate domain
|
|
161
|
+
const labelRe = /^[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?$/;
|
|
162
|
+
const ipv4Re = /^(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}$/;
|
|
163
|
+
const ipv6Re = /^IPv6:(?:[A-Fa-f0-9:]+)$/; // coarse check; detailed covered by overall tests
|
|
164
|
+
if (domain.startsWith('[') && domain.endsWith(']')) {
|
|
165
|
+
const literal = domain.slice(1, -1);
|
|
166
|
+
if (ipv4Re.test(literal))
|
|
167
|
+
return true;
|
|
168
|
+
if (ipv6Re.test(literal))
|
|
169
|
+
return true; // accept canonical IPv6 forms used in tests
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
172
|
+
const parts = domain.split('.');
|
|
173
|
+
if (parts.some(p => p.length === 0))
|
|
174
|
+
return false;
|
|
175
|
+
for (const p of parts) {
|
|
176
|
+
if (!labelRe.test(p))
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
return true;
|
|
7
180
|
}
|
|
@@ -1 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks whether a given string is empty or consists only of whitespace.
|
|
3
|
+
*
|
|
4
|
+
* Trims the input string and returns true if the resulting length is 0,
|
|
5
|
+
* indicating that the string is either empty or contains only whitespace characters.
|
|
6
|
+
*
|
|
7
|
+
* @param {string} str - The string to check.
|
|
8
|
+
* @returns {boolean} True if the string is empty or whitespace only, false otherwise.
|
|
9
|
+
*/
|
|
1
10
|
export declare function isEmpty(str: string): boolean;
|
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Checks whether a given string is empty or consists only of whitespace.
|
|
4
|
+
*
|
|
5
|
+
* Trims the input string and returns true if the resulting length is 0,
|
|
6
|
+
* indicating that the string is either empty or contains only whitespace characters.
|
|
7
|
+
*
|
|
8
|
+
* @param {string} str - The string to check.
|
|
9
|
+
* @returns {boolean} True if the string is empty or whitespace only, false otherwise.
|
|
10
|
+
*/
|
|
2
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
12
|
exports.isEmpty = isEmpty;
|
|
4
13
|
function isEmpty(str) {
|
|
@@ -8,7 +8,7 @@ exports.isHexColor = isHexColor;
|
|
|
8
8
|
* @returns True if the string is a valid hex color, false otherwise.
|
|
9
9
|
*/
|
|
10
10
|
function isHexColor(text) {
|
|
11
|
-
if (typeof text !==
|
|
11
|
+
if (typeof text !== 'string' || text.length === 0) {
|
|
12
12
|
return false;
|
|
13
13
|
}
|
|
14
14
|
return /^#?([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/.test(text.trim());
|
|
@@ -1 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks if a given string is a valid IPv4 address.
|
|
3
|
+
*
|
|
4
|
+
* Valid IPv4 addresses consist of four decimal numbers (0-255) separated by dots.
|
|
5
|
+
* Leading zeros are not allowed (e.g., "01" is invalid).
|
|
6
|
+
*
|
|
7
|
+
* @param {string} str - The string to validate as an IPv4 address.
|
|
8
|
+
* @returns {boolean} `true` if the string is a valid IPv4 address, otherwise `false`.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* isIPv4("192.168.1.1"); // true
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* isIPv4("255.255.255.255"); // true
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* isIPv4("256.100.50.0"); // false (256 is out of range)
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* isIPv4("192.168.1"); // false (not enough parts)
|
|
21
|
+
*/
|
|
1
22
|
export declare function isIPv4(str: string): boolean;
|
|
@@ -1,13 +1,33 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.isIPv4 = isIPv4;
|
|
4
|
+
/**
|
|
5
|
+
* Checks if a given string is a valid IPv4 address.
|
|
6
|
+
*
|
|
7
|
+
* Valid IPv4 addresses consist of four decimal numbers (0-255) separated by dots.
|
|
8
|
+
* Leading zeros are not allowed (e.g., "01" is invalid).
|
|
9
|
+
*
|
|
10
|
+
* @param {string} str - The string to validate as an IPv4 address.
|
|
11
|
+
* @returns {boolean} `true` if the string is a valid IPv4 address, otherwise `false`.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* isIPv4("192.168.1.1"); // true
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* isIPv4("255.255.255.255"); // true
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* isIPv4("256.100.50.0"); // false (256 is out of range)
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* isIPv4("192.168.1"); // false (not enough parts)
|
|
24
|
+
*/
|
|
4
25
|
function isIPv4(str) {
|
|
5
26
|
const parts = str.split('.');
|
|
6
27
|
if (parts.length !== 4)
|
|
7
28
|
return false;
|
|
8
|
-
return parts.every(part => {
|
|
29
|
+
return parts.every((part) => {
|
|
9
30
|
const num = parseInt(part, 10);
|
|
10
31
|
return !isNaN(num) && num >= 0 && num <= 255 && part === num.toString();
|
|
11
32
|
});
|
|
12
33
|
}
|
|
13
|
-
;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks whether the given string is a palindrome.
|
|
3
|
+
*
|
|
4
|
+
* The check is case-insensitive and ignores all non-alphanumeric characters.
|
|
5
|
+
*
|
|
6
|
+
* @param {string} str - The input string to check.
|
|
7
|
+
* @returns {boolean} True if the input is a palindrome, false otherwise.
|
|
8
|
+
* @throws {TypeError} If the input is not a string.
|
|
9
|
+
*/
|
|
10
|
+
export declare function isPalindrome(str: string): boolean;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isPalindrome = isPalindrome;
|
|
4
|
+
/**
|
|
5
|
+
* Checks whether the given string is a palindrome.
|
|
6
|
+
*
|
|
7
|
+
* The check is case-insensitive and ignores all non-alphanumeric characters.
|
|
8
|
+
*
|
|
9
|
+
* @param {string} str - The input string to check.
|
|
10
|
+
* @returns {boolean} True if the input is a palindrome, false otherwise.
|
|
11
|
+
* @throws {TypeError} If the input is not a string.
|
|
12
|
+
*/
|
|
13
|
+
function isPalindrome(str) {
|
|
14
|
+
if (typeof str !== 'string') {
|
|
15
|
+
throw new TypeError('Input must be a string');
|
|
16
|
+
}
|
|
17
|
+
const sanitized = str
|
|
18
|
+
.toLowerCase()
|
|
19
|
+
.replace(/[^a-z0-9]/gi, '');
|
|
20
|
+
return sanitized === sanitized.split('').reverse().join('');
|
|
21
|
+
}
|
|
@@ -1 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks if a given string is a valid slug.
|
|
3
|
+
*
|
|
4
|
+
* A valid slug:
|
|
5
|
+
* - Contains only lowercase letters (`a-z`), numbers (`0-9`), and hyphens (`-`).
|
|
6
|
+
* - Does not start or end with a hyphen.
|
|
7
|
+
* - Does not contain consecutive hyphens.
|
|
8
|
+
* - Is not an empty string.
|
|
9
|
+
*
|
|
10
|
+
* @param {string} str - The string to validate as a slug.
|
|
11
|
+
* @returns {boolean} `true` if the string is a valid slug, otherwise `false`.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* isSlug("valid-slug-123"); // true
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* isSlug("Invalid-Slug"); // false (uppercase letters)
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* isSlug("-starts-with-hyphen"); // false
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* isSlug("ends-with-hyphen-"); // false
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* isSlug("double--hyphen"); // false
|
|
27
|
+
*/
|
|
1
28
|
export declare function isSlug(str: string): boolean;
|
|
@@ -1,6 +1,33 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.isSlug = isSlug;
|
|
4
|
+
/**
|
|
5
|
+
* Checks if a given string is a valid slug.
|
|
6
|
+
*
|
|
7
|
+
* A valid slug:
|
|
8
|
+
* - Contains only lowercase letters (`a-z`), numbers (`0-9`), and hyphens (`-`).
|
|
9
|
+
* - Does not start or end with a hyphen.
|
|
10
|
+
* - Does not contain consecutive hyphens.
|
|
11
|
+
* - Is not an empty string.
|
|
12
|
+
*
|
|
13
|
+
* @param {string} str - The string to validate as a slug.
|
|
14
|
+
* @returns {boolean} `true` if the string is a valid slug, otherwise `false`.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* isSlug("valid-slug-123"); // true
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* isSlug("Invalid-Slug"); // false (uppercase letters)
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* isSlug("-starts-with-hyphen"); // false
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* isSlug("ends-with-hyphen-"); // false
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* isSlug("double--hyphen"); // false
|
|
30
|
+
*/
|
|
4
31
|
function isSlug(str) {
|
|
5
32
|
if (typeof str !== 'string' || str.length === 0) {
|
|
6
33
|
return false;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks if a file name or URL string has a valid extension for a given type.
|
|
3
|
+
*
|
|
4
|
+
* @param {string} input - File name or URL.
|
|
5
|
+
* @param {string} type - The type category to validate.
|
|
6
|
+
* @returns {boolean}
|
|
7
|
+
* @throws error when input is not string or type is not defined
|
|
8
|
+
*/
|
|
9
|
+
export declare function isTypeOf(input: string, type: string): boolean;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isTypeOf = isTypeOf;
|
|
4
|
+
/**
|
|
5
|
+
* Checks if a file name or URL string has a valid extension for a given type.
|
|
6
|
+
*
|
|
7
|
+
* @param {string} input - File name or URL.
|
|
8
|
+
* @param {string} type - The type category to validate.
|
|
9
|
+
* @returns {boolean}
|
|
10
|
+
* @throws error when input is not string or type is not defined
|
|
11
|
+
*/
|
|
12
|
+
function isTypeOf(input, type) {
|
|
13
|
+
var _a;
|
|
14
|
+
if (typeof input !== "string" || typeof type !== "string")
|
|
15
|
+
return false;
|
|
16
|
+
// Gets the substring after the last (.), then converts to lowercase, removes (?) and (#)
|
|
17
|
+
// Example: "image.png?version=2#top", returns "png"
|
|
18
|
+
const extension = (_a = input.split(".").pop()) === null || _a === void 0 ? void 0 : _a.toLowerCase().split("?")[0].split("#")[0];
|
|
19
|
+
if (!extension)
|
|
20
|
+
return false;
|
|
21
|
+
const typeMap = {
|
|
22
|
+
image: ["png", "jpg", "jpeg", "gif", "bmp", "svg", "webp", "ico"],
|
|
23
|
+
video: ["mp4", "webm", "avi", "mkv", "mov", "flv"],
|
|
24
|
+
audio: ["mp3", "wav", "ogg", "flac", "aac"],
|
|
25
|
+
document: ["pdf", "doc", "docx", "xls", "xlsx", "ppt", "pptx", "txt", "md"],
|
|
26
|
+
archive: ["zip", "rar", "tar", "gz", "7z"],
|
|
27
|
+
};
|
|
28
|
+
const allowed = typeMap[type.toLowerCase()];
|
|
29
|
+
return allowed ? allowed.includes(extension) : false;
|
|
30
|
+
}
|
|
@@ -1 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks if a given string is a valid URL.
|
|
3
|
+
*
|
|
4
|
+
* Uses the built-in `URL` constructor to attempt parsing the input string.
|
|
5
|
+
* Returns `true` if the string is a valid URL, otherwise `false`.
|
|
6
|
+
*
|
|
7
|
+
* @param {string} str - The string to validate as a URL.
|
|
8
|
+
* @returns {boolean} `true` if the string is a valid URL, otherwise `false`.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* isURL("https://www.example.com"); // true
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* isURL("ftp://ftp.example.com/resource.txt"); // true
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* isURL("not a url"); // false
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* isURL("http:/invalid-url"); // false
|
|
21
|
+
*/
|
|
1
22
|
export declare function isURL(str: string): boolean;
|
|
@@ -1,6 +1,27 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.isURL = isURL;
|
|
4
|
+
/**
|
|
5
|
+
* Checks if a given string is a valid URL.
|
|
6
|
+
*
|
|
7
|
+
* Uses the built-in `URL` constructor to attempt parsing the input string.
|
|
8
|
+
* Returns `true` if the string is a valid URL, otherwise `false`.
|
|
9
|
+
*
|
|
10
|
+
* @param {string} str - The string to validate as a URL.
|
|
11
|
+
* @returns {boolean} `true` if the string is a valid URL, otherwise `false`.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* isURL("https://www.example.com"); // true
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* isURL("ftp://ftp.example.com/resource.txt"); // true
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* isURL("not a url"); // false
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* isURL("http:/invalid-url"); // false
|
|
24
|
+
*/
|
|
4
25
|
function isURL(str) {
|
|
5
26
|
try {
|
|
6
27
|
new URL(str);
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "stringzy",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"build": "tsc",
|
|
8
8
|
"test": "npm run build && node --test",
|
|
9
|
-
"prepublishOnly": "npm run build"
|
|
9
|
+
"prepublishOnly": "npm run build",
|
|
10
|
+
"format": "prettier --write ."
|
|
10
11
|
},
|
|
11
12
|
"author": "Samarth Ruia",
|
|
12
13
|
"readmeFilename": "README.md",
|
|
@@ -44,7 +45,8 @@
|
|
|
44
45
|
"url": "git+https://github.com/Samarth2190/stringzy.git"
|
|
45
46
|
},
|
|
46
47
|
"devDependencies": {
|
|
47
|
-
"@types/node": "^24.0.
|
|
48
|
+
"@types/node": "^24.0.4",
|
|
49
|
+
"prettier": "^3.6.2",
|
|
48
50
|
"typescript": "^5.8.3"
|
|
49
51
|
}
|
|
50
52
|
}
|