qa-smart-validator 1.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/README.md +141 -0
- package/example.js +12 -0
- package/package.json +45 -0
- package/src/index.js +15 -0
- package/src/utils/ValidationError.js +20 -0
- package/src/utils/assertions.js +56 -0
- package/src/utils/safeValidate.js +32 -0
- package/src/validators/emailValidator.js +39 -0
- package/src/validators/phoneValidator.js +55 -0
- package/src/validators/stringValidator.js +59 -0
package/README.md
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# qa-smart-validator
|
|
2
|
+
|
|
3
|
+
A small, framework-agnostic validation library for QA automation. Use it in Node.js test scripts, CI checks, or any JavaScript environment (Node.js ≥ 18). No Playwright or test-runner dependency—just validators and a safe wrapper so your automation never crashes on bad input.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Email validator** – Standard format; supports gmail.com, outlook.com, yahoo.com, and custom domains (e.g. talentica.com). Rejects empty, null, and invalid formats.
|
|
8
|
+
- **String validator** – Ensures value is a string and enforces optional min/max length (after trim). Clear, controlled errors.
|
|
9
|
+
- **Phone validator** – Digits only; length 10–15. Rejects empty, null, non-digits, and out-of-range length.
|
|
10
|
+
- **safeValidate(fn)** – Wraps any sync validation in try/catch. Returns `{ valid: true, data }` or `{ valid: false, error }` so execution never throws.
|
|
11
|
+
- **ValidationError** – All validators throw this (subclass of `Error`) with `message`, `code`, and optional `field` for stable assertions and reporting.
|
|
12
|
+
|
|
13
|
+
## Requirements
|
|
14
|
+
|
|
15
|
+
- **Node.js** ≥ 18
|
|
16
|
+
- **ES Modules** (`"type": "module"` or `.mjs`)
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install qa-smart-validator
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Usage
|
|
25
|
+
|
|
26
|
+
```javascript
|
|
27
|
+
import {
|
|
28
|
+
validateEmail,
|
|
29
|
+
validateString,
|
|
30
|
+
validatePhone,
|
|
31
|
+
safeValidate,
|
|
32
|
+
ValidationError,
|
|
33
|
+
} from 'qa-smart-validator';
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Validator examples
|
|
37
|
+
|
|
38
|
+
### validateEmail(email)
|
|
39
|
+
|
|
40
|
+
Supports gmail.com, outlook.com, yahoo.com, and custom domains (e.g. talentica.com). Rejects empty, null, and invalid formats.
|
|
41
|
+
|
|
42
|
+
```javascript
|
|
43
|
+
validateEmail('user@gmail.com'); // { valid: true, message: 'Valid email' }
|
|
44
|
+
validateEmail('admin@talentica.com'); // { valid: true, message: 'Valid email' }
|
|
45
|
+
validateEmail(''); // throws ValidationError: Email cannot be empty
|
|
46
|
+
validateEmail(null); // throws ValidationError: Email is required
|
|
47
|
+
validateEmail('not-an-email'); // throws ValidationError: Invalid email format
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### validateString(value, minLength?, maxLength?)
|
|
51
|
+
|
|
52
|
+
Ensures value is a string and enforces optional min/max length (after trim).
|
|
53
|
+
|
|
54
|
+
```javascript
|
|
55
|
+
validateString('hello', 1, 10); // { valid: true, value: 'hello' }
|
|
56
|
+
validateString('short', 10); // throws ValidationError: String length 5 is less than minimum 10
|
|
57
|
+
validateString(123); // throws ValidationError: Value must be a string, got number
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### validatePhone(phone)
|
|
61
|
+
|
|
62
|
+
Digits only; length 10–15.
|
|
63
|
+
|
|
64
|
+
```javascript
|
|
65
|
+
validatePhone('1234567890'); // { valid: true, value: '1234567890' }
|
|
66
|
+
validatePhone('+1234567890'); // throws ValidationError: Phone must contain only digits
|
|
67
|
+
validatePhone('123'); // throws ValidationError: Phone length 3 is less than minimum 10
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## safeValidate example
|
|
71
|
+
|
|
72
|
+
Wraps execution in try/catch and returns a structured result. Never throws.
|
|
73
|
+
|
|
74
|
+
- **Success:** `{ valid: true, data }` – `data` is the return value of the function.
|
|
75
|
+
- **Failure:** `{ valid: false, error }` – `error` is the thrown error message.
|
|
76
|
+
|
|
77
|
+
```javascript
|
|
78
|
+
import { validateEmail, safeValidate } from 'qa-smart-validator';
|
|
79
|
+
|
|
80
|
+
const result = safeValidate(() => validateEmail('test@gmail.com'));
|
|
81
|
+
|
|
82
|
+
console.log(result);
|
|
83
|
+
// { valid: true, data: { valid: true, message: 'Valid email' } }
|
|
84
|
+
|
|
85
|
+
const failed = safeValidate(() => validateEmail(''));
|
|
86
|
+
console.log(failed);
|
|
87
|
+
// { valid: false, error: 'Email cannot be empty' }
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Example file
|
|
91
|
+
|
|
92
|
+
An `example.js` is included in the package. After installing, you can run it from your app directory:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
node example.js
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## API summary
|
|
99
|
+
|
|
100
|
+
| Export | Description |
|
|
101
|
+
|-------------------|-------------|
|
|
102
|
+
| `validateEmail` | Validates email; throws `ValidationError` on failure. |
|
|
103
|
+
| `validateString` | Validates string and optional length; throws `ValidationError` on failure. |
|
|
104
|
+
| `validatePhone` | Validates phone (digits, 10–15); throws `ValidationError` on failure. |
|
|
105
|
+
| `safeValidate(fn)`| Runs `fn()` in try/catch; returns `{ valid, data }` or `{ valid, error }`. |
|
|
106
|
+
| `ValidationError` | Error class with `message`, `code`, `field`. |
|
|
107
|
+
| `EMAIL_REGEX` | RegExp for email (advanced use). |
|
|
108
|
+
| `DIGITS_ONLY` | RegExp for digits (advanced use). |
|
|
109
|
+
| `PHONE_MIN_LENGTH` / `PHONE_MAX_LENGTH` | 10 and 15 (advanced use). |
|
|
110
|
+
|
|
111
|
+
## Contributing
|
|
112
|
+
|
|
113
|
+
1. Fork the repository.
|
|
114
|
+
2. Create a branch (`git checkout -b feature/your-feature`).
|
|
115
|
+
3. Run tests: `npm test`. Run lint: `npm run lint`. Format: `npm run format`.
|
|
116
|
+
4. Commit your changes and push the branch.
|
|
117
|
+
5. Open a Pull Request.
|
|
118
|
+
|
|
119
|
+
## Publishing to npm
|
|
120
|
+
|
|
121
|
+
Before publishing:
|
|
122
|
+
|
|
123
|
+
1. **Dry run** – See what will be packed and run lint/tests:
|
|
124
|
+
```bash
|
|
125
|
+
npm run prepublishOnly
|
|
126
|
+
npm pack
|
|
127
|
+
```
|
|
128
|
+
2. **Login** (if needed):
|
|
129
|
+
```bash
|
|
130
|
+
npm login
|
|
131
|
+
```
|
|
132
|
+
3. **Publish** (scoped packages use `--access public` for first publish):
|
|
133
|
+
```bash
|
|
134
|
+
npm publish --access public
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Update `repository`, `bugs`, `homepage`, and `author` in `package.json` to your own repo and identity before publishing.
|
|
138
|
+
|
|
139
|
+
## License
|
|
140
|
+
|
|
141
|
+
MIT
|
package/example.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Example usage of qa-smart-validator.
|
|
3
|
+
* Run from project root (after npm install): node example.js
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { validateEmail, safeValidate } from 'qa-smart-validator';
|
|
7
|
+
|
|
8
|
+
const result = safeValidate(() => validateEmail('test@gmail.com'));
|
|
9
|
+
|
|
10
|
+
console.log(result);
|
|
11
|
+
// Success: { valid: true, data: { valid: true, message: 'Valid email' } }
|
|
12
|
+
// Failure: { valid: false, error: '...' }
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "qa-smart-validator",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Reusable validation library for QA automation testing",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "src/index.js",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./src/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"src",
|
|
12
|
+
"example.js"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"test": "node --test \"test/*.js\"",
|
|
16
|
+
"lint": "eslint src",
|
|
17
|
+
"format": "prettier --write \"src/**/*.js\" \"test/**/*.js\" example.js",
|
|
18
|
+
"format:check": "prettier --check \"src/**/*.js\" \"test/**/*.js\" example.js",
|
|
19
|
+
"prepublishOnly": "npm run lint && npm run test"
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"qa",
|
|
23
|
+
"automation",
|
|
24
|
+
"validation",
|
|
25
|
+
"testing"
|
|
26
|
+
],
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"author": "Sarath Sasidharan <sarathsasidharan13031997@gmail.com>",
|
|
29
|
+
"repository": {
|
|
30
|
+
"type": "git",
|
|
31
|
+
"url": "https://github.com/your-org/qa-smart-validator.git"
|
|
32
|
+
},
|
|
33
|
+
"bugs": {
|
|
34
|
+
"url": "https://github.com/your-org/qa-smart-validator/issues"
|
|
35
|
+
},
|
|
36
|
+
"homepage": "https://github.com/your-org/qa-smart-validator#readme",
|
|
37
|
+
"engines": {
|
|
38
|
+
"node": ">=18"
|
|
39
|
+
},
|
|
40
|
+
"sideEffects": false,
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"eslint": "^9.15.0",
|
|
43
|
+
"prettier": "^3.3.3"
|
|
44
|
+
}
|
|
45
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* qa-smart-validator – Reusable validation library for QA automation.
|
|
3
|
+
* @module qa-smart-validator
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export { validateEmail, EMAIL_REGEX } from './validators/emailValidator.js';
|
|
7
|
+
export { validateString } from './validators/stringValidator.js';
|
|
8
|
+
export {
|
|
9
|
+
validatePhone,
|
|
10
|
+
DIGITS_ONLY,
|
|
11
|
+
PHONE_MIN_LENGTH,
|
|
12
|
+
PHONE_MAX_LENGTH,
|
|
13
|
+
} from './validators/phoneValidator.js';
|
|
14
|
+
export { safeValidate } from './utils/safeValidate.js';
|
|
15
|
+
export { ValidationError } from './utils/ValidationError.js';
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom error for validation failures. Use in try/catch to distinguish
|
|
3
|
+
* validation errors and assert on stable `code` / `field`.
|
|
4
|
+
* @extends Error
|
|
5
|
+
*/
|
|
6
|
+
export class ValidationError extends Error {
|
|
7
|
+
/**
|
|
8
|
+
* @param {string} message - Human-readable error message.
|
|
9
|
+
* @param {Object} [options] - Optional config.
|
|
10
|
+
* @param {string} [options.code] - Machine-readable code (e.g. 'EMAIL_INVALID').
|
|
11
|
+
* @param {string} [options.field] - Field name for form/API context.
|
|
12
|
+
*/
|
|
13
|
+
constructor(message, options = {}) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.name = 'ValidationError';
|
|
16
|
+
this.code = options.code ?? 'VALIDATION_ERROR';
|
|
17
|
+
this.field = options.field;
|
|
18
|
+
Object.setPrototypeOf(this, ValidationError.prototype);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared assertion helpers for validators. Centralizes error type and messages.
|
|
3
|
+
* @module utils/assertions
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { ValidationError } from './ValidationError.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Ensures value is a non-null, non-undefined string.
|
|
10
|
+
* @param {*} value - Value to check.
|
|
11
|
+
* @param {string} name - Name of the field (for error messages).
|
|
12
|
+
* @returns {string} Trimmed string.
|
|
13
|
+
* @throws {ValidationError}
|
|
14
|
+
*/
|
|
15
|
+
export function assertString(value, name = 'Value') {
|
|
16
|
+
if (value === undefined || value === null) {
|
|
17
|
+
throw new ValidationError(`${name} is required`, { code: 'REQUIRED' });
|
|
18
|
+
}
|
|
19
|
+
if (typeof value !== 'string') {
|
|
20
|
+
throw new ValidationError(
|
|
21
|
+
`${name} must be a string, got ${typeof value}`,
|
|
22
|
+
{ code: 'INVALID_TYPE' }
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
return value.trim();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Ensures a trimmed string is non-empty.
|
|
30
|
+
* @param {string} trimmed - Already trimmed string.
|
|
31
|
+
* @param {string} name - Field name for error message.
|
|
32
|
+
* @throws {ValidationError}
|
|
33
|
+
*/
|
|
34
|
+
export function assertNonEmpty(trimmed, name = 'Value') {
|
|
35
|
+
if (trimmed.length === 0) {
|
|
36
|
+
throw new ValidationError(`${name} cannot be empty`, { code: 'EMPTY' });
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Ensures a value is a valid non-negative number (for length constraints).
|
|
42
|
+
* @param {*} value - Value to check.
|
|
43
|
+
* @param {string} name - Parameter name for error message.
|
|
44
|
+
* @returns {number}
|
|
45
|
+
* @throws {ValidationError}
|
|
46
|
+
*/
|
|
47
|
+
export function assertNonNegativeNumber(value, name) {
|
|
48
|
+
const num = Number(value);
|
|
49
|
+
if (value === undefined || value === null || Number.isNaN(num) || num < 0) {
|
|
50
|
+
throw new ValidationError(
|
|
51
|
+
`${name} must be a non-negative number`,
|
|
52
|
+
{ code: 'INVALID_PARAMETER' }
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
return num;
|
|
56
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Safe validation wrapper for QA automation.
|
|
3
|
+
* Wraps a synchronous function in try/catch so execution never throws.
|
|
4
|
+
* @module utils/safeValidate
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Runs a synchronous validation (or any sync function) and returns a result object.
|
|
9
|
+
* Never throws; use in automation when you want a stable result shape instead of exceptions.
|
|
10
|
+
* @param {() => *} fn - Synchronous function to run (e.g. () => validateEmail(value)). No arguments.
|
|
11
|
+
* @returns {{ valid: true, data: * } | { valid: false, error: string, code?: string }} Success: `{ valid: true, data }`. Failure: `{ valid: false, error, code? }` (code from ValidationError if present).
|
|
12
|
+
* @example
|
|
13
|
+
* safeValidate(() => validateEmail('user@gmail.com'));
|
|
14
|
+
* // { valid: true, data: { valid: true, message: 'Valid email' } }
|
|
15
|
+
*
|
|
16
|
+
* safeValidate(() => validateEmail(''));
|
|
17
|
+
* // { valid: false, error: 'Email cannot be empty', code: 'EMPTY' }
|
|
18
|
+
*/
|
|
19
|
+
export function safeValidate(fn) {
|
|
20
|
+
if (typeof fn !== 'function') {
|
|
21
|
+
return { valid: false, error: 'safeValidate requires a function' };
|
|
22
|
+
}
|
|
23
|
+
try {
|
|
24
|
+
const data = fn();
|
|
25
|
+
return { valid: true, data };
|
|
26
|
+
} catch (err) {
|
|
27
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
28
|
+
const result = { valid: false, error: message };
|
|
29
|
+
if (err?.code) result.code = err.code;
|
|
30
|
+
return result;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Email validator for QA automation.
|
|
3
|
+
* Validates standard email format. Supports gmail.com, outlook.com, yahoo.com,
|
|
4
|
+
* and custom domains (e.g. talentica.com). Rejects empty, null, and invalid formats.
|
|
5
|
+
* @module validators/emailValidator
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { ValidationError } from '../utils/ValidationError.js';
|
|
9
|
+
import { assertString, assertNonEmpty } from '../utils/assertions.js';
|
|
10
|
+
|
|
11
|
+
/** Standard email format: local@domain.tld (supports common and custom domains) */
|
|
12
|
+
const EMAIL_REGEX = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Validates an email address.
|
|
16
|
+
* @param {string} email - The email string to validate.
|
|
17
|
+
* @returns {{ valid: true, message: string }} Success result with message.
|
|
18
|
+
* @throws {ValidationError} If email is empty, null, not a string, or invalid format.
|
|
19
|
+
* @example
|
|
20
|
+
* validateEmail('user@gmail.com'); // { valid: true, message: 'Valid email' }
|
|
21
|
+
* validateEmail('admin@talentica.com'); // { valid: true, message: 'Valid email' }
|
|
22
|
+
* validateEmail(''); // throws ValidationError: Email cannot be empty
|
|
23
|
+
* validateEmail(null); // throws ValidationError: Email is required
|
|
24
|
+
*/
|
|
25
|
+
export function validateEmail(email) {
|
|
26
|
+
const trimmed = assertString(email, 'Email');
|
|
27
|
+
assertNonEmpty(trimmed, 'Email');
|
|
28
|
+
|
|
29
|
+
if (!EMAIL_REGEX.test(trimmed)) {
|
|
30
|
+
throw new ValidationError(`Invalid email format: "${trimmed}"`, {
|
|
31
|
+
code: 'EMAIL_INVALID',
|
|
32
|
+
field: 'email',
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return { valid: true, message: 'Valid email' };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export { EMAIL_REGEX };
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phone validator for QA automation.
|
|
3
|
+
* Accepts only digits; length must be between 10 and 15 (inclusive).
|
|
4
|
+
* Rejects empty, null, non-string, non-digits, and out-of-range length.
|
|
5
|
+
* @module validators/phoneValidator
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { ValidationError } from '../utils/ValidationError.js';
|
|
9
|
+
import { assertString, assertNonEmpty } from '../utils/assertions.js';
|
|
10
|
+
|
|
11
|
+
/** Digits only (for phone validation) */
|
|
12
|
+
const DIGITS_ONLY = /^\d+$/;
|
|
13
|
+
|
|
14
|
+
/** Phone length bounds (inclusive) */
|
|
15
|
+
const PHONE_MIN_LENGTH = 10;
|
|
16
|
+
const PHONE_MAX_LENGTH = 15;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Validates a phone number (digits only, 10–15 characters).
|
|
20
|
+
* @param {string} phone - The phone string to validate.
|
|
21
|
+
* @returns {{ valid: true, value: string }} Success result with digit string.
|
|
22
|
+
* @throws {ValidationError} If phone is empty, null, non-string, contains non-digits, or length out of range.
|
|
23
|
+
* @example
|
|
24
|
+
* validatePhone('1234567890'); // { valid: true, value: '1234567890' }
|
|
25
|
+
* validatePhone('123'); // throws ValidationError: Phone length 3 is less than minimum 10
|
|
26
|
+
*/
|
|
27
|
+
export function validatePhone(phone) {
|
|
28
|
+
const trimmed = assertString(phone, 'Phone');
|
|
29
|
+
assertNonEmpty(trimmed, 'Phone');
|
|
30
|
+
|
|
31
|
+
if (!DIGITS_ONLY.test(trimmed)) {
|
|
32
|
+
throw new ValidationError('Phone must contain only digits', {
|
|
33
|
+
code: 'PHONE_INVALID',
|
|
34
|
+
field: 'phone',
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (trimmed.length < PHONE_MIN_LENGTH) {
|
|
39
|
+
throw new ValidationError(
|
|
40
|
+
`Phone length ${trimmed.length} is less than minimum ${PHONE_MIN_LENGTH}`,
|
|
41
|
+
{ code: 'PHONE_TOO_SHORT', field: 'phone' }
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (trimmed.length > PHONE_MAX_LENGTH) {
|
|
46
|
+
throw new ValidationError(
|
|
47
|
+
`Phone length ${trimmed.length} exceeds maximum ${PHONE_MAX_LENGTH}`,
|
|
48
|
+
{ code: 'PHONE_TOO_LONG', field: 'phone' }
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return { valid: true, value: trimmed };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export { DIGITS_ONLY, PHONE_MIN_LENGTH, PHONE_MAX_LENGTH };
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* String validator for QA automation.
|
|
3
|
+
* Ensures value is a string and enforces optional min/max length (after trim).
|
|
4
|
+
* @module validators/stringValidator
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { ValidationError } from '../utils/ValidationError.js';
|
|
8
|
+
import {
|
|
9
|
+
assertString,
|
|
10
|
+
assertNonNegativeNumber,
|
|
11
|
+
} from '../utils/assertions.js';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Validates a string value with optional length constraints.
|
|
15
|
+
* Value is trimmed before length checks. Throws controlled ValidationError for invalid input.
|
|
16
|
+
* @param {*} value - The value to validate (must be a string).
|
|
17
|
+
* @param {number} [minLength] - Minimum length (inclusive). Omit for no minimum.
|
|
18
|
+
* @param {number} [maxLength] - Maximum length (inclusive). Omit for no maximum.
|
|
19
|
+
* @returns {{ valid: true, value: string }} Success result with trimmed value.
|
|
20
|
+
* @throws {ValidationError} If value is null/undefined, not a string, or fails length validation.
|
|
21
|
+
* @example
|
|
22
|
+
* validateString('hello', 1, 10); // { valid: true, value: 'hello' }
|
|
23
|
+
* validateString(123); // throws ValidationError: Value must be a string, got number
|
|
24
|
+
*/
|
|
25
|
+
export function validateString(value, minLength, maxLength) {
|
|
26
|
+
const trimmed = assertString(value, 'Value');
|
|
27
|
+
|
|
28
|
+
if (minLength !== undefined && minLength !== null) {
|
|
29
|
+
const min = assertNonNegativeNumber(minLength, 'minLength');
|
|
30
|
+
if (trimmed.length < min) {
|
|
31
|
+
throw new ValidationError(
|
|
32
|
+
`String length ${trimmed.length} is less than minimum ${min}`,
|
|
33
|
+
{ code: 'STRING_TOO_SHORT', field: 'value' }
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (maxLength !== undefined && maxLength !== null) {
|
|
39
|
+
const max = assertNonNegativeNumber(maxLength, 'maxLength');
|
|
40
|
+
if (trimmed.length > max) {
|
|
41
|
+
throw new ValidationError(
|
|
42
|
+
`String length ${trimmed.length} exceeds maximum ${max}`,
|
|
43
|
+
{ code: 'STRING_TOO_LONG', field: 'value' }
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (
|
|
49
|
+
minLength != null &&
|
|
50
|
+
maxLength != null &&
|
|
51
|
+
Number(minLength) > Number(maxLength)
|
|
52
|
+
) {
|
|
53
|
+
throw new ValidationError('minLength cannot be greater than maxLength', {
|
|
54
|
+
code: 'INVALID_PARAMETER',
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return { valid: true, value: trimmed };
|
|
59
|
+
}
|