coh-content-db 2.0.0-rc.3 → 2.0.0-rc.5

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.
@@ -3,20 +3,68 @@ import { PlaqueType } from '../api/plaque-type'
3
3
  import { BadgePartialType } from '../api/badge-partial-type'
4
4
  import { EnhancementCategory } from '../api/enhancement-category'
5
5
  import { Key } from './key'
6
+ import { MarkdownString } from '../api/markdown-string'
6
7
 
7
8
  export class BadgePartial {
9
+ /**
10
+ * Key.
11
+ */
8
12
  readonly key: string
9
- readonly type: BadgePartialType | string
13
+
14
+ /**
15
+ * Type of partial.
16
+ */
17
+ readonly type: BadgePartialType
18
+
19
+ /**
20
+ * Map the partial is located on.
21
+ */
10
22
  readonly mapKey?: string
23
+
24
+ /**
25
+ * /loc coordinates.
26
+ */
11
27
  readonly loc?: number[]
12
- readonly plaqueType?: PlaqueType | string
13
- readonly inscription?: string
28
+
29
+ /**
30
+ * Is it a wall plaque or a physical monument?
31
+ */
32
+ readonly plaqueType?: PlaqueType
33
+
34
+ /**
35
+ * Plaque inscription.
36
+ */
37
+ readonly plaqueInscription?: string
38
+
39
+ /**
40
+ * The number or letter the partial appears as on Vidiot Maps.
41
+ */
14
42
  readonly vidiotMapKey?: string
43
+
44
+ /**
45
+ * The badge required for this partial.
46
+ */
15
47
  readonly badgeKey?: string
48
+
49
+ /**
50
+ * Level of the invention required.
51
+ */
16
52
  readonly inventionLevel?: number
17
- readonly inventionTypes?: (EnhancementCategory | string)[]
53
+
54
+ /**
55
+ * The types of enhancements required to be crafted.
56
+ */
57
+ readonly inventionTypes?: EnhancementCategory[]
58
+
59
+ /**
60
+ * Number of invention crafts required.
61
+ */
18
62
  readonly inventionCount?: number
19
- readonly notes?: string
63
+
64
+ /**
65
+ * Any additional notes.
66
+ */
67
+ readonly notes?: MarkdownString
20
68
 
21
69
  constructor(data: BadgePartialData) {
22
70
  this.key = new Key(data.key).value
@@ -24,7 +72,7 @@ export class BadgePartial {
24
72
  this.mapKey = data.mapKey
25
73
  this.loc = data.loc
26
74
  this.plaqueType = data.plaqueType
27
- this.inscription = data.inscription
75
+ this.plaqueInscription = data.plaqueInscription
28
76
  this.vidiotMapKey = data.vidiotMapKey
29
77
  this.badgeKey = data.badgeKey
30
78
  this.inventionLevel = data.inventionLevel
@@ -0,0 +1,51 @@
1
+ import { BadgeType } from '../api/badge-type'
2
+ import { Alignment } from '../api/alignment'
3
+
4
+ export interface BadgeSearchOptions {
5
+
6
+ /**
7
+ * Text-based search.
8
+ *
9
+ * Case-insensitive. Defaults to searching on name only.
10
+ */
11
+ query?: {
12
+ str?: string
13
+ on?: {
14
+ name?: boolean
15
+ badgeText?: boolean
16
+ acquisition?: boolean
17
+ notes?: boolean
18
+ effect?: boolean
19
+ setTitle?: boolean
20
+ }
21
+ }
22
+
23
+ /**
24
+ * Filter results matching the given values.
25
+ */
26
+ filter?: {
27
+ type?: BadgeType
28
+ mapKey?: string
29
+ alignment?: Alignment
30
+ }
31
+
32
+ /**
33
+ * Sort results.
34
+ *
35
+ * Badges are assumed to be in canonical order in the content bundle, and should match the in-game display order.
36
+ */
37
+ sort?: {
38
+ by?: 'CANONICAL' | 'BADGE_NAME' | 'MAP_NAME'
39
+ dir?: 'ASC' | 'DESC'
40
+ }
41
+
42
+ /**
43
+ * The page (1-based)
44
+ */
45
+ page?: number
46
+
47
+ /**
48
+ * How many results per page
49
+ */
50
+ pageSize?: number
51
+ }
@@ -1,10 +1,11 @@
1
1
  import { BadgeType } from '../api/badge-type'
2
- import { Alignment } from '../api/alignment'
3
2
  import { Link } from '../api/link'
4
3
  import { BadgeData } from '../api/badge-data'
5
4
  import { BadgePartial } from './badge-partial'
6
5
  import { Key } from './key'
7
6
  import { Alternates } from './alternates'
7
+ import { Alignments } from './alignments'
8
+ import { MarkdownString } from '../api/markdown-string'
8
9
 
9
10
  export class Badge {
10
11
  readonly #partialsIndex: Record<string, BadgePartial> = {}
@@ -17,7 +18,7 @@ export class Badge {
17
18
  /**
18
19
  * The type of badge.
19
20
  */
20
- readonly type: BadgeType | string
21
+ readonly type: BadgeType
21
22
 
22
23
  /**
23
24
  * The name of this badge.
@@ -29,7 +30,7 @@ export class Badge {
29
30
  /**
30
31
  * The character alignments that this badge is available to.
31
32
  */
32
- readonly alignment: Alignment[]
33
+ readonly alignment: Alignments
33
34
 
34
35
  /**
35
36
  * The badge text as it appears in-game. May vary by character sex or alignment.
@@ -38,10 +39,8 @@ export class Badge {
38
39
 
39
40
  /**
40
41
  * Description of how to acquire the badge.
41
- *
42
- * Supports {@link https://www.markdownguide.org/|Markdown} format.
43
42
  */
44
- readonly acquisition?: string
43
+ readonly acquisition?: MarkdownString
45
44
 
46
45
  /**
47
46
  * Absolute URL to this badge's icon.
@@ -52,10 +51,8 @@ export class Badge {
52
51
 
53
52
  /**
54
53
  * Freeform notes or tips about the badge.
55
- *
56
- * Supports {@link https://www.markdownguide.org/|Markdown} format.
57
54
  */
58
- readonly notes?: string
55
+ readonly notes?: MarkdownString
59
56
 
60
57
  /**
61
58
  * List of external links for this Badge. Wiki, forums, etc.
@@ -93,10 +90,8 @@ export class Badge {
93
90
 
94
91
  /**
95
92
  * A description of the effect the badge will have, such as a buff or granting a temporary power.
96
- *
97
- * Supports {@link https://www.markdownguide.org/|Markdown} format.
98
93
  */
99
- readonly effect?: string
94
+ readonly effect?: MarkdownString
100
95
 
101
96
  /**
102
97
  * A list of requirements for badges that have partial fulfilment steps, such as visiting plaques for history badges, or collecting other badges for meta-badges like accolades.
@@ -112,7 +107,7 @@ export class Badge {
112
107
  this.key = new Key(data.key).value
113
108
  this.type = data.type
114
109
  this.name = new Alternates(data.name)
115
- this.alignment = data.alignment
110
+ this.alignment = new Alignments(data.alignment)
116
111
  this.badgeText = new Alternates(data.badgeText ?? [])
117
112
  this.acquisition = data.acquisition
118
113
  this.icon = new Alternates(data.icon ?? [])
@@ -1,6 +1,7 @@
1
1
  import { ContentBundle } from '../api/content-bundle'
2
2
  import { Change } from '../api/change'
3
3
  import { Link } from '../api/link'
4
+ import { MarkdownString } from '../api/markdown-string'
4
5
 
5
6
  export class BundleMetadata {
6
7
  /**
@@ -10,10 +11,8 @@ export class BundleMetadata {
10
11
 
11
12
  /**
12
13
  * Description of the server group.
13
- *
14
- * Supports {@link https://www.markdownguide.org/|Markdown} format.
15
14
  */
16
- readonly description?: string
15
+ readonly description?: MarkdownString
17
16
 
18
17
  /**
19
18
  * Repository where the db content package is maintained.
@@ -3,11 +3,14 @@ import { Archetype } from './archetype'
3
3
  import { GameMap } from './game-map'
4
4
  import { Badge } from './badge'
5
5
  import { BundleMetadata } from './bundle-metadata'
6
+ import { BadgeIndex } from './badge-index'
7
+ import { BadgeSearchOptions } from './badge-search-options'
8
+ import { Paged } from './paged'
6
9
 
7
10
  export class CohContentDatabase {
8
11
  readonly #archetypeIndex: Record<string, Archetype> = {}
9
12
  readonly #mapIndex: Record<string, GameMap> = {}
10
- readonly #badgeIndex: Record<string, Badge> = {}
13
+ readonly #badgeIndex: BadgeIndex
11
14
 
12
15
  /**
13
16
  * Metadata about the content bundle.
@@ -42,24 +45,23 @@ export class CohContentDatabase {
42
45
  constructor(bundle: ContentBundle) {
43
46
  this.metadata = new BundleMetadata(bundle)
44
47
  this.servers = bundle.servers ?? []
48
+
45
49
  this.archetypes = bundle.archetypes?.map((data) => {
46
50
  if (this.#archetypeIndex[data.key] !== undefined) throw new Error(`Duplicate archetype key [${data.key}]`)
47
51
  const archetype = new Archetype(data)
48
52
  this.#archetypeIndex[archetype.key] = archetype
49
53
  return archetype
50
54
  }) ?? []
55
+
51
56
  this.maps = bundle.maps?.map((data) => {
52
57
  if (this.#mapIndex[data.key] !== undefined) throw new Error(`Duplicate map key [${data.key}]`)
53
58
  const map = new GameMap(data)
54
59
  this.#mapIndex[map.key] = map
55
60
  return map
56
61
  }) ?? []
57
- this.badges = bundle.badges?.map((data) => {
58
- if (this.#badgeIndex[data.key] !== undefined) throw new Error(`Duplicate badge key [${data.key}]`)
59
- const badge = new Badge(data)
60
- this.#badgeIndex[badge.key] = badge
61
- return badge
62
- }) ?? []
62
+
63
+ this.badges = bundle.badges?.map(data => new Badge(data)) ?? []
64
+ this.#badgeIndex = new BadgeIndex(this.badges, this.maps)
63
65
  }
64
66
 
65
67
  getArchetype(key: string): Archetype {
@@ -75,8 +77,16 @@ export class CohContentDatabase {
75
77
  }
76
78
 
77
79
  getBadge(key: string): Badge {
78
- const result = this.#badgeIndex[key]
79
- if (result === undefined) throw new Error(`Unknown badge key [${key}]`)
80
- return result
80
+ return this.#badgeIndex.getBadge(key)
81
+ }
82
+
83
+ /**
84
+ * Search, sort and filter the badge list.
85
+ * This is a fairly brute-forced approach and will not be as performant as loading the badge data into a traditional
86
+ * database engine, but is sufficient for most operations.
87
+ * @param options {@link BadgeSearchOptions}
88
+ */
89
+ searchBadges(options?: BadgeSearchOptions): Paged<Badge> {
90
+ return this.#badgeIndex.searchBadges(options)
81
91
  }
82
92
  }
@@ -0,0 +1,7 @@
1
+ export interface Paged<T> {
2
+ items: T[]
3
+ page: number
4
+ pageSize?: number
5
+ totalItems: number
6
+ totalPages: number
7
+ }
@@ -1,4 +1,5 @@
1
1
  import { VidiotMapPointOfInterestData } from '../api/vidiot-map-point-of-interest-data'
2
+ import { MarkdownString } from '../api/markdown-string'
2
3
 
3
4
  export class VidiotMapPointOfInterest {
4
5
  /**
@@ -10,10 +11,8 @@ export class VidiotMapPointOfInterest {
10
11
 
11
12
  /**
12
13
  * Freeform notes about the PoI.
13
- *
14
- * Supports {@link https://www.markdownguide.org/|Markdown} format.
15
14
  */
16
- readonly notes?: string
15
+ readonly notes?: MarkdownString
17
16
 
18
17
  /**
19
18
  * If the POI is a zone transfer, the map it transfers to.
package/src/main/index.ts CHANGED
@@ -10,6 +10,7 @@ export * from './api/change'
10
10
  export * from './api/enhancement-category'
11
11
  export * from './api/game-map-data'
12
12
  export * from './api/link'
13
+ export * from './api/markdown-string'
13
14
  export * from './api/plaque-type'
14
15
  export * from './api/content-bundle'
15
16
  export * from './api/sex'
@@ -17,13 +18,18 @@ export * from './api/vidiot-map-data'
17
18
  export * from './api/vidiot-map-point-of-interest-data'
18
19
 
19
20
  // DB
21
+ export * from './db/alignments'
22
+ export * from './db/alternates'
20
23
  export * from './db/archetype'
21
24
  export * from './db/badge'
25
+ export * from './db/badge-index'
22
26
  export * from './db/badge-partial'
27
+ export * from './db/badge-search-options'
28
+ export * from './db/bundle-metadata'
23
29
  export * from './db/coh-content-database'
24
30
  export * from './db/game-map'
25
31
  export * from './db/key'
26
- export * from './db/bundle-metadata'
32
+ export * from './db/paged'
27
33
  export * from './db/vidiot-map'
28
34
  export * from './db/vidiot-map-point-of-interest'
29
35
 
package/src/main/util.ts CHANGED
@@ -1,17 +1,47 @@
1
1
  /**
2
- * Create a reference string that can be used in most text strings to display a link to the given badge.
2
+ * Returns the URI of the given badge that can be used in {@link MarkdownString} links.
3
+ *
4
+ * URI format: `badge://<key>`
5
+ *
3
6
  * @param target The badge or badge key to target.
4
7
  */
5
- export function createBadgeReference(target: string | { key: string }): string {
8
+ export function badgeUri(target: string | { key: string }): string {
6
9
  const key = typeof target === 'string' ? target : target.key
7
- return `[badge:${key}]`
10
+ return `badge://${key}`
8
11
  }
9
12
 
10
13
  /**
11
- * Create a reference string that can be used in most text strings to display a link to the given map.
14
+ * Returns a {@link MarkdownString} link to the given badge.
15
+ *
16
+ * Link format: `[<key>](badge://<key>)`
17
+ *
18
+ * @param target The badge or badge key to target.
19
+ */
20
+ export function badgeLink(target: string | { key: string }): string {
21
+ const key = typeof target === 'string' ? target : target.key
22
+ return `[${key}](${badgeUri(target)})`
23
+ }
24
+
25
+ /**
26
+ * Returns the URI of the given map that can be used in {@link MarkdownString} links.
27
+ *
28
+ * URI format: `map://<key>`
29
+ *
12
30
  * @param target The {@link GameMap} or map key to target.
13
31
  */
14
- export function createMapReference(target: string | { key: string }): string {
32
+ export function mapUri(target: string | { key: string }): string {
33
+ const key = typeof target === 'string' ? target : target.key
34
+ return `map://${key}`
35
+ }
36
+
37
+ /**
38
+ * Returns a {@link MarkdownString} link to the given map.
39
+ *
40
+ * Link format: `[<key>](map://<key>)`
41
+ *
42
+ * @param target The map or map key to target.
43
+ */
44
+ export function mapLink(target: string | { key: string }): string {
15
45
  const key = typeof target === 'string' ? target : target.key
16
- return `[map:${key}]`
46
+ return `[${key}](${mapUri(target)})`
17
47
  }
@@ -0,0 +1,40 @@
1
+ import { Alignments } from '../../main'
2
+
3
+ describe(Alignments.name, () => {
4
+ test('should return the raw array', () => {
5
+ expect(new Alignments(['H', 'V']).items).toStrictEqual(['H', 'V'])
6
+ })
7
+
8
+ test('should detect a hero', () => {
9
+ expect(new Alignments(['H', 'V']).hero).toBeTruthy()
10
+ })
11
+
12
+ test('should detect a villain', () => {
13
+ expect(new Alignments(['H', 'V']).villain).toBeTruthy()
14
+ })
15
+
16
+ test('should detect a praetorian', () => {
17
+ expect(new Alignments(['H', 'V', 'P']).praetorian).toBeTruthy()
18
+ })
19
+
20
+ test('should detect a primal', () => {
21
+ expect(new Alignments(['H', 'V']).primal).toBeTruthy()
22
+ })
23
+
24
+ test('should not falsely detect a hero', () => {
25
+ expect(new Alignments(['V']).hero).toBeFalsy()
26
+ })
27
+
28
+ test('should not falsely detect a villain', () => {
29
+ expect(new Alignments(['H']).villain).toBeFalsy()
30
+ })
31
+
32
+ test('should not falsely detect a praetorian', () => {
33
+ expect(new Alignments(['V']).praetorian).toBeFalsy()
34
+ })
35
+
36
+ test('should falsely detect a primal', () => {
37
+ expect(new Alignments(['H', 'V', 'P']).primal).toBeFalsy()
38
+ expect(new Alignments(['P']).primal).toBeFalsy()
39
+ })
40
+ })
@@ -7,7 +7,7 @@ export const badgePartialDataFixture = defineFixture<BadgePartialData>((t) => {
7
7
  t.mapKey?.asString()
8
8
  t.loc?.asArray()
9
9
  t.plaqueType?.pickFrom([...PLAQUE_TYPE])
10
- t.inscription?.asLoremIpsum()
10
+ t.plaqueInscription?.asLoremIpsum()
11
11
  t.vidiotMapKey?.asString()
12
12
  t.badgeKey?.as(index => `badge-${index}`)
13
13
  t.inventionLevel?.asNumber()
@@ -1,4 +1,4 @@
1
- import { Alternates } from '../../main/db/alternates'
1
+ import { Alternates } from '../../main'
2
2
 
3
3
  describe(Alternates.name, () => {
4
4
  describe('Constructor', () => {
@@ -89,7 +89,7 @@ describe(Alternates.name, () => {
89
89
  { alignment: 'H', value: 'Hero' },
90
90
  { alignment: 'V', sex: 'M', value: 'Male Villain' },
91
91
  { alignment: 'P', sex: 'F', value: 'Praetorian Female' },
92
- ]).default).toBe('Default')
92
+ ]).default?.value).toBe('Default')
93
93
 
94
94
  expect(new Alternates([
95
95
  { alignment: 'V', sex: 'M', value: 'Male Villain' },
@@ -97,14 +97,14 @@ describe(Alternates.name, () => {
97
97
  { sex: 'M', value: 'Male' },
98
98
  { value: 'Default' },
99
99
  { alignment: 'H', value: 'Hero' },
100
- ]).default).toBe('Default')
100
+ ]).default?.value).toBe('Default')
101
101
 
102
102
  expect(new Alternates([
103
103
  { alignment: 'V', sex: 'M', value: 'Male Villain' },
104
104
  { alignment: 'P', sex: 'F', value: 'Praetorian Female' },
105
105
  { sex: 'M', value: 'Male' },
106
106
  { alignment: 'H', value: 'Hero' },
107
- ]).default).toBe('Male')
107
+ ]).default?.value).toBe('Male')
108
108
  })
109
109
  })
110
110
 
@@ -118,64 +118,30 @@ describe(Alternates.name, () => {
118
118
  { alignment: 'H', sex: 'F', value: 'Female Hero' },
119
119
  { alignment: 'P', value: 'Praetorian' },
120
120
  { sex: 'F', value: 'Female' },
121
- { alignment: 'H', sex: 'A', value: 'A Hero' },
122
- { alignment: 'Y', sex: 'A', value: 'A Y' },
123
121
  { alignment: 'V', sex: 'M', value: 'Male Villain' },
124
- { alignment: 'V', sex: 'B', value: 'B Villain' },
125
122
  { alignment: 'P', sex: 'M', value: 'Male Praetorian' },
126
123
  { alignment: 'H', value: 'Hero' },
127
- { alignment: 'V', sex: 'A', value: 'A Villain' },
128
- { sex: 'A', value: 'A Sex' },
129
- { alignment: 'X', sex: 'F', value: 'Female X' },
130
124
  { alignment: 'H', sex: 'M', value: 'Male Hero' },
131
- { alignment: 'X', value: 'X' },
132
- { alignment: 'P', sex: 'B', value: 'B Praetorian' },
133
- { alignment: 'P', sex: 'A', value: 'A Praetorian' },
134
- { alignment: 'X', sex: 'M', value: 'Male X' },
135
125
  { sex: 'M', value: 'Male' },
136
- { alignment: 'X', sex: 'B', value: 'B X' },
137
- { alignment: 'H', sex: 'B', value: 'B Hero' },
138
126
  { alignment: 'V', value: 'Villain' },
139
- { alignment: 'Y', sex: 'M', value: 'Male Y' },
140
127
  { alignment: 'V', sex: 'F', value: 'Female Villain' },
141
- { sex: 'B', value: 'B Sex' },
142
- { alignment: 'Y', sex: 'B', value: 'B Y' },
143
128
  { alignment: 'P', sex: 'F', value: 'Female Praetorian' },
144
- { alignment: 'X', sex: 'A', value: 'A X' },
145
129
  { value: 'Default' },
146
- { alignment: 'Y', sex: 'F', value: 'Female Y' },
147
130
  ]).canonical
148
131
 
149
132
  expect(result).toStrictEqual([
150
133
  { value: 'Default' },
151
134
  { sex: 'M', value: 'Male' },
152
135
  { sex: 'F', value: 'Female' },
153
- { sex: 'A', value: 'A Sex' },
154
- { sex: 'B', value: 'B Sex' },
155
136
  { alignment: 'H', value: 'Hero' },
156
137
  { alignment: 'V', value: 'Villain' },
157
138
  { alignment: 'P', value: 'Praetorian' },
158
- { alignment: 'X', value: 'X' },
159
139
  { alignment: 'H', sex: 'M', value: 'Male Hero' },
160
140
  { alignment: 'H', sex: 'F', value: 'Female Hero' },
161
- { alignment: 'H', sex: 'A', value: 'A Hero' },
162
- { alignment: 'H', sex: 'B', value: 'B Hero' },
163
141
  { alignment: 'V', sex: 'M', value: 'Male Villain' },
164
142
  { alignment: 'V', sex: 'F', value: 'Female Villain' },
165
- { alignment: 'V', sex: 'A', value: 'A Villain' },
166
- { alignment: 'V', sex: 'B', value: 'B Villain' },
167
143
  { alignment: 'P', sex: 'M', value: 'Male Praetorian' },
168
144
  { alignment: 'P', sex: 'F', value: 'Female Praetorian' },
169
- { alignment: 'P', sex: 'A', value: 'A Praetorian' },
170
- { alignment: 'P', sex: 'B', value: 'B Praetorian' },
171
- { alignment: 'X', sex: 'M', value: 'Male X' },
172
- { alignment: 'X', sex: 'F', value: 'Female X' },
173
- { alignment: 'X', sex: 'A', value: 'A X' },
174
- { alignment: 'X', sex: 'B', value: 'B X' },
175
- { alignment: 'Y', sex: 'M', value: 'Male Y' },
176
- { alignment: 'Y', sex: 'F', value: 'Female Y' },
177
- { alignment: 'Y', sex: 'A', value: 'A Y' },
178
- { alignment: 'Y', sex: 'B', value: 'B Y' },
179
145
  ])
180
146
  })
