coh-content-db 2.0.0-rc.9 → 2.0.0

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 (66) hide show
  1. package/.github/workflows/build.yml +3 -1
  2. package/CHANGELOG.md +11 -2
  3. package/README.md +33 -19
  4. package/dist/coh-content-db.d.ts +230 -170
  5. package/dist/coh-content-db.js +495 -296
  6. package/dist/coh-content-db.js.map +1 -1
  7. package/dist/coh-content-db.mjs +488 -294
  8. package/dist/coh-content-db.mjs.map +1 -1
  9. package/jest.config.mjs +1 -0
  10. package/package.json +14 -14
  11. package/src/main/api/badge-data.ts +13 -7
  12. package/src/main/api/bundle-data.ts +1 -1
  13. package/src/main/api/bundle-header-data.ts +13 -6
  14. package/src/main/api/contact-data.ts +2 -1
  15. package/src/main/api/level-range-data.ts +4 -0
  16. package/src/main/api/mission-data.ts +3 -29
  17. package/src/main/api/mission-flashback-data.ts +31 -0
  18. package/src/main/api/morality.ts +27 -9
  19. package/src/main/api/set-title-data.ts +4 -0
  20. package/src/main/api/variant-context.ts +11 -0
  21. package/src/main/api/{alternate-data.ts → variant-data.ts} +4 -4
  22. package/src/main/api/zone-data.ts +24 -0
  23. package/src/main/api/zone-type.ts +59 -0
  24. package/src/main/db/abstract-index.ts +12 -16
  25. package/src/main/db/badge-index.ts +53 -27
  26. package/src/main/db/badge-requirement.ts +1 -1
  27. package/src/main/db/badge-search-options.ts +15 -14
  28. package/src/main/db/badge.ts +46 -29
  29. package/src/main/db/bundle-header.ts +18 -10
  30. package/src/main/db/coh-content-database.ts +17 -17
  31. package/src/main/db/contact.ts +5 -4
  32. package/src/main/db/level-range.ts +15 -0
  33. package/src/main/db/mission.ts +11 -10
  34. package/src/main/db/paged.ts +7 -3
  35. package/src/main/db/set-title-ids.ts +10 -0
  36. package/src/main/db/variants.ts +84 -0
  37. package/src/main/db/zone.ts +29 -0
  38. package/src/main/index.ts +11 -4
  39. package/src/main/util/coalesce-to-array.ts +13 -0
  40. package/src/main/{util.ts → util/links.ts} +8 -22
  41. package/src/main/util/to-date.ts +9 -0
  42. package/src/test/api/alignment.test.ts +2 -2
  43. package/src/test/api/badge-data.fixture.ts +1 -0
  44. package/src/test/api/badge-data.test.ts +1 -0
  45. package/src/test/api/bundle-data.fixture.ts +3 -2
  46. package/src/test/api/bundle-header-data.fixture.ts +4 -2
  47. package/src/test/api/morality.test.ts +31 -0
  48. package/src/test/api/sex.test.ts +2 -2
  49. package/src/test/api/zone-data.fixture.ts +1 -0
  50. package/src/test/db/abstract-index.test.ts +12 -43
  51. package/src/test/db/badge-index.test.ts +197 -101
  52. package/src/test/db/badge.test.ts +122 -16
  53. package/src/test/db/bundle-header.test.ts +25 -12
  54. package/src/test/db/coh-content-database.test.ts +134 -175
  55. package/src/test/db/contact.test.ts +2 -1
  56. package/src/test/db/level-range.test.ts +47 -0
  57. package/src/test/db/mission.test.ts +8 -6
  58. package/src/test/db/morality-list.test.ts +1 -1
  59. package/src/test/db/set-title-ids.test.ts +19 -0
  60. package/src/test/db/{alternates.test.ts → variants.test.ts} +24 -24
  61. package/src/test/db/zone.test.ts +45 -0
  62. package/src/test/integration.test.ts +3 -3
  63. package/src/test/util/coalese-to-array.test.ts +17 -0
  64. package/src/test/{util.test.ts → util/links.test.ts} +5 -21
  65. package/src/test/util/to-date.test.ts +15 -0
  66. package/src/main/db/alternates.ts +0 -67
