@indodev/toolkit 0.3.1 → 0.3.3

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.
@@ -131,6 +131,30 @@ interface TruncateOptions {
131
131
  */
132
132
  wordBoundary?: boolean;
133
133
  }
134
+ /**
135
+ * Options for text masking
136
+ */
137
+ interface MaskOptions {
138
+ /**
139
+ * Masking pattern to apply
140
+ * - `all`: Mask all characters (preserves spaces)
141
+ * - `middle`: Keep start and end visible, mask middle
142
+ * - `email`: Keep first 2 chars of local part and full domain
143
+ */
144
+ pattern?: 'all' | 'middle' | 'email';
145
+ /**
146
+ * Character to use for masking (default: '*')
147
+ */
148
+ maskChar?: string;
149
+ /**
150
+ * Number of characters to keep visible at start (for 'middle' pattern, default: 2)
151
+ */
152
+ visibleStart?: number;
153
+ /**
154
+ * Number of characters to keep visible at end (for 'middle' pattern, default: 2)
155
+ */
156
+ visibleEnd?: number;
157
+ }
134
158
 
135
159
  /**
136
160
  * Capitalize the first letter of a string and lowercase the rest
@@ -988,4 +1012,4 @@ declare function compareStrings(str1: string, str2: string, options?: CompareOpt
988
1012
  */
989
1013
  declare function similarity(str1: string, str2: string): number;
990
1014
 
991
- export { type CompareOptions as C, type ExtractOptions as E, type SlugifyOptions as S, type TitleCaseOptions as T, toSentenceCase as a, sanitize as b, capitalize as c, contractAbbreviation as d, expandAbbreviation as e, truncate as f, extractWords as g, removeStopwords as h, toFormal as i, isAlay as j, compareStrings as k, similarity as l, type SanitizeOptions as m, normalizeWhitespace as n, type TruncateOptions as o, profanityFilter as p, removeAccents as r, slugify as s, toTitleCase as t };
1015
+ export { type CompareOptions as C, type ExtractOptions as E, type MaskOptions as M, type SlugifyOptions as S, type TitleCaseOptions as T, toSentenceCase as a, sanitize as b, capitalize as c, contractAbbreviation as d, expandAbbreviation as e, truncate as f, extractWords as g, removeStopwords as h, toFormal as i, isAlay as j, compareStrings as k, similarity as l, type SanitizeOptions as m, normalizeWhitespace as n, type TruncateOptions as o, profanityFilter as p, removeAccents as r, slugify as s, toTitleCase as t };
@@ -131,6 +131,30 @@ interface TruncateOptions {
131
131
  */
132
132
  wordBoundary?: boolean;
133
133
  }
134
+ /**
135
+ * Options for text masking
136
+ */
137
+ interface MaskOptions {
138
+ /**
139
+ * Masking pattern to apply
140
+ * - `all`: Mask all characters (preserves spaces)
141
+ * - `middle`: Keep start and end visible, mask middle
142
+ * - `email`: Keep first 2 chars of local part and full domain
143
+ */
144
+ pattern?: 'all' | 'middle' | 'email';
145
+ /**
146
+ * Character to use for masking (default: '*')
147
+ */
148
+ maskChar?: string;
149
+ /**
150
+ * Number of characters to keep visible at start (for 'middle' pattern, default: 2)
151
+ */
152
+ visibleStart?: number;
153
+ /**
154
+ * Number of characters to keep visible at end (for 'middle' pattern, default: 2)
155
+ */
156
+ visibleEnd?: number;
157
+ }
134
158
 
135
159
  /**
136
160
  * Capitalize the first letter of a string and lowercase the rest
@@ -988,4 +1012,4 @@ declare function compareStrings(str1: string, str2: string, options?: CompareOpt
988
1012
  */
989
1013
  declare function similarity(str1: string, str2: string): number;
990
1014
 
