coh-content-db 2.0.0-rc.1 → 2.0.0-rc.11

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.
Files changed (100) hide show
  1. package/.editorconfig +10 -11
  2. package/.github/workflows/build.yml +4 -2
  3. package/.github/workflows/pull-request.yml +1 -1
  4. package/.github/workflows/release.yml +2 -2
  5. package/CHANGELOG.md +43 -0
  6. package/README.md +52 -24
  7. package/dist/coh-content-db.d.ts +678 -279
  8. package/dist/coh-content-db.js +828 -371
  9. package/dist/coh-content-db.js.map +1 -1
  10. package/dist/coh-content-db.mjs +803 -362
  11. package/dist/coh-content-db.mjs.map +1 -1
  12. package/eslint.config.mjs +1 -0
  13. package/package.json +1 -1
  14. package/src/main/api/alignment.ts +18 -2
  15. package/src/main/api/alternate-data.ts +2 -2
  16. package/src/main/api/badge-data.ts +20 -48
  17. package/src/main/api/badge-requirement-data.ts +64 -0
  18. package/src/main/api/badge-requirement-type.ts +32 -0
  19. package/src/main/api/badge-type.ts +15 -15
  20. package/src/main/api/bundle-data.ts +47 -0
  21. package/src/main/api/bundle-header-data.ts +37 -0
  22. package/src/main/api/contact-data.ts +48 -0
  23. package/src/main/api/enhancement-category.ts +26 -26
  24. package/src/main/api/location-data.ts +28 -0
  25. package/src/main/api/markdown-string.ts +4 -0
  26. package/src/main/api/mission-data.ts +83 -0
  27. package/src/main/api/mission-type.ts +2 -0
  28. package/src/main/api/morality.ts +31 -0
  29. package/src/main/api/sex.ts +8 -1
  30. package/src/main/api/zone-data.ts +20 -0
  31. package/src/main/db/abstract-index.ts +37 -0
  32. package/src/main/db/alignment-list.ts +54 -0
  33. package/src/main/db/alternates.ts +28 -42
  34. package/src/main/db/badge-index.ts +60 -0
  35. package/src/main/db/badge-requirement.ts +81 -0
  36. package/src/main/db/badge-search-options.ts +47 -0
  37. package/src/main/db/badge.ts +76 -71
  38. package/src/main/db/bundle-header.ts +44 -0
  39. package/src/main/db/coh-content-database.ts +123 -14
  40. package/src/main/db/contact.ts +62 -0
  41. package/src/main/db/location.ts +30 -0
  42. package/src/main/db/mission.ts +107 -0
  43. package/src/main/db/morality-list.ts +99 -0
  44. package/src/main/db/paged.ts +7 -0
  45. package/src/main/db/zone.ts +28 -0
  46. package/src/main/index.ts +23 -15
  47. package/src/main/util.ts +108 -7
  48. package/src/test/api/alignment.test.ts +38 -4
  49. package/src/test/api/badge-data.fixture.ts +1 -15
  50. package/src/test/api/badge-data.test.ts +4 -4
  51. package/src/test/api/badge-requirement-data.fixture.ts +7 -0
  52. package/src/test/api/badge-requirement-type.test.ts +31 -0
  53. package/src/test/api/badge-type.test.ts +5 -5
  54. package/src/test/api/bundle-data.fixture.ts +6 -0
  55. package/src/test/api/bundle-header-data.fixture.ts +6 -0
  56. package/src/test/api/contact-data.fixture.ts +7 -0
  57. package/src/test/api/enhancement-category.test.ts +5 -5
  58. package/src/test/api/mission-data.fixture.ts +12 -0
  59. package/src/test/api/sex.test.ts +33 -1
  60. package/src/test/api/zone-data.fixture.ts +8 -0
  61. package/src/test/db/abstract-index.test.ts +55 -0
  62. package/src/test/db/alignment-list.test.ts +200 -0
  63. package/src/test/db/alternates.test.ts +82 -117
  64. package/src/test/db/badge-index.test.ts +547 -0
  65. package/src/test/db/badge-requirement.test.ts +145 -0
  66. package/src/test/db/badge.test.ts +322 -14
  67. package/src/test/db/bundle-header.test.ts +76 -0
  68. package/src/test/db/coh-content-database.test.ts +264 -24
  69. package/src/test/db/contact.test.ts +97 -0
  70. package/src/test/db/location.test.ts +51 -0
  71. package/src/test/db/mission.test.ts +171 -0
  72. package/src/test/db/morality-list.test.ts +457 -0
  73. package/src/test/db/zone.test.ts +36 -0
  74. package/src/test/integration.test.ts +16 -0
  75. package/src/test/util.test.ts +144 -18
  76. package/src/main/api/badge-partial-data.ts +0 -65
  77. package/src/main/api/badge-partial-type.ts +0 -8
  78. package/src/main/api/change.ts +0 -14
  79. package/src/main/api/game-map-data.ts +0 -26
  80. package/src/main/api/plaque-type.ts +0 -6
  81. package/src/main/api/server-group-data.ts +0 -65
  82. package/src/main/api/vidiot-map-data.ts +0 -18
  83. package/src/main/api/vidiot-map-point-of-interest-data.ts +0 -30
  84. package/src/main/changelog.ts +0 -20
  85. package/src/main/db/badge-partial.ts +0 -35
  86. package/src/main/db/game-map.ts +0 -33
  87. package/src/main/db/server-group.ts +0 -112
  88. package/src/main/db/vidiot-map-point-of-interest.ts +0 -40
  89. package/src/main/db/vidiot-map.ts +0 -25
  90. package/src/test/api/badge-partial-data.fixture.ts +0 -17
  91. package/src/test/api/badge-partial-type.test.ts +0 -31
  92. package/src/test/api/game-map-data.fixture.ts +0 -10
  93. package/src/test/api/plaque-type.test.ts +0 -31
  94. package/src/test/api/server-group-data.fixture.ts +0 -23
  95. package/src/test/api/server-group-data.test.ts +0 -15
  96. package/src/test/api/vidiot-map-point-of-interest.fixture.ts +0 -10
  97. package/src/test/api/vidiot-map.fixture.ts +0 -9
  98. package/src/test/changelog.test.ts +0 -36
  99. package/src/test/db/server-group.test.ts +0 -124
  100. package/src/test/index.test.ts +0 -10
