forked from MapComplete/MapComplete
Chore: formatting
This commit is contained in:
parent
35eff07c80
commit
c08fe03ed0
422 changed files with 31594 additions and 43019 deletions
|
|
@ -27,23 +27,23 @@ export default class LinkedDataLoader {
|
|||
opening_hours: { "@id": "http://schema.org/openingHoursSpecification" },
|
||||
openingHours: { "@id": "http://schema.org/openingHours", "@container": "@set" },
|
||||
geo: { "@id": "http://schema.org/geo" },
|
||||
alt_name: { "@id": "http://schema.org/alternateName" }
|
||||
alt_name: { "@id": "http://schema.org/alternateName" },
|
||||
}
|
||||
private static COMPACTING_CONTEXT_OH = {
|
||||
dayOfWeek: { "@id": "http://schema.org/dayOfWeek", "@container": "@set" },
|
||||
closes: {
|
||||
"@id": "http://schema.org/closes",
|
||||
"@type": "http://www.w3.org/2001/XMLSchema#time"
|
||||
"@type": "http://www.w3.org/2001/XMLSchema#time",
|
||||
},
|
||||
opens: {
|
||||
"@id": "http://schema.org/opens",
|
||||
"@type": "http://www.w3.org/2001/XMLSchema#time"
|
||||
}
|
||||
"@type": "http://www.w3.org/2001/XMLSchema#time",
|
||||
},
|
||||
}
|
||||
private static formatters: Record<"phone" | "email" | "website", Validator> = {
|
||||
phone: new PhoneValidator(),
|
||||
email: new EmailValidator(),
|
||||
website: new UrlValidator(undefined, undefined, true)
|
||||
website: new UrlValidator(undefined, undefined, true),
|
||||
}
|
||||
private static ignoreKeys = [
|
||||
"http://schema.org/logo",
|
||||
|
|
@ -56,7 +56,7 @@ export default class LinkedDataLoader {
|
|||
"http://schema.org/description",
|
||||
"http://schema.org/hasMap",
|
||||
"http://schema.org/priceRange",
|
||||
"http://schema.org/contactPoint"
|
||||
"http://schema.org/contactPoint",
|
||||
]
|
||||
|
||||
private static shapeToPolygon(str: string): Polygon {
|
||||
|
|
@ -69,8 +69,8 @@ export default class LinkedDataLoader {
|
|||
.trim()
|
||||
.split(" ")
|
||||
.map((n) => Number(n))
|
||||
)
|
||||
]
|
||||
),
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -92,18 +92,18 @@ export default class LinkedDataLoader {
|
|||
const context = {
|
||||
lat: {
|
||||
"@id": "http://schema.org/latitude",
|
||||
"@type": "http://www.w3.org/2001/XMLSchema#double"
|
||||
"@type": "http://www.w3.org/2001/XMLSchema#double",
|
||||
},
|
||||
lon: {
|
||||
"@id": "http://schema.org/longitude",
|
||||
"@type": "http://www.w3.org/2001/XMLSchema#double"
|
||||
}
|
||||
"@type": "http://www.w3.org/2001/XMLSchema#double",
|
||||
},
|
||||
}
|
||||
const flattened = await jsonld.compact(geo, context)
|
||||
|
||||
return {
|
||||
type: "Point",
|
||||
coordinates: [Number(flattened.lon), Number(flattened.lat)]
|
||||
coordinates: [Number(flattened.lon), Number(flattened.lat)],
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -288,7 +288,7 @@ export default class LinkedDataLoader {
|
|||
if (properties["latitude"] && properties["longitude"]) {
|
||||
geometry = {
|
||||
type: "Point",
|
||||
coordinates: [Number(properties["longitude"]), Number(properties["latitude"])]
|
||||
coordinates: [Number(properties["longitude"]), Number(properties["latitude"])],
|
||||
}
|
||||
delete properties["latitude"]
|
||||
delete properties["longitude"]
|
||||
|
|
@ -300,7 +300,7 @@ export default class LinkedDataLoader {
|
|||
const geo: GeoJSON = {
|
||||
type: "Feature",
|
||||
properties,
|
||||
geometry
|
||||
geometry,
|
||||
}
|
||||
delete linkedData.geo
|
||||
delete properties.shape
|
||||
|
|
@ -323,7 +323,7 @@ export default class LinkedDataLoader {
|
|||
if (output["type"]?.[0] === "https://data.velopark.be/openvelopark/terms#BicycleLocker") {
|
||||
output["bicycle_parking"] = ["lockers"]
|
||||
}
|
||||
if(output["type"] === undefined){
|
||||
if (output["type"] === undefined) {
|
||||
console.error("No type given for", output)
|
||||
}
|
||||
delete output["type"]
|
||||
|
|
@ -333,7 +333,7 @@ export default class LinkedDataLoader {
|
|||
return
|
||||
}
|
||||
output[key] = output[key].map((v) => applyF(v))
|
||||
if (!output[key].some(v => v !== undefined)) {
|
||||
if (!output[key].some((v) => v !== undefined)) {
|
||||
delete output[key]
|
||||
}
|
||||
}
|
||||
|
|
@ -418,7 +418,7 @@ export default class LinkedDataLoader {
|
|||
"brede publiek",
|
||||
"iedereen",
|
||||
"bezoekers",
|
||||
"iedereen - vooral bezoekers gemeentehuis of bibliotheek."
|
||||
"iedereen - vooral bezoekers gemeentehuis of bibliotheek.",
|
||||
].indexOf(audience.toLowerCase()) >= 0
|
||||
) {
|
||||
return "yes"
|
||||
|
|
@ -501,7 +501,7 @@ export default class LinkedDataLoader {
|
|||
mv: "http://schema.mobivoc.org/",
|
||||
gr: "http://purl.org/goodrelations/v1#",
|
||||
vp: "https://data.velopark.be/openvelopark/vocabulary#",
|
||||
vpt: "https://data.velopark.be/openvelopark/terms#"
|
||||
vpt: "https://data.velopark.be/openvelopark/terms#",
|
||||
},
|
||||
[url],
|
||||
undefined,
|
||||
|
|
@ -522,7 +522,7 @@ export default class LinkedDataLoader {
|
|||
mv: "http://schema.mobivoc.org/",
|
||||
gr: "http://purl.org/goodrelations/v1#",
|
||||
vp: "https://data.velopark.be/openvelopark/vocabulary#",
|
||||
vpt: "https://data.velopark.be/openvelopark/terms#"
|
||||
vpt: "https://data.velopark.be/openvelopark/terms#",
|
||||
},
|
||||
[url],
|
||||
"g",
|
||||
|
|
@ -654,7 +654,10 @@ export default class LinkedDataLoader {
|
|||
* The id will be saved as `ref:velopark`
|
||||
* @param url
|
||||
*/
|
||||
public static async fetchVeloparkEntry(url: string, includeExtras: boolean = false): Promise<Feature[]> {
|
||||
public static async fetchVeloparkEntry(
|
||||
url: string,
|
||||
includeExtras: boolean = false
|
||||
): Promise<Feature[]> {
|
||||
const cacheKey = includeExtras + url
|
||||
if (this.veloparkCache[cacheKey]) {
|
||||
return this.veloparkCache[cacheKey]
|
||||
|
|
@ -662,20 +665,20 @@ export default class LinkedDataLoader {
|
|||
const withProxyUrl = Constants.linkedDataProxy.replace("{url}", encodeURIComponent(url))
|
||||
const optionalPaths: Record<string, string | Record<string, string>> = {
|
||||
"schema:interactionService": {
|
||||
"schema:url": "website"
|
||||
"schema:url": "website",
|
||||
},
|
||||
"mv:operatedBy": {
|
||||
"gr:legalName": "operator"
|
||||
"gr:legalName": "operator",
|
||||
},
|
||||
"schema:contactPoint": {
|
||||
"schema:email": "email",
|
||||
"schema:telephone": "phone"
|
||||
"schema:telephone": "phone",
|
||||
},
|
||||
"schema:dateModified": "_last_edit_timestamp"
|
||||
"schema:dateModified": "_last_edit_timestamp",
|
||||
}
|
||||
if (includeExtras) {
|
||||
optionalPaths["schema:address"] = {
|
||||
"schema:streetAddress": "addr"
|
||||
"schema:streetAddress": "addr",
|
||||
}
|
||||
optionalPaths["schema:name"] = "name"
|
||||
optionalPaths["schema:description"] = "description"
|
||||
|
|
@ -693,19 +696,19 @@ export default class LinkedDataLoader {
|
|||
"schema:geo": {
|
||||
"schema:latitude": "latitude",
|
||||
"schema:longitude": "longitude",
|
||||
"schema:polygon": "shape"
|
||||
"schema:polygon": "shape",
|
||||
},
|
||||
"schema:priceSpecification": {
|
||||
"mv:freeOfCharge": "fee",
|
||||
"schema:price": "charge"
|
||||
}
|
||||
"schema:price": "charge",
|
||||
},
|
||||
}
|
||||
|
||||
const extra = [
|
||||
"schema:priceSpecification [ mv:dueForTime [ mv:timeStartValue ?chargeStart; mv:timeEndValue ?chargeEnd; mv:timeUnit ?timeUnit ] ]",
|
||||
"vp:allows [vp:bicycleType <https://data.velopark.be/openvelopark/terms#CargoBicycle>; vp:bicyclesAmount ?capacityCargobike; vp:bicycleType ?cargoBikeType]",
|
||||
"vp:allows [vp:bicycleType <https://data.velopark.be/openvelopark/terms#ElectricBicycle>; vp:bicyclesAmount ?capacityElectric; vp:bicycleType ?electricBikeType]",
|
||||
"vp:allows [vp:bicycleType <https://data.velopark.be/openvelopark/terms#TandemBicycle>; vp:bicyclesAmount ?capacityTandem; vp:bicycleType ?tandemBikeType]"
|
||||
"vp:allows [vp:bicycleType <https://data.velopark.be/openvelopark/terms#TandemBicycle>; vp:bicyclesAmount ?capacityTandem; vp:bicycleType ?tandemBikeType]",
|
||||
]
|
||||
|
||||
const unpatched = await this.fetchEntry(
|
||||
|
|
|
|||
|
|
@ -110,12 +110,12 @@ export class MangroveIdentity {
|
|||
return []
|
||||
}
|
||||
const allReviews = await MangroveReviews.getReviews({
|
||||
kid: pem
|
||||
kid: pem,
|
||||
})
|
||||
this.allReviewsById.setData(
|
||||
allReviews.reviews.map((r) => ({
|
||||
...r,
|
||||
...r.payload
|
||||
...r.payload,
|
||||
}))
|
||||
)
|
||||
})
|
||||
|
|
@ -182,10 +182,10 @@ export default class FeatureReviews {
|
|||
feature.geometry.type === "Polygon"
|
||||
) {
|
||||
coordss = feature.geometry.coordinates
|
||||
}else if(feature.geometry.type === "MultiPolygon"){
|
||||
} else if (feature.geometry.type === "MultiPolygon") {
|
||||
coordss = feature.geometry.coordinates[0]
|
||||
}else{
|
||||
throw "Invalid feature type: "+feature.geometry.type
|
||||
} else {
|
||||
throw "Invalid feature type: " + feature.geometry.type
|
||||
}
|
||||
let maxDistance = 0
|
||||
for (const coords of coordss) {
|
||||
|
|
@ -288,7 +288,7 @@ export default class FeatureReviews {
|
|||
}
|
||||
const r: Review = {
|
||||
sub: this.subjectUri.data,
|
||||
...review
|
||||
...review,
|
||||
}
|
||||
const keypair: CryptoKeyPair = await this._identity.getKeypair()
|
||||
const jwt = await MangroveReviews.signReview(keypair, r)
|
||||
|
|
@ -303,7 +303,7 @@ export default class FeatureReviews {
|
|||
...r,
|
||||
kid,
|
||||
signature: jwt,
|
||||
madeByLoggedInUser: new ImmutableStore(true)
|
||||
madeByLoggedInUser: new ImmutableStore(true),
|
||||
}
|
||||
this._reviews.data.push(reviewWithKid)
|
||||
this._reviews.ping()
|
||||
|
|
@ -350,7 +350,7 @@ export default class FeatureReviews {
|
|||
signature: reviewData.signature,
|
||||
madeByLoggedInUser: this._identity.getKeyId().map((user_key_id) => {
|
||||
return reviewData.kid === user_key_id
|
||||
})
|
||||
}),
|
||||
})
|
||||
hasNew = true
|
||||
}
|
||||
|
|
@ -369,12 +369,16 @@ export default class FeatureReviews {
|
|||
private ConstructSubjectUri(dontEncodeName: boolean = false): Store<string> {
|
||||
// https://www.rfc-editor.org/rfc/rfc5870#section-3.4.2
|
||||
// `u` stands for `uncertainty`, https://www.rfc-editor.org/rfc/rfc5870#section-3.4.3
|
||||
return this._name.map(name => {
|
||||
return this._name.map((name) => {
|
||||
let uri = `geo:${this._lat},${this._lon}?u=${Math.round(this._uncertainty)}`
|
||||
if (name) {
|
||||
uri += "&q=" + (dontEncodeName ? name : encodeURIComponent(name))
|
||||
}else if(this._uncertainty > 1000){
|
||||
console.error("Not fetching reviews. Only got a point and a very big uncertainty range ("+this._uncertainty+"), so you'd probably only get garbage. Specify a name")
|
||||
} else if (this._uncertainty > 1000) {
|
||||
console.error(
|
||||
"Not fetching reviews. Only got a point and a very big uncertainty range (" +
|
||||
this._uncertainty +
|
||||
"), so you'd probably only get garbage. Specify a name"
|
||||
)
|
||||
return undefined
|
||||
}
|
||||
return uri
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ export interface NSIItem {
|
|||
displayName: string
|
||||
id: string
|
||||
locationSet: {
|
||||
include: string[],
|
||||
include: string[]
|
||||
exclude: string[]
|
||||
}
|
||||
tags: Record<string, string>
|
||||
|
|
@ -56,11 +56,15 @@ export interface NSIItem {
|
|||
}
|
||||
|
||||
export default class NameSuggestionIndex {
|
||||
|
||||
private static readonly nsiFile: Readonly<NSIFile> = <any>nsi
|
||||
private static readonly nsiWdFile: Readonly<Record<string, {
|
||||
logos: { wikidata?: string, facebook?: string }
|
||||
}>> = <any>nsiWD["wikidata"]
|
||||
private static readonly nsiWdFile: Readonly<
|
||||
Record<
|
||||
string,
|
||||
{
|
||||
logos: { wikidata?: string; facebook?: string }
|
||||
}
|
||||
>
|
||||
> = <any>nsiWD["wikidata"]
|
||||
|
||||
private static loco = new LocationConflation(nsiFeatures) // Some additional boundaries
|
||||
|
||||
|
|
@ -71,9 +75,11 @@ export default class NameSuggestionIndex {
|
|||
return this._supportedTypes
|
||||
}
|
||||
const keys = Object.keys(NameSuggestionIndex.nsiFile.nsi)
|
||||
const all = keys.map(k => NameSuggestionIndex.nsiFile.nsi[k].properties.path.split("/")[0])
|
||||
this._supportedTypes = Utils.Dedup(all).map(s => {
|
||||
if(s.endsWith("s")){
|
||||
const all = keys.map(
|
||||
(k) => NameSuggestionIndex.nsiFile.nsi[k].properties.path.split("/")[0]
|
||||
)
|
||||
this._supportedTypes = Utils.Dedup(all).map((s) => {
|
||||
if (s.endsWith("s")) {
|
||||
s = s.substring(0, s.length - 1)
|
||||
}
|
||||
return s
|
||||
|
|
@ -81,7 +87,6 @@ export default class NameSuggestionIndex {
|
|||
return this._supportedTypes
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Fetches the data files for a single country. Note that it contains _all_ entries having this brand, not for a single type of object
|
||||
* @param type
|
||||
|
|
@ -89,19 +94,24 @@ export default class NameSuggestionIndex {
|
|||
* @private
|
||||
*/
|
||||
private static async fetchFrequenciesFor(type: string, countries: string[]) {
|
||||
let stats = await Promise.all(countries.map(c => {
|
||||
try {
|
||||
return Utils.downloadJsonCached<Record<string, number>>(`./assets/data/nsi/stats/${type}.${c.toUpperCase()}.json`, 24 * 60 * 60 * 1000)
|
||||
} catch (e) {
|
||||
console.error("Could not fetch " + type + " statistics due to", e)
|
||||
return undefined
|
||||
}
|
||||
}))
|
||||
let stats = await Promise.all(
|
||||
countries.map((c) => {
|
||||
try {
|
||||
return Utils.downloadJsonCached<Record<string, number>>(
|
||||
`./assets/data/nsi/stats/${type}.${c.toUpperCase()}.json`,
|
||||
24 * 60 * 60 * 1000
|
||||
)
|
||||
} catch (e) {
|
||||
console.error("Could not fetch " + type + " statistics due to", e)
|
||||
return undefined
|
||||
}
|
||||
})
|
||||
)
|
||||
stats = Utils.NoNull(stats)
|
||||
if (stats.length === 1) {
|
||||
return stats[0]
|
||||
}
|
||||
if(stats.length === 0){
|
||||
if (stats.length === 0) {
|
||||
return {}
|
||||
}
|
||||
const merged = stats[0]
|
||||
|
|
@ -128,7 +138,12 @@ export default class NameSuggestionIndex {
|
|||
return false
|
||||
}
|
||||
|
||||
public static async generateMappings(type: string, tags: Record<string, string>, country: string[], location?: [number, number]): Promise<Mapping[]> {
|
||||
public static async generateMappings(
|
||||
type: string,
|
||||
tags: Record<string, string>,
|
||||
country: string[],
|
||||
location?: [number, number]
|
||||
): Promise<Mapping[]> {
|
||||
const mappings: Mapping[] = []
|
||||
const frequencies = await NameSuggestionIndex.fetchFrequenciesFor(type, country)
|
||||
for (const key in tags) {
|
||||
|
|
@ -136,8 +151,14 @@ export default class NameSuggestionIndex {
|
|||
continue
|
||||
}
|
||||
const value = tags[key]
|
||||
const actualBrands = NameSuggestionIndex.getSuggestionsForKV(type, key, value, country.join(";"), location)
|
||||
if(!actualBrands){
|
||||
const actualBrands = NameSuggestionIndex.getSuggestionsForKV(
|
||||
type,
|
||||
key,
|
||||
value,
|
||||
country.join(";"),
|
||||
location
|
||||
)
|
||||
if (!actualBrands) {
|
||||
continue
|
||||
}
|
||||
for (const nsiItem of actualBrands) {
|
||||
|
|
@ -156,7 +177,9 @@ export default class NameSuggestionIndex {
|
|||
}
|
||||
mappings.push({
|
||||
if: new Tag(type, tags[type]),
|
||||
addExtraTags: Object.keys(tags).filter(k => k !== type).map(k => new Tag(k, tags[k])),
|
||||
addExtraTags: Object.keys(tags)
|
||||
.filter((k) => k !== type)
|
||||
.map((k) => new Tag(k, tags[k])),
|
||||
then: new TypedTranslation<Record<string, never>>({ "*": nsiItem.displayName }),
|
||||
hideInAnswer: false,
|
||||
ifnot: undefined,
|
||||
|
|
@ -164,22 +187,23 @@ export default class NameSuggestionIndex {
|
|||
icon,
|
||||
iconClass: "medium",
|
||||
priorityIf: frequency > 0 ? new RegexTag("id", /.*/) : undefined,
|
||||
searchTerms: { "*": [nsiItem.displayName, nsiItem.id] }
|
||||
searchTerms: { "*": [nsiItem.displayName, nsiItem.id] },
|
||||
})
|
||||
}
|
||||
}
|
||||
return mappings
|
||||
}
|
||||
|
||||
public static supportedTags(type: "operator" | "brand" | "flag" | "transit" | string): Record<string, string[]> {
|
||||
const tags: Record<string, string []> = {}
|
||||
public static supportedTags(
|
||||
type: "operator" | "brand" | "flag" | "transit" | string
|
||||
): Record<string, string[]> {
|
||||
const tags: Record<string, string[]> = {}
|
||||
const keys = Object.keys(NameSuggestionIndex.nsiFile.nsi)
|
||||
for (const key of keys) {
|
||||
|
||||
const nsiItem = NameSuggestionIndex.nsiFile.nsi[key]
|
||||
const path = nsiItem.properties.path
|
||||
const [osmType, osmkey, osmvalue] = path.split("/")
|
||||
if (type !== osmType && (type + "s" !== osmType)) {
|
||||
if (type !== osmType && type + "s" !== osmType) {
|
||||
continue
|
||||
}
|
||||
if (!tags[osmkey]) {
|
||||
|
|
@ -204,7 +228,7 @@ export default class NameSuggestionIndex {
|
|||
options.push(...suggestions)
|
||||
}
|
||||
}
|
||||
return (options)
|
||||
return options
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -212,8 +236,15 @@ export default class NameSuggestionIndex {
|
|||
* @param country: a string containing one or more country codes, separated by ";"
|
||||
* @param location: center point of the feature, should be [lon, lat]
|
||||
*/
|
||||
public static getSuggestionsFor(type: string, tags: {key: string, value: string}[], country: string = undefined, location: [number, number] = undefined): NSIItem[] {
|
||||
return tags.flatMap(tag => this.getSuggestionsForKV(type, tag.key, tag.value, country, location))
|
||||
public static getSuggestionsFor(
|
||||
type: string,
|
||||
tags: { key: string; value: string }[],
|
||||
country: string = undefined,
|
||||
location: [number, number] = undefined
|
||||
): NSIItem[] {
|
||||
return tags.flatMap((tag) =>
|
||||
this.getSuggestionsForKV(type, tag.key, tag.value, country, location)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -221,18 +252,26 @@ export default class NameSuggestionIndex {
|
|||
* @param country: a string containing one or more country codes, separated by ";"
|
||||
* @param location: center point of the feature, should be [lon, lat]
|
||||
*/
|
||||
public static getSuggestionsForKV(type: string, key: string, value: string, country: string = undefined, location: [number, number] = undefined): NSIItem[] {
|
||||
public static getSuggestionsForKV(
|
||||
type: string,
|
||||
key: string,
|
||||
value: string,
|
||||
country: string = undefined,
|
||||
location: [number, number] = undefined
|
||||
): NSIItem[] {
|
||||
const path = `${type}s/${key}/${value}`
|
||||
const entry = NameSuggestionIndex.nsiFile.nsi[path]
|
||||
return entry?.items?.filter(i => {
|
||||
return entry?.items?.filter((i) => {
|
||||
if (i.locationSet.include.indexOf("001") >= 0) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (country === undefined ||
|
||||
if (
|
||||
country === undefined ||
|
||||
// We prefer the countries provided by lonlat2country, they are more precise
|
||||
// Country might contain multiple countries, separated by ';'
|
||||
i.locationSet.include.some(c => country.indexOf(c) >= 0)) {
|
||||
i.locationSet.include.some((c) => country.indexOf(c) >= 0)
|
||||
) {
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -50,10 +50,8 @@ export default class NearbyImagesSearch {
|
|||
|
||||
constructor(options: NearbyImageOptions, features: IndexedFeatureSource) {
|
||||
this.individualStores = NearbyImagesSearch.services
|
||||
.filter(s => s !== "kartaview" /*DEAD*/)
|
||||
.map((s) =>
|
||||
NearbyImagesSearch.buildPictureFetcher(options, s)
|
||||
)
|
||||
.filter((s) => s !== "kartaview" /*DEAD*/)
|
||||
.map((s) => NearbyImagesSearch.buildPictureFetcher(options, s))
|
||||
|
||||
const allDone = new UIEventSource(false)
|
||||
this.allDone = allDone
|
||||
|
|
|
|||
|
|
@ -19,10 +19,10 @@ export interface TagInfoStats {
|
|||
}
|
||||
|
||||
interface GeofabrikCountryProperties {
|
||||
id: string,
|
||||
parent: string | "europe" | "asia",
|
||||
urls: string[],
|
||||
name: string,
|
||||
id: string
|
||||
parent: string | "europe" | "asia"
|
||||
urls: string[]
|
||||
name: string
|
||||
"iso3166-1:alpha2": string[]
|
||||
}
|
||||
|
||||
|
|
@ -38,7 +38,9 @@ export default class TagInfo {
|
|||
public async getStats(key: string, value?: string): Promise<TagInfoStats> {
|
||||
let url: string
|
||||
if (value) {
|
||||
url = `${this._backend}api/4/tag/stats?key=${encodeURIComponent(key)}&value=${encodeURIComponent(value)}`
|
||||
url = `${this._backend}api/4/tag/stats?key=${encodeURIComponent(
|
||||
key
|
||||
)}&value=${encodeURIComponent(value)}`
|
||||
} else {
|
||||
url = `${this._backend}api/4/key/stats?key=${encodeURIComponent(key)}`
|
||||
}
|
||||
|
|
@ -65,8 +67,13 @@ export default class TagInfo {
|
|||
if (TagInfo._geofabrikCountries) {
|
||||
return TagInfo._geofabrikCountries
|
||||
}
|
||||
const countriesFC: FeatureCollection = await Utils.downloadJsonCached<FeatureCollection>("https://download.geofabrik.de/index-v1-nogeom.json", 24 * 1000 * 60 * 60)
|
||||
TagInfo._geofabrikCountries = countriesFC.features.map(f => <GeofabrikCountryProperties>f.properties)
|
||||
const countriesFC: FeatureCollection = await Utils.downloadJsonCached<FeatureCollection>(
|
||||
"https://download.geofabrik.de/index-v1-nogeom.json",
|
||||
24 * 1000 * 60 * 60
|
||||
)
|
||||
TagInfo._geofabrikCountries = countriesFC.features.map(
|
||||
(f) => <GeofabrikCountryProperties>f.properties
|
||||
)
|
||||
return TagInfo._geofabrikCountries
|
||||
}
|
||||
|
||||
|
|
@ -80,7 +87,7 @@ export default class TagInfo {
|
|||
public static async getInstanceFor(countryCode: string) {
|
||||
const countries = await this.geofabrikCountries()
|
||||
countryCode = countryCode.toUpperCase()
|
||||
const country = countries.find(c => c["iso3166-1:alpha2"]?.indexOf(countryCode) >= 0)
|
||||
const country = countries.find((c) => c["iso3166-1:alpha2"]?.indexOf(countryCode) >= 0)
|
||||
if (!country || !country?.parent || !country?.id) {
|
||||
return undefined
|
||||
}
|
||||
|
|
@ -88,7 +95,11 @@ export default class TagInfo {
|
|||
return new TagInfo(url)
|
||||
}
|
||||
|
||||
private static async getDistributionsFor(countryCode: string, key: string, value?: string): Promise<TagInfoStats>{
|
||||
private static async getDistributionsFor(
|
||||
countryCode: string,
|
||||
key: string,
|
||||
value?: string
|
||||
): Promise<TagInfoStats> {
|
||||
if (!countryCode) {
|
||||
return undefined
|
||||
}
|
||||
|
|
@ -99,24 +110,30 @@ export default class TagInfo {
|
|||
try {
|
||||
return await ti.getStats(key, value)
|
||||
} catch (e) {
|
||||
console.warn("Could not fetch info for", countryCode,key,value, "due to", e)
|
||||
console.warn("Could not fetch info for", countryCode, key, value, "due to", e)
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
private static readonly blacklist =["VI","GF","PR"]
|
||||
private static readonly blacklist = ["VI", "GF", "PR"]
|
||||
|
||||
public static async getGlobalDistributionsFor(key: string, value?: string): Promise<Record<string, TagInfoStats>> {
|
||||
public static async getGlobalDistributionsFor(
|
||||
key: string,
|
||||
value?: string
|
||||
): Promise<Record<string, TagInfoStats>> {
|
||||
const countriesAll = await this.geofabrikCountries()
|
||||
const countries = countriesAll.map(c => c["iso3166-1:alpha2"]?.[0]).filter(c => !!c && TagInfo.blacklist.indexOf(c) < 0)
|
||||
const countries = countriesAll
|
||||
.map((c) => c["iso3166-1:alpha2"]?.[0])
|
||||
.filter((c) => !!c && TagInfo.blacklist.indexOf(c) < 0)
|
||||
const perCountry: Record<string, TagInfoStats> = {}
|
||||
const results = await Promise.all(countries.map(country => TagInfo.getDistributionsFor(country, key, value)))
|
||||
for (let i = 0; i < countries.length; i++){
|
||||
const results = await Promise.all(
|
||||
countries.map((country) => TagInfo.getDistributionsFor(country, key, value))
|
||||
)
|
||||
for (let i = 0; i < countries.length; i++) {
|
||||
const countryCode = countries[i]
|
||||
if(results[i]){
|
||||
perCountry[countryCode] = results[i]
|
||||
if (results[i]) {
|
||||
perCountry[countryCode] = results[i]
|
||||
}
|
||||
}
|
||||
return perCountry
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue