@avi_k/container-number-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/LICENSE +15 -0
- package/README.md +189 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +27 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +44 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +167 -0
- package/dist/index.js.map +1 -0
- package/package.json +44 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
ISC License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025, AVINASH KOTHARI
|
|
4
|
+
|
|
5
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
6
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
7
|
+
copyright notice and this permission notice appear in all copies.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
10
|
+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
11
|
+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
12
|
+
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
13
|
+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
14
|
+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
15
|
+
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# Container Number Validator
|
|
2
|
+
|
|
3
|
+
A TypeScript/JavaScript library for validating, parsing, and generating ISO 6346 shipping container numbers.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- โ
**Validate** container numbers against ISO 6346 standard
|
|
8
|
+
- ๐ **Parse** container numbers into components (owner code, equipment category, serial number, check digit)
|
|
9
|
+
- ๐ฏ **Calculate** check digits using the official algorithm
|
|
10
|
+
- ๐๏ธ **Generate** valid container numbers from components
|
|
11
|
+
- ๐ **Format** container numbers for display
|
|
12
|
+
- ๐ฏ **100% TypeScript** with full type definitions
|
|
13
|
+
- ๐งช **Fully tested** with comprehensive test suite
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install container-number-validator
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
### Basic Validation
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
import { isValidContainerNumber } from 'container-number-validator';
|
|
27
|
+
|
|
28
|
+
console.log(isValidContainerNumber('MSCU5285725')); // true
|
|
29
|
+
console.log(isValidContainerNumber('INVALID123')); // false
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Parse Container Number
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
import { parseContainerNumber } from 'container-number-validator';
|
|
36
|
+
|
|
37
|
+
const result = parseContainerNumber('MSCU5285725');
|
|
38
|
+
|
|
39
|
+
if (result.isValid) {
|
|
40
|
+
console.log(result.parts);
|
|
41
|
+
// {
|
|
42
|
+
// ownerCode: 'MSC',
|
|
43
|
+
// equipmentCategory: 'U',
|
|
44
|
+
// serialNumber: '528572',
|
|
45
|
+
// checkDigit: 5,
|
|
46
|
+
// raw: 'MSCU5285725'
|
|
47
|
+
// }
|
|
48
|
+
} else {
|
|
49
|
+
console.error(result.error);
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Generate Container Number
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
import { generateContainerNumber } from 'container-number-validator';
|
|
57
|
+
|
|
58
|
+
const containerNumber = generateContainerNumber('MSC', 'U', '528572');
|
|
59
|
+
console.log(containerNumber); // 'MSCU5285725'
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Calculate Check Digit
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
import { calculateCheckDigit } from 'container-number-validator';
|
|
66
|
+
|
|
67
|
+
const checkDigit = calculateCheckDigit('MSC', 'U', '528572');
|
|
68
|
+
console.log(checkDigit); // 5
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Format for Display
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
import { formatContainerNumber } from 'container-number-validator';
|
|
75
|
+
|
|
76
|
+
const formatted = formatContainerNumber('MSCU5285725');
|
|
77
|
+
console.log(formatted); // 'MSCU 528572 [5]'
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Get Equipment Description
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
import { getEquipmentDescription } from 'container-number-validator';
|
|
84
|
+
|
|
85
|
+
console.log(getEquipmentDescription('U')); // 'All freight containers'
|
|
86
|
+
console.log(getEquipmentDescription('J')); // 'Equipment related to freight containers (detachable)'
|
|
87
|
+
console.log(getEquipmentDescription('Z')); // 'Trailers or chassis'
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Container Number Format
|
|
91
|
+
|
|
92
|
+
A valid container number consists of 11 characters:
|
|
93
|
+
|
|
94
|
+
1. **Owner Code** (3 letters): Identifies the container owner (e.g., MSC, HLXU, TLLU)
|
|
95
|
+
2. **Equipment Category** (1 letter): Type of equipment
|
|
96
|
+
- `U` - All freight containers
|
|
97
|
+
- `J` - Equipment related to freight containers (detachable)
|
|
98
|
+
- `Z` - Trailers or chassis
|
|
99
|
+
3. **Serial Number** (6 digits): Unique identifier assigned by the owner
|
|
100
|
+
4. **Check Digit** (1 digit): Validation digit calculated using ISO 6346 algorithm
|
|
101
|
+
|
|
102
|
+
### Example Breakdown
|
|
103
|
+
|
|
104
|
+
Container Number: `MSCU5285725`
|
|
105
|
+
|
|
106
|
+
```
|
|
107
|
+
MSC U 528572 5
|
|
108
|
+
โ โ โ โ
|
|
109
|
+
โ โ โ โโ Check Digit
|
|
110
|
+
โ โ โโโโโโโโโ Serial Number
|
|
111
|
+
โ โโโโโโโโโโโโโโโโ Equipment Category (U = freight container)
|
|
112
|
+
โโโโโโโโโโโโโโโโโโโโโโ Owner Code (MSC = Mediterranean Shipping Company)
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## API Reference
|
|
116
|
+
|
|
117
|
+
### Types
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
type EquipmentCategory = 'U' | 'J' | 'Z';
|
|
121
|
+
|
|
122
|
+
interface ContainerNumberParts {
|
|
123
|
+
ownerCode: string;
|
|
124
|
+
equipmentCategory: EquipmentCategory;
|
|
125
|
+
serialNumber: string;
|
|
126
|
+
checkDigit: number;
|
|
127
|
+
raw: string;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
interface ValidationResult {
|
|
131
|
+
isValid: boolean;
|
|
132
|
+
error?: string;
|
|
133
|
+
parts?: ContainerNumberParts;
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Functions
|
|
138
|
+
|
|
139
|
+
#### `parseContainerNumber(containerNumber: string): ValidationResult`
|
|
140
|
+
|
|
141
|
+
Parses and validates a container number, returning detailed information about its components.
|
|
142
|
+
|
|
143
|
+
#### `isValidContainerNumber(containerNumber: string): boolean`
|
|
144
|
+
|
|
145
|
+
Simple validation that returns true if the container number is valid.
|
|
146
|
+
|
|
147
|
+
#### `calculateCheckDigit(ownerCode: string, equipmentCategory: string, serialNumber: string): number`
|
|
148
|
+
|
|
149
|
+
Calculates the check digit for a container number using the ISO 6346 algorithm.
|
|
150
|
+
|
|
151
|
+
#### `generateContainerNumber(ownerCode: string, equipmentCategory: EquipmentCategory, serialNumber: string): string`
|
|
152
|
+
|
|
153
|
+
Generates a complete valid container number with check digit.
|
|
154
|
+
|
|
155
|
+
#### `formatContainerNumber(containerNumber: string): string`
|
|
156
|
+
|
|
157
|
+
Formats a container number for display with spacing and bracketed check digit.
|
|
158
|
+
|
|
159
|
+
#### `getEquipmentDescription(category: EquipmentCategory): string`
|
|
160
|
+
|
|
161
|
+
Returns the description for an equipment category code.
|
|
162
|
+
|
|
163
|
+
## Standards
|
|
164
|
+
|
|
165
|
+
This library implements the **ISO 6346** standard for shipping container identification.
|
|
166
|
+
|
|
167
|
+
## Testing
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
npm test
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## License
|
|
174
|
+
|
|
175
|
+
ISC
|
|
176
|
+
|
|
177
|
+
## Contributing
|
|
178
|
+
|
|
179
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
180
|
+
|
|
181
|
+
## Known Owner Codes
|
|
182
|
+
|
|
183
|
+
- **MSC** - Mediterranean Shipping Company
|
|
184
|
+
- **HLXU** - Hapag Lloyd
|
|
185
|
+
- **TLLU** - Triton Containers International Limited
|
|
186
|
+
- **CMAU** - CMA CGM
|
|
187
|
+
- **MAEU** - Maersk Line
|
|
188
|
+
|
|
189
|
+
_Note: Owner codes are registered with the Bureau International des Containers (BIC)._
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const index_1 = require("./index");
|
|
5
|
+
const args = process.argv.slice(2);
|
|
6
|
+
if (args.length === 0) {
|
|
7
|
+
console.log('Usage: container-validator <container-number>');
|
|
8
|
+
console.log('Example: container-validator MSCU5285725');
|
|
9
|
+
process.exit(1);
|
|
10
|
+
}
|
|
11
|
+
const containerNumber = args[0];
|
|
12
|
+
const result = (0, index_1.parseContainerNumber)(containerNumber);
|
|
13
|
+
if (result.isValid && result.parts) {
|
|
14
|
+
console.log('\nโ
Valid Container Number\n');
|
|
15
|
+
console.log('Formatted:', (0, index_1.formatContainerNumber)(containerNumber));
|
|
16
|
+
console.log('\nBreakdown:');
|
|
17
|
+
console.log(' Owner Code:', result.parts.ownerCode);
|
|
18
|
+
console.log(' Equipment Category:', result.parts.equipmentCategory);
|
|
19
|
+
console.log(' Serial Number:', result.parts.serialNumber);
|
|
20
|
+
console.log(' Check Digit:', result.parts.checkDigit);
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
console.log('\nโ Invalid Container Number\n');
|
|
24
|
+
console.log('Error:', result.error);
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";;;AAEA,mCAAsE;AAEtE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAEnC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;IACtB,OAAO,CAAC,GAAG,CAAC,+CAA+C,CAAC,CAAC;IAC7D,OAAO,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC;IACxD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,eAAe,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;AAChC,MAAM,MAAM,GAAG,IAAA,4BAAoB,EAAC,eAAe,CAAC,CAAC;AAErD,IAAI,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;IACnC,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC;IAC5C,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,IAAA,6BAAqB,EAAC,eAAe,CAAC,CAAC,CAAC;IAClE,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAC5B,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IACrD,OAAO,CAAC,GAAG,CAAC,uBAAuB,EAAE,MAAM,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;IACrE,OAAO,CAAC,GAAG,CAAC,kBAAkB,EAAE,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;IAC3D,OAAO,CAAC,GAAG,CAAC,gBAAgB,EAAE,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;AACzD,CAAC;KAAM,CAAC;IACN,OAAO,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC;IAC9C,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;IACpC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Container Number Validator & Parser
|
|
3
|
+
* Validates and parses ISO 6346 shipping container numbers
|
|
4
|
+
*/
|
|
5
|
+
type EquipmentCategory = 'U' | 'J' | 'Z';
|
|
6
|
+
interface ContainerNumberParts {
|
|
7
|
+
ownerCode: string;
|
|
8
|
+
equipmentCategory: EquipmentCategory;
|
|
9
|
+
serialNumber: string;
|
|
10
|
+
checkDigit: number;
|
|
11
|
+
raw: string;
|
|
12
|
+
}
|
|
13
|
+
interface ValidationResult {
|
|
14
|
+
isValid: boolean;
|
|
15
|
+
error?: string;
|
|
16
|
+
parts?: ContainerNumberParts;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Calculates the check digit for a container number
|
|
20
|
+
* Based on ISO 6346 standard
|
|
21
|
+
*/
|
|
22
|
+
export declare function calculateCheckDigit(ownerCode: string, equipmentCategory: string, serialNumber: string): number;
|
|
23
|
+
/**
|
|
24
|
+
* Parses a container number string into its components
|
|
25
|
+
*/
|
|
26
|
+
export declare function parseContainerNumber(containerNumber: string): ValidationResult;
|
|
27
|
+
/**
|
|
28
|
+
* Validates a container number (returns only boolean)
|
|
29
|
+
*/
|
|
30
|
+
export declare function isValidContainerNumber(containerNumber: string): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Formats a container number for display
|
|
33
|
+
*/
|
|
34
|
+
export declare function formatContainerNumber(containerNumber: string): string;
|
|
35
|
+
/**
|
|
36
|
+
* Generates a container number from components
|
|
37
|
+
*/
|
|
38
|
+
export declare function generateContainerNumber(ownerCode: string, equipmentCategory: EquipmentCategory, serialNumber: string): string;
|
|
39
|
+
/**
|
|
40
|
+
* Gets equipment description from category code
|
|
41
|
+
*/
|
|
42
|
+
export declare function getEquipmentDescription(category: EquipmentCategory): string;
|
|
43
|
+
export {};
|
|
44
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,KAAK,iBAAiB,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;AAEzC,UAAU,oBAAoB;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,iBAAiB,CAAC;IACrC,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,UAAU,gBAAgB;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,oBAAoB,CAAC;CAC9B;AAyBD;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CA+B9G;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,eAAe,EAAE,MAAM,GAAG,gBAAgB,CA8E9E;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,eAAe,EAAE,MAAM,GAAG,OAAO,CAEvE;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,eAAe,EAAE,MAAM,GAAG,MAAM,CAWrE;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,EACjB,iBAAiB,EAAE,iBAAiB,EACpC,YAAY,EAAE,MAAM,GACnB,MAAM,CAGR;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,iBAAiB,GAAG,MAAM,CAE3E"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Container Number Validator & Parser
|
|
4
|
+
* Validates and parses ISO 6346 shipping container numbers
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.calculateCheckDigit = calculateCheckDigit;
|
|
8
|
+
exports.parseContainerNumber = parseContainerNumber;
|
|
9
|
+
exports.isValidContainerNumber = isValidContainerNumber;
|
|
10
|
+
exports.formatContainerNumber = formatContainerNumber;
|
|
11
|
+
exports.generateContainerNumber = generateContainerNumber;
|
|
12
|
+
exports.getEquipmentDescription = getEquipmentDescription;
|
|
13
|
+
/**
|
|
14
|
+
* Equipment category codes
|
|
15
|
+
*/
|
|
16
|
+
const EQUIPMENT_CATEGORIES = {
|
|
17
|
+
U: 'All freight containers',
|
|
18
|
+
J: 'Equipment related to freight containers (detachable)',
|
|
19
|
+
Z: 'Trailers or chassis'
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Validates if a character is a valid letter (A-Z)
|
|
23
|
+
*/
|
|
24
|
+
function isValidLetter(char) {
|
|
25
|
+
return /^[A-Z]$/.test(char);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Validates if a character is a valid digit (0-9)
|
|
29
|
+
*/
|
|
30
|
+
function isValidDigit(char) {
|
|
31
|
+
return /^[0-9]$/.test(char);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Calculates the check digit for a container number
|
|
35
|
+
* Based on ISO 6346 standard
|
|
36
|
+
*/
|
|
37
|
+
function calculateCheckDigit(ownerCode, equipmentCategory, serialNumber) {
|
|
38
|
+
const containerPrefix = ownerCode + equipmentCategory + serialNumber;
|
|
39
|
+
// Conversion table: A=10, B=12, C=13, ..., Z=38
|
|
40
|
+
const letterValues = {
|
|
41
|
+
A: 10, B: 12, C: 13, D: 14, E: 15, F: 16, G: 17, H: 18, I: 19, J: 20,
|
|
42
|
+
K: 21, L: 23, M: 24, N: 25, O: 26, P: 27, Q: 28, R: 29, S: 30, T: 31,
|
|
43
|
+
U: 32, V: 34, W: 35, X: 36, Y: 37, Z: 38
|
|
44
|
+
};
|
|
45
|
+
let sum = 0;
|
|
46
|
+
// Process each character
|
|
47
|
+
for (let i = 0; i < containerPrefix.length; i++) {
|
|
48
|
+
const char = containerPrefix[i];
|
|
49
|
+
const position = i + 1;
|
|
50
|
+
let value;
|
|
51
|
+
if (isValidLetter(char)) {
|
|
52
|
+
value = letterValues[char];
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
value = parseInt(char, 10);
|
|
56
|
+
}
|
|
57
|
+
// Multiply by 2^position
|
|
58
|
+
sum += value * Math.pow(2, position - 1);
|
|
59
|
+
}
|
|
60
|
+
// Calculate check digit: sum mod 11, if 10 then use 0
|
|
61
|
+
const checkDigit = sum % 11;
|
|
62
|
+
return checkDigit === 10 ? 0 : checkDigit;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Parses a container number string into its components
|
|
66
|
+
*/
|
|
67
|
+
function parseContainerNumber(containerNumber) {
|
|
68
|
+
// Remove any spaces and convert to uppercase
|
|
69
|
+
const cleaned = containerNumber.replace(/\s+/g, '').toUpperCase();
|
|
70
|
+
// Check length (must be 11 characters)
|
|
71
|
+
if (cleaned.length !== 11) {
|
|
72
|
+
return {
|
|
73
|
+
isValid: false,
|
|
74
|
+
error: `Invalid length: expected 11 characters, got ${cleaned.length}`
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
// Extract parts
|
|
78
|
+
const ownerCode = cleaned.substring(0, 3);
|
|
79
|
+
const equipmentCategory = cleaned.substring(3, 4);
|
|
80
|
+
const serialNumber = cleaned.substring(4, 10);
|
|
81
|
+
const checkDigitStr = cleaned.substring(10, 11);
|
|
82
|
+
// Validate owner code (first 3 characters must be letters)
|
|
83
|
+
for (let i = 0; i < 3; i++) {
|
|
84
|
+
if (!isValidLetter(ownerCode[i])) {
|
|
85
|
+
return {
|
|
86
|
+
isValid: false,
|
|
87
|
+
error: `Invalid owner code: character at position ${i + 1} must be a letter (A-Z)`
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// Validate equipment category (4th character)
|
|
92
|
+
if (!['U', 'J', 'Z'].includes(equipmentCategory)) {
|
|
93
|
+
return {
|
|
94
|
+
isValid: false,
|
|
95
|
+
error: `Invalid equipment category: must be U, J, or Z, got '${equipmentCategory}'`
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
// Validate serial number (next 6 characters must be digits)
|
|
99
|
+
for (let i = 0; i < 6; i++) {
|
|
100
|
+
if (!isValidDigit(serialNumber[i])) {
|
|
101
|
+
return {
|
|
102
|
+
isValid: false,
|
|
103
|
+
error: `Invalid serial number: character at position ${i + 5} must be a digit (0-9)`
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// Validate check digit (last character must be a digit)
|
|
108
|
+
if (!isValidDigit(checkDigitStr)) {
|
|
109
|
+
return {
|
|
110
|
+
isValid: false,
|
|
111
|
+
error: `Invalid check digit: must be a digit (0-9), got '${checkDigitStr}'`
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
const checkDigit = parseInt(checkDigitStr, 10);
|
|
115
|
+
// Calculate expected check digit
|
|
116
|
+
const expectedCheckDigit = calculateCheckDigit(ownerCode, equipmentCategory, serialNumber);
|
|
117
|
+
// Verify check digit
|
|
118
|
+
if (checkDigit !== expectedCheckDigit) {
|
|
119
|
+
return {
|
|
120
|
+
isValid: false,
|
|
121
|
+
error: `Invalid check digit: expected ${expectedCheckDigit}, got ${checkDigit}`
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
// All validations passed
|
|
125
|
+
return {
|
|
126
|
+
isValid: true,
|
|
127
|
+
parts: {
|
|
128
|
+
ownerCode,
|
|
129
|
+
equipmentCategory,
|
|
130
|
+
serialNumber,
|
|
131
|
+
checkDigit,
|
|
132
|
+
raw: cleaned
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Validates a container number (returns only boolean)
|
|
138
|
+
*/
|
|
139
|
+
function isValidContainerNumber(containerNumber) {
|
|
140
|
+
return parseContainerNumber(containerNumber).isValid;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Formats a container number for display
|
|
144
|
+
*/
|
|
145
|
+
function formatContainerNumber(containerNumber) {
|
|
146
|
+
const result = parseContainerNumber(containerNumber);
|
|
147
|
+
if (!result.isValid || !result.parts) {
|
|
148
|
+
return containerNumber;
|
|
149
|
+
}
|
|
150
|
+
const { ownerCode, equipmentCategory, serialNumber, checkDigit } = result.parts;
|
|
151
|
+
// Format: MSCU 528572 [5]
|
|
152
|
+
return `${ownerCode}${equipmentCategory} ${serialNumber} [${checkDigit}]`;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Generates a container number from components
|
|
156
|
+
*/
|
|
157
|
+
function generateContainerNumber(ownerCode, equipmentCategory, serialNumber) {
|
|
158
|
+
const checkDigit = calculateCheckDigit(ownerCode, equipmentCategory, serialNumber);
|
|
159
|
+
return `${ownerCode}${equipmentCategory}${serialNumber}${checkDigit}`;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Gets equipment description from category code
|
|
163
|
+
*/
|
|
164
|
+
function getEquipmentDescription(category) {
|
|
165
|
+
return EQUIPMENT_CATEGORIES[category] || 'Unknown equipment category';
|
|
166
|
+
}
|
|
167
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@avi_k/container-number-validator",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Validate, parse, and generate ISO 6346 shipping container numbers",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsc",
|
|
9
|
+
"test": "jest",
|
|
10
|
+
"prepare": "npm run build"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"container",
|
|
14
|
+
"shipping",
|
|
15
|
+
"iso6346",
|
|
16
|
+
"validator",
|
|
17
|
+
"parser",
|
|
18
|
+
"check-digit",
|
|
19
|
+
"logistics",
|
|
20
|
+
"freight",
|
|
21
|
+
"bic"
|
|
22
|
+
],
|
|
23
|
+
"author": "AVINASH KOTHARI",
|
|
24
|
+
"license": "ISC",
|
|
25
|
+
"repository": {
|
|
26
|
+
"type": "git",
|
|
27
|
+
"url": "https://github.com/avikothari/container-number-validator.git"
|
|
28
|
+
},
|
|
29
|
+
"files": [
|
|
30
|
+
"dist",
|
|
31
|
+
"README.md",
|
|
32
|
+
"LICENSE"
|
|
33
|
+
],
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@types/jest": "^29.5.14",
|
|
36
|
+
"@types/node": "^25.0.3",
|
|
37
|
+
"@typescript-eslint/eslint-plugin": "^6.19.0",
|
|
38
|
+
"@typescript-eslint/parser": "^6.19.0",
|
|
39
|
+
"eslint": "^8.56.0",
|
|
40
|
+
"jest": "^29.7.0",
|
|
41
|
+
"ts-jest": "^29.4.6",
|
|
42
|
+
"typescript": "^5.9.3"
|
|
43
|
+
}
|
|
44
|
+
}
|