@@ -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
+ }
@@ -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
+ }
@@ -0,0 +1,28 @@
1
+ import { Link } from '../api/link'
2
+ import { ZoneData } from '../api/zone-data'
3
+ import { Key } from './key'
4
+
5
+ export class Zone {
6
+ /**
7
+ * Unique key used to reference this zone.
8
+ *
9
+ * Keys must be unique and can only contain lowercase letters, numbers and hyphens (`-`).
10
+ */
11
+ readonly key: string
12
+
13
+ /**
14
+ * The name of the zone as it appears in-game.
15
+ */
16
+ readonly name: string
17
+
18
+ /**
19
+ * List of external links. Wiki, forums, etc.
20
+ */
21
+ readonly links: Link[]
22
+
23
+ constructor(data: ZoneData) {
24
+ this.key = new Key(data.key).value
25
+ this.name = data.name
26
+ this.links = data.links ?? []
27
+ }
28
+ }
package/src/main/index.ts CHANGED
@@ -3,31 +3,39 @@ export * from './api/alignment'
3
3
  export * from './api/alternate-data'
4
4
  export * from './api/archetype-data'
5
5
  export * from './api/badge-data'
6
- export * from './api/badge-partial-data'
7
- export * from './api/badge-partial-type'
6
+ export * from './api/badge-requirement-data'
7
+ export * from './api/badge-requirement-type'
8
8
  export * from './api/badge-type'
9
- export * from './api/change'
9
+ export * from './api/bundle-data'
10
+ export * from './api/bundle-header-data'
11
+ export * from './api/contact-data'
10
12
  export * from './api/enhancement-category'
11
- export * from './api/game-map-data'
12
13
  export * from './api/link'
