-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathindex.ts
195 lines (167 loc) · 5.73 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
import * as countries from 'country-list/data.json'
import * as countryAlts from './country-alts.json'
import * as provinces from 'provinces/provinces.json'
// Map additional data and conform data to standard format, forcing immutability.
const countryData = countries.map((val) => {
return Object.freeze({
alt: Object.freeze(countryAlts[val.code]) as string[],
...val
})
})
const provinceData = provinces.map((val) => {
return Object.freeze({
name: val.name,
code: val.short,
countryCode: val.country,
alt: Object.freeze(val.alt),
region: val.region
})
})
Object.freeze(countryData)
Object.freeze(provinceData)
// Helper functions
/** Compare two words to each other exactly. */
function compareExact(word1: string, word2: string) {
return typeof word1 !== 'undefined' && typeof word2 !== 'undefined' && word1.toLowerCase() === word2.toLowerCase()
}
/** Search for a worf within an array of words. */
function alternateNameSearch (word: string, words: readonly string[]) {
return typeof word !== 'undefined' && Array.isArray(words) && typeof words.find((val) => compareExact(val, word)) !== 'undefined'
}
// Classes
/** Static class for country lookups. */
export class Countries {
/** Immutable data member. */
static get data () {
return countryData
}
/** Lookup country data by name. */
static byName (name: string) {
return new Country(Countries.data.find((val) => {
return compareExact(name, val.name) || alternateNameSearch(name, val.alt)
}))
}
/** Lookup country data by country code. */
static byCode (code: string) {
return new Country(Countries.data.find((val) => compareExact(code, val.code)))
}
}
/** Class for looking up province data. */
export class Provinces {
/** Create an instance of Provinces narrowed by country code. */
constructor(countryCode: string) {
this.data = Provinces.data.filter((val) => compareExact(countryCode, val.countryCode))
this.countryCode = countryCode
}
private data: typeof provinceData
/** The country code used to create this instance. */
countryCode: string
/** Lookup province by name. */
byName (name: string): Province {
return new Province(Provinces.data.find((val) => {
return compareExact(name, val.name) || alternateNameSearch(name, val.alt)
}))
}
/** Lookup province by province/state code. */
byCode (code: string): Province {
return new Province(this.data.find((val) => compareExact(code, val.code)))
}
/** Lookup province by name or by code. */
byNameOrCode (nameOrCode: string): Province {
return new Province(this.data.find((val) => {
return compareExact(nameOrCode, val.name) || alternateNameSearch(nameOrCode, val.alt) || compareExact(nameOrCode, val.code)
}))
}
/** Immutable data member. */
static get data () {
return provinceData
}
/** Lookup province by name; returns the first matching province in the case of overlap. */
static byName (name: string): Province {
return new Province(Provinces.data.find((val) => {
return compareExact(name, val.name) || alternateNameSearch(name, val.alt)
}))
}
/** Lookup province by code; returns the first matching province in the case of overlap. */
static byCode (code) {
return new Province(Provinces.data.find((val) => compareExact(code, val.code)))
}
/** Lookup an array of provinces by country code. */
static byCountryCode (countryCode) {
return Provinces.data
.filter((val) => compareExact(countryCode, val.countryCode))
.map((val) => new Province(val))
}
}
/** Class for creating an instance describing Country data. */
export class Country {
constructor (nameOrCode: string | Partial<Country>) {
this.name
this.code
this.alt
if (typeof nameOrCode === 'string') {
const result = Countries.data.find((val) => {
return compareExact(nameOrCode, val.name) || alternateNameSearch(nameOrCode, val.alt) || compareExact(nameOrCode, val.code)
})
Object.assign(this, result)
} else {
Object.assign(this, nameOrCode)
}
if (this.code) {
this.provinces = new Provinces(this.code)
}
}
/** The name of this country. */
name: string
/** The code for this country. */
code: string
/** Alternate names for this country. */
alt: readonly string[]
/** Provinces related to this country. */
provinces?: Provinces
/** Lookup province by name. */
provinceByName (name: string): Province {
return this.provinces.byName(name)
}
/** Lookup province by province/state code. */
provinceByCode (code: string): Province {
return this.provinces.byCode(code)
}
/** Lookup province by name or by code. */
provinceByNameOrCode (nameOrCode: string): Province {
return this.provinces.byNameOrCode(nameOrCode)
}
}
/** Class for creating an instance describing Province data. */
export class Province {
constructor (nameOrCode: string | Partial<Province>) {
this.name
this.code
this.countryCode
this.alt
this.region
if (typeof nameOrCode === 'string') {
const result = Provinces.data.find((val) => {
return compareExact(nameOrCode, val.name) || alternateNameSearch(nameOrCode, val.alt) || compareExact(nameOrCode, val.code)
})
Object.assign(this, result)
} else {
Object.assign(this, nameOrCode)
}
if (this.countryCode) {
this.country = Countries.byCode(this.countryCode)
}
}
/** Name of the province. */
name: string
/** The province code. */
code: string
/** Code of the country related to this province. */
countryCode: string
/** Alternate names for this province. */
alt: readonly string[]
/** The region of this province. */
region?: string
/** The instance of Country related to this province. */
country?: Country
}