@@ -1,4 +1,4 @@
1
- import { Badge, compareByDefaultName, compareByZoneKey } from '../../main'
1
+ import { Badge, compareByName, compareByReleaseDate, compareByZoneKey } from '../../main'
2
2
  import { badgeDataFixture } from '../api/badge-data.fixture'
3
3
  import { badgeRequirementDataFixture } from '../api/badge-requirement-data.fixture'
4
4
 
@@ -28,6 +28,24 @@ describe(Badge.name, () => {
28
28
  const badge = new Badge(badgeDataFixture.create({ name: [{ value: 'foo' }] }))
29
29
  expect(badge.name.default).toEqual({ value: 'foo' })
30
30
  })
31
+
32
+ test('should accept a string', () => {
33
+ const badge = new Badge(badgeDataFixture.create({ name: 'foo' }))
34
+ expect(badge.name.default).toEqual({ value: 'foo' })
35
+ })
36
+ })
37
+
38
+ describe('releaseDate', () => {
39
+ test('should be set from the data', () => {
40
+ const badge = new Badge(badgeDataFixture.create({ releaseDate: '2025-08-08' }))
41
+ expect(badge.releaseDate).toEqual(new Date('2025-08-08'))
42
+ })
43
+
44
+ test('should not accept an invalid date', () => {
45
+ expect(() =>
46
+ new Badge(badgeDataFixture.create({ releaseDate: '2025-??-08' })),
47
+ ).toThrow('Invalid date')
48
+ })
31
49
  })
32
50
 
