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

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 (82) hide show
  1. package/README.md +7 -7
  2. package/dist/coh-content-db.d.ts +493 -243
  3. package/dist/coh-content-db.js +675 -353
  4. package/dist/coh-content-db.js.map +1 -1
  5. package/dist/coh-content-db.mjs +655 -345
  6. package/dist/coh-content-db.mjs.map +1 -1
  7. package/eslint.config.mjs +1 -0
  8. package/package.json +1 -1
  9. package/src/main/api/alignment.ts +18 -2
  10. package/src/main/api/badge-data.ts +15 -38
  11. package/src/main/api/badge-requirement-data.ts +64 -0
  12. package/src/main/api/badge-requirement-type.ts +32 -0
  13. package/src/main/api/badge-type.ts +15 -15
  14. package/src/main/api/contact-data.ts +48 -0
  15. package/src/main/api/content-bundle.ts +16 -4
  16. package/src/main/api/enhancement-category.ts +26 -26
  17. package/src/main/api/location-data.ts +28 -0
  18. package/src/main/api/mission-data.ts +83 -0
  19. package/src/main/api/mission-type.ts +2 -0
  20. package/src/main/api/morality.ts +31 -0
  21. package/src/main/api/sex.ts +8 -1
  22. package/src/main/api/zone-data.ts +20 -0
  23. package/src/main/changelog.ts +8 -3
  24. package/src/main/db/alignment-list.ts +54 -0
  25. package/src/main/db/alternates.ts +15 -32
  26. package/src/main/db/badge-index.ts +17 -36
  27. package/src/main/db/badge-requirement.ts +81 -0
  28. package/src/main/db/badge-search-options.ts +5 -5
  29. package/src/main/db/badge.ts +73 -62
  30. package/src/main/db/bundle-metadata.ts +3 -3
  31. package/src/main/db/coh-content-database.ts +60 -23
  32. package/src/main/db/contact.ts +62 -0
  33. package/src/main/db/location.ts +30 -0
  34. package/src/main/db/mission.ts +107 -0
  35. package/src/main/db/morality-list.ts +99 -0
  36. package/src/main/db/zone.ts +28 -0
  37. package/src/main/index.ts +16 -13
  38. package/src/main/util.ts +85 -14
  39. package/src/test/api/alignment.test.ts +38 -4
  40. package/src/test/api/badge-data.fixture.ts +1 -15
  41. package/src/test/api/badge-data.test.ts +3 -3
  42. package/src/test/api/badge-requirement-data.fixture.ts +7 -0
  43. package/src/test/api/badge-requirement-type.test.ts +31 -0
  44. package/src/test/api/badge-type.test.ts +5 -5
  45. package/src/test/api/contact-data.fixture.ts +7 -0
  46. package/src/test/api/content-bundle.fixture.ts +1 -17
  47. package/src/test/api/content-bundle.test.ts +1 -1
  48. package/src/test/api/enhancement-category.test.ts +5 -5
  49. package/src/test/api/mission-data.fixture.ts +12 -0
  50. package/src/test/api/sex.test.ts +33 -1
  51. package/src/test/api/zone-data.fixture.ts +8 -0
  52. package/src/test/db/alignment-list.test.ts +200 -0
  53. package/src/test/db/alternates.test.ts +60 -56
  54. package/src/test/db/badge-index.test.ts +108 -66
  55. package/src/test/db/badge-requirement.test.ts +145 -0
  56. package/src/test/db/badge.test.ts +310 -14
  57. package/src/test/db/coh-content-database.test.ts +110 -29
  58. package/src/test/db/contact.test.ts +97 -0
  59. package/src/test/db/location.test.ts +51 -0
  60. package/src/test/db/mission.test.ts +171 -0
  61. package/src/test/db/morality-list.test.ts +457 -0
  62. package/src/test/db/zone.test.ts +36 -0
  63. package/src/test/index.test.ts +4 -2
  64. package/src/test/util.test.ts +112 -22
  65. package/src/main/api/badge-partial-data.ts +0 -66
  66. package/src/main/api/badge-partial-type.ts +0 -8
  67. package/src/main/api/game-map-data.ts +0 -26
  68. package/src/main/api/plaque-type.ts +0 -6
  69. package/src/main/api/vidiot-map-data.ts +0 -18
  70. package/src/main/api/vidiot-map-point-of-interest-data.ts +0 -30
  71. package/src/main/db/alignments.ts +0 -17
  72. package/src/main/db/badge-partial.ts +0 -83
  73. package/src/main/db/game-map.ts +0 -33
  74. package/src/main/db/vidiot-map-point-of-interest.ts +0 -39
  75. package/src/main/db/vidiot-map.ts +0 -25
  76. package/src/test/api/alignments.test.ts +0 -40
  77. package/src/test/api/badge-partial-data.fixture.ts +0 -17
  78. package/src/test/api/badge-partial-type.test.ts +0 -31
  79. package/src/test/api/game-map-data.fixture.ts +0 -10
  80. package/src/test/api/plaque-type.test.ts +0 -31
  81. package/src/test/api/vidiot-map-point-of-interest.fixture.ts +0 -10
  82. package/src/test/api/vidiot-map.fixture.ts +0 -9
package/src/main/index.ts CHANGED
@@ -3,37 +3,40 @@ 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
9
  export * from './api/change'
