@haskou/value-objects 1.0.3 → 1.1.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 +21 -2
- package/TECHNICAL_DOCUMENTATION.md +166 -0
- package/package.json +6 -1
- package/src/errors/InvalidFormatError.ts +7 -0
- package/src/errors/InvalidHashError.ts +7 -0
- package/src/errors/InvalidLengthError.ts +9 -0
- package/src/errors/InvalidValueError.ts +7 -0
- package/src/errors/index.ts +3 -0
- package/src/patterns/index.ts +0 -2
- package/src/value-objects/hashes/Hash.ts +19 -0
- package/src/value-objects/hashes/MD5Hash.ts +32 -0
- package/src/value-objects/hashes/SHA256Hash.ts +38 -0
- package/src/value-objects/hashes/SHA512Hash.ts +38 -0
- package/src/value-objects/hashes/index.ts +4 -0
- package/src/value-objects/ids/ShortId.ts +34 -0
- package/src/value-objects/ids/UUID.ts +34 -0
- package/src/value-objects/index.ts +2 -0
- package/src/value-objects/time/CalendarDay.ts +1 -1
- package/tests/value-objects/Email.spec.ts +2 -6
- package/tests/value-objects/hashes/Hashes.spec.ts +139 -0
- package/tests/value-objects/hashes/MD5Hash.spec.ts +187 -0
- package/tests/value-objects/hashes/SHA256Hash.spec.ts +220 -0
- package/tests/value-objects/hashes/SHA512Hash.spec.ts +220 -0
- package/tests/value-objects/ids/ShortId.spec.ts +34 -0
- package/tests/value-objects/ids/UUID.spec.ts +37 -0
- /package/tests/{patterns → value-objects}/NullObject.spec.ts +0 -0
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# Value Objects
|
|
4
4
|
|
|
5
|
-
A TypeScript
|
|
5
|
+
A TypeScript lightweight library for creating safe, immutable,
|
|
6
6
|
and validated **Value Objects**. Perfect for applications that require **Domain-Driven Design (DDD)** and **type safety**.
|
|
7
7
|
|
|
8
8
|
## 🚀 Quick Start
|
|
@@ -58,6 +58,10 @@ your application.
|
|
|
58
58
|
- **`Integer`** - Whole numbers
|
|
59
59
|
- **`PositiveNumber`** - Positive numbers (> 0)
|
|
60
60
|
|
|
61
|
+
### 🆔 Identifiers
|
|
62
|
+
- **`ShortId`** - MongoDB ObjectId strings (24‑character hex)
|
|
63
|
+
- **`UUID`** - Universally Unique Identifier (v4)
|
|
64
|
+
|
|
61
65
|
### ✨ Specialized
|
|
62
66
|
- **`Email`** - Email addresses with automatic validation
|
|
63
67
|
- **`Color`** - Hex colors (#FF0000)
|
|
@@ -79,7 +83,12 @@ your application.
|
|
|
79
83
|
- **`Longitude`** - Longitude (-180 to 180)
|
|
80
84
|
- **`Coordinates`** - Coordinate pairs
|
|
81
85
|
|
|
82
|
-
###
|
|
86
|
+
### � Hashes
|
|
87
|
+
- **`MD5Hash`** - MD5 hashes with helpers
|
|
88
|
+
- **`SHA256Hash`** - SHA‑256 hashes with helpers
|
|
89
|
+
- **`SHA512Hash`** - SHA‑512 hashes with helpers
|
|
90
|
+
|
|
91
|
+
### �📝 Other
|
|
83
92
|
- **`Enum`** - Base class for typed enumerations
|
|
84
93
|
|
|
85
94
|
## 💡 Basic Examples
|
|
@@ -111,6 +120,16 @@ const coords = new Coordinates(latitude, longitude);
|
|
|
111
120
|
const hour = new Hour('09:30');
|
|
112
121
|
const year = new Year(2024);
|
|
113
122
|
console.log(year.isLeapYear()); // true
|
|
123
|
+
|
|
124
|
+
// IDs
|
|
125
|
+
const id = ShortId.generate(); // 69ad70897364ee0d1406b1d0
|
|
126
|
+
const uuid = UUID.generate(); // 3fd4c04a-8e73-4e10-aef3-f491b32ec538
|
|
127
|
+
|
|
128
|
+
// Hashes
|
|
129
|
+
const md5 = MD5Hash.from('hello'); // 5d41402abc4b2a76b9719d911017c592
|
|
130
|
+
const sha256 = SHA256Hash.from('hello'); // 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
|
|
131
|
+
const sha512 = SHA512Hash.from('hello'); // 9b71d224bd62f3785d96d46ad3ea3d73319bfbc2890caadae2dff72519673ca72323c3d99ba5c11d7c7acc6e14b8c5da0c4663475c2e5c3adef46f73bcdec043
|
|
132
|
+
console.log(md5.toBase64());
|
|
114
133
|
```
|
|
115
134
|
|
|
116
135
|
## 📚 Technical Documentation
|
|
@@ -13,6 +13,7 @@ Comprehensive technical documentation for the Value Objects library.
|
|
|
13
13
|
- [Year Value Objects](#year-value-objects)
|
|
14
14
|
- [Color Value Objects](#color-value-objects)
|
|
15
15
|
- [Email Value Objects](#email-value-objects)
|
|
16
|
+
- [ID Value Objects](#id-value-objects)
|
|
16
17
|
- [Hour Value Objects](#hour-value-objects)
|
|
17
18
|
- [Time Value Objects](#time-value-objects)
|
|
18
19
|
- [Enum Value Objects](#enum-value-objects)
|
|
@@ -471,6 +472,171 @@ const validEmails = [
|
|
|
471
472
|
];
|
|
472
473
|
```
|
|
473
474
|
|
|
475
|
+
### ID Value Objects
|
|
476
|
+
|
|
477
|
+
#### ShortId
|
|
478
|
+
|
|
479
|
+
Represents immutable MongoDB ObjectId values with automatic generation and validation.
|
|
480
|
+
|
|
481
|
+
```typescript
|
|
482
|
+
class ShortId extends ValueObject<string> {
|
|
483
|
+
public static generate(): ShortId;
|
|
484
|
+
constructor(value: string | StringValueObject);
|
|
485
|
+
}
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
**Example:**
|
|
489
|
+
```typescript
|
|
490
|
+
// Generate a new ObjectId
|
|
491
|
+
const id = ShortId.generate();
|
|
492
|
+
console.log(id.toString()); // '507f1f77bcf86cd799439011' (24-character hex string)
|
|
493
|
+
|
|
494
|
+
// Create from existing ObjectId string
|
|
495
|
+
const existingId = new ShortId('507f1f77bcf86cd799439011');
|
|
496
|
+
|
|
497
|
+
// From StringValueObject
|
|
498
|
+
const idString = new StringValueObject('507f1f77bcf86cd799439011');
|
|
499
|
+
const idFromString = new ShortId(idString);
|
|
500
|
+
|
|
501
|
+
// String representation
|
|
502
|
+
console.log(existingId.toString()); // '507f1f77bcf86cd799439011'
|
|
503
|
+
console.log(existingId.valueOf()); // '507f1f77bcf86cd799439011'
|
|
504
|
+
|
|
505
|
+
// Equality comparison
|
|
506
|
+
const id1 = new ShortId('507f1f77bcf86cd799439011');
|
|
507
|
+
const id2 = new ShortId('507f1f77bcf86cd799439011');
|
|
508
|
+
console.log(id1.isEqual(id2)); // true
|
|
509
|
+
|
|
510
|
+
// Validation
|
|
511
|
+
try {
|
|
512
|
+
new ShortId('invalid-id'); // Throws InvalidFormatError
|
|
513
|
+
new ShortId('short'); // Throws InvalidLengthError
|
|
514
|
+
} catch (error) {
|
|
515
|
+
console.error('Invalid ObjectId format');
|
|
516
|
+
}
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
#### UUID
|
|
520
|
+
|
|
521
|
+
Represents immutable UUID (Universally Unique Identifier) values with automatic generation and validation.
|
|
522
|
+
|
|
523
|
+
```typescript
|
|
524
|
+
class UUID extends ValueObject<string> {
|
|
525
|
+
public static generate(): UUID;
|
|
526
|
+
constructor(value: string | StringValueObject);
|
|
527
|
+
}
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
**Example:**
|
|
531
|
+
```typescript
|
|
532
|
+
// Generate a new UUID v4
|
|
533
|
+
const uuid = UUID.generate();
|
|
534
|
+
console.log(uuid.toString()); // '550e8400-e29b-41d4-a716-446655440000' (36-character string)
|
|
535
|
+
|
|
536
|
+
// Create from existing UUID string
|
|
537
|
+
const existingUuid = new UUID('550e8400-e29b-41d4-a716-446655440000');
|
|
538
|
+
|
|
539
|
+
// From StringValueObject
|
|
540
|
+
const uuidString = new StringValueObject('550e8400-e29b-41d4-a716-446655440000');
|
|
541
|
+
const uuidFromString = new UUID(uuidString);
|
|
542
|
+
|
|
543
|
+
// String representation
|
|
544
|
+
console.log(existingUuid.toString()); // '550e8400-e29b-41d4-a716-446655440000'
|
|
545
|
+
console.log(existingUuid.valueOf()); // '550e8400-e29b-41d4-a716-446655440000'
|
|
546
|
+
|
|
547
|
+
// Equality comparison
|
|
548
|
+
const uuid1 = new UUID('550e8400-e29b-41d4-a716-446655440000');
|
|
549
|
+
const uuid2 = new UUID('550e8400-e29b-41d4-a716-446655440000');
|
|
550
|
+
console.log(uuid1.isEqual(uuid2)); // true
|
|
551
|
+
|
|
552
|
+
// Validation
|
|
553
|
+
try {
|
|
554
|
+
new UUID('invalid-uuid'); // Throws InvalidFormatError
|
|
555
|
+
new UUID('short-uuid'); // Throws InvalidLengthError
|
|
556
|
+
} catch (error) {
|
|
557
|
+
console.error('Invalid UUID format');
|
|
558
|
+
}
|
|
559
|
+
```
|
|
560
|
+
|
|
561
|
+
### Hash Value Objects
|
|
562
|
+
|
|
563
|
+
#### MD5Hash
|
|
564
|
+
Represents immutable MD5 hashes with validation and utility methods.
|
|
565
|
+
|
|
566
|
+
```typescript
|
|
567
|
+
class MD5Hash extends Hash {
|
|
568
|
+
public static isValid(hash: string | StringValueObject): boolean;
|
|
569
|
+
public static from(buffer: Buffer | string | StringValueObject): MD5Hash;
|
|
570
|
+
constructor(source: string | StringValueObject);
|
|
571
|
+
}
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
**Example:**
|
|
575
|
+
```typescript
|
|
576
|
+
// Compute an MD5 hash from a string or buffer
|
|
577
|
+
const md5 = MD5Hash.from('hello');
|
|
578
|
+
console.log(md5.toString()); // '5d41402abc4b2a76b9719d911017c592'
|
|
579
|
+
console.log(md5.toBase64()); // 'XUEQKvLG6avlckeQEAXGSw=='
|
|
580
|
+
|
|
581
|
+
// Create from existing hash string
|
|
582
|
+
const existing = new MD5Hash('5d41402abc4b2a76b9719d911017c592');
|
|
583
|
+
|
|
584
|
+
// Validation
|
|
585
|
+
try {
|
|
586
|
+
new MD5Hash('invalid'); // Throws InvalidHashError
|
|
587
|
+
} catch (err) {
|
|
588
|
+
console.error('Invalid MD5 hash');
|
|
589
|
+
}
|
|
590
|
+
```
|
|
591
|
+
|
|
592
|
+
#### SHA256Hash
|
|
593
|
+
Represents immutable SHA‑256 hashes with validation and utility methods.
|
|
594
|
+
|
|
595
|
+
```typescript
|
|
596
|
+
class SHA256Hash extends ValueObject<string> {
|
|
597
|
+
public static isValid(hash: string | StringValueObject): boolean;
|
|
598
|
+
public static from(buffer: Buffer | string | StringValueObject): SHA256Hash;
|
|
599
|
+
constructor(source: string | StringValueObject);
|
|
600
|
+
}
|
|
601
|
+
```
|
|
602
|
+
|
|
603
|
+
**Example:**
|
|
604
|
+
```typescript
|
|
605
|
+
const sha256 = SHA256Hash.from('hello');
|
|
606
|
+
console.log(sha256.toString().length); // 64
|
|
607
|
+
console.log(sha256.toBase64());
|
|
608
|
+
|
|
609
|
+
try {
|
|
610
|
+
new SHA256Hash('abc'); // Throws InvalidHashError
|
|
611
|
+
} catch (err) {
|
|
612
|
+
console.error('Invalid SHA256 hash');
|
|
613
|
+
}
|
|
614
|
+
```
|
|
615
|
+
|
|
616
|
+
#### SHA512Hash
|
|
617
|
+
Represents immutable SHA‑512 hashes with validation and utility methods.
|
|
618
|
+
|
|
619
|
+
```typescript
|
|
620
|
+
class SHA512Hash extends ValueObject<string> {
|
|
621
|
+
public static isValid(hash: string | StringValueObject): boolean;
|
|
622
|
+
public static from(buffer: Buffer | string | StringValueObject): SHA512Hash;
|
|
623
|
+
constructor(source: string | StringValueObject);
|
|
624
|
+
}
|
|
625
|
+
```
|
|
626
|
+
|
|
627
|
+
**Example:**
|
|
628
|
+
```typescript
|
|
629
|
+
const sha512 = SHA512Hash.from('hello');
|
|
630
|
+
console.log(sha512.toString().length); // 128
|
|
631
|
+
console.log(sha512.toBase64());
|
|
632
|
+
|
|
633
|
+
try {
|
|
634
|
+
new SHA512Hash('abc'); // Throws InvalidHashError
|
|
635
|
+
} catch (err) {
|
|
636
|
+
console.error('Invalid SHA512 hash');
|
|
637
|
+
}
|
|
638
|
+
```
|
|
639
|
+
|
|
474
640
|
### Hour Value Objects
|
|
475
641
|
|
|
476
642
|
#### Hour
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@haskou/value-objects",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"main": "src/index.ts",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"publishConfig": {
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@types/jest": "^30.0.0",
|
|
30
30
|
"@types/node": "^24.0.13",
|
|
31
|
+
"@types/uuid": "8",
|
|
31
32
|
"@typescript-eslint/eslint-plugin": "6.20.0",
|
|
32
33
|
"@typescript-eslint/parser": "6.20.0",
|
|
33
34
|
"eslint": "8.57.0",
|
|
@@ -45,5 +46,9 @@
|
|
|
45
46
|
"ts-jest": "^29.4.0",
|
|
46
47
|
"ts-node": "^10.9.2",
|
|
47
48
|
"typescript": "^5.8.3"
|
|
49
|
+
},
|
|
50
|
+
"dependencies": {
|
|
51
|
+
"bson-objectid": "^2.0.4",
|
|
52
|
+
"uuid": "8"
|
|
48
53
|
}
|
|
49
54
|
}
|
package/src/errors/index.ts
CHANGED
|
@@ -4,6 +4,9 @@ export * from './InvalidColorError';
|
|
|
4
4
|
export * from './InvalidDayError';
|
|
5
5
|
export * from './InvalidDayFormatError';
|
|
6
6
|
export * from './InvalidHourError';
|
|
7
|
+
export * from './InvalidEmailError';
|
|
8
|
+
export * from './InvalidFormatError';
|
|
9
|
+
export * from './InvalidHashError';
|
|
7
10
|
export * from './InvalidIntegerError';
|
|
8
11
|
export * from './InvalidLatitudeError';
|
|
9
12
|
export * from './InvalidLongitudeError';
|
package/src/patterns/index.ts
CHANGED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { NullObject } from '../NullObject';
|
|
2
|
+
import { StringValueObject } from '../StringValueObject';
|
|
3
|
+
import { ValueObject } from '../ValueObject';
|
|
4
|
+
|
|
5
|
+
export abstract class Hash extends ValueObject<string> {
|
|
6
|
+
constructor(source: string | StringValueObject) {
|
|
7
|
+
super(source?.valueOf());
|
|
8
|
+
|
|
9
|
+
if (NullObject.isNullObject(this)) {
|
|
10
|
+
return this;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
public toBase64(): StringValueObject {
|
|
15
|
+
return new StringValueObject(
|
|
16
|
+
Buffer.from(this.valueOf(), 'hex').toString('base64'),
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import crypto from 'node:crypto';
|
|
2
|
+
|
|
3
|
+
import { InvalidHashError } from '../../errors/InvalidHashError';
|
|
4
|
+
import { assert } from '../../patterns';
|
|
5
|
+
import { NullObject } from '../NullObject';
|
|
6
|
+
import { StringValueObject } from '../StringValueObject';
|
|
7
|
+
import { Hash } from './Hash';
|
|
8
|
+
|
|
9
|
+
export class MD5Hash extends Hash {
|
|
10
|
+
public static isValid(hash: string | StringValueObject): boolean {
|
|
11
|
+
return !!hash.valueOf().match(/^[a-f0-9]{32}$/);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
public static from(buffer: Buffer | string | StringValueObject): MD5Hash {
|
|
15
|
+
return new MD5Hash(
|
|
16
|
+
crypto.createHash('md5').update(buffer.valueOf()).digest('hex'),
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
constructor(source: string | StringValueObject) {
|
|
21
|
+
super(source?.valueOf());
|
|
22
|
+
|
|
23
|
+
if (NullObject.isNullObject(this)) {
|
|
24
|
+
return this;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
assert(
|
|
28
|
+
MD5Hash.isValid(this.valueOf()),
|
|
29
|
+
new InvalidHashError('MD5', source.valueOf()),
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { createHash } from 'crypto';
|
|
2
|
+
|
|
3
|
+
import { InvalidHashError } from '../../errors/InvalidHashError';
|
|
4
|
+
import { assert } from '../../patterns';
|
|
5
|
+
import { NullObject } from '../NullObject';
|
|
6
|
+
import { StringValueObject } from '../StringValueObject';
|
|
7
|
+
import { ValueObject } from '../ValueObject';
|
|
8
|
+
|
|
9
|
+
export class SHA256Hash extends ValueObject<string> {
|
|
10
|
+
public static isValid(hash: string | StringValueObject): boolean {
|
|
11
|
+
return !!hash.valueOf().match(/^[a-f0-9]{64}$/i);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
public static from(buffer: Buffer | string | StringValueObject): SHA256Hash {
|
|
15
|
+
return new SHA256Hash(
|
|
16
|
+
createHash('sha256').update(buffer.valueOf()).digest('hex'),
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
constructor(source: string | StringValueObject) {
|
|
21
|
+
super(source?.valueOf());
|
|
22
|
+
|
|
23
|
+
if (NullObject.isNullObject(this)) {
|
|
24
|
+
return this;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
assert(
|
|
28
|
+
SHA256Hash.isValid(this.valueOf()),
|
|
29
|
+
new InvalidHashError('SHA256', source.valueOf()),
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
public toBase64(): StringValueObject {
|
|
34
|
+
return new StringValueObject(
|
|
35
|
+
Buffer.from(this.valueOf(), 'hex').toString('base64'),
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { createHash } from 'crypto';
|
|
2
|
+
|
|
3
|
+
import { InvalidHashError } from '../../errors/InvalidHashError';
|
|
4
|
+
import { assert } from '../../patterns';
|
|
5
|
+
import { NullObject } from '../NullObject';
|
|
6
|
+
import { StringValueObject } from '../StringValueObject';
|
|
7
|
+
import { ValueObject } from '../ValueObject';
|
|
8
|
+
|
|
9
|
+
export class SHA512Hash extends ValueObject<string> {
|
|
10
|
+
public static isValid(hash: string | StringValueObject): boolean {
|
|
11
|
+
return !!hash.valueOf().match(/^[a-f0-9]{128}$/i);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
public static from(buffer: Buffer | string | StringValueObject): SHA512Hash {
|
|
15
|
+
return new SHA512Hash(
|
|
16
|
+
createHash('sha512').update(buffer.valueOf()).digest('hex'),
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
constructor(source: string | StringValueObject) {
|
|
21
|
+
super(source?.valueOf());
|
|
22
|
+
|
|
23
|
+
if (NullObject.isNullObject(this)) {
|
|
24
|
+
return this;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
assert(
|
|
28
|
+
SHA512Hash.isValid(this.valueOf()),
|
|
29
|
+
new InvalidHashError('SHA512', source.valueOf()),
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
public toBase64(): StringValueObject {
|
|
34
|
+
return new StringValueObject(
|
|
35
|
+
Buffer.from(this.valueOf(), 'hex').toString('base64'),
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import ObjectId from 'bson-objectid';
|
|
2
|
+
|
|
3
|
+
import { InvalidFormatError } from '../../errors/InvalidFormatError';
|
|
4
|
+
import { InvalidLengthError } from '../../errors/InvalidLengthError';
|
|
5
|
+
import { assert } from '../../patterns';
|
|
6
|
+
import { NullObject } from '../NullObject';
|
|
7
|
+
import { StringValueObject } from '../StringValueObject';
|
|
8
|
+
import { ValueObject } from '../ValueObject';
|
|
9
|
+
|
|
10
|
+
export class ShortId extends ValueObject<string> {
|
|
11
|
+
private static readonly LENGTH = 24;
|
|
12
|
+
private static readonly PATTERN = new RegExp(`[a-zA-Z0-9]{${this.LENGTH}}$`);
|
|
13
|
+
|
|
14
|
+
public static generate(): ShortId {
|
|
15
|
+
return new ShortId(ObjectId().toHexString());
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
constructor(value: string | StringValueObject) {
|
|
19
|
+
super(value?.valueOf());
|
|
20
|
+
|
|
21
|
+
if (NullObject.isNullObject(this)) {
|
|
22
|
+
return this;
|
|
23
|
+
}
|
|
24
|
+
this.ensureIsShortId(this.value);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
private ensureIsShortId(value: string): void {
|
|
28
|
+
assert(
|
|
29
|
+
value.length === ShortId.LENGTH,
|
|
30
|
+
new InvalidLengthError(this.value, ShortId.LENGTH),
|
|
31
|
+
);
|
|
32
|
+
assert(ShortId.PATTERN.test(value), new InvalidFormatError(this.value));
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { v4 } from 'uuid';
|
|
2
|
+
|
|
3
|
+
import { InvalidFormatError } from '../../errors/InvalidFormatError';
|
|
4
|
+
import { InvalidLengthError } from '../../errors/InvalidLengthError';
|
|
5
|
+
import { assert } from '../../patterns';
|
|
6
|
+
import { NullObject } from '../NullObject';
|
|
7
|
+
import { StringValueObject } from '../StringValueObject';
|
|
8
|
+
import { ValueObject } from '../ValueObject';
|
|
9
|
+
|
|
10
|
+
export class UUID extends ValueObject<string> {
|
|
11
|
+
private static readonly LENGTH = 36;
|
|
12
|
+
private static readonly PATTERN = new RegExp(`^[a-z0-9-]{${this.LENGTH}}$`);
|
|
13
|
+
|
|
14
|
+
public static generate(): UUID {
|
|
15
|
+
return new UUID(v4());
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
constructor(value: string | StringValueObject) {
|
|
19
|
+
super(value?.valueOf());
|
|
20
|
+
|
|
21
|
+
if (NullObject.isNullObject(this)) {
|
|
22
|
+
return this;
|
|
23
|
+
}
|
|
24
|
+
this.ensureIsUUID(this.value);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
private ensureIsUUID(value: string): void {
|
|
28
|
+
assert(
|
|
29
|
+
value.length === UUID.LENGTH,
|
|
30
|
+
new InvalidLengthError(this.value, UUID.LENGTH),
|
|
31
|
+
);
|
|
32
|
+
assert(UUID.PATTERN.test(value), new InvalidFormatError(this.value));
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export * from './coordinates';
|
|
2
|
+
export * from './hashes';
|
|
2
3
|
export * from './time';
|
|
3
4
|
export * from './Color';
|
|
4
5
|
export * from './Email';
|
|
@@ -7,3 +8,4 @@ export * from './Integer';
|
|
|
7
8
|
export * from './NumberValueObject';
|
|
8
9
|
export * from './PositiveNumber';
|
|
9
10
|
export * from './StringValueObject';
|
|
11
|
+
export * from './NullObject';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { InvalidDayError } from '../../errors/InvalidDayError';
|
|
2
2
|
import { InvalidDayFormatError } from '../../errors/InvalidDayFormatError';
|
|
3
|
-
import { ValueObject } from '../../patterns';
|
|
4
3
|
import { assert } from '../../patterns/Assert';
|
|
4
|
+
import { ValueObject } from '../ValueObject';
|
|
5
5
|
import { Day } from './Day';
|
|
6
6
|
import { DayOfWeek } from './DayOfWeek';
|
|
7
7
|
import { Month } from './Month';
|
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
InvalidEmailError,
|
|
4
|
-
NullObject,
|
|
5
|
-
StringValueObject,
|
|
6
|
-
} from '../../src';
|
|
1
|
+
import { Email, InvalidEmailError, StringValueObject } from '../../src';
|
|
2
|
+
import { NullObject } from '../../src/value-objects/NullObject';
|
|
7
3
|
|
|
8
4
|
describe('Email', () => {
|
|
9
5
|
describe('constructor', () => {
|