991
- export { type CompareOptions as C, type ExtractOptions as E, type SlugifyOptions as S, type TitleCaseOptions as T, toSentenceCase as a, sanitize as b, capitalize as c, contractAbbreviation as d, expandAbbreviation as e, truncate as f, extractWords as g, removeStopwords as h, toFormal as i, isAlay as j, compareStrings as k, similarity as l, type SanitizeOptions as m, normalizeWhitespace as n, type TruncateOptions as o, profanityFilter as p, removeAccents as r, slugify as s, toTitleCase as t };
1015
+ export { type CompareOptions as C, type ExtractOptions as E, type MaskOptions as M, type SlugifyOptions as S, type TitleCaseOptions as T, toSentenceCase as a, sanitize as b, capitalize as c, contractAbbreviation as d, expandAbbreviation as e, truncate as f, extractWords as g, removeStopwords as h, toFormal as i, isAlay as j, compareStrings as k, similarity as l, type SanitizeOptions as m, normalizeWhitespace as n, type TruncateOptions as o, profanityFilter as p, removeAccents as r, slugify as s, toTitleCase as t };
@@ -0,0 +1,83 @@
1
+ 'use strict';
2
+
3
+ // src/email-validator/constants.ts
4
+ var EMAIL_REGEX = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,253}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,253}[a-zA-Z0-9])?)*$/;
5
+ var DISPOSABLE_DOMAINS = [
6
+ "mailinator.com",
7
+ "10minutemail.com",
8
+ "temp-mail.org",
9
+ "guerrillamail.com"
10
+ ];
11
+
12
+ // src/email-validator/email-validator.ts
13
+ var COMMON_PROVIDERS = ["gmail.com", "yahoo.com", "outlook.com", "hotmail.com", "icloud.com"];
14
+ var MAX_EMAIL_LENGTH = 254;
15
+ function validateEmail(email, options) {
16
+ if (!email || typeof email !== "string") {
17
+ return false;
18
+ }
19
+ const trimmedEmail = email.trim().toLowerCase();
20
+ if (trimmedEmail.length > MAX_EMAIL_LENGTH) {
21
+ return false;
22
+ }
23
+ const parts = trimmedEmail.split("@");
24
+ if (parts.length !== 2) {
25
+ return false;
26
+ }
27
+ const [username, domain] = parts;
28
+ if (!username || !domain) {
29
+ return false;
30
+ }
31
+ if (username.length > 64) {
32
+ return false;
33
+ }
34
+ if (username.includes("..") || username.startsWith(".") || username.endsWith(".") || domain.startsWith(".") || domain.endsWith(".") || domain.includes("..")) {
35
+ return false;
36
+ }
37
+ if (!EMAIL_REGEX.test(trimmedEmail)) {
38
+ return false;
39
+ }
40
+ if (options?.blockDisposable) {
41
+ if (DISPOSABLE_DOMAINS.includes(domain)) {
42
+ return false;
43
+ }
44
+ }
45
+ return true;
46
+ }
47
+ function getEmailInfo(email) {
48
+ if (!validateEmail(email)) return null;
49
+ const [username, domain] = email.trim().toLowerCase().split("@");
50
+ return {
51
+ username,
52
+ domain,
53
+ isCommonProvider: COMMON_PROVIDERS.includes(domain),
54
+ isDisposable: DISPOSABLE_DOMAINS.includes(domain)
55
+ };
56
+ }
57
+ function maskEmail(email, options) {
58
+ if (!validateEmail(email)) return email;
59
+ const { visibleStart = 1, visibleEnd = 1, maskChar = "*" } = options || {};
60
+ const [username, domain] = email.split("@");
61
+ if (username.length <= 3) {
62
+ return `${username[0]}${maskChar.repeat(3)}@${domain}`;
63
+ }
64
+ const maskedLength = username.length - (visibleStart + visibleEnd);
65
+ if (maskedLength <= 0) {
66
+ return `${username[0]}${maskChar.repeat(3)}@${domain}`;
67
+ }
68
+ const start = username.slice(0, visibleStart);
69
+ const end = username.slice(username.length - visibleEnd);
70
+ return `${start}${maskChar.repeat(maskedLength)}${end}@${domain}`;
71
+ }
72
+ function normalizeEmail(email) {
73
+ return email.trim().toLowerCase();
74
+ }
75
+
76
+ exports.DISPOSABLE_DOMAINS = DISPOSABLE_DOMAINS;
77
+ exports.EMAIL_REGEX = EMAIL_REGEX;
78
+ exports.getEmailInfo = getEmailInfo;
79
+ exports.maskEmail = maskEmail;
80
+ exports.normalizeEmail = normalizeEmail;
81
+ exports.validateEmail = validateEmail;
82
+ //# sourceMappingURL=index.cjs.map
83
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/email-validator/constants.ts","../../src/email-validator/email-validator.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Regular expression for standard email validation.\n * Optimized for RFC 5322 compliance.\n */\nexport const EMAIL_REGEX = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,253}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,253}[a-zA-Z0-9])?)*$/;\n\n/**\n * Common disposable email domains to block if needed.\n */\nexport const DISPOSABLE_DOMAINS = [\n 'mailinator.com',\n '10minutemail.com',\n 'temp-mail.org',\n 'guerrillamail.com',\n];\n","import { EMAIL_REGEX, DISPOSABLE_DOMAINS } from './constants';\nimport type { EmailValidationOptions, EmailMaskOptions, EmailInfo } from './types';\n\n/**\n * List of common global email providers.\n */\nconst COMMON_PROVIDERS = ['gmail.com', 'yahoo.com', 'outlook.com', 'hotmail.com', 'icloud.com'];\n\n/**\n * The maximum length of an email address according to RFC 5321.\n */\nconst MAX_EMAIL_LENGTH = 254;\n\n/**\n * Validates if a string is a properly formatted email address based on RFC 5322.\n * \n * Performs checks for:\n * - Proper email format (regex).\n * - RFC specific rules (no double dots, username length < 64).\n * - Maximum total length (254 characters).\n * - Optional: disposable email detection.\n * \n * @param email - The email string to validate.\n * @param options - Optional validation configuration.\n * @returns `true` if valid, `false` otherwise.\n * \n * @example\n * ```typescript\n * import { validateEmail } from '@indodev/toolkit/email-validator';\n * \n * validateEmail('user@example.com'); // true\n * validateEmail('invalid-email'); // false\n * validateEmail('spam@mailinator.com', { blockDisposable: true }); // false\n * ```\n */\nexport function validateEmail(email: string, options?: EmailValidationOptions): boolean {\n if (!email || typeof email !== 'string') {\n return false;\n }\n\n const trimmedEmail = email.trim().toLowerCase();\n\n if (trimmedEmail.length > MAX_EMAIL_LENGTH) {\n return false;\n }\n\n const parts = trimmedEmail.split('@');\n if (parts.length !== 2) {\n return false;\n }\n\n const [username, domain] = parts;\n\n if (!username || !domain) {\n return false;\n }\n\n if (username.length > 64) {\n return false;\n }\n\n if (\n username.includes('..') ||\n username.startsWith('.') ||\n username.endsWith('.') ||\n domain.startsWith('.') ||\n domain.endsWith('.') ||\n domain.includes('..')\n ) {\n return false;\n }\n\n if (!EMAIL_REGEX.test(trimmedEmail)) {\n return false;\n }\n\n if (options?.blockDisposable) {\n if (DISPOSABLE_DOMAINS.includes(domain)) {\n return false;\n }\n }\n\n return true;\n}\n\n/**\n * Parses an email address to extract useful metadata.\n * \n * @param email - The email address to parse.\n * @returns `EmailInfo` object containing details or `null` if the email is invalid.\n * \n * @example\n * ```typescript\n * import { getEmailInfo } from '@indodev/toolkit/email-validator';\n * \n * const info = getEmailInfo('adam@gmail.com');\n * // { username: 'adam', domain: 'gmail.com', isCommonProvider: true, isDisposable: false }\n * ```\n */\nexport function getEmailInfo(email: string): EmailInfo | null {\n if (!validateEmail(email)) return null;\n\n const [username, domain] = email.trim().toLowerCase().split('@');\n\n return {\n username,\n domain,\n isCommonProvider: COMMON_PROVIDERS.includes(domain),\n isDisposable: DISPOSABLE_DOMAINS.includes(domain),\n };\n}\n\n/**\n * Masks the username portion of an email for privacy protection.\n * \n * Falls back to a standard mask if the username is too short to respect visibleStart/visibleEnd.\n * \n * @param email - The email address to mask.\n * @param options - Optional masking configuration.\n * @returns Masked email string or original if invalid.\n * \n * @example\n * ```typescript\n * import { maskEmail } from '@indodev/toolkit/email-validator';\n * \n * maskEmail('user@example.com'); // 'u**r@example.com'\n * maskEmail('user@example.com', { maskChar: '#' }); // 'u##r@example.com'\n * ```\n */\nexport function maskEmail(email: string, options?: EmailMaskOptions): string {\n if (!validateEmail(email)) return email;\n\n const { visibleStart = 1, visibleEnd = 1, maskChar = '*' } = options || {};\n const [username, domain] = email.split('@');\n\n // Fallback for very short usernames\n if (username.length <= 3) {\n return `${username[0]}${maskChar.repeat(3)}@${domain}`;\n }\n\n // Calculate masked length\n const maskedLength = username.length - (visibleStart + visibleEnd);\n\n // If the result of masking would be empty or negative, use fallback\n if (maskedLength <= 0) {\n return `${username[0]}${maskChar.repeat(3)}@${domain}`;\n }\n\n const start = username.slice(0, visibleStart);\n const end = username.slice(username.length - visibleEnd);\n\n return `${start}${maskChar.repeat(maskedLength)}${end}@${domain}`;\n}\n\n/**\n * Normalizes an email address by trimming whitespace and converting to lowercase.\n * \n * @param email - The email to normalize.\n * @returns Normalized email string.\n * \n * @example\n * ```typescript\n * import { normalizeEmail } from '@indodev/toolkit/email-validator';\n * \n * normalizeEmail(' USER@Example.COM '); // 'user@example.com'\n * ```\n */\nexport function normalizeEmail(email: string): string {\n return email.trim().toLowerCase();\n}\n"]}
@@ -0,0 +1,13 @@
1
+ export { c as EmailInfo, b as EmailMaskOptions, E as EmailValidationOptions, a as EmailValidationResult, g as getEmailInfo, m as maskEmail, n as normalizeEmail, v as validateEmail } from '../email-validator-R9L5unIw.cjs';
2
+
3
+ /**
4
+ * Regular expression for standard email validation.
5
+ * Optimized for RFC 5322 compliance.
6
+ */
7
+ declare const EMAIL_REGEX: RegExp;
8
+ /**
9
+ * Common disposable email domains to block if needed.
10
+ */
11
+ declare const DISPOSABLE_DOMAINS: string[];
12
+
13
+ export { DISPOSABLE_DOMAINS, EMAIL_REGEX };
@@ -0,0 +1,13 @@
1
+ export { c as EmailInfo, b as EmailMaskOptions, E as EmailValidationOptions, a as EmailValidationResult, g as getEmailInfo, m as maskEmail, n as normalizeEmail, v as validateEmail } from '../email-validator-R9L5unIw.js';
2
+
3
+ /**
4
+ * Regular expression for standard email validation.
5
+ * Optimized for RFC 5322 compliance.
6
+ */
7
+ declare const EMAIL_REGEX: RegExp;
8
+ /**
9
+ * Common disposable email domains to block if needed.
10
+ */
11
+ declare const DISPOSABLE_DOMAINS: string[];
12
+
13
+ export { DISPOSABLE_DOMAINS, EMAIL_REGEX };
@@ -0,0 +1,76 @@
1
+ // src/email-validator/constants.ts
2
+ var EMAIL_REGEX = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,253}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,253}[a-zA-Z0-9])?)*$/;
3
+ var DISPOSABLE_DOMAINS = [
4
+ "mailinator.com",
5
+ "10minutemail.com",
6
+ "temp-mail.org",
7
+ "guerrillamail.com"
8
+ ];
9
+
10
+ // src/email-validator/email-validator.ts
11
+ var COMMON_PROVIDERS = ["gmail.com", "yahoo.com", "outlook.com", "hotmail.com", "icloud.com"];
12
+ var MAX_EMAIL_LENGTH = 254;
13
+ function validateEmail(email, options) {
14
+ if (!email || typeof email !== "string") {
15
+ return false;
16
+ }
17
+ const trimmedEmail = email.trim().toLowerCase();
18
+ if (trimmedEmail.length > MAX_EMAIL_LENGTH) {
19
+ return false;
20
+ }
21
+ const parts = trimmedEmail.split("@");
22
+ if (parts.length !== 2) {
23
+ return false;
24
+ }
25
+ const [username, domain] = parts;
26
+ if (!username || !domain) {
27
+ return false;
28
+ }
29
+ if (username.length > 64) {
30
+ return false;
31
+ }
32
+ if (username.includes("..") || username.startsWith(".") || username.endsWith(".") || domain.startsWith(".") || domain.endsWith(".") || domain.includes("..")) {
33
+ return false;
34
+ }
35
+ if (!EMAIL_REGEX.test(trimmedEmail)) {
36
+ return false;
37
+ }
38
+ if (options?.blockDisposable) {
39
+ if (DISPOSABLE_DOMAINS.includes(domain)) {
40
+ return false;
41
+ }
42
+ }
43
+ return true;
44
+ }
45
+ function getEmailInfo(email) {
46
+ if (!validateEmail(email)) return null;
47
+ const [username, domain] = email.trim().toLowerCase().split("@");
48
+ return {
49
+ username,
50
+ domain,
51
+ isCommonProvider: COMMON_PROVIDERS.includes(domain),
52
+ isDisposable: DISPOSABLE_DOMAINS.includes(domain)
53
+ };
54
+ }
55
+ function maskEmail(email, options) {
56
+ if (!validateEmail(email)) return email;
57
+ const { visibleStart = 1, visibleEnd = 1, maskChar = "*" } = options || {};
58
+ const [username, domain] = email.split("@");
59
+ if (username.length <= 3) {
60
+ return `${username[0]}${maskChar.repeat(3)}@${domain}`;
61
+ }
62
+ const maskedLength = username.length - (visibleStart + visibleEnd);
63
+ if (maskedLength <= 0) {
64
+ return `${username[0]}${maskChar.repeat(3)}@${domain}`;
65
+ }
66
+ const start = username.slice(0, visibleStart);
67
+ const end = username.slice(username.length - visibleEnd);
68
+ return `${start}${maskChar.repeat(maskedLength)}${end}@${domain}`;
69
+ }
70
+ function normalizeEmail(email) {
71
+ return email.trim().toLowerCase();
72
+ }
73
+
74
+ export { DISPOSABLE_DOMAINS, EMAIL_REGEX, getEmailInfo, maskEmail, normalizeEmail, validateEmail };
75
+ //# sourceMappingURL=index.js.map
76
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/email-validator/constants.ts","../../src/email-validator/email-validator.ts"],"names":[],"mappings":";AAIO,IAAM,WAAA,GAAc;AAKpB,IAAM,kBAAA,GAAqB;AAAA,EAChC,gBAAA;AAAA,EACA,kBAAA;AAAA,EACA,eAAA;AAAA,EACA;AACF;;;ACRA,IAAM,mBAAmB,CAAC,WAAA,EAAa,WAAA,EAAa,aAAA,EAAe,eAAe,YAAY,CAAA;AAK9F,IAAM,gBAAA,GAAmB,GAAA;AAwBlB,SAAS,aAAA,CAAc,OAAe,OAAA,EAA2C;AACtF,EAAA,IAAI,CAAC,KAAA,IAAS,OAAO,KAAA,KAAU,QAAA,EAAU;AACvC,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,MAAM,YAAA,GAAe,KAAA,CAAM,IAAA,EAAK,CAAE,WAAA,EAAY;AAE9C,EAAA,IAAI,YAAA,CAAa,SAAS,gBAAA,EAAkB;AAC1C,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,MAAM,KAAA,GAAQ,YAAA,CAAa,KAAA,CAAM,GAAG,CAAA;AACpC,EAAA,IAAI,KAAA,CAAM,WAAW,CAAA,EAAG;AACtB,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,MAAM,CAAC,QAAA,EAAU,MAAM,CAAA,GAAI,KAAA;AAE3B,EAAA,IAAI,CAAC,QAAA,IAAY,CAAC,MAAA,EAAQ;AACxB,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,IAAI,QAAA,CAAS,SAAS,EAAA,EAAI;AACxB,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,IACE,QAAA,CAAS,SAAS,IAAI,CAAA,IACtB,SAAS,UAAA,CAAW,GAAG,CAAA,IACvB,QAAA,CAAS,QAAA,CAAS,GAAG,KACrB,MAAA,CAAO,UAAA,CAAW,GAAG,CAAA,IACrB,MAAA,CAAO,QAAA,CAAS,GAAG,CAAA,IACnB,MAAA,CAAO,QAAA,CAAS,IAAI,CAAA,EACpB;AACA,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,IAAI,CAAC,WAAA,CAAY,IAAA,CAAK,YAAY,CAAA,EAAG;AACnC,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,IAAI,SAAS,eAAA,EAAiB;AAC5B,IAAA,IAAI,kBAAA,CAAmB,QAAA,CAAS,MAAM,CAAA,EAAG;AACvC,MAAA,OAAO,KAAA;AAAA,IACT;AAAA,EACF;AAEA,EAAA,OAAO,IAAA;AACT;AAgBO,SAAS,aAAa,KAAA,EAAiC;AAC5D,EAAA,IAAI,CAAC,aAAA,CAAc,KAAK,CAAA,EAAG,OAAO,IAAA;AAElC,EAAA,MAAM,CAAC,QAAA,EAAU,MAAM,CAAA,GAAI,KAAA,CAAM,MAAK,CAAE,WAAA,EAAY,CAAE,KAAA,CAAM,GAAG,CAAA;AAE/D,EAAA,OAAO;AAAA,IACL,QAAA;AAAA,IACA,MAAA;AAAA,IACA,gBAAA,EAAkB,gBAAA,CAAiB,QAAA,CAAS,MAAM,CAAA;AAAA,IAClD,YAAA,EAAc,kBAAA,CAAmB,QAAA,CAAS,MAAM;AAAA,GAClD;AACF;AAmBO,SAAS,SAAA,CAAU,OAAe,OAAA,EAAoC;AAC3E,EAAA,IAAI,CAAC,aAAA,CAAc,KAAK,CAAA,EAAG,OAAO,KAAA;AAElC,EAAA,MAAM,EAAE,eAAe,CAAA,EAAG,UAAA,GAAa,GAAG,QAAA,GAAW,GAAA,EAAI,GAAI,OAAA,IAAW,EAAC;AACzE,EAAA,MAAM,CAAC,QAAA,EAAU,MAAM,CAAA,GAAI,KAAA,CAAM,MAAM,GAAG,CAAA;AAG1C,EAAA,IAAI,QAAA,CAAS,UAAU,CAAA,EAAG;AACxB,IAAA,OAAO,CAAA,EAAG,QAAA,CAAS,CAAC,CAAC,CAAA,EAAG,SAAS,MAAA,CAAO,CAAC,CAAC,CAAA,CAAA,EAAI,MAAM,CAAA,CAAA;AAAA,EACtD;AAGA,EAAA,MAAM,YAAA,GAAe,QAAA,CAAS,MAAA,IAAU,YAAA,GAAe,UAAA,CAAA;AAGvD,EAAA,IAAI,gBAAgB,CAAA,EAAG;AACrB,IAAA,OAAO,CAAA,EAAG,QAAA,CAAS,CAAC,CAAC,CAAA,EAAG,SAAS,MAAA,CAAO,CAAC,CAAC,CAAA,CAAA,EAAI,MAAM,CAAA,CAAA;AAAA,EACtD;AAEA,EAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,KAAA,CAAM,CAAA,EAAG,YAAY,CAAA;AAC5C,EAAA,MAAM,GAAA,GAAM,QAAA,CAAS,KAAA,CAAM,QAAA,CAAS,SAAS,UAAU,CAAA;AAEvD,EAAA,OAAO,CAAA,EAAG,KAAK,CAAA,EAAG,QAAA,CAAS,MAAA,CAAO,YAAY,CAAC,CAAA,EAAG,GAAG,CAAA,CAAA,EAAI,MAAM,CAAA,CAAA;AACjE;AAeO,SAAS,eAAe,KAAA,EAAuB;AACpD,EAAA,OAAO,KAAA,CAAM,IAAA,EAAK,CAAE,WAAA,EAAY;AAClC","file":"index.js","sourcesContent":["/**\n * Regular expression for standard email validation.\n * Optimized for RFC 5322 compliance.\n */\nexport const EMAIL_REGEX = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,253}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,253}[a-zA-Z0-9])?)*$/;\n\n/**\n * Common disposable email domains to block if needed.\n */\nexport const DISPOSABLE_DOMAINS = [\n 'mailinator.com',\n '10minutemail.com',\n 'temp-mail.org',\n 'guerrillamail.com',\n];\n","import { EMAIL_REGEX, DISPOSABLE_DOMAINS } from './constants';\nimport type { EmailValidationOptions, EmailMaskOptions, EmailInfo } from './types';\n\n/**\n * List of common global email providers.\n */\nconst COMMON_PROVIDERS = ['gmail.com', 'yahoo.com', 'outlook.com', 'hotmail.com', 'icloud.com'];\n\n/**\n * The maximum length of an email address according to RFC 5321.\n */\nconst MAX_EMAIL_LENGTH = 254;\n\n/**\n * Validates if a string is a properly formatted email address based on RFC 5322.\n * \n * Performs checks for:\n * - Proper email format (regex).\n * - RFC specific rules (no double dots, username length < 64).\n * - Maximum total length (254 characters).\n * - Optional: disposable email detection.\n * \n * @param email - The email string to validate.\n * @param options - Optional validation configuration.\n * @returns `true` if valid, `false` otherwise.\n * \n * @example\n * ```typescript\n * import { validateEmail } from '@indodev/toolkit/email-validator';\n * \n * validateEmail('user@example.com'); // true\n * validateEmail('invalid-email'); // false\n * validateEmail('spam@mailinator.com', { blockDisposable: true }); // false\n * ```\n */\nexport function validateEmail(email: string, options?: EmailValidationOptions): boolean {\n if (!email || typeof email !== 'string') {\n return false;\n }\n\n const trimmedEmail = email.trim().toLowerCase();\n\n if (trimmedEmail.length > MAX_EMAIL_LENGTH) {\n return false;\n }\n\n const parts = trimmedEmail.split('@');\n if (parts.length !== 2) {\n return false;\n }\n\n const [username, domain] = parts;\n\n if (!username || !domain) {\n return false;\n }\n\n if (username.length > 64) {\n return false;\n }\n\n if (\n username.includes('..') ||\n username.startsWith('.') ||\n username.endsWith('.') ||\n domain.startsWith('.') ||\n domain.endsWith('.') ||\n domain.includes('..')\n ) {\n return false;\n }\n\n if (!EMAIL_REGEX.test(trimmedEmail)) {\n return false;\n }\n\n if (options?.blockDisposable) {\n if (DISPOSABLE_DOMAINS.includes(domain)) {\n return false;\n }\n }\n\n return true;\n}\n\n/**\n * Parses an email address to extract useful metadata.\n * \n * @param email - The email address to parse.\n * @returns `EmailInfo` object containing details or `null` if the email is invalid.\n * \n * @example\n * ```typescript\n * import { getEmailInfo } from '@indodev/toolkit/email-validator';\n * \n * const info = getEmailInfo('adam@gmail.com');\n * // { username: 'adam', domain: 'gmail.com', isCommonProvider: true, isDisposable: false }\n * ```\n */\nexport function getEmailInfo(email: string): EmailInfo | null {\n if (!validateEmail(email)) return null;\n\n const [username, domain] = email.trim().toLowerCase().split('@');\n\n return {\n username,\n domain,\n isCommonProvider: COMMON_PROVIDERS.includes(domain),\n isDisposable: DISPOSABLE_DOMAINS.includes(domain),\n };\n}\n\n/**\n * Masks the username portion of an email for privacy protection.\n * \n * Falls back to a standard mask if the username is too short to respect visibleStart/visibleEnd.\n * \n * @param email - The email address to mask.\n * @param options - Optional masking configuration.\n * @returns Masked email string or original if invalid.\n * \n * @example\n * ```typescript\n * import { maskEmail } from '@indodev/toolkit/email-validator';\n * \n * maskEmail('user@example.com'); // 'u**r@example.com'\n * maskEmail('user@example.com', { maskChar: '#' }); // 'u##r@example.com'\n * ```\n */\nexport function maskEmail(email: string, options?: EmailMaskOptions): string {\n if (!validateEmail(email)) return email;\n\n const { visibleStart = 1, visibleEnd = 1, maskChar = '*' } = options || {};\n const [username, domain] = email.split('@');\n\n // Fallback for very short usernames\n if (username.length <= 3) {\n return `${username[0]}${maskChar.repeat(3)}@${domain}`;\n }\n\n // Calculate masked length\n const maskedLength = username.length - (visibleStart + visibleEnd);\n\n // If the result of masking would be empty or negative, use fallback\n if (maskedLength <= 0) {\n return `${username[0]}${maskChar.repeat(3)}@${domain}`;\n }\n\n const start = username.slice(0, visibleStart);\n const end = username.slice(username.length - visibleEnd);\n\n return `${start}${maskChar.repeat(maskedLength)}${end}@${domain}`;\n}\n\n/**\n * Normalizes an email address by trimming whitespace and converting to lowercase.\n * \n * @param email - The email to normalize.\n * @returns Normalized email string.\n * \n * @example\n * ```typescript\n * import { normalizeEmail } from '@indodev/toolkit/email-validator';\n * \n * normalizeEmail(' USER@Example.COM '); // 'user@example.com'\n * ```\n */\nexport function normalizeEmail(email: string): string {\n return email.trim().toLowerCase();\n}\n"]}
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Email validation options.
3
+ */
4
+ interface EmailValidationOptions {
5
+ /**
6
+ * Whether to block known disposable email domains.
7
+ * @default false
8
+ */
9
+ blockDisposable?: boolean;
10
+ }
11
+ /**
12
+ * Detailed email validation result.
13
+ */
14
+ interface EmailValidationResult {
15
+ isValid: boolean;
16
+ domain?: string;
17
+ isDisposable?: boolean;
18
+ }
19
+ /**
20
+ * Options for email masking.
21
+ */
22
+ interface EmailMaskOptions {
23
+ /**
24
+ * Number of characters to keep visible at the start of the username.
25
+ * @default 1
26
+ */
27
+ visibleStart?: number;
28
+ /**
29
+ * Number of characters to keep visible at the end of the username.
30
+ * @default 1
31
+ */
32
+ visibleEnd?: number;
33
+ /**
34
+ * Character used for masking.
35
+ * @default '*'
36
+ */
37
+ maskChar?: string;
38
+ }
39
+ /**
40
+ * Detailed email information.
41
+ */
42
+ interface EmailInfo {
43
+ username: string;
44
+ domain: string;
45
+ isCommonProvider: boolean;
46
+ isDisposable: boolean;
47
+ }
48
+
49
+ /**
50
+ * Validates if a string is a properly formatted email address based on RFC 5322.
51
+ *
52
+ * Performs checks for:
53
+ * - Proper email format (regex).
54
+ * - RFC specific rules (no double dots, username length < 64).
55
+ * - Maximum total length (254 characters).
56
+ * - Optional: disposable email detection.
57
+ *
58
+ * @param email - The email string to validate.
59
+ * @param options - Optional validation configuration.
60
+ * @returns `true` if valid, `false` otherwise.
61
+ *
62
+ * @example
63
+ * ```typescript
64
+ * import { validateEmail } from '@indodev/toolkit/email-validator';
65
+ *
66
+ * validateEmail('user@example.com'); // true
67
+ * validateEmail('invalid-email'); // false
68
+ * validateEmail('spam@mailinator.com', { blockDisposable: true }); // false
69
+ * ```
70
+ */
71
+ declare function validateEmail(email: string, options?: EmailValidationOptions): boolean;
72
+ /**
73
+ * Parses an email address to extract useful metadata.
74
+ *
75
+ * @param email - The email address to parse.
76
+ * @returns `EmailInfo` object containing details or `null` if the email is invalid.
77
+ *
78
+ * @example
79
+ * ```typescript
80
+ * import { getEmailInfo } from '@indodev/toolkit/email-validator';
81
+ *
82
+ * const info = getEmailInfo('adam@gmail.com');
83
+ * // { username: 'adam', domain: 'gmail.com', isCommonProvider: true, isDisposable: false }
84
+ * ```
85
+ */
86
+ declare function getEmailInfo(email: string): EmailInfo | null;
87
+ /**
88
+ * Masks the username portion of an email for privacy protection.
89
+ *
90
+ * Falls back to a standard mask if the username is too short to respect visibleStart/visibleEnd.
91
+ *
92
+ * @param email - The email address to mask.
93
+ * @param options - Optional masking configuration.
94
+ * @returns Masked email string or original if invalid.
95
+ *
96
+ * @example
97
+ * ```typescript
98
+ * import { maskEmail } from '@indodev/toolkit/email-validator';
99
+ *
100
+ * maskEmail('user@example.com'); // 'u**r@example.com'
101
+ * maskEmail('user@example.com', { maskChar: '#' }); // 'u##r@example.com'
102
+ * ```
103
+ */
104
+ declare function maskEmail(email: string, options?: EmailMaskOptions): string;
105
+ /**
106
+ * Normalizes an email address by trimming whitespace and converting to lowercase.
107
+ *
108
+ * @param email - The email to normalize.
109
+ * @returns Normalized email string.
110
+ *
111
+ * @example
112
+ * ```typescript
113
+ * import { normalizeEmail } from '@indodev/toolkit/email-validator';
114
+ *
115
+ * normalizeEmail(' USER@Example.COM '); // 'user@example.com'
116
+ * ```
117
+ */
118
+ declare function normalizeEmail(email: string): string;
119
+
120
+ export { type EmailValidationOptions as E, type EmailValidationResult as a, type EmailMaskOptions as b, type EmailInfo as c, getEmailInfo as g, maskEmail as m, normalizeEmail as n, validateEmail as v };
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Email validation options.
3
+ */
4
+ interface EmailValidationOptions {
5
+ /**
6
+ * Whether to block known disposable email domains.
7
+ * @default false
8
+ */
9
+ blockDisposable?: boolean;
10
+ }
11
+ /**
12
+ * Detailed email validation result.
13
+ */
14
+ interface EmailValidationResult {
15
+ isValid: boolean;
16
+ domain?: string;
17
+ isDisposable?: boolean;
18
+ }
19
+ /**
20
+ * Options for email masking.
21
+ */
22
+ interface EmailMaskOptions {
23
+ /**
24
+ * Number of characters to keep visible at the start of the username.
25
+ * @default 1
26
+ */
27
+ visibleStart?: number;
28
+ /**
29
+ * Number of characters to keep visible at the end of the username.
30
+ * @default 1
31
+ */
32
+ visibleEnd?: number;
33
+ /**
34
+ * Character used for masking.
35
+ * @default '*'
36
+ */
37
+ maskChar?: string;
38
+ }
39
+ /**
40
+ * Detailed email information.
41
+ */
42
+ interface EmailInfo {
43
+ username: string;
44
+ domain: string;
45
+ isCommonProvider: boolean;
46
+ isDisposable: boolean;
47
+ }
48
+
49
+ /**
50
+ * Validates if a string is a properly formatted email address based on RFC 5322.
51
+ *
52
+ * Performs checks for:
53
+ * - Proper email format (regex).
54
+ * - RFC specific rules (no double dots, username length < 64).
55
+ * - Maximum total length (254 characters).
56
+ * - Optional: disposable email detection.
57
+ *
58
+ * @param email - The email string to validate.
59
+ * @param options - Optional validation configuration.
60
+ * @returns `true` if valid, `false` otherwise.
61
+ *
62
+ * @example
63
+ * ```typescript
64
+ * import { validateEmail } from '@indodev/toolkit/email-validator';
65
+ *
66
+ * validateEmail('user@example.com'); // true
67
+ * validateEmail('invalid-email'); // false
68
+ * validateEmail('spam@mailinator.com', { blockDisposable: true }); // false
69
+ * ```
70
+ */
71
+ declare function validateEmail(email: string, options?: EmailValidationOptions): boolean;
72
+ /**
73
+ * Parses an email address to extract useful metadata.
74
+ *
75
+ * @param email - The email address to parse.
76
+ * @returns `EmailInfo` object containing details or `null` if the email is invalid.
77
+ *
78
+ * @example
79
+ * ```typescript
80
+ * import { getEmailInfo } from '@indodev/toolkit/email-validator';
81
+ *
82
+ * const info = getEmailInfo('adam@gmail.com');
83
+ * // { username: 'adam', domain: 'gmail.com', isCommonProvider: true, isDisposable: false }
84
+ * ```
85
+ */
86
+ declare function getEmailInfo(email: string): EmailInfo | null;
87
+ /**
88
+ * Masks the username portion of an email for privacy protection.
89
+ *
90
+ * Falls back to a standard mask if the username is too short to respect visibleStart/visibleEnd.
91
+ *
92
+ * @param email - The email address to mask.
93
+ * @param options - Optional masking configuration.
94
+ * @returns Masked email string or original if invalid.
95
+ *
96
+ * @example
97
+ * ```typescript
98
+ * import { maskEmail } from '@indodev/toolkit/email-validator';
99
+ *
100
+ * maskEmail('user@example.com'); // 'u**r@example.com'
101
+ * maskEmail('user@example.com', { maskChar: '#' }); // 'u##r@example.com'
102
+ * ```
103
+ */
104
+ declare function maskEmail(email: string, options?: EmailMaskOptions): string;
105
+ /**
106
+ * Normalizes an email address by trimming whitespace and converting to lowercase.
107
+ *
108
+ * @param email - The email to normalize.
109
+ * @returns Normalized email string.
110
+ *
111
+ * @example
112
+ * ```typescript
113
+ * import { normalizeEmail } from '@indodev/toolkit/email-validator';
114
+ *
115
+ * normalizeEmail(' USER@Example.COM '); // 'user@example.com'
116
+ * ```
117
+ */
118
+ declare function normalizeEmail(email: string): string;
119
+
120
+ export { type EmailValidationOptions as E, type EmailValidationResult as a, type EmailMaskOptions as b, type EmailInfo as c, getEmailInfo as g, maskEmail as m, normalizeEmail as n, validateEmail as v };
package/dist/index.cjs CHANGED
@@ -1251,6 +1251,79 @@ function validateVIN(vin) {
1251
1251
  return actualCheckDigit === expectedCheckDigit;
1252
1252
  }
1253
1253
 
1254
+ // src/email-validator/constants.ts
1255
+ var EMAIL_REGEX = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,253}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,253}[a-zA-Z0-9])?)*$/;
1256
+ var DISPOSABLE_DOMAINS = [
1257
+ "mailinator.com",
1258
+ "10minutemail.com",
1259
+ "temp-mail.org",
1260
+ "guerrillamail.com"
1261
+ ];
1262
+
1263
+ // src/email-validator/email-validator.ts
1264
+ var COMMON_PROVIDERS = ["gmail.com", "yahoo.com", "outlook.com", "hotmail.com", "icloud.com"];
1265
+ var MAX_EMAIL_LENGTH = 254;
1266
+ function validateEmail(email, options) {
1267
+ if (!email || typeof email !== "string") {
1268
+ return false;
1269
+ }
1270
+ const trimmedEmail = email.trim().toLowerCase();
1271
+ if (trimmedEmail.length > MAX_EMAIL_LENGTH) {
1272
+ return false;
1273
+ }
1274
+ const parts = trimmedEmail.split("@");
1275
+ if (parts.length !== 2) {
1276
+ return false;
1277
+ }
1278
+ const [username, domain] = parts;
1279
+ if (!username || !domain) {
1280
+ return false;
1281
+ }
1282
+ if (username.length > 64) {
1283
+ return false;
1284
+ }
1285
+ if (username.includes("..") || username.startsWith(".") || username.endsWith(".") || domain.startsWith(".") || domain.endsWith(".") || domain.includes("..")) {
1286
+ return false;
1287
+ }
1288
+ if (!EMAIL_REGEX.test(trimmedEmail)) {
1289
+ return false;
1290
+ }
1291
+ if (options?.blockDisposable) {
1292
+ if (DISPOSABLE_DOMAINS.includes(domain)) {
1293
+ return false;
1294
+ }
1295
+ }
1296
+ return true;
1297
+ }
1298
+ function getEmailInfo(email) {
1299
+ if (!validateEmail(email)) return null;
1300
+ const [username, domain] = email.trim().toLowerCase().split("@");
1301
+ return {
1302
+ username,
1303
+ domain,
1304
+ isCommonProvider: COMMON_PROVIDERS.includes(domain),
1305
+ isDisposable: DISPOSABLE_DOMAINS.includes(domain)
1306
+ };
1307
+ }
1308
+ function maskEmail(email, options) {
1309
+ if (!validateEmail(email)) return email;
1310
+ const { visibleStart = 1, visibleEnd = 1, maskChar = "*" } = options || {};
1311
+ const [username, domain] = email.split("@");
1312
+ if (username.length <= 3) {
1313
+ return `${username[0]}${maskChar.repeat(3)}@${domain}`;
1314
+ }
1315
+ const maskedLength = username.length - (visibleStart + visibleEnd);
1316
+ if (maskedLength <= 0) {
1317
+ return `${username[0]}${maskChar.repeat(3)}@${domain}`;
1318
+ }
1319
+ const start = username.slice(0, visibleStart);
1320
+ const end = username.slice(username.length - visibleEnd);
1321
+ return `${start}${maskChar.repeat(maskedLength)}${end}@${domain}`;
1322
+ }
1323
+ function normalizeEmail(email) {
1324
+ return email.trim().toLowerCase();
1325
+ }
1326
+
1254
1327
  // src/currency/format.ts
