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
@@ -87,6 +87,46 @@ const ENHANCEMENT_CATEGORY = [
87
87
  const MISSION_TYPE = ["story-arc", "mission", "task-force", "strike-force", "trial", "personal-story"];
88
88
 
89
89
  const MORALITY = ["hero", "vigilante", "villain", "rogue", "resistance", "loyalist"];
90
+ const MORALITY_EXTENDED = [
91
+ ...MORALITY,
92
+ /**
93
+ * Any of the Primal Earth moralities - Hero, Vigilante, Villain, Rogue.
94
+ */
95
+ "primal",
96
+ /**
97
+ * Either of the Praetorian Earth moralities - Resistance or Loyalist.
98
+ */
99
+ "praetorian",
100
+ /**
101
+ * The moralities that roll up to the Hero {@link Alignment} - Hero and Vigilante.
102
+ */
103
+ "heroic",
104
+ /**
105
+ * The moralities that roll up to the Villain {@link Alignment} - Villain and Rogue.
106
+ */
107
+ "villainous",
108
+ /**
109
+ * Moralities with access to Paragon City - Hero, Vigilante and Rogue.
110
+ */
111
+ "paragon-city-access",
112
+ /**
113
+ * Moralities with access to the Rogue Isles - Villain, Rogue and Vigilante.
114
+ */
115
+ "rogue-isles-access",
116
+ /**
117
+ * All the moralities.
118
+ */
119
+ "all"
120
+ ];
121
+ const MoralityMap = {
122
+ hero: "hero",
123
+ vigilante: "hero",
124
+ villain: "villain",
125
+ rogue: "villain",
126
+ loyalist: "praetorian",
127
+ resistance: "praetorian",
128
+ praetorian: "praetorian"
129
+ };
90
130
 
91
131
  const SEX = ["M", "F"];
92
132
  const SEX_ORDER = Object.fromEntries(SEX.map((x, index) => [x, index]));
@@ -96,25 +136,84 @@ function compareSex(a, b) {
96
136
  return orderA - orderB;
97
137
  }
98
138
 
99
- var __defProp$a = Object.defineProperty;
100
- var __typeError$7 = (msg) => {
139
+ const ZONE_TYPE = [
140
+ /**
141
+ * The standard zone type, even if not technically occurring in the 'City' proper.
142
+ */
143
+ "city",
144
+ /**
145
+ * An Ouroboros flashback to a zone as it was in a previous era.
146
+ */
147
+ "echo",
148
+ /**
149
+ * Tutorial zon, usually inaccessible after leaving.
150
+ */
151
+ "tutorial",
152
+ /**
153
+ * Trial zones, like the Abandoned Sewers trial.
154
+ */
155
+ "trial",
156
+ /**
157
+ * Hazard zones like the Hollows.
158
+ */
159
+ "hazard",
160
+ /**
161
+ * Mayhem mission zones.
162
+ */
163
+ "mayhem",
164
+ /**
165
+ * Safeguard mission zones.
166
+ */
167
+ "safeguard",
168
+ /**
169
+ * Exists inside a mission not covered by the other types.
170
+ */
171
+ "mission",
172
+ /**
173
+ * Incarnate trial zones.
174
+ */
175
+ "incarnate",
176
+ /**
177
+ * Cooprative zones where Heroes and Villains can team up for PvE content.
178
+ */
179
+ "co-op",
180
+ /**
181
+ * PvP zones like Bloody Bay.
182
+ */
183
+ "pvp",
184
+ /**
185
+ * Located in an arena PvP map.
186
+ */
187
+ "arena",
188
+ /**
189
+ * A building, usually contained within another zone, like the AE buildings.
190
+ */
191
+ "building",
192
+ /**
193
+ * Stuff like the (Phone only) zone.
194
+ */
195
+ "other"
196
+ ];
197
+
198
+ var __defProp$c = Object.defineProperty;
199
+ var __typeError$6 = (msg) => {
101
200
  throw TypeError(msg);
102
201
  };
103
- var __defNormalProp$a = (obj, key, value) => key in obj ? __defProp$a(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
104
- var __publicField$a = (obj, key, value) => __defNormalProp$a(obj, typeof key !== "symbol" ? key + "" : key, value);
105
- var __accessCheck$7 = (obj, member, msg) => member.has(obj) || __typeError$7("Cannot " + msg);
106
- var __privateGet$6 = (obj, member, getter) => (__accessCheck$7(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
107
- var __privateAdd$7 = (obj, member, value) => member.has(obj) ? __typeError$7("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
108
- var __privateSet$5 = (obj, member, value, setter) => (__accessCheck$7(obj, member, "write to private field"), member.set(obj, value), value);
202
+ var __defNormalProp$c = (obj, key, value) => key in obj ? __defProp$c(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
203
+ var __publicField$c = (obj, key, value) => __defNormalProp$c(obj, typeof key !== "symbol" ? key + "" : key, value);
204
+ var __accessCheck$6 = (obj, member, msg) => member.has(obj) || __typeError$6("Cannot " + msg);
205
+ var __privateGet$5 = (obj, member, getter) => (__accessCheck$6(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
206
+ var __privateAdd$6 = (obj, member, value) => member.has(obj) ? __typeError$6("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
207
+ var __privateSet$5 = (obj, member, value, setter) => (__accessCheck$6(obj, member, "write to private field"), member.set(obj, value), value);
109
208
  var _items$1;
110
209
  class AlignmentList {
111
210
  constructor(items) {
112
- __privateAdd$7(this, _items$1);
113
- __publicField$a(this, "hero");
114
- __publicField$a(this, "villain");
115
- __publicField$a(this, "praetorian");
116
- __publicField$a(this, "primal");
117
- __publicField$a(this, "all");
211
+ __privateAdd$6(this, _items$1);
212
+ __publicField$c(this, "hero");
213
+ __publicField$c(this, "villain");
214
+ __publicField$c(this, "praetorian");
215
+ __publicField$c(this, "primal");
216
+ __publicField$c(this, "all");
118
217
  const set = new Set(items ?? [...ALIGNMENT]);
119
218
  this.hero = set.has("hero") || set.has("primal") || set.has("all");
120
219
  this.villain = set.has("villain") || set.has("primal") || set.has("all");
@@ -122,12 +221,12 @@ class AlignmentList {
122
221
  this.primal = this.hero && this.villain;
123
222
  this.all = this.hero && this.villain && this.praetorian;
124
223
  __privateSet$5(this, _items$1, /* @__PURE__ */ new Set());
125
- if (this.hero) __privateGet$6(this, _items$1).add("hero");
126
- if (this.villain) __privateGet$6(this, _items$1).add("villain");
127
- if (this.praetorian) __privateGet$6(this, _items$1).add("praetorian");
224
+ if (this.hero) __privateGet$5(this, _items$1).add("hero");
225
+ if (this.villain) __privateGet$5(this, _items$1).add("villain");
226
+ if (this.praetorian) __privateGet$5(this, _items$1).add("praetorian");
128
227
  }
129
228
  get items() {
130
- return [...__privateGet$6(this, _items$1)];
229
+ return [...__privateGet$5(this, _items$1)];
131
230
  }
132
231
  has(alignment) {
133
232
  switch (alignment) {
@@ -154,86 +253,22 @@ class AlignmentList {
154
253
  }
155
254
  _items$1 = new WeakMap();
156
255
 
157
- var __typeError$6 = (msg) => {
158
- throw TypeError(msg);
159
- };
160
- var __accessCheck$6 = (obj, member, msg) => member.has(obj) || __typeError$6("Cannot " + msg);
161
- var __privateGet$5 = (obj, member, getter) => (__accessCheck$6(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
162
- var __privateAdd$6 = (obj, member, value) => member.has(obj) ? __typeError$6("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
163
- var __privateSet$4 = (obj, member, value, setter) => (__accessCheck$6(obj, member, "write to private field"), member.set(obj, value), value);
164
- var __privateMethod$2 = (obj, member, method) => (__accessCheck$6(obj, member, "access private method"), method);
165
- var _sortedValues, _Alternates_instances, compareAlternates_fn;
166
- class Alternates {
167
- /**
168
- * Create an alternate set from either a list of categorized values, or a single value when there are no alternates.
169
- * @param value List of alternates, or a single value.
170
- */
171
- constructor(value) {
172
- __privateAdd$6(this, _Alternates_instances);
173
- __privateAdd$6(this, _sortedValues, []);
174
- if (Array.isArray(value)) {
175
- __privateSet$4(this, _sortedValues, value.sort());
176
- __privateGet$5(this, _sortedValues).sort((a, b) => __privateMethod$2(this, _Alternates_instances, compareAlternates_fn).call(this, a, b));
177
- } else {
178
- __privateSet$4(this, _sortedValues, [{ value }]);
179
- }
180
- }
181
- getValue(alignment, sex) {
182
- for (let index = __privateGet$5(this, _sortedValues).length; index--; ) {
183
- const entry = __privateGet$5(this, _sortedValues)[index];
184
- if ((entry.alignment === void 0 || entry.alignment === alignment) && (entry.sex === void 0 || entry.sex === sex)) return entry.value;
185
- }
186
- return this.default?.value;
187
- }
188
- /**
189
- * Get the default value for this list of alternates, the value with the highest priority and lowest specificity.
190
- */
191
- get default() {
192
- return __privateGet$5(this, _sortedValues)[0];
193
- }
194
- /**
195
- * Get the list of alternates sorted in canonical order (alignment then sex, low to high specificity).
196
- */
197
- get canonical() {
198
- return __privateGet$5(this, _sortedValues);
199
- }
200
- /**
201
- * Create a joined string from the alternate values in canonical order.
202
- * @param separator Separator to use. Default is ' / '
203
- */
204
- toString(separator) {
205
- return this.canonical.map((x) => x.value).join(separator);
206
- }
207
- }
208
- _sortedValues = new WeakMap();
209
- _Alternates_instances = new WeakSet();
210
- compareAlternates_fn = function(a, b) {
211
- const aSpecificity = (a.alignment ? 2 : 0) + (a.sex ? 1 : 0);
212
- const bSpecificity = (b.alignment ? 2 : 0) + (b.sex ? 1 : 0);
213
- if (aSpecificity !== bSpecificity) return aSpecificity - bSpecificity;
214
- const alignmentComparison = compareAlignment(a.alignment, b.alignment);
215
- if (alignmentComparison !== 0) return alignmentComparison;
216
- const sexComparison = compareSex(a.sex, b.sex);
217
- if (sexComparison !== 0) return sexComparison;
218
- return String(a.value).localeCompare(String(b.value));
219
- };
220
-
221
256
  var __typeError$5 = (msg) => {
222
257
  throw TypeError(msg);
223
258
  };
224
259
  var __accessCheck$5 = (obj, member, msg) => member.has(obj) || __typeError$5("Cannot " + msg);
225
260
  var __privateGet$4 = (obj, member, getter) => (__accessCheck$5(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
226
261
  var __privateAdd$5 = (obj, member, value) => member.has(obj) ? __typeError$5("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
227
- var __privateSet$3 = (obj, member, value, setter) => (__accessCheck$5(obj, member, "write to private field"), member.set(obj, value), value);
228
- var __privateMethod$1 = (obj, member, method) => (__accessCheck$5(obj, member, "access private method"), method);
262
+ var __privateSet$4 = (obj, member, value, setter) => (__accessCheck$5(obj, member, "write to private field"), member.set(obj, value), value);
263
+ var __privateMethod$2 = (obj, member, method) => (__accessCheck$5(obj, member, "access private method"), method);
229
264
  var _value, _Key_instances, validateKey_fn;
230
265
  const INVALID_KEY_PATTERN = /[^a-z0-9-]/;
231
266
  class Key {
232
267
  constructor(value) {
233
268
  __privateAdd$5(this, _Key_instances);
234
269
  __privateAdd$5(this, _value);
235
- __privateMethod$1(this, _Key_instances, validateKey_fn).call(this, value);
236
- __privateSet$3(this, _value, value);
270
+ __privateMethod$2(this, _Key_instances, validateKey_fn).call(this, value);
271
+ __privateSet$4(this, _value, value);
237
272
  }
238
273
  get value() {
239
274
  return __privateGet$4(this, _value);
@@ -245,60 +280,28 @@ validateKey_fn = function(key) {
245
280
  if (INVALID_KEY_PATTERN.test(key)) throw new Error(`Invalid key: [${key}]; Keys can only contain lowercase characters, numbers and dashes.`);
246
281
  };
247
282
 
248
- var __defProp$9 = Object.defineProperty;
249
- var __defNormalProp$9 = (obj, key, value) => key in obj ? __defProp$9(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
250
- var __publicField$9 = (obj, key, value) => __defNormalProp$9(obj, typeof key !== "symbol" ? key + "" : key, value);
283
+ var __defProp$b = Object.defineProperty;
284
+ var __defNormalProp$b = (obj, key, value) => key in obj ? __defProp$b(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
285
+ var __publicField$b = (obj, key, value) => __defNormalProp$b(obj, typeof key !== "symbol" ? key + "" : key, value);
251
286
  class Archetype {
252
287
  constructor(data) {
253
- __publicField$9(this, "key");
254
- __publicField$9(this, "name");
255
- __publicField$9(this, "description");
288
+ __publicField$b(this, "key");
289
+ __publicField$b(this, "name");
290
+ __publicField$b(this, "description");
256
291
  this.key = new Key(data.key).value;
257
292
  this.name = data.name;
258
293
  this.description = data.description;
259
294
  }
260
295
  }
261
296
 
262
- function badgeUri(target) {
263
- const key = typeof target === "string" ? target : target.key;
264
- return `badge://${key}`;
265
- }
266
- function badgeLink(target) {
267
- const key = typeof target === "string" ? target : target.key;
268
- return `[${key}](${badgeUri(target)})`;
269
- }
270
- function contactUri(target) {
271
- const key = typeof target === "string" ? target : target.key;
272
- return `contact://${key}`;
273
- }
274
- function contactLink(target) {
275
- const key = typeof target === "string" ? target : target.key;
276
- return `[${key}](${contactUri(target)})`;
277
- }
278
- function missionUri(target) {
279
- const key = typeof target === "string" ? target : target.key;
280
- return `mission://${key}`;
281
- }
282
- function missionLink(target) {
283
- const key = typeof target === "string" ? target : target.key;
284
- return `[${key}](${missionUri(target)})`;
285
- }
286
- function zoneUri(target) {
287
- const key = typeof target === "string" ? target : target.key;
288
- return `zone://${key}`;
289
- }
290
- function zoneLink(target) {
291
- const key = typeof target === "string" ? target : target.key;
292
- return `[${key}](${zoneUri(target)})`;
293
- }
294
297
  function coalesceToArray(value) {
295
298
  if (!value) return void 0;
296
299
  return Array.isArray(value) ? value : [value];
297
300
  }
298
301
 
299
- var __defProp$8 = Object.defineProperty;
300
- var __defNormalProp$8 = (obj, key, value) => key in obj ? __defProp$8(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
301
- var __publicField$8 = (obj, key, value) => __defNormalProp$8(obj, typeof key !== "symbol" ? key + "" : key, value);
302
+ var __defProp$a = Object.defineProperty;
303
+ var __defNormalProp$a = (obj, key, value) => key in obj ? __defProp$a(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
304
+ var __publicField$a = (obj, key, value) => __defNormalProp$a(obj, typeof key !== "symbol" ? key + "" : key, value);
302
305
  class BadgeRequirement {
303
306
  constructor(data) {
304
307
  /**
@@ -306,47 +309,47 @@ class BadgeRequirement {
306
309
  *
307
310
  * Keys must be unique and can only contain lowercase letters, numbers and hyphens (`-`).
308
311
  */
309
- __publicField$8(this, "key");
312
+ __publicField$a(this, "key");
310
313
  /**
311
314
  * The requirement type.
312
315
  */
313
- __publicField$8(this, "type");
316
+ __publicField$a(this, "type");
314
317
  /**
315
318
  * If the requirement involves a location, where it is.
316
319
  */
317
- __publicField$8(this, "location");
320
+ __publicField$a(this, "location");
318
321
  /**
319
322
  * If the requirement involves a badge, the badge key.
320
323
  */
321
- __publicField$8(this, "badgeKey");
324
+ __publicField$a(this, "badgeKey");
322
325
  /**
323
326
  * If the requirement involves a mission, the mission key.
324
327
  */
325
- __publicField$8(this, "missionKey");
328
+ __publicField$a(this, "missionKey");
326
329
  /**
327
330
  * If the requirement involves a monument, the text that is displayed thereon.
328
331
  */
329
- __publicField$8(this, "monumentText");
332
+ __publicField$a(this, "monumentText");
330
333
  /**
331
334
  * If the requirement involves crafting an invention, the Level of the invention required.
332
335
  */
333
- __publicField$8(this, "inventionLevel");
336
+ __publicField$a(this, "inventionLevel");
334
337
  /**
335
338
  * If the requirement involves crafting an invention, the types of enhancements that will qualify.
336
339
  */
337
- __publicField$8(this, "inventionTypes");
340
+ __publicField$a(this, "inventionTypes");
338
341
  /**
339
342
  * Number of times the task needs to be repeated.
340
343
  */
341
- __publicField$8(this, "count");
344
+ __publicField$a(this, "count");
342
345
  /**
343
346
  * Additional information about the requirement.
344
347
  */
345
- __publicField$8(this, "notes");
348
+ __publicField$a(this, "notes");
346
349
  /**
347
350
  * List of external links. Wiki, forums, etc.
348
351
  */
349
- __publicField$8(this, "links");
352
+ __publicField$a(this, "links");
350
353
  this.key = new Key(data.key).value;
351
354
  this.type = data.type;
352
355
  this.location = coalesceToArray(data.location);
@@ -361,33 +364,110 @@ class BadgeRequirement {
361
364
  }
362
365
  }
363
366
 
364
- var __defProp$7 = Object.defineProperty;
365
367
  var __typeError$4 = (msg) => {
366
368
  throw TypeError(msg);
367
369
  };
368
- var __defNormalProp$7 = (obj, key, value) => key in obj ? __defProp$7(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
369
- var __publicField$7 = (obj, key, value) => __defNormalProp$7(obj, typeof key !== "symbol" ? key + "" : key, value);
370
370
  var __accessCheck$4 = (obj, member, msg) => member.has(obj) || __typeError$4("Cannot " + msg);
371
371
  var __privateGet$3 = (obj, member, getter) => (__accessCheck$4(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
372
372
  var __privateAdd$4 = (obj, member, value) => member.has(obj) ? __typeError$4("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
373
- var __privateSet$2 = (obj, member, value, setter) => (__accessCheck$4(obj, member, "write to private field"), member.set(obj, value), value);
373
+ var __privateSet$3 = (obj, member, value, setter) => (__accessCheck$4(obj, member, "write to private field"), member.set(obj, value), value);
374
+ var __privateMethod$1 = (obj, member, method) => (__accessCheck$4(obj, member, "access private method"), method);
375
+ var _sortedValues, _Variants_instances, compareVariants_fn;
376
+ class Variants {
377
+ /**
378
+ * Create a variant set from either a list of categorized values, or a single value when there are no variants.
379
+ * @param value List of variants, or a single value.
380
+ */
381
+ constructor(value) {
382
+ __privateAdd$4(this, _Variants_instances);
383
+ __privateAdd$4(this, _sortedValues, []);
384
+ if (Array.isArray(value)) {
385
+ __privateSet$3(this, _sortedValues, value.toSorted());
386
+ __privateGet$3(this, _sortedValues).sort((a, b) => __privateMethod$1(this, _Variants_instances, compareVariants_fn).call(this, a, b));
387
+ } else {
388
+ __privateSet$3(this, _sortedValues, [{ value }]);
389
+ }
390
+ }
391
+ /**
392
+ * Get a variant by context
393
+ * @param context The context
394
+ */
395
+ getVariant(context) {
396
+ const alignment = context?.morality ? MoralityMap[context.morality] : void 0;
397
+ const sex = context?.sex;
398
+ for (let index = __privateGet$3(this, _sortedValues).length; index--; ) {
399
+ const entry = __privateGet$3(this, _sortedValues)[index];
400
+ if ((entry.alignment === void 0 || entry.alignment === alignment) && (entry.sex === void 0 || entry.sex === sex)) return entry;
401
+ }
402
+ return this.default;
403
+ }
404
+ /**
405
+ * Get a value by variant context
406
+ * @param context The context
407
+ */
408
+ getValue(context) {
409
+ return this.getVariant(context)?.value;
410
+ }
411
+ /**
412
+ * Get the default value for this list of variants, the value with the highest priority and lowest specificity.
413
+ */
414
+ get default() {
415
+ return __privateGet$3(this, _sortedValues)[0];
416
+ }
417
+ /**
418
+ * Get the list of variants sorted in canonical order (alignment then sex, low to high specificity).
419
+ */
420
+ get canonical() {
421
+ return __privateGet$3(this, _sortedValues);
422
+ }
423
+ /**
424
+ * Create a joined string from the variant values in canonical order.
425
+ * @param separator Separator to use. Default is ' / '
426
+ */
427
+ toString(separator) {
428
+ return this.canonical.map((x) => x.value).join(separator);
429
+ }
430
+ }
431
+ _sortedValues = new WeakMap();
432
+ _Variants_instances = new WeakSet();
433
+ compareVariants_fn = function(a, b) {
434
+ const aSpecificity = (a.alignment ? 2 : 0) + (a.sex ? 1 : 0);
435
+ const bSpecificity = (b.alignment ? 2 : 0) + (b.sex ? 1 : 0);
436
+ if (aSpecificity !== bSpecificity) return aSpecificity - bSpecificity;
437
+ const alignmentComparison = compareAlignment(a.alignment, b.alignment);
438
+ if (alignmentComparison !== 0) return alignmentComparison;
439
+ const sexComparison = compareSex(a.sex, b.sex);
440
+ if (sexComparison !== 0) return sexComparison;
441
+ return String(a.value).localeCompare(String(b.value));
442
+ };
443
+
444
+ var __defProp$9 = Object.defineProperty;
445
+ var __typeError$3 = (msg) => {
446
+ throw TypeError(msg);
447
+ };
448
+ var __defNormalProp$9 = (obj, key, value) => key in obj ? __defProp$9(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
449
+ var __publicField$9 = (obj, key, value) => __defNormalProp$9(obj, typeof key !== "symbol" ? key + "" : key, value);
450
+ var __accessCheck$3 = (obj, member, msg) => member.has(obj) || __typeError$3("Cannot " + msg);
451
+ var __privateGet$2 = (obj, member, getter) => (__accessCheck$3(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
452
+ var __privateAdd$3 = (obj, member, value) => member.has(obj) ? __typeError$3("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
453
+ var __privateSet$2 = (obj, member, value, setter) => (__accessCheck$3(obj, member, "write to private field"), member.set(obj, value), value);
374
454
  var _items;
375
455
  class MoralityList {
376
456
  constructor(items) {
377
- __privateAdd$4(this, _items);
378
- __publicField$7(this, "hero");
379
- __publicField$7(this, "vigilante");
380
- __publicField$7(this, "villain");
381
- __publicField$7(this, "rogue");
382
- __publicField$7(this, "resistance");
383
- __publicField$7(this, "loyalist");
384
- __publicField$7(this, "primal");
385
- __publicField$7(this, "praetorian");
386
- __publicField$7(this, "heroic");
387
- __publicField$7(this, "villainous");
388
- __publicField$7(this, "paragonCityAccess");
389
- __publicField$7(this, "rogueIslesAccess");
390
- __publicField$7(this, "all");
457
+ __privateAdd$3(this, _items);
458
+ __publicField$9(this, "hero");
459
+ __publicField$9(this, "vigilante");
460
+ __publicField$9(this, "villain");
461
+ __publicField$9(this, "rogue");
462
+ __publicField$9(this, "resistance");
463
+ __publicField$9(this, "loyalist");
464
+ __publicField$9(this, "primal");
465
+ __publicField$9(this, "praetorian");
466
+ __publicField$9(this, "heroic");
467
+ __publicField$9(this, "villainous");
468
+ __publicField$9(this, "paragonCityAccess");
469
+ __publicField$9(this, "rogueIslesAccess");
470
+ __publicField$9(this, "all");
391
471
  const set = new Set(items ?? [...MORALITY]);
392
472
  this.hero = set.has("hero") || set.has("primal") || set.has("heroic") || set.has("paragon-city-access") || set.has("all");
393
473
  this.vigilante = set.has("vigilante") || set.has("primal") || set.has("heroic") || set.has("paragon-city-access") || set.has("rogue-isles-access") || set.has("all");
@@ -403,15 +483,15 @@ class MoralityList {
403
483
  this.rogueIslesAccess = this.villainous && this.vigilante;
404
484
  this.all = this.primal && this.praetorian;
405
485
  __privateSet$2(this, _items, /* @__PURE__ */ new Set());
406
- if (this.hero) __privateGet$3(this, _items).add("hero");
407
- if (this.vigilante) __privateGet$3(this, _items).add("vigilante");
408
- if (this.villain) __privateGet$3(this, _items).add("villain");
409
- if (this.rogue) __privateGet$3(this, _items).add("rogue");
410
- if (this.resistance) __privateGet$3(this, _items).add("resistance");
411
- if (this.loyalist) __privateGet$3(this, _items).add("loyalist");
486
+ if (this.hero) __privateGet$2(this, _items).add("hero");
487
+ if (this.vigilante) __privateGet$2(this, _items).add("vigilante");
488
+ if (this.villain) __privateGet$2(this, _items).add("villain");
489
+ if (this.rogue) __privateGet$2(this, _items).add("rogue");
490
+ if (this.resistance) __privateGet$2(this, _items).add("resistance");
491
+ if (this.loyalist) __privateGet$2(this, _items).add("loyalist");
412
492
  }
413
493
  get items() {
414
- return [...__privateGet$3(this, _items)];
494
+ return [...__privateGet$2(this, _items)];
415
495
  }
416
496
  has(morality) {
417
497
  switch (morality) {
@@ -462,20 +542,74 @@ class MoralityList {
462
542
  }
463
543
  _items = new WeakMap();
464
544
 
545
+ var __defProp$8 = Object.defineProperty;
546
+ var __defNormalProp$8 = (obj, key, value) => key in obj ? __defProp$8(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
547
+ var __publicField$8 = (obj, key, value) => __defNormalProp$8(obj, typeof key !== "symbol" ? key + "" : key, value);
548
+ class AbstractIndex {
549
+ /**
550
+ * Create a new index.
551
+ * @param keyField The field of the values that will act as the key.
552
+ * @param values Values to index.
553
+ */
554
+ constructor(keyField, values) {
555
+ __publicField$8(this, "_values", []);
556
+ __publicField$8(this, "_hashTable", {});
557
+ this._values = values ?? [];
558
+ this._hashTable = {};
559
+ for (const value of this.values) {
560
+ const key = value[keyField];
561
+ if (this._hashTable[key] !== void 0) throw new Error(`Duplicate key [${key}]`);
562
+ this._hashTable[key] = value;
563
+ }
564
+ }
565
+ /**
566
+ * Return all indexed values
567
+ */
568
+ get values() {
569
+ return this._values;
570
+ }
571
+ /**
572
+ * Get a value from the index
573
+ * @param key Key string
574
+ */
575
+ get(key) {
576
+ if (!key) return void 0;
577
+ return this._hashTable[key];
578
+ }
579
+ }
580
+
581
+ function toDate(iso) {
582
+ const date = new Date(iso);
583
+ if (!date || Number.isNaN(date.getTime())) throw new Error(`Invalid date format: [${iso}]`);
584
+ return date;
585
+ }
586
+
587
+ var __defProp$7 = Object.defineProperty;
588
+ var __defNormalProp$7 = (obj, key, value) => key in obj ? __defProp$7(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
589
+ var __publicField$7 = (obj, key, value) => __defNormalProp$7(obj, typeof key !== "symbol" ? key + "" : key, value);
590
+ class SetTitleIds {
591
+ constructor(value) {
592
+ __publicField$7(this, "primal");
593
+ __publicField$7(this, "praetorian");
594
+ [this.primal, this.praetorian] = value;
595
+ }
596
+ }
597
+
465
598
  var __defProp$6 = Object.defineProperty;
466
- var __typeError$3 = (msg) => {
599
+ var __typeError$2 = (msg) => {
467
600
  throw TypeError(msg);
468
601
  };
469
602
  var __defNormalProp$6 = (obj, key, value) => key in obj ? __defProp$6(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
470
603
  var __publicField$6 = (obj, key, value) => __defNormalProp$6(obj, typeof key !== "symbol" ? key + "" : key, value);
471
- var __accessCheck$3 = (obj, member, msg) => member.has(obj) || __typeError$3("Cannot " + msg);
472
- var __privateGet$2 = (obj, member, getter) => (__accessCheck$3(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
473
- var __privateAdd$3 = (obj, member, value) => member.has(obj) ? __typeError$3("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
604
+ var __accessCheck$2 = (obj, member, msg) => member.has(obj) || __typeError$2("Cannot " + msg);
605
+ var __privateGet$1 = (obj, member, getter) => (__accessCheck$2(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
606
+ var __privateAdd$2 = (obj, member, value) => member.has(obj) ? __typeError$2("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
607
+ var __privateSet$1 = (obj, member, value, setter) => (__accessCheck$2(obj, member, "write to private field"), member.set(obj, value), value);
474
608
  var _requirementsIndex, _zoneKeys;
475
609
  class Badge {
476
610
  constructor(badgeData) {
477
- __privateAdd$3(this, _requirementsIndex, {});
478
- __privateAdd$3(this, _zoneKeys, /* @__PURE__ */ new Set());
611
+ __privateAdd$2(this, _requirementsIndex);
612
+ __privateAdd$2(this, _zoneKeys, /* @__PURE__ */ new Set());
479
613
  /**
480
614
  * The database key for this badge.
481
615
  */
@@ -490,6 +624,10 @@ class Badge {
490
624
  * May vary by character sex or alignment.
491
625
  */
492
626
  __publicField$6(this, "name");
627
+ /**
628
+ * The date that the badge was added to the game.
629
+ */
630
+ __publicField$6(this, "releaseDate");
493
631
  /**
494
632
  * The character moralities that this badge is available to.
495
633
  */
@@ -525,59 +663,57 @@ class Badge {
525
663
  * A description of the effect the badge will have, such as a buff or granting a temporary power.
526
664
  */
527
665
  __publicField$6(this, "effect");
528
- /**
529
- * Represents the requirements for badges with multiple fulfillment steps, such as visiting monuments for history badges, completing missions, or collecting other badges.
530
- */
531
- __publicField$6(this, "requirements");
532
666
  /**
533
667
  * Some badges are not included in the badge total count... such as Flames of Prometheus, which can be removed by redeeming it for a Notice of the Well.
534
668
  */
535
669
  __publicField$6(this, "ignoreInTotals");
536
670
  this.key = new Key(badgeData.key).value;
537
671
  this.type = badgeData.type;
538
- this.name = new Alternates(badgeData.name);
672
+ this.name = new Variants(badgeData.name);
673
+ this.releaseDate = toDate(badgeData.releaseDate);
539
674
  this.morality = new MoralityList(coalesceToArray(badgeData.morality));
540
- this.badgeText = new Alternates(badgeData.badgeText ?? []);
675
+ this.badgeText = new Variants(badgeData.badgeText ?? []);
541
676
  this.acquisition = badgeData.acquisition;
542
- this.icon = new Alternates(badgeData.icon ?? []);
677
+ this.icon = new Variants(badgeData.icon ?? []);
543
678
  this.notes = badgeData.notes;
544
679
  this.links = badgeData.links ?? [];
545
680
  this.effect = badgeData.effect;
546
- this.setTitleId = badgeData.setTitleId;
681
+ this.setTitleId = badgeData.setTitleId ? new SetTitleIds(badgeData.setTitleId) : void 0;
547
682
  this.ignoreInTotals = badgeData.ignoreInTotals ?? false;
548
- this.requirements = badgeData.requirements?.map((requirementData) => {
549
- if (__privateGet$2(this, _requirementsIndex)[requirementData.key]) throw new Error(`Duplicate badge requirement key [${badgeData.key}:${requirementData.key}]`);
550
- const requirement = new BadgeRequirement(requirementData);
551
- __privateGet$2(this, _requirementsIndex)[requirement.key] = requirement;
683
+ __privateSet$1(this, _requirementsIndex, new AbstractIndex("key", badgeData.requirements?.map((x) => new BadgeRequirement(x))));
684
+ for (const requirement of __privateGet$1(this, _requirementsIndex).values) {
552
685
  if (requirement.location) for (const location of requirement.location) {
553
- if (location.zoneKey) __privateGet$2(this, _zoneKeys).add(location.zoneKey);
686
+ if (location.zoneKey) __privateGet$1(this, _zoneKeys).add(location.zoneKey);
554
687
  }
555
- return requirement;
556
- });
688
+ }
689
+ }
690
+ /**
691
+ * Represents the requirements for badges with multiple fulfillment steps, such as visiting monuments for history badges, completing missions, or collecting other badges.
692
+ */
693
+ get requirements() {
694
+ return __privateGet$1(this, _requirementsIndex).values;
557
695
  }
558
696
  getRequirement(key) {
559
- const result = __privateGet$2(this, _requirementsIndex)[key];
560
- if (result === void 0) throw new Error(`Unknown badge requirement key [${key}]`);
561
- return result;
697
+ return __privateGet$1(this, _requirementsIndex).get(key);
562
698
  }
563
699
  /**
564
700
  * Return a list of all the zone keys referenced by this badge.
565
701
  */
566
702
  get zoneKeys() {
567
- return [...__privateGet$2(this, _zoneKeys)];
703
+ return [...__privateGet$1(this, _zoneKeys)];
568
704
  }
569
705
  /**
570
706
  * The zone key if this badge relates to a single zone.
571
707
  */
572
708
  get zoneKey() {
573
- return __privateGet$2(this, _zoneKeys).size === 1 ? __privateGet$2(this, _zoneKeys).values().next().value : void 0;
709
+ return __privateGet$1(this, _zoneKeys).size === 1 ? __privateGet$1(this, _zoneKeys).values().next().value : void 0;
574
710
  }
575
711
  }
576
712
  _requirementsIndex = new WeakMap();
577
713
  _zoneKeys = new WeakMap();
578
- function compareByDefaultName(a, b) {
579
- const aName = a?.name.default?.value;
580
- const bName = b?.name.default?.value;
714
+ function compareByName(a, b, context) {
715
+ const aName = a?.name?.getValue(context);
716
+ const bName = b?.name?.getValue(context);
581
717
  if (!aName && !bName) return 0;
582
718
  if (!aName) return 1;
583
719
  if (!bName) return -1;
@@ -591,54 +727,14 @@ function compareByZoneKey(a, b) {
591
727
  if (!bZone) return -1;
592
728
  return aZone.localeCompare(bZone);
593
729
  }
594
-
595
- var __defProp$5 = Object.defineProperty;
596
- var __typeError$2 = (msg) => {
597
- throw TypeError(msg);
598
- };
599
- var __defNormalProp$5 = (obj, key, value) => key in obj ? __defProp$5(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
600
- var __publicField$5 = (obj, key, value) => __defNormalProp$5(obj, typeof key !== "symbol" ? key + "" : key, value);
601
- var __accessCheck$2 = (obj, member, msg) => member.has(obj) || __typeError$2("Cannot " + msg);
602
- var __privateGet$1 = (obj, member, getter) => (__accessCheck$2(obj, member, "read from private field"), member.get(obj));
603
- var __privateAdd$2 = (obj, member, value) => member.has(obj) ? __typeError$2("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
604
- var __privateSet$1 = (obj, member, value, setter) => (__accessCheck$2(obj, member, "write to private field"), member.set(obj, value), value);
605
- var _keyField;
606
- class AbstractIndex {
607
- constructor(keyField) {
608
- __privateAdd$2(this, _keyField);
609
- __publicField$5(this, "_values", []);
610
- __publicField$5(this, "_hashTable", {});
611
- __privateSet$1(this, _keyField, keyField);
612
- }
613
- /**
614
- * Return all indexed values
615
- */
616
- get values() {
617
- return this._values;
618
- }
619
- /**
620
- * Load the given list of values into the index, replacing any existing data.
621
- * @param values List of values.
622
- */
623
- load(values) {
624
- this._values = values ?? [];
625
- this._hashTable = {};
626
- for (const value of this.values) {
627
- const key = value[__privateGet$1(this, _keyField)];
628
- if (this._hashTable[key] !== void 0) throw new Error(`Duplicate key [${key}]`);
629
- this._hashTable[key] = value;
630
- }
631
- }
632
- /**
633
- * Get a value from the index
634
- * @param key Key string
635
- */
636
- get(key) {
637
- if (!key) return void 0;
638
- return this._hashTable[key];
639
- }
730
+ function compareByReleaseDate(a, b) {
731
+ const aReleaseDate = a?.releaseDate?.getTime();
732
+ const bReleaseDate = b?.releaseDate?.getTime();
733
+ if (aReleaseDate === bReleaseDate) return 0;
734
+ if (!aReleaseDate) return 1;
735
+ if (!bReleaseDate) return -1;
736
+ return aReleaseDate < bReleaseDate ? -1 : 1;
640
737
  }
641
- _keyField = new WeakMap();
642
738
 
643
739
  var __typeError$1 = (msg) => {
644
740
  throw TypeError(msg);
@@ -648,76 +744,123 @@ var __privateAdd$1 = (obj, member, value) => member.has(obj) ? __typeError$1("Ca
648
744
  var __privateMethod = (obj, member, method) => (__accessCheck$1(obj, member, "access private method"), method);
649
745
  var _BadgeIndex_instances, satisfiesQueryPredicate_fn, satisfiesFilterPredicate_fn, sort_fn;
650
746
  class BadgeIndex extends AbstractIndex {
651
- constructor() {
652
- super("key");
747
+ constructor(values) {
748
+ super("key", values);
653
749
  __privateAdd$1(this, _BadgeIndex_instances);
654
750
  }
655
751
  search(options) {
656
- const filtered = options?.query || options?.filter ? this._values.filter((badge) => __privateMethod(this, _BadgeIndex_instances, satisfiesQueryPredicate_fn).call(this, badge, options?.query) && __privateMethod(this, _BadgeIndex_instances, satisfiesFilterPredicate_fn).call(this, badge, options?.filter)) : this._values;
657
- const totalPages = options?.pageSize ? Math.ceil(filtered.length / options?.pageSize) : 1;
658
- const page = Math.max(1, Math.min(totalPages, options?.page ?? 1));
659
- const paged = options?.pageSize ? filtered.slice((page - 1) * options.pageSize, page * options?.pageSize) : filtered;
660
- const sorted = __privateMethod(this, _BadgeIndex_instances, sort_fn).call(this, paged, options?.sort);
752
+ const matched = options?.query || options?.filter ? this._values.filter((badge) => __privateMethod(this, _BadgeIndex_instances, satisfiesQueryPredicate_fn).call(this, badge, options?.query) && __privateMethod(this, _BadgeIndex_instances, satisfiesFilterPredicate_fn).call(this, badge, options?.filter)) : this._values;
753
+ const sorted = __privateMethod(this, _BadgeIndex_instances, sort_fn).call(this, matched, options);
754
+ const totalPages = options?.pageSize ? Math.ceil(matched.length / options?.pageSize) : 1;
755
+ const pageNumber = Math.max(1, Math.min(totalPages, options?.page ?? 1));
756
+ const items = options?.pageSize ? sorted.slice((pageNumber - 1) * options.pageSize, pageNumber * options?.pageSize) : sorted;
661
757
  return {
662
- items: sorted,
663
- page,
758
+ items,
759
+ pageIndex: pageNumber - 1,
760
+ pageNumber,
664
761
  pageSize: options?.pageSize,
665
- totalItems: filtered.length,
666
- totalPages
762
+ matchedItemCount: matched.length,
763
+ totalItemCount: this._values.length,
764
+ totalPageCount: totalPages
667
765
  };
668
766
  }
669
767
  }
670
768
  _BadgeIndex_instances = new WeakSet();
671
769
  satisfiesQueryPredicate_fn = function(badge, query) {
672
770
  const queryString = query?.str?.toLowerCase() ?? "";
673
- return !!((query?.on?.name ?? true) && badge.name.canonical.some((x) => x.value.toLowerCase().includes(queryString)) || query?.on?.badgeText && badge.badgeText.canonical.some((x) => x.value.toLowerCase().includes(queryString)) || query?.on?.acquisition && badge.acquisition?.toLowerCase().includes(queryString) || query?.on?.effect && badge.effect?.toLowerCase().includes(queryString) || query?.on?.notes && badge.notes?.toLowerCase().includes(queryString) || query?.on?.setTitle && badge.setTitleId?.some((x) => x?.toString().includes(queryString)));
771
+ const fields = query?.fields ? new Set(query?.fields) : /* @__PURE__ */ new Set(["name"]);
772
+ if (fields.size === 0) return true;
773
+ return !!(fields.has("name") && badge.name.canonical.some((x) => x.value.toLowerCase().includes(queryString)) || fields.has("badge-text") && badge.badgeText.canonical.some((x) => x.value.toLowerCase().includes(queryString)) || fields.has("acquisition") && badge.acquisition?.toLowerCase().includes(queryString) || fields.has("effect") && badge.effect?.toLowerCase().includes(queryString) || fields.has("notes") && badge.notes?.toLowerCase().includes(queryString) || fields.has("set-title-id") && badge.setTitleId?.primal.toString() === queryString || fields.has("set-title-id") && badge.setTitleId?.praetorian?.toString() === queryString);
674
774
  };
675
775
  satisfiesFilterPredicate_fn = function(badge, filter) {
676
- return (!filter?.type || badge.type === filter.type) && (!filter?.zoneKey || badge.zoneKey === filter.zoneKey) && (!filter?.morality || badge.morality.has(filter.morality));
776
+ return (!filter?.type || badge.type === filter.type) && (!filter?.zoneKey || badge.zoneKey === filter.zoneKey) && (!filter?.morality || badge.morality.has(filter.morality)) && (!filter?.predicate || filter.predicate(badge));
677
777
  };
678
- sort_fn = function(badges, sort) {
679
- if (!sort) return badges;
680
- const ascending = sort.dir !== "desc";
681
- if (sort.by === "badge-name") return badges.sort((a, b) => ascending ? compareByDefaultName(a, b) : compareByDefaultName(b, a));
682
- if (sort.by === "zone-key") return badges.sort((a, b) => ascending ? compareByZoneKey(a, b) : compareByZoneKey(b, a));
683
- return sort.dir === "desc" ? badges.reverse() : badges;
778
+ sort_fn = function(badges, options) {
779
+ switch (options?.sort) {
780
+ case "name.asc": {
781
+ return badges.toSorted((a, b) => compareByName(a, b, options.context));
782
+ }
783
+ case "name.desc": {
784
+ return badges.toSorted((a, b) => compareByName(b, a, options.context));
785
+ }
786
+ case "zone-key.asc": {
787
+ return badges.toSorted(compareByZoneKey);
788
+ }
789
+ case "zone-key.desc": {
790
+ return badges.toSorted((a, b) => compareByZoneKey(b, a));
791
+ }
792
+ case "release-date.asc": {
793
+ return badges.toSorted(compareByReleaseDate);
794
+ }
795
+ case "release-date.desc": {
796
+ return badges.toSorted((a, b) => compareByReleaseDate(b, a));
797
+ }
798
+ case "canonical.desc": {
799
+ return badges.toReversed();
800
+ }
801
+ default: {
802
+ return [...badges];
803
+ }
804
+ }
684
805
  };
685
806
 
686
- var __defProp$4 = Object.defineProperty;
687
- var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
688
- var __publicField$4 = (obj, key, value) => __defNormalProp$4(obj, typeof key !== "symbol" ? key + "" : key, value);
807
+ var __defProp$5 = Object.defineProperty;
808
+ var __defNormalProp$5 = (obj, key, value) => key in obj ? __defProp$5(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
809
+ var __publicField$5 = (obj, key, value) => __defNormalProp$5(obj, typeof key !== "symbol" ? key + "" : key, value);
689
810
  class BundleHeader {
690
811
  constructor(data) {
691
812
  /**
692
- * Name of the content bundle.
813
+ * Name of the fork this bundle contains data for.
814
+ */
815
+ __publicField$5(this, "name");
816
+ /**
817
+ * Version number for this data package.
693
818
  */
694
- __publicField$4(this, "name");
819
+ __publicField$5(this, "version");
820
+ /**
821
+ * The time this bundle was last updated.
822
+ */
823
+ __publicField$5(this, "lastUpdateTime");
695
824
  /**
696
825
  * Description of the fork.
697
826
  */
698
- __publicField$4(this, "description");
827
+ __publicField$5(this, "description");
699
828
  /**
700
829
  * Url for the repository where the bundle is maintained.
701
830
  */
702
- __publicField$4(this, "repositoryUrl");
831
+ __publicField$5(this, "repositoryUrl");
703
832
  /**
704
833
  * Url for the location of the changelog.
705
834
  */
706
- __publicField$4(this, "changelogUrl");
835
+ __publicField$5(this, "changelogUrl");
707
836
  /**
708
837
  * List of external links. Wiki, forums, etc.
709
838
  */
710
- __publicField$4(this, "links");
711
- /**
712
- * The current version of the data package.
713
- */
714
- __publicField$4(this, "version");
715
- this.name = data?.name;
839
+ __publicField$5(this, "links");
840
+ if (!data) throw new Error("Missing header data");
841
+ this.name = data.name;
842
+ this.version = data.version;
843
+ this.lastUpdateTime = toDate(data.lastUpdateTime);
716
844
  this.description = data?.description;
717
845
  this.repositoryUrl = data?.repositoryUrl;
718
846
  this.changelogUrl = data?.changelogUrl;
719
847
  this.links = data?.links ?? [];
720
- this.version = data?.version;
848
+ }
849
+ }
850
+
851
+ var __defProp$4 = Object.defineProperty;
852
+ var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
853
+ var __publicField$4 = (obj, key, value) => __defNormalProp$4(obj, typeof key !== "symbol" ? key + "" : key, value);
854
+ class LevelRange {
855
+ constructor(value) {
856
+ __publicField$4(this, "min");
857
+ __publicField$4(this, "max");
858
+ if (Array.isArray(value)) {
859
+ this.min = value[0];
860
+ this.max = value[1] === void 0 ? void 0 : value[1];
861
+ } else {
862
+ this.min = value;
863
+ }
721
864
  }
722
865
  }
723
866
 
@@ -736,12 +879,32 @@ class Zone {
736
879
  * The name of the zone as it appears in-game.
737
880
  */
738
881
  __publicField$3(this, "name");
882
+ /**
883
+ * The type of zone.
884
+ */
885
+ __publicField$3(this, "type");
886
+ /**
887
+ * The character moralities that this zone is accessible by.
888
+ */
889
+ __publicField$3(this, "morality");
890
+ /**
891
+ * The level range this zone is recommended for.
892
+ */
893
+ __publicField$3(this, "levelRange");
894
+ /**
895
+ * Freeform notes or tips about the zone.
896
+ */
897
+ __publicField$3(this, "notes");
739
898
  /**
740
899
  * List of external links. Wiki, forums, etc.
741
900
  */
742
901
  __publicField$3(this, "links");
743
902
  this.key = new Key(data.key).value;
744
903
  this.name = data.name;
904
+ this.type = data.type;
905
+ this.morality = new MoralityList(coalesceToArray(data.morality));
906
+ this.levelRange = data.levelRange ? new LevelRange(data.levelRange) : void 0;
907
+ this.notes = data.notes;
745
908
  this.links = data.links ?? [];
746
909
  }
747
910
  }
@@ -790,7 +953,7 @@ class Contact {
790
953
  this.title = data.title;
791
954
  this.morality = new MoralityList(coalesceToArray(data.morality));
792
955
  this.location = data.location;
793
- this.levelRange = data.levelRange;
956
+ this.levelRange = data.levelRange ? new LevelRange(data.levelRange) : void 0;
794
957
  this.notes = data.notes;
795
958
  this.links = data.links ?? [];
796
959
  }
@@ -846,7 +1009,7 @@ class Mission {
846
1009
  this.type = data.type;
847
1010
  this.morality = new MoralityList(coalesceToArray(data.morality));
848
1011
  this.contactKeys = coalesceToArray(data.contactKeys);
849
- this.levelRange = data.levelRange;
1012
+ this.levelRange = data.levelRange ? new LevelRange(data.levelRange) : void 0;
850
1013
  this.notes = data.notes;
851
1014
  this.links = data.links ?? [];
852
1015
  this.flashback = createFlashback(data);
@@ -856,7 +1019,7 @@ function createFlashback(data) {
856
1019
  if (!data.flashback) return void 0;
857
1020
  return {
858
1021
  id: data.flashback.id,
859
- levelRange: data.flashback.levelRange ?? data.levelRange,
1022
+ levelRange: data.flashback.levelRange ? new LevelRange(data.flashback.levelRange) : void 0,
860
1023
  name: data.flashback.name ?? data.name,
861
1024
  morality: new MoralityList(coalesceToArray(data.flashback.morality ?? data.morality)),
862
1025
  notes: data.flashback.notes
@@ -872,27 +1035,25 @@ var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot
872
1035
  var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), member.set(obj, value), value);
873
1036
  var _archetypeIndex, _zoneIndex, _contactIndex, _missionIndex, _badgeIndex, _header, _servers;
874
1037
  class CohContentDatabase {
875
- constructor() {
876
- __privateAdd(this, _archetypeIndex, new AbstractIndex("key"));
877
- __privateAdd(this, _zoneIndex, new AbstractIndex("key"));
878
- __privateAdd(this, _contactIndex, new AbstractIndex("key"));
879
- __privateAdd(this, _missionIndex, new AbstractIndex("key"));
880
- __privateAdd(this, _badgeIndex, new BadgeIndex());
881
- __privateAdd(this, _header);
882
- __privateAdd(this, _servers);
883
- }
884
1038
  /**
885
- * Load the given content bundle, resetting the db if a bundle is already loaded.
1039
+ * Create a db instance from the given content bundle.
886
1040
  * @param bundle The bundle to load.
887
1041
  */
888
- load(bundle) {
1042
+ constructor(bundle) {
1043
+ __privateAdd(this, _archetypeIndex);
1044
+ __privateAdd(this, _zoneIndex);
1045
+ __privateAdd(this, _contactIndex);
1046
+ __privateAdd(this, _missionIndex);
1047
+ __privateAdd(this, _badgeIndex);
1048
+ __privateAdd(this, _header);
1049
+ __privateAdd(this, _servers);
889
1050
  __privateSet(this, _header, new BundleHeader(bundle.header));
890
1051
  __privateSet(this, _servers, bundle.servers ?? []);
891
- __privateGet(this, _archetypeIndex).load(bundle.archetypes?.map((x) => new Archetype(x)));
892
- __privateGet(this, _zoneIndex).load(bundle.zones?.map((x) => new Zone(x)));
893
- __privateGet(this, _contactIndex).load(bundle.contacts?.map((x) => new Contact(x)));
894
- __privateGet(this, _missionIndex).load(bundle.missions?.map((x) => new Mission(x)));
895
- __privateGet(this, _badgeIndex).load(bundle.badges?.map((x) => new Badge(x)));
1052
+ __privateSet(this, _archetypeIndex, new AbstractIndex("key", bundle.archetypes?.map((x) => new Archetype(x))));
1053
+ __privateSet(this, _zoneIndex, new AbstractIndex("key", bundle.zones?.map((x) => new Zone(x))));
1054
+ __privateSet(this, _contactIndex, new AbstractIndex("key", bundle.contacts?.map((x) => new Contact(x))));
1055
+ __privateSet(this, _missionIndex, new AbstractIndex("key", bundle.missions?.map((x) => new Mission(x))));
1056
+ __privateSet(this, _badgeIndex, new BadgeIndex(bundle.badges?.map((x) => new Badge(x))));
896
1057
  }
897
1058
  /**
898
1059
  * Header information about the content bundle.
@@ -906,7 +1067,7 @@ class CohContentDatabase {
906
1067
  * Torchbearer, Excelsior, etc.
907
1068
  */
908
1069
  get servers() {
909
- return __privateGet(this, _servers) ?? [];
1070
+ return __privateGet(this, _servers);
910
1071
  }
911
1072
  /**
912
1073
  * List of archetypes.
@@ -1019,5 +1180,38 @@ class Location {
1019
1180
  }
1020
1181
  }
1021
1182
 
1022
- export { ALIGNMENT, AlignmentList, Alternates, Archetype, BADGE_REQUIREMENT_TYPE, BADGE_TYPE, Badge, BadgeIndex, BadgeRequirement, BundleHeader, CohContentDatabase, Contact, ENHANCEMENT_CATEGORY, Key, Location, MISSION_TYPE, MORALITY, Mission, MoralityList, SEX, Zone, badgeLink, badgeUri, coalesceToArray, compareAlignment, compareByDefaultName, compareByZoneKey, compareSex, contactLink, contactUri, missionLink, missionUri, zoneLink, zoneUri };
1183
+ function badgeUri(target) {
1184
+ const key = typeof target === "string" ? target : target.key;
1185
+ return `badge://${key}`;
1186
+ }
1187
+ function badgeLink(target) {
1188
+ const key = typeof target === "string" ? target : target.key;
1189
+ return `[${key}](${badgeUri(target)})`;
1190
+ }
1191
+ function contactUri(target) {
1192
+ const key = typeof target === "string" ? target : target.key;
1193
+ return `contact://${key}`;
1194
+ }
1195
+ function contactLink(target) {
1196
+ const key = typeof target === "string" ? target : target.key;
1197
+ return `[${key}](${contactUri(target)})`;
1198
+ }
1199
+ function missionUri(target) {
1200
+ const key = typeof target === "string" ? target : target.key;
1201
+ return `mission://${key}`;
1202
+ }
1203
+ function missionLink(target) {
1204
+ const key = typeof target === "string" ? target : target.key;
1205
+ return `[${key}](${missionUri(target)})`;
1206
+ }
1207
+ function zoneUri(target) {
1208
+ const key = typeof target === "string" ? target : target.key;
1209
+ return `zone://${key}`;
1210
+ }
1211
+ function zoneLink(target) {
1212
+ const key = typeof target === "string" ? target : target.key;
1213
+ return `[${key}](${zoneUri(target)})`;
1214
+ }
1215
+
1216
+ export { ALIGNMENT, AlignmentList, Archetype, BADGE_REQUIREMENT_TYPE, BADGE_TYPE, Badge, BadgeIndex, BadgeRequirement, BundleHeader, CohContentDatabase, Contact, ENHANCEMENT_CATEGORY, Key, LevelRange, Location, MISSION_TYPE, MORALITY, MORALITY_EXTENDED, Mission, MoralityList, MoralityMap, SEX, SetTitleIds, Variants, ZONE_TYPE, Zone, badgeLink, badgeUri, compareAlignment, compareByName, compareByReleaseDate, compareByZoneKey, compareSex, contactLink, contactUri, missionLink, missionUri, zoneLink, zoneUri };
1023
1217
  //# sourceMappingURL=coh-content-db.mjs.map