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

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 (84) hide show
  1. package/.editorconfig +25 -0
  2. package/.github/workflows/build.yml +38 -0
  3. package/.github/workflows/pull-request.yml +32 -0
  4. package/.github/workflows/release.yml +52 -0
  5. package/LICENSE +24 -674
  6. package/README.md +74 -17
  7. package/dist/coh-content-db.d.ts +584 -22
  8. package/dist/coh-content-db.js +587 -2
  9. package/dist/coh-content-db.js.map +1 -0
  10. package/dist/coh-content-db.mjs +568 -0
  11. package/dist/coh-content-db.mjs.map +1 -0
  12. package/eslint.config.mjs +30 -0
  13. package/jest.config.mjs +7 -0
  14. package/package.json +31 -23
  15. package/rollup.config.mjs +27 -0
  16. package/src/main/api/alignment.ts +3 -0
  17. package/src/main/api/alternate-data.ts +22 -0
  18. package/src/main/api/archetype-data.ts +5 -0
  19. package/src/main/api/badge-data.ts +109 -0
  20. package/src/main/api/badge-partial-data.ts +65 -0
  21. package/src/main/api/badge-partial-type.ts +8 -0
  22. package/src/main/api/badge-type.ts +19 -0
  23. package/src/main/api/change.ts +14 -0
  24. package/src/main/api/enhancement-category.ts +30 -0
  25. package/src/main/api/game-map-data.ts +26 -0
  26. package/src/main/api/link.ts +4 -0
  27. package/src/main/api/plaque-type.ts +6 -0
  28. package/src/main/api/server-group-data.ts +65 -0
  29. package/src/main/api/sex.ts +3 -0
  30. package/src/main/api/vidiot-map-data.ts +18 -0
  31. package/src/main/api/vidiot-map-point-of-interest-data.ts +30 -0
  32. package/src/main/changelog.ts +20 -0
  33. package/src/main/db/alternates.ts +81 -0
  34. package/src/main/db/archetype.ts +14 -0
  35. package/src/main/db/badge-partial.ts +35 -0
  36. package/src/main/db/badge.ts +141 -0
  37. package/src/main/db/coh-content-database.ts +29 -0
  38. package/src/main/db/game-map.ts +33 -0
  39. package/src/main/db/key.ts +18 -0
  40. package/src/main/db/server-group.ts +112 -0
  41. package/src/main/db/vidiot-map-point-of-interest.ts +40 -0
  42. package/src/main/db/vidiot-map.ts +25 -0
  43. package/src/main/index.ts +33 -0
  44. package/src/main/util.ts +17 -0
  45. package/src/test/api/alignment.test.ts +31 -0
  46. package/src/test/api/archetype-data.fixture.ts +8 -0
  47. package/src/test/api/badge-data.fixture.ts +22 -0
  48. package/src/test/api/badge-data.test.ts +15 -0
  49. package/src/test/api/badge-partial-data.fixture.ts +17 -0
  50. package/src/test/api/badge-partial-type.test.ts +31 -0
  51. package/src/test/api/badge-type.test.ts +35 -0
  52. package/src/test/api/enhancement-category.test.ts +35 -0
  53. package/src/test/api/game-map-data.fixture.ts +10 -0
  54. package/src/test/api/plaque-type.test.ts +31 -0
  55. package/src/test/api/server-group-data.fixture.ts +23 -0
  56. package/src/test/api/server-group-data.test.ts +15 -0
  57. package/src/test/api/sex.test.ts +31 -0
  58. package/src/test/api/vidiot-map-point-of-interest.fixture.ts +10 -0
  59. package/src/test/api/vidiot-map.fixture.ts +9 -0
  60. package/src/test/changelog.test.ts +36 -0
  61. package/src/test/db/alternates.test.ts +223 -0
  62. package/src/test/db/archetype.test.ts +38 -0
  63. package/src/test/db/badge.test.ts +41 -0
  64. package/src/test/db/coh-content-database.test.ts +42 -0
  65. package/src/test/db/key.test.ts +22 -0
  66. package/src/test/db/server-group.test.ts +124 -0
  67. package/src/test/index.test.ts +10 -0
  68. package/src/test/util.test.ts +39 -0
  69. package/tsconfig.json +117 -0
  70. package/dist/_changelog.d.ts +0 -3
  71. package/dist/coh-content-db.nomin.js +0 -635
  72. package/dist/content-refence-utils.d.ts +0 -4
  73. package/dist/index.d.ts +0 -8
  74. package/dist/internal/_common.d.ts +0 -4
  75. package/dist/internal/archetype.d.ts +0 -10
  76. package/dist/internal/badge.d.ts +0 -44
  77. package/dist/internal/game-map.d.ts +0 -33
  78. package/dist/internal/server-group.d.ts +0 -24
  79. package/dist/types/archetype.d.ts +0 -9
  80. package/dist/types/badge.d.ts +0 -192
  81. package/dist/types/enhancement.d.ts +0 -28
  82. package/dist/types/game-map.d.ts +0 -47
  83. package/dist/types/link.d.ts +0 -4
  84. package/dist/types/server-group.d.ts +0 -75