33
51
  describe('morality', () => {
@@ -55,6 +73,11 @@ describe(Badge.name, () => {
55
73
  expect(badge.badgeText.default).toEqual({ value: 'foo' })
56
74
  })
57
75
 
76
+ test('should accept a string', () => {
77
+ const badge = new Badge(badgeDataFixture.create({ badgeText: 'foo' }))
78
+ expect(badge.badgeText.default).toEqual({ value: 'foo' })
79
+ })
80
+
58
81
  test('should be optional', () => {
59
82
  const badge = new Badge(badgeDataFixture.omit('badgeText').create())
60
83
  expect(badge.badgeText.default).toBeUndefined()
@@ -79,6 +102,11 @@ describe(Badge.name, () => {
79
102
  expect(badge.icon.default).toEqual({ value: 'foo' })
80
103
  })
81
104
 
105
+ test('should accept a string', () => {
106
+ const badge = new Badge(badgeDataFixture.create({ icon: 'foo' }))
107
+ expect(badge.icon.default).toEqual({ value: 'foo' })
108
+ })
109
+
82
110
  test('should be optional', () => {
83
111
  const badge = new Badge(badgeDataFixture.omit('icon').create())
84
112
  expect(badge.icon.default).toBeUndefined()
@@ -124,12 +152,14 @@ describe(Badge.name, () => {
124
152
  describe('setTitle', () => {
125
153
  test('should be set from the data', () => {
126
154
  const badge = new Badge(badgeDataFixture.create({ setTitleId: [123, 456] }))
127
- expect(badge.setTitleId).toStrictEqual([123, 456])
155
+ expect(badge.setTitleId?.primal).toEqual(123)
156
+ expect(badge.setTitleId?.praetorian).toEqual(456)
128
157
  })
129
158
 
130
159
  test('should treat the praetorian id as optional', () => {
131
160
  const badge = new Badge(badgeDataFixture.create({ setTitleId: [123] }))
132
- expect(badge.setTitleId).toStrictEqual([123])
161
+ expect(badge.setTitleId?.primal).toEqual(123)
162
+ expect(badge.setTitleId?.praetorian).toBeUndefined()
133
163
  })
134
164
 
135
165
  test('should be optional', () => {
@@ -159,7 +189,19 @@ describe(Badge.name, () => {
159
189
  badgeRequirementDataFixture.create({ key: 'foo' }),
160
190
  ],
161
191
  })
162
- expect(() => new Badge(data)).toThrow('Duplicate badge requirement key [badge:foo]')
192
+ expect(() => new Badge(data)).toThrow('Duplicate key [foo]')
193
+ })
194
+
195
+ test(`should return requirement list`, () => {
196
+ const data = badgeDataFixture.create({
197
+ requirements: [
198
+ badgeRequirementDataFixture.create({ key: 'foo' }),
199
+ badgeRequirementDataFixture.create({ key: 'bar' }),
200
+ ],
201
+ })
202
+ const badge = new Badge(data)
203
+
204
+ expect(badge.requirements.map(x => x.key)).toStrictEqual(['foo', 'bar'])
163
205
  })
164
206
  })
165
207
 
@@ -172,12 +214,12 @@ describe(Badge.name, () => {
172
214
  expect(new Badge(data).getRequirement('foo')).not.toBeUndefined()
173
215
  })
174
216
 
175
- test(`should throw error for unknown requirement`, () => {
217
+ test(`should return undefined for unknown requirement`, () => {
176
218
  const data = badgeDataFixture.create({
177
219
  requirements: [],
178
220
  })
179
221
 
180
- expect(() => new Badge(data).getRequirement('foo')).toThrow('Unknown badge requirement key [foo]')
222
+ expect(new Badge(data).getRequirement('foo')).toBeUndefined()
181
223
  })
182
224
  })
183
225
 
@@ -214,6 +256,17 @@ describe(Badge.name, () => {
214
256
  }))
215
257
  expect(badge.zoneKeys).toStrictEqual(['a', 'c'])
216
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
+ })
217
270
  })
218
271
 
219
272
  describe('zoneKey', () => {
@@ -246,31 +299,53 @@ describe(Badge.name, () => {
246
299
  })
247
300
  })
248
301
 
249
- describe(compareByDefaultName.name, () => {
302
+ describe(compareByName.name, () => {
250
303
  test(`should compare two badges by name`, () => {
251
304
  const badgeA = new Badge(badgeDataFixture.create({ name: 'A' }))
252
305
  const badgeB = new Badge(badgeDataFixture.create({ name: 'B' }))
253
- expect(compareByDefaultName(badgeA, badgeB)).toBeLessThan(0)
254
- expect([badgeB, badgeA].sort(compareByDefaultName)).toStrictEqual([badgeA, badgeB])
306
+ expect(compareByName(badgeA, badgeB)).toBeLessThan(0)
307
+ expect([badgeB, badgeA].toSorted(compareByName)).toStrictEqual([badgeA, badgeB])
255
308
  })
256
309
 
257
310
  test(`should return 0 for equal names`, () => {
258
311
  const badgeA = new Badge(badgeDataFixture.create({ name: 'A' }))
259
312
  const badgeB = new Badge(badgeDataFixture.create({ name: 'A' }))
260
- expect(compareByDefaultName(badgeA, badgeB)).toEqual(0)
313
+ expect(compareByName(badgeA, badgeB)).toEqual(0)
261
314
  })
262
315
 
263
316
  test(`should compare two undefined values`, () => {
264
317
  const badgeA = new Badge(badgeDataFixture.create({ name: [] }))
265
318
  const badgeB = new Badge(badgeDataFixture.create({ name: [] }))
266
- expect(compareByDefaultName(badgeA, badgeB)).toEqual(0)
319
+ expect(compareByName(badgeA, badgeB)).toEqual(0)
267
320
  })
268
321
 
269
322
  test(`should sort undefined values last`, () => {
270
323
  const badgeA = new Badge(badgeDataFixture.create({ name: 'A' }))
271
324
  const badgeB = new Badge(badgeDataFixture.create({ name: [] }))
272
- expect([badgeA, badgeB].sort(compareByDefaultName)).toStrictEqual([badgeA, badgeB])
273
- expect([badgeB, badgeA].sort(compareByDefaultName)).toStrictEqual([badgeA, badgeB])
325
+ expect([badgeA, badgeB].toSorted(compareByName)).toStrictEqual([badgeA, badgeB])
326
+ expect([badgeB, badgeA].toSorted(compareByName)).toStrictEqual([badgeA, badgeB])
327
+ })
328
+
329
+ test(`should take morality context into account`, () => {
330
+ const badgeA = new Badge(badgeDataFixture.create({ name: [{ value: 'ZZZ' }, { alignment: 'villain', value: 'AAA' }] }))
331
+ const badgeB = new Badge(badgeDataFixture.create({ name: 'B' }))
332
+ expect([badgeA, badgeB].toSorted((a, b) => compareByName(a, b, { morality: 'villain' }))).toStrictEqual([badgeA, badgeB])
333
+ expect([badgeA, badgeB].toSorted((a, b) => compareByName(a, b, {}))).toStrictEqual([badgeB, badgeA])
334
+ })
335
+
336
+ test(`should take sex context into account`, () => {
337
+ const badgeA = new Badge(badgeDataFixture.create({ name: [{ value: 'ZZZ' }, { sex: 'F', value: 'AAA' }] }))
338
+ const badgeB = new Badge(badgeDataFixture.create({ name: 'B' }))
339
+ expect([badgeA, badgeB].toSorted((a, b) => compareByName(a, b, { sex: 'F' }))).toStrictEqual([badgeA, badgeB])
340
+ expect([badgeA, badgeB].toSorted((a, b) => compareByName(a, b, {}))).toStrictEqual([badgeB, badgeA])
341
+ })
342
+
343
+ test(`should take full variant context into account`, () => {
344
+ const badgeA = new Badge(badgeDataFixture.create({ name: [{ value: 'A' }, { sex: 'F', value: 'B' }] }))
345
+ const badgeB = new Badge(badgeDataFixture.create({ name: [{ value: 'B' }, { alignment: 'praetorian', sex: 'F', value: 'A' }] }))
346
+ const badgeC = new Badge(badgeDataFixture.create({ name: 'C' }))
347
+ expect([badgeA, badgeB, badgeC].toSorted((a, b) => compareByName(a, b, { morality: 'resistance', sex: 'F' }))).toStrictEqual([badgeB, badgeA, badgeC])
348
+ expect([badgeA, badgeB, badgeC].toSorted((a, b) => compareByName(a, b, {}))).toStrictEqual([badgeA, badgeB, badgeC])
274
349
  })
275
350
  })
276
351
 
@@ -287,7 +362,7 @@ describe(Badge.name, () => {
287
362
  ],
288
363
  }))
289
364
  expect(compareByZoneKey(badgeA, badgeB)).toBeLessThan(0)
290
- expect([badgeB, badgeA].sort(compareByZoneKey)).toStrictEqual([badgeA, badgeB])
365
+ expect([badgeB, badgeA].toSorted(compareByZoneKey)).toStrictEqual([badgeA, badgeB])
291
366
  })
