67 lines
1.6 KiB
TypeScript
67 lines
1.6 KiB
TypeScript
/**
|
|
* PortCode Value Object
|
|
*
|
|
* Encapsulates UN/LOCODE port code validation and behavior
|
|
*
|
|
* Business Rules:
|
|
* - Port code must follow UN/LOCODE format (2-letter country + 3-letter/digit location)
|
|
* - Port code is always uppercase
|
|
* - Port code is immutable
|
|
*
|
|
* Format: CCLLL
|
|
* - CC: ISO 3166-1 alpha-2 country code
|
|
* - LLL: 3-character location code (letters or digits)
|
|
*
|
|
* Examples: NLRTM (Rotterdam), USNYC (New York), SGSIN (Singapore)
|
|
*/
|
|
|
|
export class PortCode {
|
|
private readonly value: string;
|
|
|
|
private constructor(code: string) {
|
|
this.value = code;
|
|
}
|
|
|
|
static create(code: string): PortCode {
|
|
if (!code || code.trim().length === 0) {
|
|
throw new Error('Port code cannot be empty.');
|
|
}
|
|
|
|
const normalized = code.trim().toUpperCase();
|
|
|
|
if (!PortCode.isValid(normalized)) {
|
|
throw new Error(
|
|
`Invalid port code format: ${code}. Must follow UN/LOCODE format (e.g., NLRTM, USNYC).`
|
|
);
|
|
}
|
|
|
|
return new PortCode(normalized);
|
|
}
|
|
|
|
private static isValid(code: string): boolean {
|
|
// UN/LOCODE format: 2-letter country code + 3-character location code
|
|
const unlocodePattern = /^[A-Z]{2}[A-Z0-9]{3}$/;
|
|
return unlocodePattern.test(code);
|
|
}
|
|
|
|
getValue(): string {
|
|
return this.value;
|
|
}
|
|
|
|
getCountryCode(): string {
|
|
return this.value.substring(0, 2);
|
|
}
|
|
|
|
getLocationCode(): string {
|
|
return this.value.substring(2);
|
|
}
|
|
|
|
equals(other: PortCode): boolean {
|
|
return this.value === other.value;
|
|
}
|
|
|
|
toString(): string {
|
|
return this.value;
|
|
}
|
|
}
|