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