292
367
 
293
368
  test(`should return 0 for equal zoneKeys`, () => {
@@ -330,8 +405,39 @@ describe(Badge.name, () => {
330
405
  badgeRequirementDataFixture.create({ location: { zoneKey: 'c' } }),
331
406
  ],
332
407
  }))
333
- expect([badgeA, badgeB].sort(compareByZoneKey)).toStrictEqual([badgeA, badgeB])
334
- expect([badgeB, badgeA].sort(compareByZoneKey)).toStrictEqual([badgeA, badgeB])
408
+ expect([badgeA, badgeB].toSorted(compareByZoneKey)).toStrictEqual([badgeA, badgeB])
409
+ expect([badgeB, badgeA].toSorted(compareByZoneKey)).toStrictEqual([badgeA, badgeB])
410
+ })
411
+ })
412
+
413
+ describe(compareByReleaseDate.name, () => {
414
+ test(`should compare two badges by releaseDate`, () => {
415
+ const badgeA = new Badge(badgeDataFixture.create({ releaseDate: '2024-01-01' }))
416
+ const badgeB = new Badge(badgeDataFixture.create({ releaseDate: '2025-01-01' }))
417
+ expect(compareByReleaseDate(badgeA, badgeB)).toBeLessThan(0)
418
+ expect([badgeB, badgeA].toSorted(compareByReleaseDate)).toStrictEqual([badgeA, badgeB])
419
+ })
420
+
421
+ test(`should return 0 for equal releaseDates`, () => {
422
+ const badgeA = new Badge(badgeDataFixture.create({ releaseDate: '2025-01-01' }))
423
+ const badgeB = new Badge(badgeDataFixture.create({ releaseDate: '2025-01-01' }))
424
+ expect(compareByReleaseDate(badgeA, badgeB)).toEqual(0)
425
+ })
426
+
427
+ test(`should equate two undefined values`, () => {
428
+ const badgeA = undefined
429
+ const badgeB = undefined
430
+ expect(compareByReleaseDate(badgeA, badgeB)).toEqual(0)
431
+ })
432
+
433
+ test(`should compare undefined value as higher`, () => {
434
+ const badgeA = undefined
435
+ const badgeB = new Badge(badgeDataFixture.create({ releaseDate: '2025-01-01' }))
436
+ expect(compareByReleaseDate(badgeA, badgeB)).toBeGreaterThan(0)
437
+ expect([badgeA, badgeB].toSorted(compareByReleaseDate)).toStrictEqual([badgeB, badgeA])
438
+
439
+ expect(compareByReleaseDate(badgeB, badgeA)).toBeLessThan(0)
440
+ expect([badgeB, badgeA].toSorted(compareByReleaseDate)).toStrictEqual([badgeB, badgeA])
335
441
  })
336
442
  })
