nino-validator
Version:
A lightweight npm package for validating UK National Insurance Numbers (NINO)
555 lines (417 loc) • 15.3 kB
Markdown
# NINO Validator
[](https://badge.fury.io/js/nino-validator)
[](https://opensource.org/licenses/MIT)
A lightweight, fast, and comprehensive npm package for validating UK National Insurance Numbers (NINO) with full compliance to HMRC rules.
## Features
- ✅ **Complete HMRC compliance** - Validates against all official NINO rules
- 🚀 **Blazing fast** - 5M+ ops/sec, zero dependencies, all functions rated "Excellent"
- 🛡️ **Type safe** - Full JSDoc documentation with TypeScript-friendly types
- 🔧 **Flexible options** - Configurable validation behavior
- 🎯 **100% test coverage** - Thoroughly tested with comprehensive test suite
- 📱 **Cross-platform** - Works in Node.js and browsers
- 📦 **Dual package** - Supports both CommonJS and ES Modules (ESM)
- 🏷️ **TypeScript ready** - Includes TypeScript declaration files
## Installation
```bash
npm install nino-validator
```
## Quick Start
### CommonJS (Node.js)
```javascript
const { validateNINO } = require('nino-validator');
// Simple validation
console.log(validateNINO('AB123456C')); // true
console.log(validateNINO('invalid')); // false
```
### ES Modules (ESM)
```javascript
import { validateNINO } from 'nino-validator';
// Simple validation
console.log(validateNINO('AB123456C')); // true
console.log(validateNINO('invalid')); // false
```
### TypeScript
```typescript
import { validateNINO, ValidationOptions } from 'nino-validator';
const options: ValidationOptions = { requireSuffix: true };
const isValid: boolean = validateNINO('AB123456C', options);
```
## Complete Usage Guide
### Basic Validation
**CommonJS:**
```javascript
const { validateNINO, formatNINO, parseNINO, generateRandomNINO } = require('nino-validator');
```
**ES Modules:**
```javascript
import { validateNINO, formatNINO, parseNINO, generateRandomNINO } from 'nino-validator';
```
**Usage (same for both formats):**
```javascript
// Validate different NINO formats
validateNINO('AB123456C'); // true - standard format
validateNINO('AB123456'); // true - suffix optional by default
validateNINO('ab123456c'); // true - case insensitive
validateNINO('AB 12 34 56 C'); // true - spaces allowed by default
validateNINO(' AB123456C '); // true - whitespace trimmed
validateNINO('invalid-nino'); // false - invalid format
```
### Advanced Validation Options
```javascript
// Require suffix letter
validateNINO('AB123456', { requireSuffix: true }); // false - no suffix
validateNINO('AB123456C', { requireSuffix: true }); // true - has suffix
// Strict formatting (no spaces allowed)
validateNINO('AB 12 34 56 C', { allowSpaces: false }); // false - contains spaces
validateNINO('AB123456C', { allowSpaces: false }); // true - no spaces
// Combine options
validateNINO('AB123456C', {
requireSuffix: true,
allowSpaces: false
}); // true
```
### Formatting NINOs
```javascript
// Standard formatting with spaces
formatNINO('AB123456C'); // 'AB 12 34 56 C'
formatNINO('ab123456c'); // 'AB 12 34 56 C' (normalized)
formatNINO('AB123456'); // 'AB 12 34 56' (no suffix)
formatNINO('invalid'); // null (invalid NINO)
// Clean up user input
const userInput = ' ab 12 34 56 c ';
const formatted = formatNINO(userInput); // 'AB 12 34 56 C'
```
### Parsing NINO Components
```javascript
// Extract all components
const result = parseNINO('AB123456C');
console.log(result);
// Output:
// {
// prefix: 'AB',
// numbers: '123456',
// suffix: 'C',
// formatted: 'AB 12 34 56 C',
// original: 'AB123456C'
// }
// Handle NINOs without suffix
const noSuffix = parseNINO('AB123456');
console.log(noSuffix.suffix); // null
// Invalid NINOs return null
parseNINO('invalid'); // null
```
### Generate Test Data
```javascript
// Generate random valid NINOs for testing
const testNINO = generateRandomNINO();
console.log(testNINO); // e.g., 'JG123789A'
console.log(validateNINO(testNINO)); // always true
// Generate multiple test cases
const testCases = Array.from({ length: 10 }, () => generateRandomNINO());
console.log(testCases);
// ['AB123456C', 'JK789012G', 'MN345678P', ...]
```
## API Reference
### `validateNINO(nino, options?)`
Validates a UK National Insurance Number against HMRC rules.
**Parameters:**
- `nino` (string): The NINO to validate
- `options` (object, optional):
- `allowSpaces` (boolean, default: `true`): Allow spaces in the input
- `requireSuffix` (boolean, default: `false`): Require the suffix letter
**Returns:** `boolean` - `true` if valid, `false` otherwise
**Example:**
```javascript
validateNINO('AB123456C'); // true
validateNINO('AB123456', { requireSuffix: true }); // false
```
### `formatNINO(nino)`
Formats a NINO with standard UK government spacing (XX ## ## ## X).
**Parameters:**
- `nino` (string): The NINO to format
**Returns:** `string | null` - Formatted NINO or `null` if invalid
**Example:**
```javascript
formatNINO('AB123456C'); // 'AB 12 34 56 C'
formatNINO('invalid'); // null
```
### `parseNINO(nino)`
Extracts and validates components from a NINO.
**Parameters:**
- `nino` (string): The NINO to parse
**Returns:** `object | null` - Components object or `null` if invalid
**Return object structure:**
```typescript
{
prefix: string; // Two-letter prefix (e.g., 'AB')
numbers: string; // Six-digit number (e.g., '123456')
suffix: string | null; // Single suffix letter or null
formatted: string; // Standardized format
original: string; // Original input
}
```
### `generateRandomNINO()`
Generates a random valid NINO for testing purposes.
**Returns:** `string` - A randomly generated valid NINO
**Example:**
```javascript
const testNINO = generateRandomNINO(); // 'JK789012M'
```
### `validateNINOWithDetails(nino, options?)`
Provides detailed validation with localized error messages.
**Parameters:**
- `nino` (string): The NINO to validate
- `options` (object, optional): Same as `validateNINO()`
**Returns:** `ValidationResult` - Detailed validation result
**Return object structure:**
```typescript
{
isValid: boolean;
error: string | null; // Localized error message
errorCode: string | null; // Machine-readable error code
suggestion: string | null; // Localized suggestion
}
```
**Example:**
```javascript
const result = validateNINOWithDetails('AB123');
console.log(result);
// {
// isValid: false,
// error: 'NINO too short (5 characters). Minimum 8 characters required',
// errorCode: 'TOO_SHORT',
// suggestion: 'Ensure the NINO has 2 letters, 6 digits, and optionally 1 letter'
// }
```
## Internationalization (i18n)
The NINO Validator supports multiple languages for error messages. Currently supported languages are English (`en`) and Greek (`el`).
### Language Management
```javascript
const {
setLanguage,
getCurrentLanguage,
getSupportedLanguages,
isLanguageSupported
} = require('nino-validator');
// Check supported languages
console.log(getSupportedLanguages());
// { en: 'English', el: 'Ελληνικά (Greek)' }
// Switch to Greek
setLanguage('el');
console.log(getCurrentLanguage()); // 'el'
// Validate with Greek error messages
const result = validateNINOWithDetails('invalid');
console.log(result.error);
// 'Μη έγκυρη μορφή NINO. Αναμενόμενη μορφή: XX123456X (το επίθημα είναι προαιρετικό)'
// Switch back to English
setLanguage('en');
```
### Auto-Detection and Initialization
```javascript
const { detectLanguage, initializeI18n } = require('nino-validator');
// Auto-detect language from environment
const detected = detectLanguage();
console.log(detected); // 'el' if Greek locale detected
// Initialize with auto-detection
const language = initializeI18n({ autoDetect: true });
console.log(`Language set to: ${language}`);
// Initialize with fallback
initializeI18n({
autoDetect: true,
fallbackLanguage: 'el'
});
```
### Language Support Features
- **Consistent Error Codes**: Error codes remain the same across languages for programmatic handling
- **Parameter Interpolation**: Dynamic values (like lengths, invalid characters) are properly inserted into translated messages
- **Environment Detection**: Automatically detects language from Node.js environment variables or browser settings
- **Fallback Handling**: Gracefully falls back to English if requested language is not supported
### Adding New Languages
To add support for additional languages, error messages need to be translated in the internal message files. Contact the maintainer for language addition requests.
## NINO Validation Rules
This package validates against all official HMRC rules:
### ✅ Valid Format
- **Structure**: Two letters + Six digits + One optional letter
- **Example**: `AB123456C` or `AB123456`
### ❌ Invalid Patterns
1. **Invalid Prefixes**: BG, GB, NK, KN, TN, NT, ZZ, and all combinations starting with D, F, G, I, N, O, Q, U, V
2. **Invalid First Letters**: D, F, I, Q, U, V
3. **Invalid Second Letters**: D, F, I, Q, U, V
4. **Invalid Suffixes**: D, F, I, Q, U, V
5. **Repeated Numbers**: All six digits cannot be identical (e.g., 111111)
### Examples
```javascript
// ✅ Valid NINOs
'AB123456C' // Standard format
'AB123456' // Without suffix
'JG103759A' // Real-world example
'AB 12 34 56 C' // With spaces
// ❌ Invalid NINOs
'BG123456C' // Invalid prefix 'BG'
'AB111111C' // All digits the same
'AB123456D' // Invalid suffix 'D'
'DA123456C' // Invalid first letter 'D'
'AB12345' // Too few digits
'A1234567' // Wrong format
```
## Error Handling
The package handles errors gracefully:
```javascript
// Type safety
validateNINO(null); // false
validateNINO(undefined); // false
validateNINO(123456789); // false
validateNINO(''); // false
// Invalid formats return null
formatNINO('invalid'); // null
parseNINO('invalid'); // null
// Options validation
validateNINO('AB123456C', { invalidOption: true }); // Works (ignores invalid options)
```
## Performance
NINO Validator is designed for high performance with comprehensive benchmarking:
- **Zero dependencies** - No external packages required
- **Fast validation** - Optimized regex and lookup operations
- **Memory efficient** - Minimal memory footprint
- **Browser compatible** - Works in all modern browsers
### Performance Benchmarks
Run comprehensive performance tests:
```bash
# Full benchmark suite with detailed analysis
npm run benchmark
# Quick CI-friendly performance check
npm run benchmark:ci
# Memory-focused benchmarks with GC control
npm run benchmark:memory
```
**Sample Benchmark Output:**
```
⚡ NINO Validator CI Benchmarks
===============================
✅ validateNINO (valid) | 2,350,000 ops/sec | 0.4μs/op
✅ validateNINO (invalid) | 5,150,000 ops/sec | 0.2μs/op
✅ formatNINO | 915,000 ops/sec | 1.1μs/op
✅ parseNINO | 800,000 ops/sec | 1.2μs/op
✅ generateRandomNINO | 575,000 ops/sec | 1.7μs/op
✅ Bulk validation | 3,000,000 ops/sec | 0.3μs/op
🎯 Performance check: ✅ PASS
```
### Typical Performance Results
On modern hardware (Node.js v18+):
| Function | Operations/Second | Rating | Use Case |
|----------|------------------|--------|----------|
| `validateNINO` (valid) | 2,350,000+ | 🟢 Excellent | Form validation |
| `validateNINO` (invalid) | 5,150,000+ | 🟢 Excellent | Input filtering |
| `formatNINO` | 915,000+ | 🟢 Excellent | Display formatting |
| `parseNINO` | 800,000+ | 🟢 Excellent | Data extraction |
| `generateRandomNINO` | 575,000+ | 🟢 Excellent | Test data generation |
| **Bulk validation** | **3,000,000+** | 🟢 **Excellent** | **Batch processing** |
### Performance Ratings Scale
| Rating | Operations/Second | Description |
|--------|------------------|-------------|
| 🟢 Excellent | ≥100,000 | Outstanding performance |
| 🟡 Good | ≥10,000 | Acceptable performance |
| 🔴 Poor | <10,000 | May need optimization |
**Performance Insights:**
- Invalid inputs are validated ~2x faster than valid ones (short-circuit validation)
- Bulk operations can process over **3 million NINOs per second**
- Memory usage is minimal (~0.1MB for 10,000 operations)
- All functions consistently achieve "Excellent" performance ratings
- Zero performance degradation with large datasets
See [benchmark documentation](./benchmark/README.md) for detailed performance analysis and optimization tips.
## Browser Usage
```html
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/nino-validator@latest/index.js"></script>
</head>
<body>
<script>
// Use the global ninoValidator object
console.log(ninoValidator.validateNINO('AB123456C')); // true
</script>
</body>
</html>
```
## TypeScript Support
While this package is written in JavaScript, it includes comprehensive JSDoc comments for TypeScript IntelliSense:
```typescript
import { validateNINO, formatNINO, parseNINO, generateRandomNINO } from 'nino-validator';
const isValid: boolean = validateNINO('AB123456C');
const formatted: string | null = formatNINO('AB123456C');
```
## Testing
```bash
# Run tests
npm test
# Run tests with coverage
npm run test:coverage
# Run linting
npm run lint
```
## Real-World Examples
### Form Validation
```javascript
function validateNINOInput(input) {
const nino = input.trim();
if (!nino) {
return { valid: false, error: 'NINO is required' };
}
if (!validateNINO(nino)) {
return { valid: false, error: 'Invalid NINO format' };
}
return { valid: true, formatted: formatNINO(nino) };
}
// Usage
const result = validateNINOInput(' ab 12 34 56 c ');
console.log(result); // { valid: true, formatted: 'AB 12 34 56 C' }
```
### Database Storage
```javascript
function normalizeNINO(input) {
const parsed = parseNINO(input);
if (!parsed) return null;
return {
prefix: parsed.prefix,
numbers: parsed.numbers,
suffix: parsed.suffix,
display: parsed.formatted
};
}
```
### Test Data Generation
```javascript
function createTestUser() {
return {
id: Math.random().toString(36),
nino: generateRandomNINO(),
name: 'Test User'
};
}
```
## Changelog
See [CHANGELOG.md](CHANGELOG.md) for version history.
## Contributing
Contributions are welcome! Please:
1. Fork the repository
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
3. Make your changes
4. Add tests for new functionality
5. Ensure all tests pass (`npm test`)
6. Commit your changes (`git commit -m 'Add amazing feature'`)
7. Push to the branch (`git push origin feature/amazing-feature`)
8. Open a Pull Request
### Development Setup
```bash
git clone https://github.com/icodenet/nino-validator.git
cd nino-validator
npm install
npm test
```
## License
MIT © [Byron Thanopoulos](https://github.com/icodenet)
## Support
- 📧 Email: byron.thanopoulos@gmail.com
- 🐛 Issues: [GitHub Issues](https://github.com/icodenet/nino-validator/issues)
- 💬 Discussions: [GitHub Discussions](https://github.com/icodenet/nino-validator/discussions)