13
- export * from './api/plaque-type'
14
- export * from './api/server-group-data'
14
+ export * from './api/location-data'
15
+ export * from './api/markdown-string'
16
+ export * from './api/mission-data'
17
+ export * from './api/mission-type'
18
+ export * from './api/morality'
15
19
  export * from './api/sex'
16
- export * from './api/vidiot-map-data'
17
- export * from './api/vidiot-map-point-of-interest-data'
20
+ export * from './api/zone-data'
18
21
 
19
22
  // DB
23
+ export * from './db/alignment-list'
24
+ export * from './db/alternates'
20
25
  export * from './db/archetype'
21
26
  export * from './db/badge'
22
- export * from './db/badge-partial'
27
+ export * from './db/badge-index'
28
+ export * from './db/badge-requirement'
29
+ export * from './db/badge-search-options'
30
+ export * from './db/bundle-header'
23
31
  export * from './db/coh-content-database'
24
- export * from './db/game-map'
32
+ export * from './db/contact'
25
33
  export * from './db/key'
26
- export * from './db/server-group'
27
- export * from './db/vidiot-map'
28
- export * from './db/vidiot-map-point-of-interest'
34
+ export * from './db/location'
35
+ export * from './db/mission'
36
+ export * from './db/morality-list'
37
+ export * from './db/paged'
38
+ export * from './db/zone'
29
39
 
30
40
  // ROOT
31
- export { CHANGELOG } from './changelog'
32
-
33
41
  export * from './util'
package/src/main/util.ts CHANGED
@@ -1,17 +1,118 @@
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
+
1
10
  /**
2
- * Create a reference string that can be used in most text strings to display a link to the given badge.
11
+ * Returns the URI of the given badge that can be used in {@link MarkdownString} fields.
12
+ *
13
+ * URI format: `badge://<key>`
14
+ *
3
15
  * @param target The badge or badge key to target.
4
16
  */
5
- export function createBadgeReference(target: string | { key: string }): string {
17
+ export function badgeUri(target: string | Badge | BadgeData): string {
18
+ const key = typeof target === 'string' ? target : target.key
19
+ return `badge://${key}`
20
+ }
21
+
22
+ /**
23
+ * Returns a {@link MarkdownString} link to the given badge.
24
+ *
25
+ * Link format: `[<key>](badge://<key>)`
26
+ *
27
+ * @param target The {@link Badge} or badge key to target.
28
+ */
29
+ export function badgeLink(target: string | Badge | BadgeData): string {
30
+ const key = typeof target === 'string' ? target : target.key
31
+ return `[${key}](${badgeUri(target)})`
32
+ }
33
+
34
+ /**
35
+ * Returns the URI of the given contact that can be used in {@link MarkdownString} fields.
36
+ *
37
+ * URI format: `contact://<key>`
38
+ *
39
+ * @param target The {@link Contact} or contact key to target.
40
+ */
41
+ export function contactUri(target: string | Contact | ContactData): string {
6
42
  const key = typeof target === 'string' ? target : target.key
7
- return `[badge:${key}]`
43
+ return `contact://${key}`
8
44
  }
9
45
 
10
46
  /**
11
- * Create a reference string that can be used in most text strings to display a link to the given map.
12
- * @param target The {@link GameMap} or map key to target.
47
+ * Returns a {@link MarkdownString} link to the given contact.
48
+ *
49
+ * Link format: `[<key>](contact://<key>)`
50
+ *
51
+ * @param target The {@link Contact} or contact key to target.
13
52
  */
14
- export function createMapReference(target: string | { key: string }): string {
53
+ export function contactLink(target: string | Contact | ContactData): string {
15
54
  const key = typeof target === 'string' ? target : target.key
16
- return `[map:${key}]`
55
+ return `[${key}](${contactUri(target)})`
56
+ }
57
+
58
+ /**
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.
84
+ *
85
+ * URI format: `zone://<key>`
86
+ *
87
+ * @param target The {@link Zone} or zone key to target.
88
+ */
89
+ export function zoneUri(target: string | Zone | ZoneData): string {
90
+ const key = typeof target === 'string' ? target : target.key
91
+ return `zone://${key}`
92
+ }
93
+
94
+ /**
95
+ * Returns a {@link MarkdownString} link to the given zone.
96
+ *
97
+ * Link format: `[<key>](zone://<key>)`
98
+ *
99
+ * @param target The {@link Zone} or zone key to target.
100
+ */
101
+ export function zoneLink(target: string | Zone | ZoneData): string {
102
+ const key = typeof target === 'string' ? target : target.key
103
+ return `[${key}](${zoneUri(target)})`
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]
17
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 = ['H', 'V', 'P']
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 = 'H'
29
- expect(field).toBe('H')
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,22 +1,8 @@
1
1
  import { defineFixture } from 'efate'
2
- import { ALIGNMENT, BADGE_TYPE, BadgeData } from '../../main'
3
- import { badgePartialDataFixture } from './badge-partial-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?.asArray([{ value: 'https://nouri.org' }])
13
- t.notes?.asLoremIpsum()
14
- t.links?.asArray([{ href: 'https://nouri.org' }])
15
- t.mapKey?.asString()
16
- t.loc?.asArray()
17
- t.vidiotMapKey?.asString()
18
- t.setTitle?.asArray({ length: 2 })
19
- t.effect?.asString()
20
- t.partials?.arrayOfFixture({ fixture: badgePartialDataFixture })
21
- t.ignoreInTotals?.asBoolean()
22
8
  })