10
+ export * from './api/contact-data'
11
+ export * from './api/content-bundle'
10
12
  export * from './api/enhancement-category'
11
- export * from './api/game-map-data'
12
13
  export * from './api/link'
14
+ export * from './api/location-data'
13
15
  export * from './api/markdown-string'
14
- export * from './api/plaque-type'
15
- export * from './api/content-bundle'
16
+ export * from './api/mission-data'
17
+ export * from './api/mission-type'
18
+ export * from './api/morality'
16
19
  export * from './api/sex'
17
- export * from './api/vidiot-map-data'
18
- export * from './api/vidiot-map-point-of-interest-data'
20
+ export * from './api/zone-data'
19
21
 
20
22
  // DB
21
- export * from './db/alignments'
23
+ export * from './db/alignment-list'
22
24
  export * from './db/alternates'
23
25
  export * from './db/archetype'
24
26
  export * from './db/badge'
25
27
  export * from './db/badge-index'
26
- export * from './db/badge-partial'
28
+ export * from './db/badge-requirement'
27
29
  export * from './db/badge-search-options'
28
30
  export * from './db/bundle-metadata'
29
31
  export * from './db/coh-content-database'
30
- export * from './db/game-map'
32
+ export * from './db/contact'
31
33
  export * from './db/key'
34
+ export * from './db/location'
35
+ export * from './db/mission'
36
+ export * from './db/morality-list'
32
37
  export * from './db/paged'
33
- export * from './db/vidiot-map'
34
- export * from './db/vidiot-map-point-of-interest'
38
+ export * from './db/zone'
35
39
 
36
40
  // ROOT
37
41
  export { CHANGELOG } from './changelog'
38
-
39
42
  export * from './util'
package/src/main/util.ts CHANGED
@@ -1,11 +1,20 @@
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
- * Returns the URI of the given badge that can be used in {@link MarkdownString} links.
11
+ * Returns the URI of the given badge that can be used in {@link MarkdownString} fields.
3
12
  *
4
13
  * URI format: `badge://<key>`
5
14
  *
6
15
  * @param target The badge or badge key to target.
7
16
  */
8
- export function badgeUri(target: string | { key: string }): string {
17
+ export function badgeUri(target: string | Badge | BadgeData): string {
9
18
  const key = typeof target === 'string' ? target : target.key
10
19
  return `badge://${key}`
11
20
  }
@@ -15,33 +24,95 @@ export function badgeUri(target: string | { key: string }): string {
15
24
  *
16
25
  * Link format: `[<key>](badge://<key>)`
17
26
  *
18
- * @param target The badge or badge key to target.
27
+ * @param target The {@link Badge} or badge key to target.
19
28
  */
20
- export function badgeLink(target: string | { key: string }): string {
29
+ export function badgeLink(target: string | Badge | BadgeData): string {
21
30
  const key = typeof target === 'string' ? target : target.key
22
31
  return `[${key}](${badgeUri(target)})`
23
32
  }
24
33
 
25
34
  /**
26
- * Returns the URI of the given map that can be used in {@link MarkdownString} links.
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 {
42
+ const key = typeof target === 'string' ? target : target.key
43
+ return `contact://${key}`
44
+ }
45
+
46
+ /**
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.
52
+ */
53
+ export function contactLink(target: string | Contact | ContactData): string {
54
+ const key = typeof target === 'string' ? target : target.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.
27
84
  *
28
- * URI format: `map://<key>`
85
+ * URI format: `zone://<key>`
29
86
  *
30
- * @param target The {@link GameMap} or map key to target.
87
+ * @param target The {@link Zone} or zone key to target.
31
88
  */
32
- export function mapUri(target: string | { key: string }): string {
89
+ export function zoneUri(target: string | Zone | ZoneData): string {
33
90
  const key = typeof target === 'string' ? target : target.key
34
- return `map://${key}`
91
+ return `zone://${key}`
35
92
  }
36
93
 
37
94
  /**
38
- * Returns a {@link MarkdownString} link to the given map.
95
+ * Returns a {@link MarkdownString} link to the given zone.
39
96
  *
40
- * Link format: `[<key>](map://<key>)`
97
+ * Link format: `[<key>](zone://<key>)`
41
98
  *
42
- * @param target The map or map key to target.
99
+ * @param target The {@link Zone} or zone key to target.
43
100
  */
44
- export function mapLink(target: string | { key: string }): string {
101
+ export function zoneLink(target: string | Zone | ZoneData): string {
45
102
  const key = typeof target === 'string' ? target : target.key
46
- return `[${key}](${mapUri(target)})`
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]
47
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,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: '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', () => {
@@ -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,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
+ })
@@ -1,22 +1,6 @@
1
1
  import { defineFixture } from 'efate'
2
- import { Change, ContentBundle } from '../../main'
3
- import { archetypeDataFixture } from './archetype-data.fixture'
4
- import { gameMapDataFixture } from './game-map-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.maps?.arrayOfFixture({ fixture: gameMapDataFixture })
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
  })
@@ -7,7 +7,7 @@ export const TEST_BUNDLE: ContentBundle = {
7
7
  badges: [TEST_BADGE],
8
8
  }
9
9
 
10
- describe('ServerGroupData', () => {
10
+ describe('ContentBundle', () => {
11
11
  test('should be a usable interface', () => {
12
12
  expect(TEST_BUNDLE).not.toBeUndefined()
13
13
  })
@@ -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
+ })