337
443
  })
@@ -14,6 +14,31 @@ describe(BundleHeader.name, () => {
14
14
  })
15
15
  })
16
16
 
17
+ describe('version', () => {
18
+ test(`should be set from the data`, () => {
19
+ const header = new BundleHeader(bundleHeaderDataFixture.create({ version: 'foo' }))
20
+ expect(header.version).toEqual('foo')
21
+ })
22
+
23
+ test(`should be optional`, () => {
24
+ const header = new BundleHeader(bundleHeaderDataFixture.omit('version').create())
25
+ expect(header.version).toBeUndefined()
26
+ })
27
+ })
28
+
29
+ describe('releaseDate', () => {
30
+ test('should be set from the data', () => {
31
+ const header = new BundleHeader(bundleHeaderDataFixture.create({ lastUpdateTime: '2025-04-21T01:02:03Z' }))
32
+ expect(header.lastUpdateTime).toStrictEqual(new Date('2025-04-21T01:02:03Z'))
33
+ })
34
+
35
+ test('should not accept an invalid date', () => {
36
+ expect(() =>
37
+ new BundleHeader(bundleHeaderDataFixture.create({ lastUpdateTime: 'blah' })),
38
+ ).toThrow('Invalid date')
39
+ })
40
+ })
41
+
17
42
  describe('description', () => {
18
43
  test(`should be set from the data`, () => {
19
44
  const header = new BundleHeader(bundleHeaderDataFixture.create({ description: 'foo' }))
@@ -61,16 +86,4 @@ describe(BundleHeader.name, () => {
61
86
  expect(header.links).toHaveLength(0)
62
87
  })
63
88
  })
64
-
65
- describe('version', () => {
66
- test(`should be set from the data`, () => {
67
- const header = new BundleHeader(bundleHeaderDataFixture.create({ version: 'foo' }))
68
- expect(header.version).toEqual('foo')
69
- })
70
-
71
- test(`should be optional`, () => {
72
- const header = new BundleHeader(bundleHeaderDataFixture.omit('version').create())
73
- expect(header.version).toBeUndefined()
74
- })
75
- })
76
89
  })