@@ -3,13 +3,13 @@ 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: 'ACHIEVEMENT',
7
- name: [{ value: 'Test Badge' }, { alignment: 'P', value: 'My Badge for Praetorians' }],
8
- alignment: ['H', 'V', 'P'],
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', () => {
12
12
  test('should be a usable interface', () => {
13
- expect(TEST_BADGE).not.toBeNull()
13
+ expect(TEST_BADGE).not.toBeUndefined()
14
14
  })
15
15
  })
@@ -0,0 +1,7 @@
1
+ import { defineFixture } from 'efate'
2
+ import { BADGE_REQUIREMENT_TYPE, BadgeRequirementData } from '../../main'
3
+
4
+ export const badgeRequirementDataFixture = defineFixture<BadgeRequirementData>((t) => {
5
+ t.key.as(index => `badge-requirement-${index}`)
6
+ t.type.pickFrom([...BADGE_REQUIREMENT_TYPE])
7
+ })
@@ -0,0 +1,31 @@
1
+ import { BADGE_REQUIREMENT_TYPE, BadgeRequirementType } from '../../main'
2
+
3
+ describe('BADGE_REQUIREMENT_TYPE', () => {
4
+ test('should be an array', () => {
5
+ expect(Array.isArray(BADGE_REQUIREMENT_TYPE)).toBeTruthy()
6
+ })
7
+
8
+ test('should not be empty', () => {
9
+ expect(BADGE_REQUIREMENT_TYPE).not.toHaveLength(0)
10
+ })
11
+
12
+ test('should contain only strings', () => {
13
+ for (const entry of BADGE_REQUIREMENT_TYPE) {
14
+ expect(typeof entry).toBe('string')
15
+ }
16
+ })
17
+
18
+ test('should contain all known badge requirement types', () => {
19
+ const expected = ['badge', 'invention', 'invention-plus-one', 'location', 'monument', 'mission', 'task']
20
+ for (const category of expected) {
21
+ expect(BADGE_REQUIREMENT_TYPE).toContain(category)
22
+ }
23
+ })
24
+ })
25
+
26
+ describe('BadgeRequirementType', () => {
27
+ test('should be a usable type', () => {
28
+ const field: BadgeRequirementType = 'monument'
29
+ expect(field).toBe('monument')
30
+ })
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
- 'EXPLORATION', 'HISTORY', 'ACCOMPLISHMENT', 'ACHIEVEMENT', 'ACCOLADE',
21
- 'GLADIATOR', 'VETERAN', 'PVP', 'INVENTION', 'DEFEAT',
22
- 'EVENT', 'OUROBOROS', 'CONSIGNMENT', 'DAY_JOB', 'AE',
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 = 'EXPLORATION'
33
- expect(field).toBe('EXPLORATION')
32
+ const field: BadgeType = 'exploration'
33
+ expect(field).toBe('exploration')
34
34
  })