1255
1328
  function formatRupiah(amount, options) {
1256
1329
  const {
@@ -3229,6 +3302,7 @@ exports.generateSmsLink = generateSmsLink;
3229
3302
  exports.generateTelLink = generateTelLink;
3230
3303
  exports.generateWALink = generateWALink;
3231
3304
  exports.getAge = getAge;
3305
+ exports.getEmailInfo = getEmailInfo;
3232
3306
  exports.getOperator = getOperator;
3233
3307
  exports.getRegionFromPlate = getRegionFromPlate;
3234
3308
  exports.isAlay = isAlay;
@@ -3237,9 +3311,11 @@ exports.isMobileNumber = isMobileNumber;
3237
3311
  exports.isProvider = isProvider;
3238
3312
  exports.isValidForBirthDate = isValidForBirthDate;
3239
3313
  exports.isValidForGender = isValidForGender;
3314
+ exports.maskEmail = maskEmail;
3240
3315
  exports.maskNIK = maskNIK;
3241
3316
  exports.maskNPWP = maskNPWP;
3242
3317
  exports.maskPhoneNumber = maskPhoneNumber;
3318
+ exports.normalizeEmail = normalizeEmail;
3243
3319
  exports.normalizeWhitespace = normalizeWhitespace;
3244
3320
  exports.parseNIK = parseNIK;
3245
3321
  exports.parseNPWP = parseNPWP;
@@ -3260,6 +3336,7 @@ exports.toSentenceCase = toSentenceCase;
3260
3336
  exports.toTitleCase = toTitleCase;
3261
3337
  exports.toWords = toWords;
3262
3338
  exports.truncate = truncate;
3339
+ exports.validateEmail = validateEmail;
3263
3340
  exports.validateNIK = validateNIK;
3264
3341
  exports.validateNPWP = validateNPWP;
3265
3342
  exports.validatePhoneNumber = validatePhoneNumber;