181
147
 
@@ -191,41 +157,17 @@ describe(Alternates.name, () => {
191
157
  ])
192
158
  })
193
159
 
194
- test('should sort identical values similarly', () => {
160
+ test('should sort identical values by value alpha', () => {
195
161
  expect(new Alternates([
196
- { value: 'A' },
197
- { value: 'B' },
198
- { value: 'C' },
199
- { value: 'B' },
200
- ]).canonical).toStrictEqual([
201
- { value: 'A' },
202
- { value: 'B' },
203
- { value: 'B' },
204
- { value: 'C' },
205
- ])
206
- })
207
-
208
- test('should sort unknown alignments by alpha', () => {
209
- expect(new Alternates([
210
- { alignment: 'A', value: 'A' },
211
- { alignment: 'C', value: 'C' },
212
- { alignment: 'B', value: 'B' },
213
- ]).canonical).toStrictEqual([
214
- { alignment: 'A', value: 'A' },
215
- { alignment: 'B', value: 'B' },
216
- { alignment: 'C', value: 'C' },
217
- ])
218
- })
219
-
220
- test('should sort unknown sex by alpha', () => {
221
- expect(new Alternates([
222
- { sex: 'A', value: 'A' },
223
- { sex: 'C', value: 'C' },
224
- { sex: 'B', value: 'B' },
162
+ { alignment: 'V', value: 'B' },
163
+ { sex: 'M', value: 'D' },
164
+ { alignment: 'V', value: 'A' },
165
+ { sex: 'M', value: 'C' },
225
166
  ]).canonical).toStrictEqual([
226
- { sex: 'A', value: 'A' },
227
- { sex: 'B', value: 'B' },
228
- { sex: 'C', value: 'C' },
167
+ { sex: 'M', value: 'C' },
168
+ { sex: 'M', value: 'D' },
169
+ { alignment: 'V', value: 'A' },
170
+ { alignment: 'V', value: 'B' },
229
171
  ])
230
172
  })
231
173
  })
@@ -233,9 +175,9 @@ describe(Alternates.name, () => {
233
175
  describe('toString', () => {
234
176
  test('should create a string separated by the separator', () => {
235
177
  expect(new Alternates([
236
- { sex: 'A', value: 'A' },
237
- { sex: 'B', value: 'B' },
238
- { sex: 'C', value: 'C' },
178
+ { sex: 'M', value: 'A' },
179
+ { sex: 'F', value: 'B' },
180
+ { alignment: 'H', value: 'C' },
239
181
  ]).toString(', ')).toBe('A, B, C')
240
182
  })
241
183
  })