coh-content-db 2.0.0-rc.6 → 2.0.0-rc.8
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/.github/workflows/pull-request.yml +1 -1
- package/.github/workflows/release.yml +1 -1
- package/README.md +3 -3
- package/dist/coh-content-db.d.ts +444 -194
- package/dist/coh-content-db.js +720 -413
- package/dist/coh-content-db.js.map +1 -1
- package/dist/coh-content-db.mjs +708 -412
- package/dist/coh-content-db.mjs.map +1 -1
- package/eslint.config.mjs +1 -0
- package/package.json +1 -1
- package/src/main/api/alignment.ts +18 -2
- package/src/main/api/badge-data.ts +12 -42
- package/src/main/api/badge-requirement-data.ts +17 -35
- package/src/main/api/badge-requirement-type.ts +28 -7
- package/src/main/api/badge-type.ts +15 -15
- package/src/main/api/contact-data.ts +7 -5
- package/src/main/api/content-bundle.ts +6 -0
- package/src/main/api/enhancement-category.ts +26 -26
- package/src/main/api/location-data.ts +28 -0
- package/src/main/api/mission-data.ts +83 -0
- package/src/main/api/mission-type.ts +2 -0
- package/src/main/api/morality.ts +31 -0
- package/src/main/api/sex.ts +8 -1
- package/src/main/api/zone-data.ts +1 -1
- package/src/main/changelog.ts +5 -4
- package/src/main/db/abstract-index.ts +41 -0
- package/src/main/db/alignment-list.ts +54 -0
- package/src/main/db/alternates.ts +15 -32
- package/src/main/db/badge-index.ts +14 -50
- package/src/main/db/badge-requirement.ts +22 -43
- package/src/main/db/badge-search-options.ts +4 -4
- package/src/main/db/badge.ts +53 -54
- package/src/main/db/bundle-metadata.ts +8 -2
- package/src/main/db/coh-content-database.ts +80 -67
- package/src/main/db/contact.ts +17 -14
- package/src/main/db/location.ts +30 -0
- package/src/main/db/mission.ts +107 -0
- package/src/main/db/morality-list.ts +99 -0
- package/src/main/db/zone.ts +1 -1
- package/src/main/index.ts +8 -3
- package/src/main/util.ts +43 -3
- package/src/test/api/alignment.test.ts +38 -4
- package/src/test/api/badge-data.fixture.ts +1 -17
- package/src/test/api/badge-data.test.ts +3 -3
- package/src/test/api/badge-requirement-data.fixture.ts +1 -11
- package/src/test/api/badge-requirement-type.test.ts +3 -3
- package/src/test/api/badge-type.test.ts +5 -5
- package/src/test/api/contact-data.fixture.ts +0 -6
- package/src/test/api/content-bundle.fixture.ts +1 -17
- package/src/test/api/enhancement-category.test.ts +5 -5
- package/src/test/api/mission-data.fixture.ts +12 -0
- package/src/test/api/sex.test.ts +33 -1
- package/src/test/api/zone-data.fixture.ts +1 -1
- package/src/test/db/abstract-index.test.ts +86 -0
- package/src/test/db/alignment-list.test.ts +200 -0
- package/src/test/db/alternates.test.ts +60 -56
- package/src/test/db/badge-index.test.ts +220 -183
- package/src/test/db/badge-requirement.test.ts +35 -70
- package/src/test/db/badge.test.ts +185 -64
- package/src/test/db/bundle-metadata.test.ts +17 -0
- package/src/test/db/coh-content-database.test.ts +193 -119
- package/src/test/db/contact.test.ts +25 -24
- package/src/test/db/location.test.ts +51 -0
- package/src/test/db/mission.test.ts +171 -0
- package/src/test/db/morality-list.test.ts +457 -0
- package/src/test/db/zone.test.ts +4 -4
- package/src/test/util.test.ts +54 -1
- package/src/main/api/plaque-type.ts +0 -6
- package/src/main/db/alignments.ts +0 -17
- package/src/test/api/alignments.test.ts +0 -40
- package/src/test/api/plaque-type.test.ts +0 -31
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { MissionType } from '../api/mission-type'
|
|
2
|
+
import { MarkdownString } from '../api/markdown-string'
|
|
3
|
+
import { Link } from '../api/link'
|
|
4
|
+
import { MissionData } from '../api/mission-data'
|
|
5
|
+
import { Key } from './key'
|
|
6
|
+
import { coalesceToArray } from '../util'
|
|
7
|
+
import { MoralityList } from './morality-list'
|
|
8
|
+
|
|
9
|
+
export class Mission {
|
|
10
|
+
/**
|
|
11
|
+
* Unique key used to reference this mission.
|
|
12
|
+
*
|
|
13
|
+
* Keys must be unique and can only contain lowercase letters, numbers and hyphens (`-`).
|
|
14
|
+
*/
|
|
15
|
+
readonly key: string
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* The name of the mission as it appears from the contact.
|
|
19
|
+
*
|
|
20
|
+
* The name may be different when viewed in Ouroboros as a Flashback.
|
|
21
|
+
*/
|
|
22
|
+
readonly name: string
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* The type of mission... Story arc, task force, trial, etc.
|
|
26
|
+
*/
|
|
27
|
+
readonly type: MissionType
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* The character moralities that may accept the mission.
|
|
31
|
+
*/
|
|
32
|
+
readonly morality: MoralityList
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* The keys of any contacts that provide this mission.
|
|
36
|
+
*/
|
|
37
|
+
readonly contactKeys?: string[]
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* The level range this mission is available for.
|
|
41
|
+
*/
|
|
42
|
+
readonly levelRange?: [number, number?]
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Freeform notes or tips about the mission.
|
|
46
|
+
*/
|
|
47
|
+
readonly notes?: MarkdownString
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* List of external links. Wiki, forums, etc.
|
|
51
|
+
*/
|
|
52
|
+
readonly links: Link[]
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* If the mission is available in Ouroboros as a Flashback.
|
|
56
|
+
*/
|
|
57
|
+
readonly flashback?: {
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* The id of the mission as seen in the Flashback menu, i.e. '14.01'.
|
|
61
|
+
*/
|
|
62
|
+
readonly id: string
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* The level range this mission appears under as a Flashback. Leave undefined if the same as the base mission.
|
|
66
|
+
*/
|
|
67
|
+
readonly levelRange?: [number, number?]
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* The name as it appears in the Flashback list. Leave undefined if the same as the base mission.
|
|
71
|
+
*/
|
|
72
|
+
readonly name?: string
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* The character moralities that the mission will appear for in the Flashback list. Leave undefined if the same as the base mission.
|
|
76
|
+
*/
|
|
77
|
+
readonly morality?: MoralityList
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Freeform notes or tips about the Flashback version of the mission.
|
|
81
|
+
*/
|
|
82
|
+
readonly notes?: MarkdownString
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
constructor(data: MissionData) {
|
|
86
|
+
this.key = new Key(data.key).value
|
|
87
|
+
this.name = data.name
|
|
88
|
+
this.type = data.type
|
|
89
|
+
this.morality = new MoralityList(coalesceToArray(data.morality))
|
|
90
|
+
this.contactKeys = coalesceToArray(data.contactKeys)
|
|
91
|
+
this.levelRange = data.levelRange
|
|
92
|
+
this.notes = data.notes
|
|
93
|
+
this.links = data.links ?? []
|
|
94
|
+
this.flashback = createFlashback(data)
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function createFlashback(data: MissionData): Mission['flashback'] {
|
|
99
|
+
if (!data.flashback) return undefined
|
|
100
|
+
return {
|
|
101
|
+
id: data.flashback.id,
|
|
102
|
+
levelRange: data.flashback.levelRange ?? data.levelRange,
|
|
103
|
+
name: data.flashback.name ?? data.name,
|
|
104
|
+
morality: new MoralityList(coalesceToArray(data.flashback.morality ?? data.morality)),
|
|
105
|
+
notes: data.flashback.notes,
|
|
106
|
+
}
|
|
107
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { MORALITY, Morality, MoralityExtended } from '../api/morality'
|
|
2
|
+
|
|
3
|
+
export class MoralityList {
|
|
4
|
+
readonly #items: Set<Morality>
|
|
5
|
+
|
|
6
|
+
readonly hero: boolean
|
|
7
|
+
readonly vigilante: boolean
|
|
8
|
+
readonly villain: boolean
|
|
9
|
+
readonly rogue: boolean
|
|
10
|
+
readonly resistance: boolean
|
|
11
|
+
readonly loyalist: boolean
|
|
12
|
+
|
|
13
|
+
readonly primal: boolean
|
|
14
|
+
readonly praetorian: boolean
|
|
15
|
+
readonly heroic: boolean
|
|
16
|
+
readonly villainous: boolean
|
|
17
|
+
readonly paragonCityAccess: boolean
|
|
18
|
+
readonly rogueIslesAccess: boolean
|
|
19
|
+
|
|
20
|
+
readonly all: boolean
|
|
21
|
+
|
|
22
|
+
constructor(items?: MoralityExtended[]) {
|
|
23
|
+
const set = new Set(items ?? [...MORALITY])
|
|
24
|
+
this.hero = set.has('hero') || set.has('primal') || set.has('heroic') || set.has('paragon-city-access') || set.has('all')
|
|
25
|
+
this.vigilante = set.has('vigilante') || set.has('primal') || set.has('heroic') || set.has('paragon-city-access') || set.has('rogue-isles-access') || set.has('all')
|
|
26
|
+
this.villain = set.has('villain') || set.has('primal') || set.has('villainous') || set.has('rogue-isles-access') || set.has('all')
|
|
27
|
+
this.rogue = set.has('rogue') || set.has('primal') || set.has('villainous') || set.has('paragon-city-access') || set.has('rogue-isles-access') || set.has('all')
|
|
28
|
+
this.resistance = set.has('resistance') || set.has('praetorian') || set.has('all')
|
|
29
|
+
this.loyalist = set.has('loyalist') || set.has('praetorian') || set.has('all')
|
|
30
|
+
|
|
31
|
+
this.primal = this.hero && this.vigilante && this.villain && this.rogue
|
|
32
|
+
this.praetorian = this.loyalist && this.resistance
|
|
33
|
+
this.heroic = this.hero && this.vigilante
|
|
34
|
+
this.villainous = this.villain && this.rogue
|
|
35
|
+
this.paragonCityAccess = this.heroic && this.rogue
|
|
36
|
+
this.rogueIslesAccess = this.villainous && this.vigilante
|
|
37
|
+
|
|
38
|
+
this.all = this.primal && this.praetorian
|
|
39
|
+
|
|
40
|
+
this.#items = new Set()
|
|
41
|
+
if (this.hero) this.#items.add('hero')
|
|
42
|
+
if (this.vigilante) this.#items.add('vigilante')
|
|
43
|
+
if (this.villain) this.#items.add('villain')
|
|
44
|
+
if (this.rogue) this.#items.add('rogue')
|
|
45
|
+
if (this.resistance) this.#items.add('resistance')
|
|
46
|
+
if (this.loyalist) this.#items.add('loyalist')
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
get items(): Morality[] {
|
|
50
|
+
return [...this.#items]
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
has(morality?: MoralityExtended): boolean {
|
|
54
|
+
switch (morality) {
|
|
55
|
+
case 'hero': {
|
|
56
|
+
return this.hero
|
|
57
|
+
}
|
|
58
|
+
case 'vigilante': {
|
|
59
|
+
return this.vigilante
|
|
60
|
+
}
|
|
61
|
+
case 'villain': {
|
|
62
|
+
return this.villain
|
|
63
|
+
}
|
|
64
|
+
case 'rogue': {
|
|
65
|
+
return this.rogue
|
|
66
|
+
}
|
|
67
|
+
case 'resistance': {
|
|
68
|
+
return this.resistance
|
|
69
|
+
}
|
|
70
|
+
case 'loyalist': {
|
|
71
|
+
return this.loyalist
|
|
72
|
+
}
|
|
73
|
+
case 'primal' : {
|
|
74
|
+
return this.primal
|
|
75
|
+
}
|
|
76
|
+
case 'praetorian': {
|
|
77
|
+
return this.praetorian
|
|
78
|
+
}
|
|
79
|
+
case 'heroic': {
|
|
80
|
+
return this.hero
|
|
81
|
+
}
|
|
82
|
+
case 'paragon-city-access': {
|
|
83
|
+
return this.paragonCityAccess
|
|
84
|
+
}
|
|
85
|
+
case 'rogue-isles-access': {
|
|
86
|
+
return this.rogueIslesAccess
|
|
87
|
+
}
|
|
88
|
+
case 'villainous': {
|
|
89
|
+
return this.villainous
|
|
90
|
+
}
|
|
91
|
+
case 'all': {
|
|
92
|
+
return this.all
|
|
93
|
+
}
|
|
94
|
+
default: {
|
|
95
|
+
return false
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
package/src/main/db/zone.ts
CHANGED
|
@@ -6,7 +6,7 @@ export class Zone {
|
|
|
6
6
|
/**
|
|
7
7
|
* Unique key used to reference this zone.
|
|
8
8
|
*
|
|
9
|
-
* Keys can only contain lowercase letters, numbers and hyphens (`-`).
|
|
9
|
+
* Keys must be unique and can only contain lowercase letters, numbers and hyphens (`-`).
|
|
10
10
|
*/
|
|
11
11
|
readonly key: string
|
|
12
12
|
|
package/src/main/index.ts
CHANGED
|
@@ -11,13 +11,16 @@ export * from './api/contact-data'
|
|
|
11
11
|
export * from './api/content-bundle'
|
|
12
12
|
export * from './api/enhancement-category'
|
|
13
13
|
export * from './api/link'
|
|
14
|
+
export * from './api/location-data'
|
|
14
15
|
export * from './api/markdown-string'
|
|
15
|
-
export * from './api/
|
|
16
|
+
export * from './api/mission-data'
|
|
17
|
+
export * from './api/mission-type'
|
|
18
|
+
export * from './api/morality'
|
|
16
19
|
export * from './api/sex'
|
|
17
20
|
export * from './api/zone-data'
|
|
18
21
|
|
|
19
22
|
// DB
|
|
20
|
-
export * from './db/
|
|
23
|
+
export * from './db/alignment-list'
|
|
21
24
|
export * from './db/alternates'
|
|
22
25
|
export * from './db/archetype'
|
|
23
26
|
export * from './db/badge'
|
|
@@ -28,10 +31,12 @@ export * from './db/bundle-metadata'
|
|
|
28
31
|
export * from './db/coh-content-database'
|
|
29
32
|
export * from './db/contact'
|
|
30
33
|
export * from './db/key'
|
|
34
|
+
export * from './db/location'
|
|
35
|
+
export * from './db/mission'
|
|
36
|
+
export * from './db/morality-list'
|
|
31
37
|
export * from './db/paged'
|
|
32
38
|
export * from './db/zone'
|
|
33
39
|
|
|
34
40
|
// ROOT
|
|
35
41
|
export { CHANGELOG } from './changelog'
|
|
36
|
-
|
|
37
42
|
export * from './util'
|
package/src/main/util.ts
CHANGED
|
@@ -4,9 +4,11 @@ import { ZoneData } from './api/zone-data'
|
|
|
4
4
|
import { Zone } from './db/zone'
|
|
5
5
|
import { Contact } from './db/contact'
|
|
6
6
|
import { ContactData } from './api/contact-data'
|
|
7
|
+
import { Mission } from './db/mission'
|
|
8
|
+
import { MissionData } from './api/mission-data'
|
|
7
9
|
|
|
8
10
|
/**
|
|
9
|
-
* Returns the URI of the given badge that can be used in {@link MarkdownString}
|
|
11
|
+
* Returns the URI of the given badge that can be used in {@link MarkdownString} fields.
|
|
10
12
|
*
|
|
11
13
|
* URI format: `badge://<key>`
|
|
12
14
|
*
|
|
@@ -30,7 +32,7 @@ export function badgeLink(target: string | Badge | BadgeData): string {
|
|
|
30
32
|
}
|
|
31
33
|
|
|
32
34
|
/**
|
|
33
|
-
* Returns the URI of the given contact that can be used in {@link MarkdownString}
|
|
35
|
+
* Returns the URI of the given contact that can be used in {@link MarkdownString} fields.
|
|
34
36
|
*
|
|
35
37
|
* URI format: `contact://<key>`
|
|
36
38
|
*
|
|
@@ -54,7 +56,31 @@ export function contactLink(target: string | Contact | ContactData): string {
|
|
|
54
56
|
}
|
|
55
57
|
|
|
56
58
|
/**
|
|
57
|
-
* Returns the URI of the given
|
|
59
|
+
* Returns the URI of the given mission that can be used in {@link MarkdownString} fields.
|
|
60
|
+
*
|
|
61
|
+
* URI format: `mission://<key>`
|
|
62
|
+
*
|
|
63
|
+
* @param target The {@link Mission} or mission key to target.
|
|
64
|
+
*/
|
|
65
|
+
export function missionUri(target: string | Mission | MissionData): string {
|
|
66
|
+
const key = typeof target === 'string' ? target : target.key
|
|
67
|
+
return `mission://${key}`
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Returns a {@link MarkdownString} link to the given mission.
|
|
72
|
+
*
|
|
73
|
+
* Link format: `[<key>](mission://<key>)`
|
|
74
|
+
*
|
|
75
|
+
* @param target The {@link Mission} or mission key to target.
|
|
76
|
+
*/
|
|
77
|
+
export function missionLink(target: string | Mission | MissionData): string {
|
|
78
|
+
const key = typeof target === 'string' ? target : target.key
|
|
79
|
+
return `[${key}](${missionUri(target)})`
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Returns the URI of the given zone that can be used in {@link MarkdownString} fields.
|
|
58
84
|
*
|
|
59
85
|
* URI format: `zone://<key>`
|
|
60
86
|
*
|
|
@@ -76,3 +102,17 @@ export function zoneLink(target: string | Zone | ZoneData): string {
|
|
|
76
102
|
const key = typeof target === 'string' ? target : target.key
|
|
77
103
|
return `[${key}](${zoneUri(target)})`
|
|
78
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
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Alignment, ALIGNMENT } from '../../main'
|
|
1
|
+
import { Alignment, ALIGNMENT, compareAlignment } from '../../main'
|
|
2
2
|
|
|
3
3
|
describe('ALIGNMENT', () => {
|
|
4
4
|
test('should be an array', () => {
|
|
@@ -16,7 +16,7 @@ describe('ALIGNMENT', () => {
|
|
|
16
16
|
})
|
|
17
17
|
|
|
18
18
|
test('should contain all known alignments', () => {
|
|
19
|
-
const expected = ['
|
|
19
|
+
const expected = ['hero', 'villain', 'praetorian']
|
|
20
20
|
for (const category of expected) {
|
|
21
21
|
expect(ALIGNMENT).toContain(category)
|
|
22
22
|
}
|
|
@@ -25,7 +25,41 @@ describe('ALIGNMENT', () => {
|
|
|
25
25
|
|
|
26
26
|
describe('Alignment', () => {
|
|
27
27
|
test('should be a usable type', () => {
|
|
28
|
-
const field: Alignment = '
|
|
29
|
-
expect(field).toBe('
|
|
28
|
+
const field: Alignment = 'hero'
|
|
29
|
+
expect(field).toBe('hero')
|
|
30
|
+
})
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
describe('compareAlignment', () => {
|
|
34
|
+
test('should return <0 if first argument comes first', () => {
|
|
35
|
+
expect(compareAlignment('hero', 'villain')).toBeLessThan(0)
|
|
36
|
+
expect(compareAlignment('hero', 'praetorian')).toBeLessThan(0)
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
test('should return >0 if second argument comes first', () => {
|
|
40
|
+
expect(compareAlignment('villain', 'hero')).toBeGreaterThan(0)
|
|
41
|
+
expect(compareAlignment('praetorian', 'hero')).toBeGreaterThan(0)
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
test('should return 0 if arguments match', () => {
|
|
45
|
+
expect(compareAlignment('hero', 'hero')).toBe(0)
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
test('should return 0 if both arguments are undefined', () => {
|
|
49
|
+
expect(compareAlignment()).toBe(0)
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
test('should work as a compare function', () => {
|
|
53
|
+
const unsorted: (Alignment | undefined)[] = [undefined, 'hero', 'villain', 'praetorian', undefined, 'villain', 'praetorian']
|
|
54
|
+
const sorted = unsorted.sort(compareAlignment)
|
|
55
|
+
|
|
56
|
+
expect(sorted).toStrictEqual(['hero', 'villain', 'villain', 'praetorian', 'praetorian', undefined, undefined])
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
test('should sort against undefined', () => {
|
|
60
|
+
const unsorted: (Alignment | undefined)[] = [undefined, 'hero']
|
|
61
|
+
const sorted = unsorted.sort(compareAlignment)
|
|
62
|
+
|
|
63
|
+
expect(sorted).toStrictEqual(['hero', undefined])
|
|
30
64
|
})
|
|
31
65
|
})
|
|
@@ -1,24 +1,8 @@
|
|
|
1
1
|
import { defineFixture } from 'efate'
|
|
2
|
-
import {
|
|
3
|
-
import { badgeRequirementDataFixture } from './badge-requirement-data.fixture'
|
|
2
|
+
import { BADGE_TYPE, BadgeData } from '../../main'
|
|
4
3
|
|
|
5
4
|
export const badgeDataFixture = defineFixture<BadgeData>((t) => {
|
|
6
5
|
t.key.as(index => `badge-${index}`)
|
|
7
6
|
t.type.pickFrom([...BADGE_TYPE])
|
|
8
7
|
t.name.as(index => [{ value: `Badge ${index}` }])
|
|
9
|
-
t.alignment.pickFrom([...ALIGNMENT])
|
|
10
|
-
t.badgeText?.as(index => [{ value: `This is badge ${index}` }])
|
|
11
|
-
t.acquisition?.asLoremIpsum()
|
|
12
|
-
t.icon?.as(() => [{ value: 'https://nouri.org' }])
|
|
13
|
-
t.notes?.asLoremIpsum()
|
|
14
|
-
t.links?.as(() => [{ href: 'https://nouri.org' }])
|
|
15
|
-
t.zoneKey?.asString()
|
|
16
|
-
t.loc?.as(index => [index, index, index])
|
|
17
|
-
t.vidiotMapKey?.asString()
|
|
18
|
-
t.setTitle?.as((index) => {
|
|
19
|
-
return { id: index }
|
|
20
|
-
})
|
|
21
|
-
t.effect?.asString()
|
|
22
|
-
t.requirements?.as(() => [[badgeRequirementDataFixture]])
|
|
23
|
-
t.ignoreInTotals?.asBoolean()
|
|
24
8
|
})
|
|
@@ -3,9 +3,9 @@ import { BadgeData } from '../../main'
|
|
|
3
3
|
// If you change this test, update the example in the README as well
|
|
4
4
|
export const TEST_BADGE: BadgeData = {
|
|
5
5
|
key: 'test-badge',
|
|
6
|
-
type: '
|
|
7
|
-
name: [{ value: 'Test Badge' }, { alignment: '
|
|
8
|
-
|
|
6
|
+
type: 'achievement',
|
|
7
|
+
name: [{ value: 'Test Badge' }, { alignment: 'praetorian', value: 'My Badge for Praetorians' }],
|
|
8
|
+
morality: ['hero', 'praetorian'],
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
describe('BadgeData', () => {
|
|
@@ -1,17 +1,7 @@
|
|
|
1
1
|
import { defineFixture } from 'efate'
|
|
2
|
-
import { BADGE_REQUIREMENT_TYPE, BadgeRequirementData
|
|
2
|
+
import { BADGE_REQUIREMENT_TYPE, BadgeRequirementData } from '../../main'
|
|
3
3
|
|
|
4
4
|
export const badgeRequirementDataFixture = defineFixture<BadgeRequirementData>((t) => {
|
|
5
5
|
t.key.as(index => `badge-requirement-${index}`)
|
|
6
6
|
t.type.pickFrom([...BADGE_REQUIREMENT_TYPE])
|
|
7
|
-
t.zoneKey?.asString()
|
|
8
|
-
t.loc?.as(index => [index, index, index])
|
|
9
|
-
t.plaqueType?.pickFrom([...PLAQUE_TYPE])
|
|
10
|
-
t.plaqueInscription?.asLoremIpsum()
|
|
11
|
-
t.vidiotMapKey?.asString()
|
|
12
|
-
t.badgeKey?.as(index => `badge-${index}`)
|
|
13
|
-
t.inventionLevel?.asNumber()
|
|
14
|
-
t.inventionTypes?.pickFrom([...ENHANCEMENT_CATEGORY])
|
|
15
|
-
t.inventionCount?.asNumber()
|
|
16
|
-
t.notes?.asLoremIpsum()
|
|
17
7
|
})
|
|
@@ -16,7 +16,7 @@ describe('BADGE_REQUIREMENT_TYPE', () => {
|
|
|
16
16
|
})
|
|
17
17
|
|
|
18
18
|
test('should contain all known badge requirement types', () => {
|
|
19
|
-
const expected = ['
|
|
19
|
+
const expected = ['badge', 'invention', 'invention-plus-one', 'location', 'monument', 'mission', 'task']
|
|
20
20
|
for (const category of expected) {
|
|
21
21
|
expect(BADGE_REQUIREMENT_TYPE).toContain(category)
|
|
22
22
|
}
|
|
@@ -25,7 +25,7 @@ describe('BADGE_REQUIREMENT_TYPE', () => {
|
|
|
25
25
|
|
|
26
26
|
describe('BadgeRequirementType', () => {
|
|
27
27
|
test('should be a usable type', () => {
|
|
28
|
-
const field: BadgeRequirementType = '
|
|
29
|
-
expect(field).toBe('
|
|
28
|
+
const field: BadgeRequirementType = 'monument'
|
|
29
|
+
expect(field).toBe('monument')
|
|
30
30
|
})
|
|
31
31
|
})
|
|
@@ -17,9 +17,9 @@ describe('BADGE_TYPE', () => {
|
|
|
17
17
|
|
|
18
18
|
test('should contain all known basic badge types', () => {
|
|
19
19
|
const expected = [
|
|
20
|
-
'
|
|
21
|
-
'
|
|
22
|
-
'
|
|
20
|
+
'exploration', 'history', 'accomplishment', 'achievement', 'accolade',
|
|
21
|
+
'gladiator', 'veteran', 'pvp', 'invention', 'defeat',
|
|
22
|
+
'event', 'ouroboros', 'consignment', 'day-job', 'architect-entertainment',
|
|
23
23
|
]
|
|
24
24
|
for (const category of expected) {
|
|
25
25
|
expect(BADGE_TYPE).toContain(category)
|
|
@@ -29,7 +29,7 @@ describe('BADGE_TYPE', () => {
|
|
|
29
29
|
|
|
30
30
|
describe('BadgeType', () => {
|
|
31
31
|
test('should be a usable type', () => {
|
|
32
|
-
const field: BadgeType = '
|
|
33
|
-
expect(field).toBe('
|
|
32
|
+
const field: BadgeType = 'exploration'
|
|
33
|
+
expect(field).toBe('exploration')
|
|
34
34
|
})
|
|
35
35
|
})
|
|
@@ -4,10 +4,4 @@ import { ContactData } from '../../main'
|
|
|
4
4
|
export const contactDataFixture = defineFixture<ContactData>((t) => {
|
|
5
5
|
t.key.as(index => `contact-${index}`)
|
|
6
6
|
t.name.as(index => [{ value: `Contact ${index}` }])
|
|
7
|
-
t.title?.as(index => [{ value: `Contact title ${index}` }])
|
|
8
|
-
t.zoneKey?.asString()
|
|
9
|
-
t.loc?.as(index => [index, index, index])
|
|
10
|
-
t.levelRange?.as(index => [index, index])
|
|
11
|
-
t.notes?.asLoremIpsum()
|
|
12
|
-
t.links?.as(() => [{ href: 'https://nouri.org' }])
|
|
13
7
|
})
|
|
@@ -1,22 +1,6 @@
|
|
|
1
1
|
import { defineFixture } from 'efate'
|
|
2
|
-
import {
|
|
3
|
-
import { archetypeDataFixture } from './archetype-data.fixture'
|
|
4
|
-
import { zoneDataFixture } from './zone-data.fixture'
|
|
5
|
-
import { badgeDataFixture } from './badge-data.fixture'
|
|
2
|
+
import { ContentBundle } from '../../main'
|
|
6
3
|
|
|
7
4
|
export const contentBundleFixture = defineFixture<ContentBundle>((t) => {
|
|
8
5
|
t.name.as(index => `Bundle ${index}`)
|
|
9
|
-
t.description?.asLoremIpsum()
|
|
10
|
-
t.repository?.as(index => `https://nouri.org?id=${index}`)
|
|
11
|
-
t.servers?.asArray()
|
|
12
|
-
t.archetypes?.arrayOfFixture({ fixture: archetypeDataFixture })
|
|
13
|
-
t.zones?.arrayOfFixture({ fixture: zoneDataFixture })
|
|
14
|
-
t.badges?.arrayOfFixture({ fixture: badgeDataFixture })
|
|
15
|
-
t.changelog?.arrayOfFixture({
|
|
16
|
-
fixture: defineFixture<Change>((t) => {
|
|
17
|
-
t.version.as(index => `${index}`)
|
|
18
|
-
t.date.as(() => new Date())
|
|
19
|
-
t.description?.asLoremIpsum()
|
|
20
|
-
}),
|
|
21
|
-
})
|
|
22
6
|
})
|
|
@@ -17,9 +17,9 @@ describe('ENHANCEMENT_CATEGORY', () => {
|
|
|
17
17
|
|
|
18
18
|
test('should contain all known default enhancement categories', () => {
|
|
19
19
|
const expected = [
|
|
20
|
-
'
|
|
21
|
-
'
|
|
22
|
-
'
|
|
20
|
+
'defense-debuff', 'to-hit-debuff', 'taunt', 'confuse', 'healing', 'defense-buff', 'resist-damage', 'intangibility', 'sleep', 'slow', 'hold', 'stun', 'immobilize',
|
|
21
|
+
'fear', 'endurance-modification', 'endurance-reduction', 'recharge-reduction', 'interrupt-duration', 'accuracy', 'to-hit-buff', 'damage', 'knockback', 'run-speed',
|
|
22
|
+
'jump', 'fly-speed', 'range',
|
|
23
23
|
]
|
|
24
24
|
for (const category of expected) {
|
|
25
25
|
expect(ENHANCEMENT_CATEGORY).toContain(category)
|
|
@@ -29,7 +29,7 @@ describe('ENHANCEMENT_CATEGORY', () => {
|
|
|
29
29
|
|
|
30
30
|
describe('EnhancementCategory', () => {
|
|
31
31
|
test('should be a usable type', () => {
|
|
32
|
-
const field: EnhancementCategory = '
|
|
33
|
-
expect(field).toBe('
|
|
32
|
+
const field: EnhancementCategory = 'run-speed'
|
|
33
|
+
expect(field).toBe('run-speed')
|
|
34
34
|
})
|
|
35
35
|
})
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { defineFixture } from 'efate'
|
|
2
|
+
import { MISSION_TYPE, MissionData, MissionFlashbackData } from '../../main'
|
|
3
|
+
|
|
4
|
+
export const missionDataFixture = defineFixture<MissionData>((t) => {
|
|
5
|
+
t.key.as(index => `mission-${index}`)
|
|
6
|
+
t.name.as(index => `Mission ${index}`)
|
|
7
|
+
t.type.pickFrom([...MISSION_TYPE])
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
export const missionFlashbackDataFixture = defineFixture<MissionFlashbackData>((t) => {
|
|
11
|
+
t.id.as(index => `${index}.${index}`)
|
|
12
|
+
})
|
package/src/test/api/sex.test.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Sex, SEX } from '../../main'
|
|
1
|
+
import { compareSex, Sex, SEX } from '../../main'
|
|
2
2
|
|
|
3
3
|
describe('SEX', () => {
|
|
4
4
|
test('should be an array', () => {
|
|
@@ -29,3 +29,35 @@ describe('Sex', () => {
|
|
|
29
29
|
expect(field).toBe('M')
|
|
30
30
|
})
|
|
31
31
|
})
|
|
32
|
+
|
|
33
|
+
describe('compareSex', () => {
|
|
34
|
+
test('should return <0 if first argument comes first', () => {
|
|
35
|
+
expect(compareSex('M', 'F')).toBeLessThan(0)
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
test('should return >0 if second argument comes first', () => {
|
|
39
|
+
expect(compareSex('F', 'M')).toBeGreaterThan(0)
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
test('should return 0 if arguments match', () => {
|
|
43
|
+
expect(compareSex('F', 'F')).toBe(0)
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
test('should return 0 if both arguments are undefined', () => {
|
|
47
|
+
expect(compareSex()).toBe(0)
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
test('should work as a compare function', () => {
|
|
51
|
+
const unsorted: (Sex | undefined)[] = [undefined, 'M', 'F', 'M', undefined, 'F', 'M']
|
|
52
|
+
const sorted = unsorted.sort(compareSex)
|
|
53
|
+
|
|
54
|
+
expect(sorted).toStrictEqual(['M', 'M', 'M', 'F', 'F', undefined, undefined])
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
test('should sort against undefined', () => {
|
|
58
|
+
const unsorted: (Sex | undefined)[] = [undefined, 'M']
|
|
59
|
+
const sorted = unsorted.sort(compareSex)
|
|
60
|
+
|
|
61
|
+
expect(sorted).toStrictEqual(['M', undefined])
|
|
62
|
+
})
|
|
63
|
+
})
|
|
@@ -4,5 +4,5 @@ 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.links?.as(() => [{ href: 'https://nouri.org' }])
|
|
7
|
+
t.links?.as(() => [{ title: 'foo', href: 'https://nouri.org' }])
|
|
8
8
|
})
|