@@ -0,0 +1,20 @@
1
+ import { Change } from './api/change'
2
+
3
+ export const CHANGELOG: Change[] = [
4
+ {
5
+ version: '2.0.0',
6
+ date: new Date('2025-03-12'),
7
+ description: ''
8
+ + '* Replaced redundant interfaces with their concrete equivalents.\n'
9
+ + '* Replaced enums with extensible union types; Server groups with new badge types, enhancement types, etc. can now extend them locally.\n'
10
+ + '* Removed the `serverGroup` property from entities to simplify the object tree; Server group context will need to be managed separately.\n'
11
+ + '* Standardized pluralization of some field names (name, icon).\n'
12
+ + '* Combined `settitle` ids into a single tuple field.\n'
13
+ + '* Change from GNU to The Unlicense.\n'
14
+ + '* Removed dependency on lodash. There are now no third-party runtime dependencies.\n'
15
+ + '* Moved from webpack to rollup for packaging.\n'
16
+ + '* Add eslint for linting.\n'
17
+ + '* Add jest for unit tests.\n'
18
+ + '* Added GitHub Actions for CI.\n',
19
+ },
20
+ ]
@@ -0,0 +1,81 @@
1
+ import { AlternateData } from '../api/alternate-data'
2
+ import { Sex } from '../api/sex'
3
+ import { Alignment } from '../api/alignment'
4
+
5
+ const ALIGNMENT_SORT: Record<string, number> = { H: 2, V: 1, P: 0 }
6
+ const SEX_SORT: Record<string, number> = { M: 1, F: 0 }
7
+
8
+ export class Alternates<T> {
9
+ readonly #sortedValues: AlternateData<T>[] = []
10
+
11
+ constructor(values: AlternateData<T>[]) {
12
+ this.#sortedValues = values.sort()
13
+ this.#sortedValues.sort((a, b) => this.#compareAlternates(a, b))
14
+ }
15
+
16
+ getValue(alignment?: Alignment | string, sex?: Sex | string): T | undefined {
17
+ for (let index = this.#sortedValues.length; index--;) {
18
+ const entry = this.#sortedValues[index]
19
+ if ((entry.alignment === undefined || entry.alignment === alignment)
20
+ && (entry.sex === undefined || entry.sex === sex)
21
+ ) return entry.value
22
+ }
23
+ return undefined
24
+ }
25
+
26
+ /**
27
+ * Get the default value for this list of alternates, the value with the highest priority and lowest specificity.
28
+ */
29
+ get default(): T | undefined {
30
+ return this.#sortedValues[0]?.value
31
+ }
32
+
33
+ /**
34
+ * Get the list of alternates sorted in canonical order (alignment then sex, low to high specificity).
35
+ */
36
+ get canonical(): AlternateData<T>[] {
37
+ return this.#sortedValues
38
+ }
39
+
40
+ #compareAlternates(a: AlternateData<T>, b: AlternateData<T>): number {
41
+ const aSpecificity = (a.alignment ? 2 : 0) + (a.sex ? 1 : 0)
42
+ const bSpecificity = (b.alignment ? 2 : 0) + (b.sex ? 1 : 0)
43
+ if (aSpecificity !== bSpecificity) return aSpecificity - bSpecificity // Order first by least-specific
44
+
45
+ const alignmentComparison = this.#compareAlignment(a.alignment, b.alignment) // Next by alignment
46
+ if (alignmentComparison !== 0) return alignmentComparison
47
+
48
+ const sexComparison = this.#compareSex(a.sex, b.sex) // Last by sex
49
+ if (sexComparison !== 0) return sexComparison
50
+
51
+ return String(a.value).localeCompare(String(b.value))
52
+ }
53
+
54
+ #compareAlignment(a: Alignment | string | undefined, b: Alignment | string | undefined): number {
55
+ if (a === b) return 0
56
+ if (a === undefined && b !== undefined) return -1
57
+ if (b === undefined && a !== undefined) return 1
58
+
59
+ const aSort = a === undefined ? -1 : ALIGNMENT_SORT[a] ?? -1 // Unknown values get -1 priority
60
+ const bSort = b === undefined ? -1 : ALIGNMENT_SORT[b] ?? -1
61
+
62
+ if (aSort !== bSort) return bSort - aSort
63
+
64
+ // Unknown values (not in ALIGNMENT_SORT) are sorted alphabetically
65
+ return a?.localeCompare(b ?? '') ?? 0
66
+ }
67
+
68
+ #compareSex(a?: Sex | string | undefined, b?: Sex | string | undefined): number {
69
+ if (a === b) return 0
70
+ if (a === undefined && b !== undefined) return -1
71
+ if (b === undefined && a !== undefined) return 1
72
+
73
+ const aSort = SEX_SORT[a ?? -1] ?? -1 // Unknown values get -1 priority
74
+ const bSort = SEX_SORT[b ?? -1] ?? -1
75
+
76
+ if (aSort !== bSort) return bSort - aSort
77
+
78
+ // Unknown values (not in SEX_SORT) are sorted alphabetically
79
+ return a?.localeCompare(b ?? '') ?? 0
80
+ }
81
+ }
@@ -0,0 +1,14 @@
1
+ import { Key } from './key'
2
+ import { ArchetypeData } from '../api/archetype-data'
3
+
4
+ export class Archetype {
5
+ readonly key: string
6
+ readonly name: string
7
+ readonly description?: string
8
+
9
+ constructor(data: ArchetypeData) {
10
+ this.key = new Key(data.key).value
11
+ this.name = data.name
12
+ this.description = data.description
13
+ }
14
+ }
@@ -0,0 +1,35 @@
1
+ import { BadgePartialData } from '../api/badge-partial-data'
2
+ import { PlaqueType } from '../api/plaque-type'
3
+ import { BadgePartialType } from '../api/badge-partial-type'
4
+ import { EnhancementCategory } from '../api/enhancement-category'
5
+ import { Key } from './key'
6
+
7
+ export class BadgePartial {
8
+ readonly key: string
9
+ readonly type: BadgePartialType | string
10
+ readonly mapKey?: string
11
+ readonly loc?: number[]
12
+ readonly plaqueType?: PlaqueType | string
13
+ readonly inscription?: string
14
+ readonly vidiotMapKey?: string
15
+ readonly badgeKey?: string
16
+ readonly inventionLevel?: number
17
+ readonly inventionTypes?: (EnhancementCategory | string)[]
18
+ readonly inventionCount?: number
19
+ readonly notes?: string
20
+
21
+ constructor(data: BadgePartialData) {
22
+ this.key = new Key(data.key).value
23
+ this.type = data.type
24
+ this.mapKey = data.mapKey
25
+ this.loc = data.loc
26
+ this.plaqueType = data.plaqueType
27
+ this.inscription = data.inscription
28
+ this.vidiotMapKey = data.vidiotMapKey
29
+ this.badgeKey = data.badgeKey
30
+ this.inventionLevel = data.inventionLevel
31
+ this.inventionTypes = data.inventionTypes
32
+ this.inventionCount = data.inventionCount
33
+ this.notes = data.notes
34
+ }
35
+ }
@@ -0,0 +1,141 @@
1
+ import { BadgeType } from '../api/badge-type'
2
+ import { Alignment } from '../api/alignment'
3
+ import { Link } from '../api/link'
4
+ import { BadgeData } from '../api/badge-data'
5
+ import { BadgePartial } from './badge-partial'
6
+ import { Key } from './key'
7
+ import { Alternates } from './alternates'
8
+
9
+ export class Badge {
10
+ readonly #partialsIndex: Record<string, BadgePartial> = {}
11
+
12
+ /**
13
+ * The database key for this badge.
14
+ */
15
+ readonly key: string
16
+
17
+ /**
18
+ * The type of badge.
19
+ */
20
+ readonly type: BadgeType | string
21
+
22
+ /**
23
+ * The name of this badge.
24
+ *
25
+ * May vary by character sex or alignment.
26
+ */
27
+ readonly name: Alternates<string>
28
+
29
+ /**
30
+ * The character alignments that this badge is available to.
31
+ */
32
+ readonly alignment: Alignment[]
33
+
34
+ /**
35
+ * The badge text as it appears in-game. May vary by character sex or alignment.
36
+ */
37
+ readonly badgeText: Alternates<string>
38
+
39
+ /**
40
+ * Description of how to acquire the badge.
41
+ *
42
+ * Supports {@link https://www.markdownguide.org/|Markdown} format.
43
+ */
44
+ readonly acquisition?: string
45
+
46
+ /**
47
+ * Absolute URL to this badge's icon.
48
+ *
49
+ * May vary by character sex or alignment.
50
+ */
51
+ readonly icon: Alternates<string>
52
+
53
+ /**
54
+ * Freeform notes or tips about the badge.
55
+ *
56
+ * Supports {@link https://www.markdownguide.org/|Markdown} format.
57
+ */
58
+ readonly notes?: string
59
+
60
+ /**
61
+ * List of external links for this Badge. Wiki, forums, etc.
62
+ */
63
+ readonly links?: Link[]
64
+
65
+ /**
66
+ * For exploration badges, the key of the {@link GameMap} that this badge is found on.
67
+ */
68
+ readonly mapKey?: string
69
+
70
+ /**
71
+ * For exploration badges, the `/loc` coordinates of the badge on the in-game map.
72
+ */
73
+ readonly loc?: [number, number, number]
74
+
75
+ /**
76
+ * For badges that appear on a Vidiot Map, the number or letter the badge appears as.
77
+ */
78
+ readonly vidiotMapKey?: string
79
+
80
+ /**
81
+ * ID used with the in-game `/settitle` command to apply the badge.
82
+ */
83
+ readonly setTitle?: {
84
+ /**
85
+ * `/settitle` id.
86
+ */
87
+ id?: number
88
+ /**
89
+ * `/settitle` id if different for praetorian characters.
90
+ */
91
+ praetorianId?: number
92
+ }
93
+
94
+ /**
95
+ * A description of the effect the badge will have, such as a buff or granting a temporary power.
96
+ *
97
+ * Supports {@link https://www.markdownguide.org/|Markdown} format.
98
+ */
99
+ readonly effect?: string
100
+
101
+ /**
102
+ * A list of requirements for badges that have partial fulfilment steps, such as visiting plaques for history badges, or collecting other badges for meta-badges like accolades.
103
+ */
104
+ readonly partials?: BadgePartial[]
105
+
106
+ /**
107
+ * 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.
108
+ */
109
+ readonly ignoreInTotals: boolean
110
+
111
+ constructor(data: BadgeData) {
112
+ this.key = new Key(data.key).value
113
+ this.type = data.type
114
+ this.name = new Alternates(data.name)
115
+ this.alignment = data.alignment
116
+ this.badgeText = new Alternates(data.badgeText ?? [])
117
+ this.acquisition = data.acquisition
118
+ this.icon = new Alternates(data.icon ?? [])
119
+ this.notes = data.notes
120
+ this.links = data.links
121
+ this.mapKey = data.mapKey
122
+ this.loc = data.loc
123
+ this.effect = data.effect
124
+ this.vidiotMapKey = data.vidiotMapKey
125
+ this.setTitle = data.setTitle
126
+ this.ignoreInTotals = data.ignoreInTotals ?? false
127
+
128
+ this.partials = data.partials?.map((data) => {
129
+ if (this.#partialsIndex[data.key] !== undefined) throw new Error(`Duplicate badge partial key [${data.key}]`)
130
+ const badge = new BadgePartial(data)
131
+ this.#partialsIndex[badge.key] = badge
132
+ return badge
133
+ })
134
+ }
135
+
136
+ getPartial(key: string): BadgePartial {
137
+ const result = this.#partialsIndex[key]
138
+ if (result === undefined) throw new Error(`Unknown badge partial key [${key}]`)
139
+ return result
140
+ }
141
+ }
@@ -0,0 +1,29 @@
1
+ import { ServerGroup } from './server-group'
2
+ import { ServerGroupData } from '../api/server-group-data'
3
+
4
+ export class CohContentDatabase {
5
+ readonly #serverGroups: Record<string, ServerGroup> = {}
6
+
7
+ /**
8
+ * Load a server group data package into the database.
9
+ * @param data The data to load.
10
+ */
11
+ loadServerGroupData(data: ServerGroupData): void {
12
+ this.#serverGroups[data.key] = new ServerGroup(data)
13
+ }
14
+
15
+ /**
16
+ * Get all the server groups currently loaded in the database.
17
+ */
18
+ listServerGroups(): ServerGroup[] {
19
+ return Object.values(this.#serverGroups)
20
+ }
21
+
22
+ /**
23
+ * get a server group by key.
24
+ * @param serverGroupKey The key.
25
+ */
26
+ getServerGroup(serverGroupKey: string): ServerGroup | null {
27
+ return this.#serverGroups[serverGroupKey]
28
+ }
29
+ }
@@ -0,0 +1,33 @@
1
+ import { VidiotMap } from './vidiot-map'
2
+ import { Link } from '../api/link'
3
+ import { GameMapData } from '../api/game-map-data'
4
+ import { Key } from './key'
5
+
6
+ export class GameMap {
7
+ /**
8
+ * The database key for this map.
9
+ */
10
+ readonly key: string
11
+
12
+ /**
13
+ * The name of the map as it appears in-game.
14
+ */
15
+ readonly name: string
16
+
17
+ /**
18
+ * List of external links for this Map. Wiki, forums, etc.
19
+ */
20
+ readonly links?: Link[]
21
+
22
+ /**
23
+ * List of Vidiot Map assets for this map.
24
+ */
25
+ readonly vidiotMaps?: VidiotMap[]
26
+
27
+ constructor(data: GameMapData) {
28
+ this.key = new Key(data.key).value
29
+ this.name = data.name
30
+ this.links = data.links
31
+ this.vidiotMaps = data.vidiotMaps?.map(data => new VidiotMap(data))
32
+ }
33
+ }
@@ -0,0 +1,18 @@
1
+ const INVALID_KEY_PATTERN = /[^a-z0-9-]/
2
+
3
+ export class Key {
4
+ readonly #value: string
5
+
6
+ constructor(value: string) {
7
+ this.#validateKey(value)
8
+ this.#value = value
9
+ }
10
+
11
+ get value(): string {
12
+ return this.#value
13
+ }
14
+
15
+ #validateKey(key: string): void {
16
+ if (INVALID_KEY_PATTERN.test(key)) throw new Error(`Invalid key: [${key}]; Keys can only contain lowercase characters, numbers and dashes.`)
17
+ }
18
+ }
@@ -0,0 +1,112 @@
1
+ import { Archetype } from './archetype'
2
+ import { Badge } from './badge'
3
+ import { ServerGroupData } from '../api/server-group-data'
4
+ import { Key } from './key'
5
+ import { Change } from '../api/change'
6
+ import { GameMap } from './game-map'
7
+ import { Link } from '../api/link'
8
+
9
+ export class ServerGroup {
10
+ readonly #archetypeIndex: Record<string, Archetype> = {}
11
+ readonly #mapIndex: Record<string, GameMap> = {}
12
+ readonly #badgeIndex: Record<string, Badge> = {}
13
+
14
+ /**
15
+ * The database key for this server group.
16
+ */
17
+ readonly key: string
18
+
19
+ /**
20
+ * Name of the server group.
21
+ */
22
+ readonly name: string
23
+
24
+ /**
25
+ * Description of the server group.
26
+ *
27
+ * Supports {@link https://www.markdownguide.org/|Markdown} format.
28
+ */
29
+ readonly description?: string
30
+
31
+ /**
32
+ * Repository where the db content package is maintained.
33
+ */
34
+ readonly repository?: string
35
+
36
+ /**
37
+ * List of external links for this Server Group. Wiki, forums, etc.
38
+ */
39
+ readonly links?: Link[]
40
+
41
+ /**
42
+ * List of the game server names in this server group.
43
+ * Torchbearer, Excelsior, etc.
44
+ */
45
+ readonly servers: string[]
46
+
47
+ /**
48
+ * List of archetypes available in this server group.
49
+ */
50
+ readonly archetypes: Archetype[]
51
+
52
+ /**
53
+ * List of game maps supported by this server group.
54
+ */
55
+ readonly maps: GameMap[]
56
+
57
+ /**
58
+ * List of badges available on this server group.
59
+ */
60
+ readonly badges: Badge[]
61
+
62
+ /**
63
+ * Change log for this data package.
64
+ */
65
+ readonly changelog?: Change[]
66
+
67
+ constructor(data: ServerGroupData) {
68
+ this.key = new Key(data.key).value
69
+ this.name = data.name
70
+ this.description = data.description
71
+ this.repository = data.repository
72
+ this.links = data.links
73
+ this.servers = data.servers ?? []
74
+ this.archetypes = data.archetypes?.map((data) => {
75
+ if (this.#archetypeIndex[data.key] !== undefined) throw new Error(`Duplicate archetype key [${data.key}]`)
76
+ const archetype = new Archetype(data)
77
+ this.#archetypeIndex[archetype.key] = archetype
78
+ return archetype
79
+ }) ?? []
80
+ this.maps = data.maps?.map((data) => {
81
+ if (this.#mapIndex[data.key] !== undefined) throw new Error(`Duplicate map key [${data.key}]`)
82
+ const map = new GameMap(data)
83
+ this.#mapIndex[map.key] = map
84
+ return map
85
+ }) ?? []
86
+ this.badges = data.badges?.map((data) => {
87
+ if (this.#badgeIndex[data.key] !== undefined) throw new Error(`Duplicate badge key [${data.key}]`)
88
+ const badge = new Badge(data)
89
+ this.#badgeIndex[badge.key] = badge
90
+ return badge
91
+ }) ?? []
92
+ this.changelog = data.changelog
93
+ }
94
+
95
+ getArchetype(key: string): Archetype {
96
+ const result = this.#archetypeIndex[key]
97
+ if (result === undefined) throw new Error(`Unknown archetype key [${key}]`)
98
+ return result
99
+ }
100
+
101
+ getMap(key: string): GameMap {
102
+ const result = this.#mapIndex[key]
103
+ if (result === undefined) throw new Error(`Unknown map key [${key}]`)
104
+ return result
105
+ }
106
+
107
+ getBadge(key: string): Badge {
108
+ const result = this.#badgeIndex[key]
109
+ if (result === undefined) throw new Error(`Unknown badge key [${key}]`)
110
+ return result
111
+ }
112
+ }
@@ -0,0 +1,40 @@
1
+ import { VidiotMapPointOfInterestData } from '../api/vidiot-map-point-of-interest-data'
2
+
3
+ export class VidiotMapPointOfInterest {
4
+ /**
5
+ * The pixel-space position of the PoI on the map graphic.
6
+ *
7
+ * Screen-space, pixels from top-left `[0, 0]`.
8
+ */
9
+ readonly pos?: [number, number]
10
+
11
+ /**
12
+ * Freeform notes about the PoI.
13
+ *
14
+ * Supports {@link https://www.markdownguide.org/|Markdown} format.
15
+ */
16
+ readonly notes?: string
17
+
18
+ /**
19
+ * If the POI is a zone transfer, the map it transfers to.
20
+ */
21
+ readonly mapKey?: string
22
+
23
+ /**
24
+ * If the POI is a badge, the badge.
25
+ */
26
+ readonly badgeKey?: string
27
+
28
+ /**
29
+ * If the POI is a partial for a badge, the partial key.
30
+ */
31
+ readonly badgePartialKey?: string
32
+
33
+ constructor(data: VidiotMapPointOfInterestData) {
34
+ this.pos = data.pos
35
+ this.notes = data.notes
36
+ this.mapKey = data.mapKey
37
+ this.badgeKey = data.badgeKey
38
+ this.badgePartialKey = data.badgePartialKey
39
+ }
40
+ }
@@ -0,0 +1,25 @@
1
+ import { VidiotMapData } from '../api/vidiot-map-data'
2
+ import { VidiotMapPointOfInterest } from './vidiot-map-point-of-interest'
3
+
4
+ export class VidiotMap {
5
+ /**
6
+ * URL of the map image.
7
+ */
8
+ readonly imageUrl: string
9
+
10
+ /**
11
+ * Name to display for the Vidiot map.
12
+ */
13
+ readonly name?: string
14
+
15
+ /**
16
+ * List of Points of Interest labelled on the image.
17
+ */
18
+ readonly pointsOfInterest?: VidiotMapPointOfInterest[]
19
+
20
+ constructor(data: VidiotMapData) {
21
+ this.imageUrl = data.imageUrl
22
+ this.name = data.name
23
+ this.pointsOfInterest = data.pointsOfInterest?.map(data => new VidiotMapPointOfInterest(data))
24
+ }
25
+ }
@@ -0,0 +1,33 @@
1
+ // API
2
+ export * from './api/alignment'
3
+ export * from './api/alternate-data'
4
+ export * from './api/archetype-data'
5
+ export * from './api/badge-data'
6
+ export * from './api/badge-partial-data'
7
+ export * from './api/badge-partial-type'
8
+ export * from './api/badge-type'
9
+ export * from './api/change'
10
+ export * from './api/enhancement-category'
11
+ export * from './api/game-map-data'
12
+ export * from './api/link'
13
+ export * from './api/plaque-type'
14
+ export * from './api/server-group-data'
15
+ export * from './api/sex'
16
+ export * from './api/vidiot-map-data'
17
+ export * from './api/vidiot-map-point-of-interest-data'
18
+
19
+ // DB
20
+ export * from './db/archetype'
21
+ export * from './db/badge'
22
+ export * from './db/badge-partial'
23
+ export * from './db/coh-content-database'
24
+ export * from './db/game-map'
25
+ export * from './db/key'
26
+ export * from './db/server-group'
27
+ export * from './db/vidiot-map'
28
+ export * from './db/vidiot-map-point-of-interest'
29
+
30
+ // ROOT
31
+ export { CHANGELOG } from './changelog'
32
+
33
+ export * from './util'
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Create a reference string that can be used in most text strings to display a link to the given badge.
3
+ * @param target The badge or badge key to target.
4
+ */
5
+ export function createBadgeReference(target: string | { key: string }): string {
6
+ const key = typeof target === 'string' ? target : target.key
7
+ return `[badge:${key}]`
8
+ }
9
+
10
+ /**
11
+ * Create a reference string that can be used in most text strings to display a link to the given map.
12
+ * @param target The {@link GameMap} or map key to target.
13
+ */
14
+ export function createMapReference(target: string | { key: string }): string {
15
+ const key = typeof target === 'string' ? target : target.key
16
+ return `[map:${key}]`
17
+ }
@@ -0,0 +1,31 @@
1
+ import { Alignment, ALIGNMENT } from '../../main'
2
+
3
+ describe('ALIGNMENT', () => {
4
+ test('should be an array', () => {
5
+ expect(Array.isArray(ALIGNMENT)).toBeTruthy()
6
+ })
7
+
8
+ test('should not be empty', () => {
9
+ expect(ALIGNMENT).not.toHaveLength(0)
10
+ })
11
+
12
+ test('should contain only strings', () => {
13
+ for (const entry of ALIGNMENT) {
14
+ expect(typeof entry).toBe('string')
15
+ }
16
+ })
17
+
18
+ test('should contain all known alignments', () => {
19
+ const expected = ['H', 'V', 'P']
20
+ for (const category of expected) {
21
+ expect(ALIGNMENT).toContain(category)
22
+ }
23
+ })
24
+ })
25
+
26
+ describe('Alignment', () => {
27
+ test('should be a usable type', () => {
28
+ const field: Alignment = 'H'
29
+ expect(field).toBe('H')
30
+ })
31
+ })
@@ -0,0 +1,8 @@
1
+ import { defineFixture } from 'efate'
2
+ import { ArchetypeData } from '../../main'
3
+
4
+ export const archetypeDataFixture = defineFixture<ArchetypeData>((t) => {
5
+ t.key.as(index => `archetype-${index}`)
6
+ t.name.as(index => `Archetype ${index}`)
7
+ t.description?.asLoremIpsum()
8
+ })
@@ -0,0 +1,22 @@
1
+ import { defineFixture } from 'efate'
2
+ import { ALIGNMENT, BADGE_TYPE, BadgeData } from '../../main'
3
+ import { badgePartialDataFixture } from './badge-partial-data.fixture'
4
+
5
+ export const badgeDataFixture = defineFixture<BadgeData>((t) => {
6
+ t.key.as(index => `badge-${index}`)
7
+ t.type.pickFrom([...BADGE_TYPE])
8
+ t.name.as(index => [{ value: `Badge ${index}` }])
9
+ t.alignment.pickFrom([...ALIGNMENT])
10
+ t.badgeText?.as(index => [{ value: `This is badge ${index}` }])
11
+ t.acquisition?.asLoremIpsum()
12
+ t.icon?.asArray([{ value: 'https://nouri.org' }])
13
+ t.notes?.asLoremIpsum()
14
+ t.links?.asArray([{ href: 'https://nouri.org' }])
15
+ t.mapKey?.asString()
16
+ t.loc?.asArray()
17
+ t.vidiotMapKey?.asString()
18
+ t.setTitle?.asArray({ length: 2 })
19
+ t.effect?.asString()
20
+ t.partials?.arrayOfFixture({ fixture: badgePartialDataFixture })
21
+ t.ignoreInTotals?.asBoolean()
22
+ })