@whiteslove/parsing-lexicon 0.6.2 → 0.6.4
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.
- package/package.json +5 -1
- package/src/central-asia-locations.js +3 -3
- package/src/central-asia.js +26 -2
- package/src/geo.js +7 -7
- package/src/geography-display.js +1 -1
- package/src/geography-zone-display.js +1 -1
- package/src/geography.js +13 -4
- package/src/hiring-requirements.js +5 -5
- package/src/hiring-salary-context.js +6 -2
- package/src/hiring-temporal.js +4 -0
- package/src/housing-address.js +1 -1
- package/src/housing-display.js +14 -1
- package/src/housing-listing-enrichment.js +8 -8
- package/src/housing-money.js +1 -1
- package/src/housing-source-aliases.js +3 -0
- package/src/index.js +2 -0
- package/src/kg-location-extensions.js +91 -11
- package/src/kz-district-extensions.js +36 -0
- package/src/kz-location-extensions.js +3 -3
- package/src/locations-runtime.js +5 -0
- package/src/locations.js +127 -39
- package/src/money-core.js +1 -1
- package/src/money-lexicon.js +1 -1
- package/src/money.js +16 -1
- package/src/normalization.js +39 -4
- package/src/tashkent-colloquial.js +8 -1
- package/src/tashkent-gastronomic-streets.js +108 -0
- package/src/tashkent-pois.js +38 -18
- package/src/ua-city-location-expansions.js +88 -0
- package/src/ua-geo-coordinates.d.ts +14 -0
- package/src/ua-geo-coordinates.js +209 -0
- package/src/ua-geo-resolver.d.ts +31 -0
- package/src/ua-geo-resolver.js +171 -0
- package/src/ua-location-extensions-metro.js +42 -1
- package/src/ua-location-extensions-regional.js +2 -2
- package/src/ua-secondary-cities.js +6 -4
- package/src/uz-geo-coordinates.d.ts +14 -0
- package/src/uz-geo-coordinates.js +166 -0
package/src/locations.js
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
matchUkraineRegion,
|
|
7
7
|
matchUkraineSecondaryCity,
|
|
8
8
|
} from './location-data.js';
|
|
9
|
-
import {
|
|
9
|
+
import { mergeLocationCountries } from './location-merge.js';
|
|
10
10
|
import { aliasesToRegex } from './normalization.js';
|
|
11
11
|
import { KZ_LOCATION_EXTENSIONS } from './kz-location-extensions.js';
|
|
12
12
|
import { UZ_LOCATION_EXTENSIONS } from './uz-location-extensions.js';
|
|
@@ -17,7 +17,7 @@ import { UA_METRO_LOCATION_EXTENSIONS } from './ua-location-extensions-metro.js'
|
|
|
17
17
|
import { UA_KHARKIV_LOCATION_TRANSLATIONS } from './ua-kharkiv-location-translations.js';
|
|
18
18
|
import { UA_CITY_LOCATION_EXPANSIONS } from './ua-city-location-expansions.js';
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
const UA_EXTRA_LOCATION_DICTIONARIES = Object.freeze({
|
|
21
21
|
...RAW_UA_EXTRA_LOCATION_DICTIONARIES,
|
|
22
22
|
Zaporizhzhia: Object.freeze({
|
|
23
23
|
...RAW_UA_EXTRA_LOCATION_DICTIONARIES.Zaporizhzhia,
|
|
@@ -38,6 +38,46 @@ const TASHKENT_UNSUPPORTED_SEED_MICRODISTRICTS = new Set([
|
|
|
38
38
|
'Yunusabad-22',
|
|
39
39
|
]);
|
|
40
40
|
|
|
41
|
+
const TASHKENT_MAHALLA_ALIAS_ADDITIONS = Object.freeze({
|
|
42
|
+
Humoyun: Object.freeze([
|
|
43
|
+
'Khumoyun',
|
|
44
|
+
'Humoyun MFY',
|
|
45
|
+
'Ҳумоюн маҳалласи',
|
|
46
|
+
'Хумоюн',
|
|
47
|
+
'махалля Хумаюн',
|
|
48
|
+
]),
|
|
49
|
+
"Bog'ko'cha": Object.freeze([
|
|
50
|
+
"Bog'ko'cha mahallasi",
|
|
51
|
+
"Bog'ko'cha MFY",
|
|
52
|
+
'Боғкўча маҳалласи',
|
|
53
|
+
'Богкуча махалла',
|
|
54
|
+
'махалля Богкуча',
|
|
55
|
+
]),
|
|
56
|
+
"Bog'bon": Object.freeze([
|
|
57
|
+
"Bog'bon MFY",
|
|
58
|
+
'Богбон махалла',
|
|
59
|
+
]),
|
|
60
|
+
Shifokorlar: Object.freeze([
|
|
61
|
+
'Shifokorlar MFY',
|
|
62
|
+
'Шифокорлар маҳалласи',
|
|
63
|
+
'Шифокорлар махалласи',
|
|
64
|
+
'махалля Шифокорлар',
|
|
65
|
+
]),
|
|
66
|
+
"Chamanbog'": Object.freeze([
|
|
67
|
+
"Chamanbog' mahallasi",
|
|
68
|
+
"Chamanbog' MFY",
|
|
69
|
+
'Чаманбоғ маҳалласи',
|
|
70
|
+
'Чаманбог махалла',
|
|
71
|
+
'махалля Чаманбог',
|
|
72
|
+
]),
|
|
73
|
+
Asalobod: Object.freeze([
|
|
74
|
+
'Asalobod MFY',
|
|
75
|
+
'Асалобод маҳалласи',
|
|
76
|
+
'Асалобод махалла',
|
|
77
|
+
'махалля Асалобод',
|
|
78
|
+
]),
|
|
79
|
+
});
|
|
80
|
+
|
|
41
81
|
const LEGACY_SAMARKAND_SILK_ROAD_RESIDENCE = (
|
|
42
82
|
BASE_LOCATION_DICTIONARIES.UZ?.Samarkand?.residentialComplexes || []
|
|
43
83
|
).find(({ name }) => name === 'Silk Road Residence');
|
|
@@ -102,10 +142,29 @@ function normalizeUzSemanticLocations(country) {
|
|
|
102
142
|
})];
|
|
103
143
|
}),
|
|
104
144
|
));
|
|
145
|
+
|
|
105
146
|
const tashkent = normalized?.Tashkent;
|
|
106
|
-
|
|
147
|
+
if (tashkent) {
|
|
148
|
+
normalized = Object.freeze({
|
|
149
|
+
...normalized,
|
|
150
|
+
Tashkent: Object.freeze({
|
|
151
|
+
...tashkent,
|
|
152
|
+
mahallas: Object.freeze((tashkent.mahallas || []).map((entry) => {
|
|
153
|
+
const additions = TASHKENT_MAHALLA_ALIAS_ADDITIONS[entry.name];
|
|
154
|
+
return additions
|
|
155
|
+
? semanticEntry(entry, entry.name, [...(entry.aliases || []), ...additions], 'mahalla')
|
|
156
|
+
: entry;
|
|
157
|
+
})),
|
|
158
|
+
}),
|
|
159
|
+
});
|
|
160
|
+
}
|
|
107
161
|
|
|
108
|
-
|
|
162
|
+
const normalizedTashkent = normalized?.Tashkent;
|
|
163
|
+
const qorasuv = (normalizedTashkent?.microdistricts || []).find(({ name }) => name === 'Qorasuv');
|
|
164
|
+
|
|
165
|
+
if (normalizedTashkent && qorasuv) {
|
|
166
|
+
// Bare Qorasuv is ambiguous with numbered Qorasuv/Karasu blocks. The
|
|
167
|
+
// umbrella area therefore requires an area/massif/daha form in free text.
|
|
109
168
|
const qorasuvAliases = Object.freeze([...new Set([
|
|
110
169
|
...(qorasuv.aliases || []).filter((alias) => !/^(?:qorasuv|korasuv|корасув|карасу)$/iu.test(String(alias).trim())),
|
|
111
170
|
'Qorasuv dahasi',
|
|
@@ -126,10 +185,10 @@ function normalizeUzSemanticLocations(country) {
|
|
|
126
185
|
normalized = Object.freeze({
|
|
127
186
|
...normalized,
|
|
128
187
|
Tashkent: Object.freeze({
|
|
129
|
-
...
|
|
130
|
-
microdistricts: Object.freeze((
|
|
188
|
+
...normalizedTashkent,
|
|
189
|
+
microdistricts: Object.freeze((normalizedTashkent.microdistricts || []).filter(({ name }) => name !== 'Qorasuv')),
|
|
131
190
|
localAreas: Object.freeze([
|
|
132
|
-
...(
|
|
191
|
+
...(normalizedTashkent.localAreas || []),
|
|
133
192
|
qorasuvArea,
|
|
134
193
|
]),
|
|
135
194
|
}),
|
|
@@ -144,6 +203,10 @@ function normalizeUzSemanticLocations(country) {
|
|
|
144
203
|
const landmarks = samarkand.landmarks || [];
|
|
145
204
|
const localAreas = samarkand.localAreas || [];
|
|
146
205
|
const streets = samarkand.streets || [];
|
|
206
|
+
|
|
207
|
+
// Legacy UZ seeds contain a few Samarkand listing labels as separate
|
|
208
|
+
// canonicals or under the wrong semantic collection. Normalize them to the
|
|
209
|
+
// single physical subjects already represented by geo-catalog.
|
|
147
210
|
const centralPark = landmarks.find(({ name }) => name === 'Central Park');
|
|
148
211
|
const alisherPark = landmarks.find(({ name }) => name === 'Alisher Navoiy Park');
|
|
149
212
|
const canonicalPark = centralPark || alisherPark;
|
|
@@ -352,6 +415,8 @@ function normalizeUzSemanticLocations(country) {
|
|
|
352
415
|
const oldCity = localAreas.find(({ name }) => name === 'Old City');
|
|
353
416
|
|
|
354
417
|
if (ichanKala && oldCity) {
|
|
418
|
+
// UNESCO identifies Itchan Kala as the historic inner-city of Khiva.
|
|
419
|
+
// Keep listing-friendly Old City forms as aliases of that one place.
|
|
355
420
|
const normalizedIchanKala = semanticEntry(ichanKala, 'Ichan Kala', [
|
|
356
421
|
...(ichanKala.aliases || []),
|
|
357
422
|
...(oldCity.aliases || []),
|
|
@@ -453,6 +518,57 @@ function normalizeUzSemanticLocations(country) {
|
|
|
453
518
|
});
|
|
454
519
|
}
|
|
455
520
|
|
|
521
|
+
const nukus = normalized?.Nukus;
|
|
522
|
+
if (nukus) {
|
|
523
|
+
const mahallas = nukus.mahallas || [];
|
|
524
|
+
const localAreas = nukus.localAreas || [];
|
|
525
|
+
const aliasesByCanonical = new Map([
|
|
526
|
+
['Qizil qum', ['Qızıl qum', 'Qızılqum']],
|
|
527
|
+
['Gúzar', ['Guzar']],
|
|
528
|
+
['Isbilermenler aymagi', ['Isbilermenler aymaǵı']],
|
|
529
|
+
['Darbent', ['Dárbent']],
|
|
530
|
+
['Abat makan', ['Abat mákan']],
|
|
531
|
+
['Jolshilar', ['Jolshılar']],
|
|
532
|
+
['Qutli qonis', ['Qutlı qonıs']],
|
|
533
|
+
['Amanliq guzari', ['Amanlıq gúzarı']],
|
|
534
|
+
['Aydin jol', ['Aydın jol']],
|
|
535
|
+
['Qum awil', ['Qum awıl']],
|
|
536
|
+
['Qutli makan', ['Qutlı mákan']],
|
|
537
|
+
['Shimbay shayxana', ['Shımbay shayxana']],
|
|
538
|
+
['Shayirlar awili', ['Shayırlar awılı']],
|
|
539
|
+
['Tungish qonis', ['Tunǵısh qonıs']],
|
|
540
|
+
['Qurilisshi', ['Qurılısshı']],
|
|
541
|
+
['Ornek', ['Órnek', "O'rnek"]],
|
|
542
|
+
['Jana zaman', ['Jańa zaman']],
|
|
543
|
+
['Baqshiliq', ['Baqshılıq']],
|
|
544
|
+
['Tinishliq', ['Tınıshlıq']],
|
|
545
|
+
['Xaliqlar dosligi', ['Xalıqlar doslıǵı']],
|
|
546
|
+
['Boz awil', ['Boz awıl']],
|
|
547
|
+
['Jas awlad', ['Jas áwlad']],
|
|
548
|
+
['Aq jagis', ['Aq jaǵıs']],
|
|
549
|
+
['Tele oray', ['Telecentr']],
|
|
550
|
+
['Shadli awil', ['Shadlı']],
|
|
551
|
+
['Qumbiz awil', ['Qumbız awıl']],
|
|
552
|
+
]);
|
|
553
|
+
|
|
554
|
+
normalized = Object.freeze({
|
|
555
|
+
...normalized,
|
|
556
|
+
Nukus: Object.freeze({
|
|
557
|
+
...nukus,
|
|
558
|
+
mahallas: Object.freeze(mahallas.map((entry) => {
|
|
559
|
+
const aliases = aliasesByCanonical.get(entry.name);
|
|
560
|
+
return aliases
|
|
561
|
+
? semanticEntry(entry, entry.name, [...(entry.aliases || []), ...aliases], 'mahalla')
|
|
562
|
+
: entry;
|
|
563
|
+
})),
|
|
564
|
+
// These names already have canonical mahalla owners. Keeping a second
|
|
565
|
+
// local-area owner makes exact bridge resolution ambiguous and causes
|
|
566
|
+
// the crawler to inspect the same physical place twice.
|
|
567
|
+
localAreas: Object.freeze(localAreas.filter(({ name }) => !['Dosliq', 'Samanbay'].includes(name))),
|
|
568
|
+
}),
|
|
569
|
+
});
|
|
570
|
+
}
|
|
571
|
+
|
|
456
572
|
return normalized;
|
|
457
573
|
}
|
|
458
574
|
|
|
@@ -462,6 +578,9 @@ function normalizeUaSemanticLocations(country) {
|
|
|
462
578
|
const odesa = country?.Odesa;
|
|
463
579
|
if (!odesa) return country;
|
|
464
580
|
|
|
581
|
+
// “5–16 station of Velykyi Fontan” are traditional listing/locality zones
|
|
582
|
+
// anchored to the Fontanska Road transit stops, not twelve standalone city
|
|
583
|
+
// microdistricts. Keep their parsing value but expose them as local areas.
|
|
465
584
|
const fontanStationAreas = Object.freeze(
|
|
466
585
|
(odesa.microdistricts || [])
|
|
467
586
|
.filter(({ name }) => ODESA_FONTAN_STATION_RE.test(name))
|
|
@@ -523,35 +642,4 @@ export {
|
|
|
523
642
|
UA_SECONDARY_CITIES,
|
|
524
643
|
matchUkraineRegion,
|
|
525
644
|
matchUkraineSecondaryCity,
|
|
526
|
-
};
|
|
527
|
-
|
|
528
|
-
export function dictionaryFor(countryCode, city) {
|
|
529
|
-
return LOCATION_DICTIONARIES[countryCode]?.[city] || null;
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
export function locationCities(countryCode) {
|
|
533
|
-
return LOCATION_DICTIONARIES[countryCode] || Object.freeze({});
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
export function matchDictionaryLocation(text, countryCode, city = null) {
|
|
537
|
-
const country = locationCities(countryCode);
|
|
538
|
-
const cities = city && country[city] ? [[city, country[city]]] : Object.entries(country);
|
|
539
|
-
const value = String(text || '');
|
|
540
|
-
let best = null;
|
|
541
|
-
for (const [cityName, data] of cities) {
|
|
542
|
-
for (const type of LOCATION_LIST_KEYS) {
|
|
543
|
-
for (const entry of data[type] || []) {
|
|
544
|
-
const match = entry?.re?.exec(value);
|
|
545
|
-
if (!match) continue;
|
|
546
|
-
const start = match.index;
|
|
547
|
-
const end = start + match[0].length;
|
|
548
|
-
const containsBest = best && start <= best.start && end >= best.end && end - start > best.end - best.start;
|
|
549
|
-
if (best && !containsBest) continue;
|
|
550
|
-
best = { city: cityName, type, name: entry.name, aliases: entry.aliases, start, end };
|
|
551
|
-
}
|
|
552
|
-
}
|
|
553
|
-
}
|
|
554
|
-
if (!best) return null;
|
|
555
|
-
const { start: _start, end: _end, ...result } = best;
|
|
556
|
-
return result;
|
|
557
|
-
}
|
|
645
|
+
};
|
package/src/money-core.js
CHANGED
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
// ("4 00 000" instead of "400 000"). Accept that only when there are at least
|
|
13
13
|
// two spaced groups, which keeps ordinary two-number prose out of money parsing.
|
|
14
14
|
export const MONEY_NUMBER_PATTERN = '(?:\\d{1,3}(?:[ \\u00a0]\\d{2,3}){2,}(?:[.,]\\d+)?|\\d{1,3}(?:[ \\u00a0]\\d{3})+(?:[.,]\\d+)?|\\d{1,3}(?:,\\d{3})+(?:\\.\\d+)?|\\d{1,3}(?:\\.\\d{3})+(?:,\\d+)?|\\d+(?:[.,]\\d+)?)';
|
|
15
|
-
export const MONEY_SCALE_PATTERN = 'k|к|тыс\\.?|тысяч(?:а|и)?|тис\\.?|thousand|ming
|
|
15
|
+
export const MONEY_SCALE_PATTERN = 'k|к|тыс\\.?|тысяч(?:а|и)?|тис\\.?|thousand|ming|минг|мың|mii|m|м|млн\\.?|mln|million|миллион(?:ов)?|мільйон(?:ів)?|mil|milioane|bn|млрд|mlrd|billion|mld|miliard(?:e)?';
|
|
16
16
|
// Each scale group needs the token-boundary guard MONEY_SINGLE_RE already has
|
|
17
17
|
// below: without it, "2 до 3 месяцев" reads "м" off "месяцев" as the million
|
|
18
18
|
// abbreviation and turns 3 into 3,000,000. The boundary is nested inside the
|
package/src/money-lexicon.js
CHANGED
|
@@ -75,5 +75,5 @@ export const SALARY_MODIFIERS = Object.freeze({
|
|
|
75
75
|
export const NUMBER_MULTIPLIERS = Object.freeze([
|
|
76
76
|
group('thousand', { ru: ['к', 'тыс', 'тыс.', 'тысяч', 'тысячи'], en: ['k', 'thousand'], uk: ['к', 'тис', 'тис.', 'тисяч'], ro: ['k', 'mii'], uzLatn: ['k', 'ming'], uzCyrl: ['минг'], kk: ['k', 'мың'] }, { multiplier: 1_000 }),
|
|
77
77
|
group('million', { ru: ['м', 'млн', 'млн.', 'миллион', 'миллионов'], en: ['m', 'mln', 'million', 'millions'], uk: ['м', 'млн', 'мільйон', 'мільйонів'], ro: ['m', 'mil', 'milioane'], uzLatn: ['m', 'mln', 'million'], uzCyrl: ['млн', 'миллион'], kk: ['м', 'млн', 'миллион'] }, { multiplier: 1_000_000 }),
|
|
78
|
-
group('billion', { ru: ['млрд', 'миллиард', 'миллиардов'], en: ['bn', 'billion'], uk: ['млрд', 'мільярд'], ro: ['mld', 'miliard'], uzLatn: ['mlrd', 'billion'], uzCyrl: ['млрд', 'миллиард'], kk: ['млрд', 'миллиард'] }, { multiplier: 1_000_000_000 }),
|
|
78
|
+
group('billion', { ru: ['млрд', 'миллиард', 'миллиардов'], en: ['bn', 'billion'], uk: ['млрд', 'мільярд'], ro: ['mld', 'miliard', 'miliarde'], uzLatn: ['mlrd', 'billion'], uzCyrl: ['млрд', 'миллиард'], kk: ['млрд', 'миллиард'] }, { multiplier: 1_000_000_000 }),
|
|
79
79
|
]);
|
package/src/money.js
CHANGED
|
@@ -108,6 +108,21 @@ function rangeSearchText(text) {
|
|
|
108
108
|
return normalized;
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
+
function isWorkTimeRange(text, match, start, end) {
|
|
112
|
+
if (CLOCK_RANGE_RE.test(match[0])) return true;
|
|
113
|
+
|
|
114
|
+
const first = Number(String(match[1] || '').replace(',', '.'));
|
|
115
|
+
const second = Number(String(match[3] || '').replace(',', '.'));
|
|
116
|
+
if (!Number.isFinite(first) || !Number.isFinite(second) || first > 24 || second > 24) return false;
|
|
117
|
+
|
|
118
|
+
// Bare 9-19 can be a schedule too. Reject it as money only when the nearby
|
|
119
|
+
// context explicitly talks about working hours/schedule; a real salary such
|
|
120
|
+
// as "$9-19/hour" still survives because it has pay/currency context and no
|
|
121
|
+
// schedule marker.
|
|
122
|
+
const window = text.slice(Math.max(0, start - 48), Math.min(text.length, end + 48));
|
|
123
|
+
return WORK_TIME_CONTEXT_RE.test(window);
|
|
124
|
+
}
|
|
125
|
+
|
|
111
126
|
function bestRange(text, protectedSpans) {
|
|
112
127
|
const ranges = new RegExp(MONEY_RANGE_RE.source, 'giu');
|
|
113
128
|
const candidates = [];
|
|
@@ -199,4 +214,4 @@ export function salaryPeriod(value) {
|
|
|
199
214
|
export function currencyAliases(code) {
|
|
200
215
|
const entry = CURRENCY_TERMS.find((item) => item.canonical === code);
|
|
201
216
|
return entry ? [entry.canonical, ...aliasesOf(entry)] : [];
|
|
202
|
-
}
|
|
217
|
+
}
|
package/src/normalization.js
CHANGED
|
@@ -48,6 +48,22 @@ const KAZAKH_SEARCH_EQUIVALENCE = Object.freeze({
|
|
|
48
48
|
ә: 'а', ғ: 'г', қ: 'к', ң: 'н', ө: 'о', ұ: 'у', ү: 'у', і: 'и', һ: 'х',
|
|
49
49
|
});
|
|
50
50
|
|
|
51
|
+
// Karakalpak Latin source data commonly alternates between ASCII-friendly
|
|
52
|
+
// spellings and the current Latin letters used by OSM/local sources. Treat
|
|
53
|
+
// these as search equivalences only; canonical spelling remains source-owned.
|
|
54
|
+
const KARAKALPAK_LATIN_SEARCH_EQUIVALENCE = Object.freeze({
|
|
55
|
+
á: 'a', ǵ: 'g', ı: 'i', ń: 'n', ó: 'o', ú: 'u',
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
const KARAKALPAK_LATIN_PATTERN_EQUIVALENCE = Object.freeze({
|
|
59
|
+
a: '[aá]', á: '[aá]',
|
|
60
|
+
g: '[gǵ]', ǵ: '[gǵ]',
|
|
61
|
+
i: '[iı]', ı: '[iı]',
|
|
62
|
+
n: '[nń]', ń: '[nń]',
|
|
63
|
+
o: '[oó]', ó: '[oó]',
|
|
64
|
+
u: '[uú]', ú: '[uú]',
|
|
65
|
+
});
|
|
66
|
+
|
|
51
67
|
/** Search-oriented Cyrillic folding; canonical identity still comes from explicit aliases. */
|
|
52
68
|
export function foldCyrillicForSearch(value) {
|
|
53
69
|
return normalizeUnicode(value)
|
|
@@ -65,9 +81,17 @@ function foldKazakhForSearch(value) {
|
|
|
65
81
|
.join('');
|
|
66
82
|
}
|
|
67
83
|
|
|
84
|
+
function foldKarakalpakLatinForSearch(value) {
|
|
85
|
+
return normalizeUnicode(value)
|
|
86
|
+
.toLocaleLowerCase()
|
|
87
|
+
.split('')
|
|
88
|
+
.map((char) => KARAKALPAK_LATIN_SEARCH_EQUIVALENCE[char] ?? char)
|
|
89
|
+
.join('');
|
|
90
|
+
}
|
|
91
|
+
|
|
68
92
|
export function normalizedAliasKeys(value, { transliteration = true } = {}) {
|
|
69
93
|
const forms = transliteration
|
|
70
|
-
? [value, foldCyrillicForSearch(value), foldKazakhForSearch(value)]
|
|
94
|
+
? [value, foldCyrillicForSearch(value), foldKazakhForSearch(value), foldKarakalpakLatinForSearch(value)]
|
|
71
95
|
: [value];
|
|
72
96
|
return [...new Set(forms.flatMap((form) => [
|
|
73
97
|
normalizeForMatch(form),
|
|
@@ -103,7 +127,7 @@ function createAliasOwnersIndex(entries, { transliteration = true } = {}) {
|
|
|
103
127
|
for (const entry of entries || []) {
|
|
104
128
|
for (const sourceAlias of valuesOf(entry)) {
|
|
105
129
|
const searchForms = transliteration
|
|
106
|
-
? [sourceAlias, foldCyrillicForSearch(sourceAlias), foldKazakhForSearch(sourceAlias)]
|
|
130
|
+
? [sourceAlias, foldCyrillicForSearch(sourceAlias), foldKazakhForSearch(sourceAlias), foldKarakalpakLatinForSearch(sourceAlias)]
|
|
107
131
|
: [sourceAlias];
|
|
108
132
|
for (const searchAlias of searchForms) {
|
|
109
133
|
for (const key of normalizedAliasKeys(searchAlias, { transliteration: false })) {
|
|
@@ -186,8 +210,19 @@ export function escapeRegex(value) {
|
|
|
186
210
|
}
|
|
187
211
|
|
|
188
212
|
function aliasPattern(value) {
|
|
189
|
-
|
|
190
|
-
|
|
213
|
+
const source = normalizeUnicode(value).trim();
|
|
214
|
+
let pattern = '';
|
|
215
|
+
let separatorOpen = false;
|
|
216
|
+
for (const char of source) {
|
|
217
|
+
if (/[\s\-–—'’‘`ʻʼ]/u.test(char)) {
|
|
218
|
+
if (!separatorOpen) pattern += "[\\s\\-–—'’‘`ʻʼ]*";
|
|
219
|
+
separatorOpen = true;
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
separatorOpen = false;
|
|
223
|
+
pattern += KARAKALPAK_LATIN_PATTERN_EQUIVALENCE[char.toLocaleLowerCase()] ?? escapeRegex(char);
|
|
224
|
+
}
|
|
225
|
+
return pattern;
|
|
191
226
|
}
|
|
192
227
|
|
|
193
228
|
function matcherFor(entries, { transliteration = true } = {}) {
|
|
@@ -14,6 +14,10 @@ export const TASHKENT_AREA_ADDITIONS = Object.freeze({
|
|
|
14
14
|
Almazar: Object.freeze([
|
|
15
15
|
area('Shifokorlar-1', ['шифокорлар 1', 'shifokorlar 1']),
|
|
16
16
|
area('Shifokorlar-2', ['шифокорлар 2', 'shifokorlar 2']),
|
|
17
|
+
area('Shifokorlar-3', ['шифокорлар 3', 'shifokorlar 3']),
|
|
18
|
+
area('Shifokorlar-4', ['шифокорлар 4', 'shifokorlar 4', 'toshgu toshpi', 'тошгу тошпи']),
|
|
19
|
+
area('Shifokorlar-5', ['шифокорлар 5', 'shifokorlar 5']),
|
|
20
|
+
area('Shifokorlar-6', ['шифокорлар 6', 'shifokorlar 6']),
|
|
17
21
|
area('Beruni-3', ['беруни 3', 'beruniy 3', 'beruni 3']),
|
|
18
22
|
area('Hislat', ['хислат', 'hislat', 'xislat']),
|
|
19
23
|
...[1, 2, 3, 4].map((n) => area(`Beshkurgan-${n}`, [`бешкурган ${n}`, `бешқўрғон ${n}`, `beshqo rg on ${n}`, `beshkurgan ${n}`])),
|
|
@@ -21,6 +25,9 @@ export const TASHKENT_AREA_ADDITIONS = Object.freeze({
|
|
|
21
25
|
Bektemir: Object.freeze([
|
|
22
26
|
area('Suvsoz-1', ['сувсоз 1', 'водник 1', 'suvsoz 1']),
|
|
23
27
|
area('Suvsoz-2', ['сувсоз 2', 'водник 2', 'suvsoz 2']),
|
|
28
|
+
area('Suvsoz-3', ['сувсоз 3', 'suvsoz 3']),
|
|
29
|
+
area('Suvsoz-4', ['сувсоз 4', 'suvsoz 4']),
|
|
30
|
+
area('Suvsoz-5', ['сувсоз 5', 'suvsoz 5']),
|
|
24
31
|
area('Binokor', ['бинокор', 'binokor']),
|
|
25
32
|
area('Binokor-2', ['бинокор 2', 'binokor 2']),
|
|
26
33
|
area('Majnuntol', ['мажнунтол', 'majnuntol']),
|
|
@@ -79,4 +86,4 @@ export const FULL_TASHKENT_AREAS = Object.freeze(Object.fromEntries(
|
|
|
79
86
|
...(TASHKENT_AREAS[district] || []),
|
|
80
87
|
...(TASHKENT_AREA_ADDITIONS[district] || []),
|
|
81
88
|
])]),
|
|
82
|
-
));
|
|
89
|
+
));
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { aliasesToRegex } from './normalization.js';
|
|
2
|
+
|
|
3
|
+
function gastronomicStreet(canonical, aliases = [], district = null) {
|
|
4
|
+
const all = Object.freeze([...new Set([canonical, ...aliases].filter(Boolean))]);
|
|
5
|
+
return Object.freeze({
|
|
6
|
+
canonical,
|
|
7
|
+
name: canonical,
|
|
8
|
+
category: 'gastronomic_street',
|
|
9
|
+
entityType: 'street',
|
|
10
|
+
country: 'UZ',
|
|
11
|
+
city: 'Tashkent',
|
|
12
|
+
district,
|
|
13
|
+
aliases: all,
|
|
14
|
+
re: aliasesToRegex(all),
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const TASHKENT_GASTRONOMIC_STREETS = Object.freeze([
|
|
19
|
+
gastronomicStreet('Taras Shevchenko Street', [
|
|
20
|
+
'Taras Shevchenko Gastronomic Street',
|
|
21
|
+
'Taras Shevchenko nomidagi gastronomik ko‘cha',
|
|
22
|
+
"Taras Shevchenko nomidagi gastronomik ko'cha",
|
|
23
|
+
'Гастрономическая улица имени Тараса Шевченко',
|
|
24
|
+
'улица Тараса Шевченко',
|
|
25
|
+
'Taras Shevchenko ko‘chasi',
|
|
26
|
+
], 'Mirobod'),
|
|
27
|
+
gastronomicStreet('Mehrgiyo Street', [
|
|
28
|
+
'"Mehrgiyo" Gastronomic Street',
|
|
29
|
+
'Mehrgiyo Gastronomic Street',
|
|
30
|
+
'"Mehrgiyo" gastronomik ko‘chasi',
|
|
31
|
+
"Mehrgiyo gastronomik ko'chasi",
|
|
32
|
+
'Гастрономическая улица «Мехргиё»',
|
|
33
|
+
'Улица Мехригийо',
|
|
34
|
+
'Mehrgiyo ko‘chasi',
|
|
35
|
+
], 'Yangihayot'),
|
|
36
|
+
gastronomicStreet('Al-Khwarizmi Street', [
|
|
37
|
+
'Al-Khwarizmi Gastronomic Street',
|
|
38
|
+
'Al-Xorazmiy gastronomik ko‘chasi',
|
|
39
|
+
"Al-Xorazmiy gastronomik ko'chasi",
|
|
40
|
+
'Гастрономическая улица Аль-Хоразмий',
|
|
41
|
+
'Гастрономическая улица Аль-Хорезми',
|
|
42
|
+
'улица Ал-Хоразмий',
|
|
43
|
+
'Al-Xorazmiy ko‘chasi',
|
|
44
|
+
], 'Chilanzar'),
|
|
45
|
+
gastronomicStreet('Dilsaroy Street', [
|
|
46
|
+
'“Dilsaroy” Gastronomic Street',
|
|
47
|
+
'Dilsaroy Gastronomic Street',
|
|
48
|
+
'“Dilsaroy” gastronomik ko‘chasi',
|
|
49
|
+
"Dilsaroy gastronomik ko'chasi",
|
|
50
|
+
'Гастрономическая улица «Дильсарой»',
|
|
51
|
+
'улица Дильсарой',
|
|
52
|
+
'Dilsaroy ko‘chasi',
|
|
53
|
+
], 'Almazar'),
|
|
54
|
+
gastronomicStreet('Rihsili Street', [
|
|
55
|
+
'Rihsili Gastronomic Street',
|
|
56
|
+
'Rihsiliy gastronomik ko‘chasi',
|
|
57
|
+
'Rixsiliy gastronomik ko‘chasi',
|
|
58
|
+
'Гастрономическая улица Рихсили',
|
|
59
|
+
'Улица Рихсили',
|
|
60
|
+
'Rihsili Street',
|
|
61
|
+
'Rixsiliy ko‘chasi',
|
|
62
|
+
], 'Yunusabad'),
|
|
63
|
+
gastronomicStreet('Shota Rustaveli Street', [
|
|
64
|
+
'Shota Rustaveli Gastronomic Street',
|
|
65
|
+
'Shota Rustaveli gastronomik ko‘chasi',
|
|
66
|
+
'Гастрономическая улица Шота Руставели',
|
|
67
|
+
'улица Шота Руставели',
|
|
68
|
+
'Shota Rustaveli ko‘chasi',
|
|
69
|
+
], 'Yakkasaray'),
|
|
70
|
+
gastronomicStreet('Chigatoy-Darvoza Street', [
|
|
71
|
+
'Chigatoy–Darvoza gastronomic street',
|
|
72
|
+
'Chig‘atoy–Darvoza gastronomik ko‘chasi',
|
|
73
|
+
'Chigatay–Darvoza Street',
|
|
74
|
+
'Chigatoy–Darvoza Street',
|
|
75
|
+
'Гастрономическая улица Чигатой–Дарвоза',
|
|
76
|
+
'Улица Чигатой-Дарвоза',
|
|
77
|
+
], 'Almazar'),
|
|
78
|
+
gastronomicStreet('Gulkhaniy Street', [
|
|
79
|
+
'Gulkhani Gastronomic Street',
|
|
80
|
+
'Gulxaniy gastronomik ko‘chasi',
|
|
81
|
+
'Гастрономическая улица Гулханий',
|
|
82
|
+
'Улица Гулханий',
|
|
83
|
+
'Gulkhaniy Street',
|
|
84
|
+
'Gulxaniy ko‘chasi',
|
|
85
|
+
], 'Shaykhantahur'),
|
|
86
|
+
gastronomicStreet('Farhod Street', [
|
|
87
|
+
'Farhod Gastronomic Street',
|
|
88
|
+
'Farhod gastronomik ko‘chasi',
|
|
89
|
+
"Farhod gastronomik ko'chasi",
|
|
90
|
+
'Фархадская гастрономическая улица',
|
|
91
|
+
'Улица Фарход',
|
|
92
|
+
'Farhod ko‘chasi',
|
|
93
|
+
], 'Uchtepa'),
|
|
94
|
+
gastronomicStreet('Sogdiyona Street', [
|
|
95
|
+
'Sogdiyona Gastronomic Street',
|
|
96
|
+
'So‘g‘diyona gastronomik ko‘chasi',
|
|
97
|
+
"So'g'diyona gastronomik ko'chasi",
|
|
98
|
+
'Гастрономическая улица Согдиёна',
|
|
99
|
+
'Улица Согдиёна',
|
|
100
|
+
'So‘g‘diyona ko‘chasi',
|
|
101
|
+
], 'Sergeli'),
|
|
102
|
+
]);
|
|
103
|
+
|
|
104
|
+
export function resolveTashkentGastronomicStreet(value) {
|
|
105
|
+
const text = String(value || '').trim();
|
|
106
|
+
if (!text) return null;
|
|
107
|
+
return TASHKENT_GASTRONOMIC_STREETS.find((entry) => entry.re.test(text)) || null;
|
|
108
|
+
}
|
package/src/tashkent-pois.js
CHANGED
|
@@ -11,10 +11,12 @@ function poi(name, category, aliases = [], options = {}) {
|
|
|
11
11
|
re: aliasesToRegex(all),
|
|
12
12
|
contextRequired: Boolean(options.contextRequired),
|
|
13
13
|
contextRe: options.context ? new RegExp(options.context, 'iu') : null,
|
|
14
|
+
...(options.parent ? { parent: options.parent } : {}),
|
|
14
15
|
});
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
const MALL_CONTEXT = '(?:mall|молл|трц|тц|торгов(?:ый|ого)\\s+центр|savdo\\s+markazi|shopping\\s+(?:center|centre))';
|
|
19
|
+
const PARK_CONTEXT = '(?:парк|bog|бог|боғ|park|national|milliy|navoi|наво)';
|
|
18
20
|
|
|
19
21
|
export const TASHKENT_PARKS = Object.freeze([
|
|
20
22
|
poi('Tashkent City Park', 'park', ['Ташкент Сити парк', 'Парк Tashkent City']),
|
|
@@ -22,21 +24,28 @@ export const TASHKENT_PARKS = Object.freeze([
|
|
|
22
24
|
poi('Ecopark', 'park', ['Eco Park', 'Экопарк', 'Центральный экопарк']),
|
|
23
25
|
poi('Central Park Mirzo Ulugbek', 'park', ['Центральный парк имени Мирзо Улугбека', 'Центральный парк', 'Central Park', 'Парк Мирзо Улугбека']),
|
|
24
26
|
poi('Japanese Garden', 'park', ['Японский сад', "Yapon bog'i", 'Yapon bog‘i', 'Yapon bogʻI']),
|
|
25
|
-
poi('
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
poi('Alisher Navoi National Park', 'park', [
|
|
28
|
+
'Парк имени Алишера Навои',
|
|
29
|
+
'Национальный парк Узбекистана имени Алишера Навои',
|
|
30
|
+
'Milliy Bog Park',
|
|
31
|
+
"Milliy Bog'",
|
|
32
|
+
'Milliy Bog‘',
|
|
33
|
+
'Milliy Bogʻ',
|
|
34
|
+
'Миллий бог',
|
|
35
|
+
'Национальный парк',
|
|
36
|
+
], { contextRequired: true, context: PARK_CONTEXT }),
|
|
37
|
+
poi('Dream Park', 'park', ['Dream Park имени Гафура Гуляма', 'Парк имени Гафура Гуляма', 'Парк Гафура Гуляма', 'Gafur Gulyam Park', 'Gafur Gulam Dream Park', "G'afur G'ulom bog'i", 'Парк культуры и отдыха имени Гафура Гуляма']),
|
|
38
|
+
poi('Anhor Lokomotiv Park', 'park', ['Anhor Lokomotiv', 'Anhor-Lokomotiv', 'Анхор Локомотив', 'Парк Анхор Локомотив', 'Парк Локомотив']),
|
|
30
39
|
poi('Tashkentland', 'park', ['Ташкентленд']),
|
|
31
40
|
poi('Victory Park', 'park', ['Парк Победы', "G'alaba Bog'i", 'G‘alaba Bog‘i', 'Gʻalaba Bogʻi']),
|
|
32
|
-
poi('Ashgabat Park', 'park', ['Ашхабад парк', 'Ashxobod Park']),
|
|
33
|
-
poi('Dostlik Park', 'park', ['Парк Дустлик', "Do'stlik Park", 'Do‘stlik Park', 'Doʻstlik Park']),
|
|
34
|
-
poi('Navruz Park', 'park', ['Парк Навруз']),
|
|
35
|
-
poi('
|
|
36
|
-
poi('Furqat Park', 'park', ['Парк Фурката']),
|
|
41
|
+
poi('Ashgabat Park', 'park', ['Ашхабад парк', 'Ashxobod Park', "Ashxobod bog'i", 'Ashxobod bog‘i']),
|
|
42
|
+
poi('Dostlik Park', 'park', ['Парк Дустлик', "Do'stlik Park", 'Do‘stlik Park', 'Doʻstlik Park', 'Bobur Park', 'Парк Бабура', 'Парк Бобура', "Bobur bog'i", 'Bobur bog‘i']),
|
|
43
|
+
poi('Navruz Park', 'park', ['Парк Навруз', 'Navroʻz bogʻi', "Navro'z bog'i"]),
|
|
44
|
+
poi('Furqat Park', 'park', ['Парк Фурката', "Furqat bog'i", 'Furqat bog‘i']),
|
|
37
45
|
poi('Yakub Kolas Park', 'park', ['Парк Якуба Коласа', 'Парк имени Якуба Коласа']),
|
|
38
|
-
poi('Friendship of Peoples Park', 'park', ['Парк Дружбы народов']),
|
|
39
|
-
poi('Yangi Ozbekiston Park', 'park', ["Yangi O'zbekiston Bog'i", 'Yangi O‘zbekiston Bog‘i', 'Парк Новый Узбекистан', 'Новый Узбекистан', "Yangi O'zbekiston Park"]),
|
|
46
|
+
poi('Friendship of Peoples Park', 'park', ['Парк Дружбы народов', "Xalqlar Do'stligi Park", 'Xalqlar Do‘stligi Park']),
|
|
47
|
+
poi('Yangi Ozbekiston Park', 'park', ["Yangi O'zbekiston Bog'i", 'Yangi O‘zbekiston Bog‘i', 'Yangi Oʻzbekiston bogʻi', 'Парк Новый Узбекистан', 'Новый Узбекистан', "Yangi O'zbekiston Park"]),
|
|
48
|
+
poi('Tashkent Botanical Garden', 'park', ['Botanical Garden named after Fyodor Rusanov', 'Botanical Garden named after Fyodor Rusananov', 'Ботанический сад имени Фёдора Русанова', 'Ташкентский ботанический сад', 'Fyodor Rusanov nomidagi Botanika bog‘i', 'Toshkent botanika bog‘i']),
|
|
40
49
|
]);
|
|
41
50
|
|
|
42
51
|
export const TASHKENT_SQUARES = Object.freeze([
|
|
@@ -65,15 +74,17 @@ export const TASHKENT_MARKETS = Object.freeze([
|
|
|
65
74
|
poi('Ippodrom Bazaar', 'market', ['Ипподром']),
|
|
66
75
|
poi('Abu Sahiy', 'market', ['Абу Сахий']),
|
|
67
76
|
poi('Orikzor Bazaar', 'market', ['Урикзор', "O'rikzor", 'O‘rikzor', 'Oʻrikzor']),
|
|
77
|
+
poi('Stroygorod', 'market', ['Стройгород', 'рынок Стройгород', 'Стройгород рынок', 'Stroygorod market', 'Stroygorod bazaar'], { parent: 'Uchtepa' }),
|
|
68
78
|
poi('Kadysheva Bazaar', 'market', ['Кадышева рынок', 'Кадышева базар']),
|
|
69
79
|
poi('Yangiobod Bazaar', 'market', ['Янгиабадский рынок', 'Янгиабад', 'Yangiobod bozori']),
|
|
70
80
|
]);
|
|
71
81
|
|
|
72
82
|
export const TASHKENT_MALLS = Object.freeze([
|
|
73
83
|
poi('Tashkent City Mall', 'mall', ['Ташкент Сити Молл']),
|
|
74
|
-
poi('Samarqand Darvoza', 'mall', ['Самарканд Дарвоза']),
|
|
84
|
+
poi('Samarqand Darvoza', 'mall', ['Самарканд Дарвоза', 'Samarkand Darvoza']),
|
|
75
85
|
poi('Compass Mall', 'mall', ['Compass', 'ТРЦ Compass', 'ТЦ Compass', 'Compass savdo markazi'], { contextRequired: true, context: MALL_CONTEXT }),
|
|
76
86
|
poi('Mega Planet', 'mall', ['MegaPlanet', 'Мега Планет', 'ТРЦ Mega Planet', 'Mega Planet savdo markazi']),
|
|
87
|
+
poi('Anhor Park Mall', 'mall', ['Anhor Park', 'Anhor Mall', 'Anhor Park Savdo Markazi', 'Анхор Парк', 'Анхор Молл', 'ТРЦ Анхор', 'ТЦ Анхор']),
|
|
77
88
|
poi('Riviera Mall', 'mall', ['Riviera', 'Ривьера Молл', 'ТРЦ Riviera', 'Riviera savdo markazi'], { contextRequired: true, context: MALL_CONTEXT }),
|
|
78
89
|
poi('NEXT Mall', 'mall', ['Next', 'NEXT', 'Некст Молл', 'ТРЦ NEXT', 'NEXT savdo markazi'], { contextRequired: true, context: MALL_CONTEXT }),
|
|
79
90
|
poi('Atlas Mall', 'mall', ['Atlas', 'Атлас Молл', 'ТРЦ Atlas', 'Atlas savdo markazi'], { contextRequired: true, context: MALL_CONTEXT }),
|
|
@@ -81,13 +92,15 @@ export const TASHKENT_MALLS = Object.freeze([
|
|
|
81
92
|
poi('Depo Mall', 'mall', ['Depo', 'Депо Молл', 'ТРЦ Depo', 'Depo savdo markazi'], { contextRequired: true, context: MALL_CONTEXT }),
|
|
82
93
|
poi('Vega Centre', 'mall', ['Vega Center', 'Вега Центр', 'Vega savdo markazi']),
|
|
83
94
|
poi('Yunusabad Gallery', 'mall', ['Юнусабад Галерея', 'Yunusobod Galereya', 'Yunusobod Gallery']),
|
|
84
|
-
poi('Poytaxt Mall', 'mall', ['Poytaxt', 'Пойтахт Молл', 'Пойтахт', 'Poytaxt savdo markazi'], { contextRequired: true, context: MALL_CONTEXT }),
|
|
95
|
+
poi('Poytaxt Mall', 'mall', ['Poytaxt', 'Пойтахт Молл', 'Пойтахт', 'Poytaxt Shopping Center', 'Poytaxt savdo markazi'], { contextRequired: true, context: MALL_CONTEXT }),
|
|
85
96
|
poi('Alfraganus Mall', 'mall', ['Alfraganus', 'Альфраганус Молл', 'Alfraganus savdo markazi'], { contextRequired: true, context: MALL_CONTEXT }),
|
|
86
|
-
poi('
|
|
97
|
+
poi('High Town Mall', 'mall', ['HT Mall', 'HT Молл', 'HT savdo markazi']),
|
|
87
98
|
poi('Seoul Mun Mall', 'mall', ['Seoul Mun', 'Сеул Мун Молл', 'Seoul Mun savdo markazi'], { contextRequired: true, context: MALL_CONTEXT }),
|
|
88
99
|
poi('Ecobozor', 'mall', ['Eco Bozor', 'Ekobozor', 'Эко Бозор', 'Экобозор']),
|
|
89
|
-
poi('
|
|
90
|
-
poi('
|
|
100
|
+
poi('Chimgan Shopping Center', 'mall', ['Chimgan', 'Chimgan Mall', 'ТРЦ Чимган', 'ТЦ Чимган', 'Chimgan savdo markazi'], { contextRequired: true, context: MALL_CONTEXT }),
|
|
101
|
+
poi('Golden Life', 'mall', ['Golden Life Mall', 'Голден Лайф', 'ТРЦ Golden Life', 'ТЦ Golden Life']),
|
|
102
|
+
poi("Chig'atoy Mall", 'mall', ["Chig'atoy", 'Chigatoy', "ТРЦ Chig'atoy", 'ТРЦ Чигатай', 'ТЦ Чигатай']),
|
|
103
|
+
poi('Scopus Mall', 'mall', ['Scopus', 'Скопус Молл', 'ТРЦ Scopus']),
|
|
91
104
|
]);
|
|
92
105
|
|
|
93
106
|
export const TASHKENT_ATTRACTIONS = Object.freeze([
|
|
@@ -180,6 +193,13 @@ export const TASHKENT_MEDICAL_POIS = Object.freeze([
|
|
|
180
193
|
poi('Republic Specialized Nephrology and Transplantation Centre', 'medical', ['Republican Nephrology Center', 'Республиканский нефрологический центр', 'Центр нефрологии и трансплантации']),
|
|
181
194
|
poi('Republican Perinatal Center', 'medical', ['Республиканский перинатальный центр', 'Перинатальный центр']),
|
|
182
195
|
poi('Institute of Obstetrics and Gynecology', 'medical', ['Институт акушерства и гинекологии']),
|
|
196
|
+
poi('AKFA Medline', 'medical', ['AKFA MEDLINE', 'Akfa Medline', 'Акфа Медлайн']),
|
|
197
|
+
poi('Shifo Nur', 'medical', ['Шифо Нур']),
|
|
198
|
+
poi('Nano Medical Clinic', 'medical', ['Клиника Нано', 'Nano Clinic', 'Nano Klinikasi', 'Nano tibbiy klinikasi']),
|
|
199
|
+
poi('Medas Medical Center', 'medical', ['Medas Group', 'MEDAS', 'Медицинский центр MEDAS']),
|
|
200
|
+
poi('Prof Med Clinic', 'medical', ['ProfMedService', 'Prof Med Klinikasi', 'Клиника Профмедсервис']),
|
|
201
|
+
poi('Dr. Akshay Kumar Eye Clinic', 'medical', ['Глазная клиника доктора Акшая Кумара', 'Vedanta Medical']),
|
|
202
|
+
poi('Shox International Hospital', 'medical', ['Shox Hospital', 'Международная больница Шоx']),
|
|
183
203
|
]);
|
|
184
204
|
|
|
185
205
|
export const TASHKENT_LEGACY_LANDMARKS = Object.freeze([
|
|
@@ -231,4 +251,4 @@ export function matchTashkentPoi(value, category = null) {
|
|
|
231
251
|
}
|
|
232
252
|
matches.sort((a, b) => b.length - a.length || a.start - b.start);
|
|
233
253
|
return matches[0]?.entry ?? null;
|
|
234
|
-
}
|
|
254
|
+
}
|