35
35
  })
@@ -0,0 +1,6 @@
1
+ import { defineFixture } from 'efate'
2
+ import { BundleData } from '../../main'
3
+
4
+ export const bundleDataFixture = defineFixture<BundleData>(() => {
5
+ // no mandatory fields
6
+ })
@@ -0,0 +1,6 @@
1
+ import { defineFixture } from 'efate'
2
+ import { BundleHeaderData } from '../../main'
3
+
4
+ export const bundleHeaderDataFixture = defineFixture<BundleHeaderData>(() => {
5
+ // no mandatory fields
6
+ })
@@ -0,0 +1,7 @@
1
+ import { defineFixture } from 'efate'
2
+ import { ContactData } from '../../main'
3
+
4
+ export const contactDataFixture = defineFixture<ContactData>((t) => {
5
+ t.key.as(index => `contact-${index}`)
6
+ t.name.as(index => [{ value: `Contact ${index}` }])
7
+ })
@@ -17,9 +17,9 @@ describe('ENHANCEMENT_CATEGORY', () => {
17
17
 
18
18
  test('should contain all known default enhancement categories', () => {
19
19
  const expected = [
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',
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 = 'RUN_SPEED'
33
- expect(field).toBe('RUN_SPEED')
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
+ })
@@ -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
+ })
@@ -0,0 +1,8 @@
1
+ import { ZoneData } from '../../main'
2
+ import { defineFixture } from 'efate'
3
+
4
+ export const zoneDataFixture = defineFixture<ZoneData>((t) => {
5
+ t.key.as(index => `zone-${index}`)
6
+ t.name.as(index => `Zone ${index}`)
7
+ t.links?.as(() => [{ title: 'foo', href: 'https://nouri.org' }])
8
+ })
@@ -0,0 +1,55 @@
1
+ import { AbstractIndex } from '../../main/db/abstract-index'
2
+
3
+ interface TestObject {
4
+ key: string
5
+ otherValue: number
6
+ }
7
+
8
+ describe(AbstractIndex.name, () => {
9
+ describe('Constructor', () => {
10
+ test(`should accept the key field`, () => {
11
+ new AbstractIndex<TestObject>('key', [])
12
+ })
13
+
14
+ test(`should throw an error on duplicate key`, () => {
15
+ expect(() => new AbstractIndex<TestObject>('key', [
16
+ { key: '1', otherValue: 1 },
17
+ { key: '1', otherValue: 1 },
18
+ ])).toThrow('Duplicate key [1]')
19
+ })
20
+ })
21
+
22
+ describe('value', () => {
23
+ test(`should return the original values`, () => {
24
+ const values = [
25
+ { key: '1', otherValue: 1 },
26
+ { key: '2', otherValue: 2 },
27
+ ]
28
+ const index = new AbstractIndex<TestObject>('key', values)
29
+ expect(index.values).toStrictEqual(values)
30
+ })
31
+ })
32
+
33
+ describe('get', () => {
34
+ test(`should return the indexed value on match`, () => {
35
+ const index = new AbstractIndex<TestObject>('key', [
36
+ { key: '1', otherValue: 1 },
37
+ { key: '2', otherValue: 2 },
38
+ ])
39
+
40
+ expect(index.get('2')).toStrictEqual({ key: '2', otherValue: 2 })
41
+ })
42
+
43
+ test(`should return undefined on no match`, () => {
44
+ const index = new AbstractIndex<TestObject>('key', [])
45
+
46
+ expect(index.get('2')).toBeUndefined()
47
+ })
48
+
49
+ test(`should return undefined on undefined key`, () => {
50
+ const index = new AbstractIndex<TestObject>('key', [])
51
+ const key = undefined
52
+ expect(index.get(key)).toBeUndefined()
53
+ })
54
+ })
55
+ })