coh-content-db 2.0.0-rc.15 → 2.0.0-rc.17
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/.github/workflows/build.yml +1 -1
- package/CHANGELOG.md +3 -1
- package/README.md +9 -1
- package/dist/coh-content-db.d.ts +93 -44
- package/dist/coh-content-db.js +230 -121
- package/dist/coh-content-db.js.map +1 -1
- package/dist/coh-content-db.mjs +228 -121
- package/dist/coh-content-db.mjs.map +1 -1
- package/jest.config.mjs +1 -0
- package/package.json +14 -14
- package/src/main/api/badge-data.ts +2 -1
- package/src/main/api/contact-data.ts +2 -1
- package/src/main/api/level-range-data.ts +4 -0
- package/src/main/api/mission-data.ts +3 -29
- package/src/main/api/mission-flashback-data.ts +31 -0
- package/src/main/api/set-title-data.ts +4 -0
- package/src/main/api/zone-data.ts +24 -0
- package/src/main/api/zone-type.ts +59 -0
- package/src/main/db/alternates.ts +1 -1
- package/src/main/db/badge-index.ts +10 -8
- package/src/main/db/badge-requirement.ts +1 -1
- package/src/main/db/badge.ts +5 -4
- package/src/main/db/bundle-header.ts +1 -1
- package/src/main/db/contact.ts +5 -4
- package/src/main/db/level-range.ts +15 -0
- package/src/main/db/mission.ts +9 -8
- package/src/main/db/set-title-ids.ts +10 -0
- package/src/main/db/zone.ts +29 -0
- package/src/main/index.ts +8 -2
- package/src/main/util/coalesce-to-array.ts +13 -0
- package/src/main/{util.ts → util/links.ts} +8 -22
- package/src/test/api/alignment.test.ts +2 -2
- package/src/test/api/sex.test.ts +2 -2
- package/src/test/api/zone-data.fixture.ts +1 -0
- package/src/test/db/badge.test.ts +24 -11
- package/src/test/db/contact.test.ts +2 -1
- package/src/test/db/level-range.test.ts +47 -0
- package/src/test/db/mission.test.ts +8 -6
- package/src/test/db/morality-list.test.ts +1 -1
- package/src/test/db/set-title-ids.test.ts +19 -0
- package/src/test/db/zone.test.ts +45 -0
- package/src/test/util/coalese-to-array.test.ts +17 -0
- package/src/test/{util.test.ts → util/links.test.ts} +5 -21
- package/src/test/{to-date.test.ts → util/to-date.test.ts} +1 -1
- /package/src/main/{to-date.ts → util/to-date.ts} +0 -0
|
@@ -11,7 +11,7 @@ export class Alternates<T> {
|
|
|
11
11
|
*/
|
|
12
12
|
constructor(value: AlternateData<T>[] | T) {
|
|
13
13
|
if (Array.isArray(value)) {
|
|
14
|
-
this.#sortedValues = value.
|
|
14
|
+
this.#sortedValues = value.toSorted()
|
|
15
15
|
this.#sortedValues.sort((a, b) => this.#compareAlternates(a, b))
|
|
16
16
|
} else {
|
|
17
17
|
this.#sortedValues = [{ value }]
|
|
@@ -38,7 +38,9 @@ export class BadgeIndex extends AbstractIndex<Badge> {
|
|
|
38
38
|
|| (fields.has('acquisition') && badge.acquisition?.toLowerCase().includes(queryString))
|
|
39
39
|
|| (fields.has('effect') && badge.effect?.toLowerCase().includes(queryString))
|
|
40
40
|
|| (fields.has('notes') && badge.notes?.toLowerCase().includes(queryString))
|
|
41
|
-
|| (fields.has('set-title-id') && (badge.setTitleId?.
|
|
41
|
+
|| (fields.has('set-title-id') && (badge.setTitleId?.primal.toString() === queryString))
|
|
42
|
+
|| (fields.has('set-title-id') && (badge.setTitleId?.praetorian?.toString() === queryString))
|
|
43
|
+
)
|
|
42
44
|
}
|
|
43
45
|
|
|
44
46
|
#satisfiesFilterPredicate(badge: Badge, filter?: BadgeSearchOptions['filter']): boolean {
|
|
@@ -50,25 +52,25 @@ export class BadgeIndex extends AbstractIndex<Badge> {
|
|
|
50
52
|
#sort(badges: Badge[], sort?: BadgeSearchOptions['sort']): Badge[] {
|
|
51
53
|
switch (sort) {
|
|
52
54
|
case 'name.asc': {
|
|
53
|
-
return badges.
|
|
55
|
+
return badges.toSorted(compareByDefaultName)
|
|
54
56
|
}
|
|
55
57
|
case 'name.desc': {
|
|
56
|
-
return badges.
|
|
58
|
+
return badges.toSorted((a, b) => compareByDefaultName(b, a))
|
|
57
59
|
}
|
|
58
60
|
case 'zone-key.asc': {
|
|
59
|
-
return badges.
|
|
61
|
+
return badges.toSorted(compareByZoneKey)
|
|
60
62
|
}
|
|
61
63
|
case 'zone-key.desc': {
|
|
62
|
-
return badges.
|
|
64
|
+
return badges.toSorted((a, b) => compareByZoneKey(b, a))
|
|
63
65
|
}
|
|
64
66
|
case 'release-date.asc': {
|
|
65
|
-
return badges.
|
|
67
|
+
return badges.toSorted(compareByReleaseDate)
|
|
66
68
|
}
|
|
67
69
|
case 'release-date.desc': {
|
|
68
|
-
return badges.
|
|
70
|
+
return badges.toSorted((a, b) => compareByReleaseDate(b, a))
|
|
69
71
|
}
|
|
70
72
|
case 'canonical.desc': {
|
|
71
|
-
return badges.
|
|
73
|
+
return badges.toReversed()
|
|
72
74
|
}
|
|
73
75
|
default: {
|
|
74
76
|
return [...badges]
|
|
@@ -5,7 +5,7 @@ import { Key } from './key'
|
|
|
5
5
|
import { MarkdownString } from '../api/markdown-string'
|
|
6
6
|
import { Link } from '../api/link'
|
|
7
7
|
import { Location } from './location'
|
|
8
|
-
import { coalesceToArray } from '../util'
|
|
8
|
+
import { coalesceToArray } from '../util/coalesce-to-array'
|
|
9
9
|
|
|
10
10
|
export class BadgeRequirement {
|
|
11
11
|
/**
|
package/src/main/db/badge.ts
CHANGED
|
@@ -5,10 +5,11 @@ import { BadgeRequirement } from './badge-requirement'
|
|
|
5
5
|
import { Key } from './key'
|
|
6
6
|
import { Alternates } from './alternates'
|
|
7
7
|
import { MarkdownString } from '../api/markdown-string'
|
|
8
|
-
import { coalesceToArray } from '../util'
|
|
9
8
|
import { MoralityList } from './morality-list'
|
|
10
9
|
import { AbstractIndex } from './abstract-index'
|
|
11
|
-
import { toDate } from '../to-date'
|
|
10
|
+
import { toDate } from '../util/to-date'
|
|
11
|
+
import { coalesceToArray } from '../util/coalesce-to-array'
|
|
12
|
+
import { SetTitleIds } from './set-title-ids'
|
|
12
13
|
|
|
13
14
|
export class Badge {
|
|
14
15
|
readonly #requirementsIndex: AbstractIndex<BadgeRequirement>
|
|
@@ -72,7 +73,7 @@ export class Badge {
|
|
|
72
73
|
* The id used with the in-game `/settitle` command to apply the badge.
|
|
73
74
|
* The first value is the id for primal characters and the (optional) second number is the id for praetorian characters.
|
|
74
75
|
*/
|
|
75
|
-
readonly setTitleId?:
|
|
76
|
+
readonly setTitleId?: SetTitleIds
|
|
76
77
|
|
|
77
78
|
/**
|
|
78
79
|
* A description of the effect the badge will have, such as a buff or granting a temporary power.
|
|
@@ -96,7 +97,7 @@ export class Badge {
|
|
|
96
97
|
this.notes = badgeData.notes
|
|
97
98
|
this.links = badgeData.links ?? []
|
|
98
99
|
this.effect = badgeData.effect
|
|
99
|
-
this.setTitleId = badgeData.setTitleId
|
|
100
|
+
this.setTitleId = badgeData.setTitleId ? new SetTitleIds(badgeData.setTitleId) : undefined
|
|
100
101
|
this.ignoreInTotals = badgeData.ignoreInTotals ?? false
|
|
101
102
|
|
|
102
103
|
this.#requirementsIndex = new AbstractIndex<BadgeRequirement>('key', badgeData.requirements?.map(x => new BadgeRequirement(x)))
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Link } from '../api/link'
|
|
2
2
|
import { MarkdownString } from '../api/markdown-string'
|
|
3
3
|
import { BundleHeaderData } from '../api/bundle-header-data'
|
|
4
|
-
import { toDate } from '../to-date'
|
|
4
|
+
import { toDate } from '../util/to-date'
|
|
5
5
|
|
|
6
6
|
export class BundleHeader {
|
|
7
7
|
/**
|
package/src/main/db/contact.ts
CHANGED
|
@@ -4,7 +4,8 @@ import { MarkdownString } from '../api/markdown-string'
|
|
|
4
4
|
import { ContactData } from '../api/contact-data'
|
|
5
5
|
import { Location } from './location'
|
|
6
6
|
import { MoralityList } from './morality-list'
|
|
7
|
-
import { coalesceToArray } from '../util'
|
|
7
|
+
import { coalesceToArray } from '../util/coalesce-to-array'
|
|
8
|
+
import { LevelRange } from './level-range'
|
|
8
9
|
|
|
9
10
|
export class Contact {
|
|
10
11
|
/**
|
|
@@ -27,7 +28,7 @@ export class Contact {
|
|
|
27
28
|
/**
|
|
28
29
|
* The character moralities that this contact will interact with.
|
|
29
30
|
*/
|
|
30
|
-
readonly morality
|
|
31
|
+
readonly morality: MoralityList
|
|
31
32
|
|
|
32
33
|
/**
|
|
33
34
|
* The location of this contact.
|
|
@@ -37,7 +38,7 @@ export class Contact {
|
|
|
37
38
|
/**
|
|
38
39
|
* The level range this contact will offer missions for.
|
|
39
40
|
*/
|
|
40
|
-
readonly levelRange?:
|
|
41
|
+
readonly levelRange?: LevelRange
|
|
41
42
|
|
|
42
43
|
/**
|
|
43
44
|
* Freeform notes or tips about the contact.
|
|
@@ -55,7 +56,7 @@ export class Contact {
|
|
|
55
56
|
this.title = data.title
|
|
56
57
|
this.morality = new MoralityList(coalesceToArray(data.morality))
|
|
57
58
|
this.location = data.location
|
|
58
|
-
this.levelRange = data.levelRange
|
|
59
|
+
this.levelRange = data.levelRange ? new LevelRange(data.levelRange) : undefined
|
|
59
60
|
this.notes = data.notes
|
|
60
61
|
this.links = data.links ?? []
|
|
61
62
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { LevelRangeData } from '../api/level-range-data'
|
|
2
|
+
|
|
3
|
+
export class LevelRange {
|
|
4
|
+
readonly min: number
|
|
5
|
+
readonly max?: number
|
|
6
|
+
|
|
7
|
+
constructor(value: LevelRangeData) {
|
|
8
|
+
if (Array.isArray(value)) {
|
|
9
|
+
this.min = value[0]
|
|
10
|
+
this.max = value[1] === undefined ? undefined : value[1]
|
|
11
|
+
} else {
|
|
12
|
+
this.min = value
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
package/src/main/db/mission.ts
CHANGED
|
@@ -3,8 +3,9 @@ import { MarkdownString } from '../api/markdown-string'
|
|
|
3
3
|
import { Link } from '../api/link'
|
|
4
4
|
import { MissionData } from '../api/mission-data'
|
|
5
5
|
import { Key } from './key'
|
|
6
|
-
import { coalesceToArray } from '../util'
|
|
7
6
|
import { MoralityList } from './morality-list'
|
|
7
|
+
import { coalesceToArray } from '../util/coalesce-to-array'
|
|
8
|
+
import { LevelRange } from './level-range'
|
|
8
9
|
|
|
9
10
|
export class Mission {
|
|
10
11
|
/**
|
|
@@ -39,7 +40,7 @@ export class Mission {
|
|
|
39
40
|
/**
|
|
40
41
|
* The level range this mission is available for.
|
|
41
42
|
*/
|
|
42
|
-
readonly levelRange?:
|
|
43
|
+
readonly levelRange?: LevelRange
|
|
43
44
|
|
|
44
45
|
/**
|
|
45
46
|
* Freeform notes or tips about the mission.
|
|
@@ -62,17 +63,17 @@ export class Mission {
|
|
|
62
63
|
readonly id: string
|
|
63
64
|
|
|
64
65
|
/**
|
|
65
|
-
* The level range this mission appears under as a Flashback.
|
|
66
|
+
* The level range this mission appears under as a Flashback.
|
|
66
67
|
*/
|
|
67
|
-
readonly levelRange?:
|
|
68
|
+
readonly levelRange?: LevelRange
|
|
68
69
|
|
|
69
70
|
/**
|
|
70
|
-
* The name as it appears in the Flashback list.
|
|
71
|
+
* The name as it appears in the Flashback list.
|
|
71
72
|
*/
|
|
72
73
|
readonly name?: string
|
|
73
74
|
|
|
74
75
|
/**
|
|
75
|
-
* The character moralities that the mission will appear for in the Flashback list.
|
|
76
|
+
* The character moralities that the mission will appear for in the Flashback list.
|
|
76
77
|
*/
|
|
77
78
|
readonly morality?: MoralityList
|
|
78
79
|
|
|
@@ -88,7 +89,7 @@ export class Mission {
|
|
|
88
89
|
this.type = data.type
|
|
89
90
|
this.morality = new MoralityList(coalesceToArray(data.morality))
|
|
90
91
|
this.contactKeys = coalesceToArray(data.contactKeys)
|
|
91
|
-
this.levelRange = data.levelRange
|
|
92
|
+
this.levelRange = data.levelRange ? new LevelRange(data.levelRange) : undefined
|
|
92
93
|
this.notes = data.notes
|
|
93
94
|
this.links = data.links ?? []
|
|
94
95
|
this.flashback = createFlashback(data)
|
|
@@ -99,7 +100,7 @@ function createFlashback(data: MissionData): Mission['flashback'] {
|
|
|
99
100
|
if (!data.flashback) return undefined
|
|
100
101
|
return {
|
|
101
102
|
id: data.flashback.id,
|
|
102
|
-
levelRange: data.flashback.levelRange
|
|
103
|
+
levelRange: data.flashback.levelRange ? new LevelRange(data.flashback.levelRange) : undefined,
|
|
103
104
|
name: data.flashback.name ?? data.name,
|
|
104
105
|
morality: new MoralityList(coalesceToArray(data.flashback.morality ?? data.morality)),
|
|
105
106
|
notes: data.flashback.notes,
|
package/src/main/db/zone.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { Link } from '../api/link'
|
|
2
2
|
import { ZoneData } from '../api/zone-data'
|
|
3
3
|
import { Key } from './key'
|
|
4
|
+
import { MoralityList } from './morality-list'
|
|
5
|
+
import { coalesceToArray } from '../util/coalesce-to-array'
|
|
6
|
+
import { ZoneType } from '../api/zone-type'
|
|
7
|
+
import { MarkdownString } from '../api/markdown-string'
|
|
8
|
+
import { LevelRange } from './level-range'
|
|
4
9
|
|
|
5
10
|
export class Zone {
|
|
6
11
|
/**
|
|
@@ -15,6 +20,26 @@ export class Zone {
|
|
|
15
20
|
*/
|
|
16
21
|
readonly name: string
|
|
17
22
|
|
|
23
|
+
/**
|
|
24
|
+
* The type of zone.
|
|
25
|
+
*/
|
|
26
|
+
readonly type: ZoneType
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* The character moralities that this zone is accessible by.
|
|
30
|
+
*/
|
|
31
|
+
readonly morality: MoralityList
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* The level range this zone is recommended for.
|
|
35
|
+
*/
|
|
36
|
+
readonly levelRange?: LevelRange
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Freeform notes or tips about the zone.
|
|
40
|
+
*/
|
|
41
|
+
readonly notes?: MarkdownString
|
|
42
|
+
|
|
18
43
|
/**
|
|
19
44
|
* List of external links. Wiki, forums, etc.
|
|
20
45
|
*/
|
|
@@ -23,6 +48,10 @@ export class Zone {
|
|
|
23
48
|
constructor(data: ZoneData) {
|
|
24
49
|
this.key = new Key(data.key).value
|
|
25
50
|
this.name = data.name
|
|
51
|
+
this.type = data.type
|
|
52
|
+
this.morality = new MoralityList(coalesceToArray(data.morality))
|
|
53
|
+
this.levelRange = data.levelRange ? new LevelRange(data.levelRange) : undefined
|
|
54
|
+
this.notes = data.notes
|
|
26
55
|
this.links = data.links ?? []
|
|
27
56
|
}
|
|
28
57
|
}
|
package/src/main/index.ts
CHANGED
|
@@ -12,12 +12,16 @@ export * from './api/contact-data'
|
|
|
12
12
|
export * from './api/enhancement-category'
|
|
13
13
|
export * from './api/link'
|
|
14
14
|
export * from './api/location-data'
|
|
15
|
+
export * from './api/level-range-data'
|
|
15
16
|
export * from './api/markdown-string'
|
|
16
17
|
export * from './api/mission-data'
|
|
18
|
+
export * from './api/mission-flashback-data'
|
|
17
19
|
export * from './api/mission-type'
|
|
18
20
|
export * from './api/morality'
|
|
21
|
+
export * from './api/set-title-data'
|
|
19
22
|
export * from './api/sex'
|
|
20
23
|
export * from './api/zone-data'
|
|
24
|
+
export * from './api/zone-type'
|
|
21
25
|
|
|
22
26
|
// DB
|
|
23
27
|
export * from './db/alignment-list'
|
|
@@ -32,10 +36,12 @@ export * from './db/coh-content-database'
|
|
|
32
36
|
export * from './db/contact'
|
|
33
37
|
export * from './db/key'
|
|
34
38
|
export * from './db/location'
|
|
39
|
+
export * from './db/level-range'
|
|
35
40
|
export * from './db/mission'
|
|
36
41
|
export * from './db/morality-list'
|
|
37
42
|
export * from './db/paged'
|
|
43
|
+
export * from './db/set-title-ids'
|
|
38
44
|
export * from './db/zone'
|
|
39
45
|
|
|
40
|
-
//
|
|
41
|
-
export * from './util'
|
|
46
|
+
// UTILS
|
|
47
|
+
export * from './util/links'
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* For fields that accept either an array of values or a single value, coalesces the value to an array.
|
|
3
|
+
*
|
|
4
|
+
* Arrays are returned as-is.
|
|
5
|
+
* Single values are returned as a single-value array.
|
|
6
|
+
* Undefined values are returned as undefined.
|
|
7
|
+
*
|
|
8
|
+
* @param value The value to coalesce.
|
|
9
|
+
*/
|
|
10
|
+
export function coalesceToArray<T>(value?: T | T[]): T[] | undefined {
|
|
11
|
+
if (!value) return undefined
|
|
12
|
+
return Array.isArray(value) ? value as T[] : [value]
|
|
13
|
+
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { BadgeData } from '
|
|
2
|
-
import { Badge } from '
|
|
3
|
-
import { ZoneData } from '
|
|
4
|
-
import { Zone } from '
|
|
5
|
-
import { Contact } from '
|
|
6
|
-
import { ContactData } from '
|
|
7
|
-
import { Mission } from '
|
|
8
|
-
import { MissionData } from '
|
|
1
|
+
import { BadgeData } from '../api/badge-data'
|
|
2
|
+
import { Badge } from '../db/badge'
|
|
3
|
+
import { ZoneData } from '../api/zone-data'
|
|
4
|
+
import { Zone } from '../db/zone'
|
|
5
|
+
import { Contact } from '../db/contact'
|
|
6
|
+
import { ContactData } from '../api/contact-data'
|
|
7
|
+
import { Mission } from '../db/mission'
|
|
8
|
+
import { MissionData } from '../api/mission-data'
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Returns the URI of the given badge that can be used in {@link MarkdownString} fields.
|
|
@@ -102,17 +102,3 @@ export function zoneLink(target: string | Zone | ZoneData): string {
|
|
|
102
102
|
const key = typeof target === 'string' ? target : target.key
|
|
103
103
|
return `[${key}](${zoneUri(target)})`
|
|
104
104
|
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* For fields that accept either an array of values or a single value, coalesces the value to an array.
|
|
108
|
-
*
|
|
109
|
-
* Arrays are returned as-is.
|
|
110
|
-
* Single values are returned as a single-value array.
|
|
111
|
-
* Undefined values are returned as undefined.
|
|
112
|
-
*
|
|
113
|
-
* @param value The value to coalesce.
|
|
114
|
-
*/
|
|
115
|
-
export function coalesceToArray<T>(value?: T | T[]): T[] | undefined {
|
|
116
|
-
if (!value) return undefined
|
|
117
|
-
return Array.isArray(value) ? value as T[] : [value]
|
|
118
|
-
}
|
|
@@ -51,14 +51,14 @@ describe('compareAlignment', () => {
|
|
|
51
51
|
|
|
52
52
|
test('should work as a compare function', () => {
|
|
53
53
|
const unsorted: (Alignment | undefined)[] = [undefined, 'hero', 'villain', 'praetorian', undefined, 'villain', 'praetorian']
|
|
54
|
-
const sorted = unsorted.
|
|
54
|
+
const sorted = unsorted.toSorted(compareAlignment)
|
|
55
55
|
|
|
56
56
|
expect(sorted).toStrictEqual(['hero', 'villain', 'villain', 'praetorian', 'praetorian', undefined, undefined])
|
|
57
57
|
})
|
|
58
58
|
|
|
59
59
|
test('should sort against undefined', () => {
|
|
60
60
|
const unsorted: (Alignment | undefined)[] = [undefined, 'hero']
|
|
61
|
-
const sorted = unsorted.
|
|
61
|
+
const sorted = unsorted.toSorted(compareAlignment)
|
|
62
62
|
|
|
63
63
|
expect(sorted).toStrictEqual(['hero', undefined])
|
|
64
64
|
})
|
package/src/test/api/sex.test.ts
CHANGED
|
@@ -49,14 +49,14 @@ describe('compareSex', () => {
|
|
|
49
49
|
|
|
50
50
|
test('should work as a compare function', () => {
|
|
51
51
|
const unsorted: (Sex | undefined)[] = [undefined, 'M', 'F', 'M', undefined, 'F', 'M']
|
|
52
|
-
const sorted = unsorted.
|
|
52
|
+
const sorted = unsorted.toSorted(compareSex)
|
|
53
53
|
|
|
54
54
|
expect(sorted).toStrictEqual(['M', 'M', 'M', 'F', 'F', undefined, undefined])
|
|
55
55
|
})
|
|
56
56
|
|
|
57
57
|
test('should sort against undefined', () => {
|
|
58
58
|
const unsorted: (Sex | undefined)[] = [undefined, 'M']
|
|
59
|
-
const sorted = unsorted.
|
|
59
|
+
const sorted = unsorted.toSorted(compareSex)
|
|
60
60
|
|
|
61
61
|
expect(sorted).toStrictEqual(['M', undefined])
|
|
62
62
|
})
|
|
@@ -4,5 +4,6 @@ import { defineFixture } from 'efate'
|
|
|
4
4
|
export const zoneDataFixture = defineFixture<ZoneData>((t) => {
|
|
5
5
|
t.key.as(index => `zone-${index}`)
|
|
6
6
|
t.name.as(index => `Zone ${index}`)
|
|
7
|
+
t.type.withValue('city')
|
|
7
8
|
t.links?.as(() => [{ title: 'foo', href: 'https://nouri.org' }])
|
|
8
9
|
})
|
|
@@ -152,12 +152,14 @@ describe(Badge.name, () => {
|
|
|
152
152
|
describe('setTitle', () => {
|
|
153
153
|
test('should be set from the data', () => {
|
|
154
154
|
const badge = new Badge(badgeDataFixture.create({ setTitleId: [123, 456] }))
|
|
155
|
-
expect(badge.setTitleId).
|
|
155
|
+
expect(badge.setTitleId?.primal).toEqual(123)
|
|
156
|
+
expect(badge.setTitleId?.praetorian).toEqual(456)
|
|
156
157
|
})
|
|
157
158
|
|
|
158
159
|
test('should treat the praetorian id as optional', () => {
|
|
159
160
|
const badge = new Badge(badgeDataFixture.create({ setTitleId: [123] }))
|
|
160
|
-
expect(badge.setTitleId).
|
|
161
|
+
expect(badge.setTitleId?.primal).toEqual(123)
|
|
162
|
+
expect(badge.setTitleId?.praetorian).toBeUndefined()
|
|
161
163
|
})
|
|
162
164
|
|
|
163
165
|
test('should be optional', () => {
|
|
@@ -254,6 +256,17 @@ describe(Badge.name, () => {
|
|
|
254
256
|
}))
|
|
255
257
|
expect(badge.zoneKeys).toStrictEqual(['a', 'c'])
|
|
256
258
|
})
|
|
259
|
+
|
|
260
|
+
test(`should ignore locations with no zone key`, () => {
|
|
261
|
+
const badge = new Badge(badgeDataFixture.create({
|
|
262
|
+
requirements: [
|
|
263
|
+
badgeRequirementDataFixture.create({ location: { zoneKey: 'a' } }),
|
|
264
|
+
badgeRequirementDataFixture.create({ location: { coords: [1, 2, 3] } }),
|
|
265
|
+
badgeRequirementDataFixture.create({ location: { zoneKey: 'c' } }),
|
|
266
|
+
],
|
|
267
|
+
}))
|
|
268
|
+
expect(badge.zoneKeys).toStrictEqual(['a', 'c'])
|
|
269
|
+
})
|
|
257
270
|
})
|
|
258
271
|
|
|
259
272
|
describe('zoneKey', () => {
|
|
@@ -291,7 +304,7 @@ describe(Badge.name, () => {
|
|
|
291
304
|
const badgeA = new Badge(badgeDataFixture.create({ name: 'A' }))
|
|
292
305
|
const badgeB = new Badge(badgeDataFixture.create({ name: 'B' }))
|
|
293
306
|
expect(compareByDefaultName(badgeA, badgeB)).toBeLessThan(0)
|
|
294
|
-
expect([badgeB, badgeA].
|
|
307
|
+
expect([badgeB, badgeA].toSorted(compareByDefaultName)).toStrictEqual([badgeA, badgeB])
|
|
295
308
|
})
|
|
296
309
|
|
|
297
310
|
test(`should return 0 for equal names`, () => {
|
|
@@ -309,8 +322,8 @@ describe(Badge.name, () => {
|
|
|
309
322
|
test(`should sort undefined values last`, () => {
|
|
310
323
|
const badgeA = new Badge(badgeDataFixture.create({ name: 'A' }))
|
|
311
324
|
const badgeB = new Badge(badgeDataFixture.create({ name: [] }))
|
|
312
|
-
expect([badgeA, badgeB].
|
|
313
|
-
expect([badgeB, badgeA].
|
|
325
|
+
expect([badgeA, badgeB].toSorted(compareByDefaultName)).toStrictEqual([badgeA, badgeB])
|
|
326
|
+
expect([badgeB, badgeA].toSorted(compareByDefaultName)).toStrictEqual([badgeA, badgeB])
|
|
314
327
|
})
|
|
315
328
|
})
|
|
316
329
|
|
|
@@ -327,7 +340,7 @@ describe(Badge.name, () => {
|
|
|
327
340
|
],
|
|
328
341
|
}))
|
|
329
342
|
expect(compareByZoneKey(badgeA, badgeB)).toBeLessThan(0)
|
|
330
|
-
expect([badgeB, badgeA].
|
|
343
|
+
expect([badgeB, badgeA].toSorted(compareByZoneKey)).toStrictEqual([badgeA, badgeB])
|
|
331
344
|
})
|
|
332
345
|
|
|
333
346
|
test(`should return 0 for equal zoneKeys`, () => {
|
|
@@ -370,8 +383,8 @@ describe(Badge.name, () => {
|
|
|
370
383
|
badgeRequirementDataFixture.create({ location: { zoneKey: 'c' } }),
|
|
371
384
|
],
|
|
372
385
|
}))
|
|
373
|
-
expect([badgeA, badgeB].
|
|
374
|
-
expect([badgeB, badgeA].
|
|
386
|
+
expect([badgeA, badgeB].toSorted(compareByZoneKey)).toStrictEqual([badgeA, badgeB])
|
|
387
|
+
expect([badgeB, badgeA].toSorted(compareByZoneKey)).toStrictEqual([badgeA, badgeB])
|
|
375
388
|
})
|
|
376
389
|
})
|
|
377
390
|
|
|
@@ -380,7 +393,7 @@ describe(Badge.name, () => {
|
|
|
380
393
|
const badgeA = new Badge(badgeDataFixture.create({ releaseDate: '2024-01-01' }))
|
|
381
394
|
const badgeB = new Badge(badgeDataFixture.create({ releaseDate: '2025-01-01' }))
|
|
382
395
|
expect(compareByReleaseDate(badgeA, badgeB)).toBeLessThan(0)
|
|
383
|
-
expect([badgeB, badgeA].
|
|
396
|
+
expect([badgeB, badgeA].toSorted(compareByReleaseDate)).toStrictEqual([badgeA, badgeB])
|
|
384
397
|
})
|
|
385
398
|
|
|
386
399
|
test(`should return 0 for equal releaseDates`, () => {
|
|
@@ -399,10 +412,10 @@ describe(Badge.name, () => {
|
|
|
399
412
|
const badgeA = undefined
|
|
400
413
|
const badgeB = new Badge(badgeDataFixture.create({ releaseDate: '2025-01-01' }))
|
|
401
414
|
expect(compareByReleaseDate(badgeA, badgeB)).toBeGreaterThan(0)
|
|
402
|
-
expect([badgeA, badgeB].
|
|
415
|
+
expect([badgeA, badgeB].toSorted(compareByReleaseDate)).toStrictEqual([badgeB, badgeA])
|
|
403
416
|
|
|
404
417
|
expect(compareByReleaseDate(badgeB, badgeA)).toBeLessThan(0)
|
|
405
|
-
expect([badgeB, badgeA].
|
|
418
|
+
expect([badgeB, badgeA].toSorted(compareByReleaseDate)).toStrictEqual([badgeB, badgeA])
|
|
406
419
|
})
|
|
407
420
|
})
|
|
408
421
|
})
|
|
@@ -62,7 +62,8 @@ describe(Contact.name, () => {
|
|
|
62
62
|
describe('levelRange', () => {
|
|
63
63
|
test(`should be set from the data`, () => {
|
|
64
64
|
const contact = new Contact(contactDataFixture.create({ levelRange: [1, 2] }))
|
|
65
|
-
expect(contact
|
|
65
|
+
expect(contact?.levelRange?.min).toEqual(1)
|
|
66
|
+
expect(contact?.levelRange?.max).toEqual(2)
|
|
66
67
|
})
|
|
67
68
|
|
|
68
69
|
test(`should be optional`, () => {
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { LevelRange } from '../../main'
|
|
2
|
+
|
|
3
|
+
describe(LevelRange.name, () => {
|
|
4
|
+
describe('Constructor', () => {
|
|
5
|
+
test('should accept a full array (5-10)', () => {
|
|
6
|
+
const range = new LevelRange([5, 10])
|
|
7
|
+
expect(range).toBeDefined()
|
|
8
|
+
expect(range.min).toEqual(5)
|
|
9
|
+
expect(range.max).toEqual(10)
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
test('should accept a partial array (15+)', () => {
|
|
13
|
+
const range = new LevelRange([15])
|
|
14
|
+
expect(range).toBeDefined()
|
|
15
|
+
expect(range.min).toEqual(15)
|
|
16
|
+
expect(range.max).toBeUndefined()
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
test('should not coalesce a explicit max of 50 (20-50)', () => {
|
|
20
|
+
const range = new LevelRange([20, 50])
|
|
21
|
+
expect(range).toBeDefined()
|
|
22
|
+
expect(range.min).toEqual(20)
|
|
23
|
+
expect(range.max).toEqual(50)
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
test('should accept a single-level range (1-1)', () => {
|
|
27
|
+
const range = new LevelRange([1, 1])
|
|
28
|
+
expect(range).toBeDefined()
|
|
29
|
+
expect(range.min).toEqual(1)
|
|
30
|
+
expect(range.max).toEqual(1)
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
test('should accept a zero value (0-0)', () => {
|
|
34
|
+
const range = new LevelRange([0, 0])
|
|
35
|
+
expect(range).toBeDefined()
|
|
36
|
+
expect(range.min).toEqual(0)
|
|
37
|
+
expect(range.max).toEqual(0)
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
test('should accept a number (5+)', () => {
|
|
41
|
+
const range = new LevelRange(5)
|
|
42
|
+
expect(range).toBeDefined()
|
|
43
|
+
expect(range.min).toEqual(5)
|
|
44
|
+
expect(range.max).toBeUndefined()
|
|
45
|
+
})
|
|
46
|
+
})
|
|
47
|
+
})
|
|
@@ -56,8 +56,9 @@ describe(Mission.name, () => {
|
|
|
56
56
|
|
|
57
57
|
describe('levelRange', () => {
|
|
58
58
|
test(`should be set from the data`, () => {
|
|
59
|
-
const mission = new Mission(missionDataFixture.create({ levelRange:
|
|
60
|
-
expect(mission
|
|
59
|
+
const mission = new Mission(missionDataFixture.create({ levelRange: 25 }))
|
|
60
|
+
expect(mission?.levelRange?.min).toEqual(25)
|
|
61
|
+
expect(mission?.levelRange?.max).toBeUndefined()
|
|
61
62
|
})
|
|
62
63
|
|
|
63
64
|
test(`should be optional`, () => {
|
|
@@ -105,13 +106,14 @@ describe(Mission.name, () => {
|
|
|
105
106
|
|
|
106
107
|
describe('levelRange', () => {
|
|
107
108
|
test(`should be set from the data`, () => {
|
|
108
|
-
const mission = new Mission(missionDataFixture.create({ flashback: { levelRange: [1,
|
|
109
|
-
expect(mission.flashback?.levelRange).
|
|
109
|
+
const mission = new Mission(missionDataFixture.create({ flashback: { levelRange: [1, 20] } }))
|
|
110
|
+
expect(mission.flashback?.levelRange?.min).toEqual(1)
|
|
111
|
+
expect(mission.flashback?.levelRange?.max).toEqual(20)
|
|
110
112
|
})
|
|
111
113
|
|
|
112
|
-
test(`should default to the mission value`, () => {
|
|
114
|
+
test(`should *not* default to the mission value due to Ouro level grouping`, () => {
|
|
113
115
|
const mission = new Mission(missionDataFixture.create({ levelRange: [1, 2], flashback: missionFlashbackDataFixture.omit('levelRange').create() }))
|
|
114
|
-
expect(mission.flashback?.levelRange).
|
|
116
|
+
expect(mission.flashback?.levelRange).toBeUndefined()
|
|
115
117
|
})
|
|
116
118
|
|
|
117
119
|
test(`should be optional`, () => {
|
|
@@ -29,7 +29,7 @@ describe(MoralityList.name, () => {
|
|
|
29
29
|
expect(new MoralityList().items).toStrictEqual(['hero', 'vigilante', 'villain', 'rogue', 'resistance', 'loyalist'])
|
|
30
30
|
})
|
|
31
31
|
|
|
32
|
-
test('should treat empty as no values', () => {
|
|
32
|
+
test('should treat explicit empty as no values', () => {
|
|
33
33
|
expect(new MoralityList([]).items).toStrictEqual([])
|
|
34
34
|
})
|
|
35
35
|
})
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { SetTitleIds } from '../../main'
|
|
2
|
+
|
|
3
|
+
describe(SetTitleIds.name, () => {
|
|
4
|
+
describe('Constructor', () => {
|
|
5
|
+
test('should accept both primal and praetorian values', () => {
|
|
6
|
+
const ids = new SetTitleIds([5, 10])
|
|
7
|
+
expect(ids).toBeDefined()
|
|
8
|
+
expect(ids.primal).toEqual(5)
|
|
9
|
+
expect(ids.praetorian).toEqual(10)
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
test('should accept primal only', () => {
|
|
13
|
+
const ids = new SetTitleIds([1])
|
|
14
|
+
expect(ids).toBeDefined()
|
|
15
|
+
expect(ids.primal).toEqual(1)
|
|
16
|
+
expect(ids.praetorian).toBeUndefined()
|
|
17
|
+
})
|
|
18
|
+
})
|
|
19
|
+
})
|