@whiteslove/parsing-lexicon 0.2.0 → 0.2.2
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/LICENSE +21 -21
- package/README.md +137 -137
- package/index.d.ts +374 -374
- package/package.json +77 -75
- package/src/central-asia-locations.js +211 -211
- package/src/central-asia.js +233 -233
- package/src/contact.d.ts +44 -44
- package/src/contact.js +159 -159
- package/src/countries.js +175 -175
- package/src/country-context.d.ts +10 -10
- package/src/country-context.js +22 -22
- package/src/currency.d.ts +14 -14
- package/src/currency.js +66 -66
- package/src/geo.js +169 -169
- package/src/geography-central-asia.js +42 -42
- package/src/geography-detection.d.ts +14 -14
- package/src/geography-detection.js +64 -64
- package/src/geography-display.d.ts +13 -13
- package/src/geography-display.js +113 -113
- package/src/geography.js +210 -210
- package/src/hiring-advanced.js +147 -147
- package/src/hiring-candidate-fields.d.ts +9 -9
- package/src/hiring-candidate-fields.js +92 -92
- package/src/hiring-context.d.ts +64 -64
- package/src/hiring-context.js +412 -412
- package/src/hiring-language-extensions.d.ts +19 -19
- package/src/hiring-language-extensions.js +139 -139
- package/src/hiring-languages.js +135 -135
- package/src/hiring-location-fields.d.ts +3 -3
- package/src/hiring-location-fields.js +53 -53
- package/src/hiring-professions-ro.js +191 -191
- package/src/hiring-professions.js +437 -437
- package/src/hiring-requirements.d.ts +16 -16
- package/src/hiring-requirements.js +170 -170
- package/src/hiring-salary-context.d.ts +27 -27
- package/src/hiring-salary-context.js +76 -76
- package/src/hiring-semantics.d.ts +29 -29
- package/src/hiring-semantics.js +218 -218
- package/src/hiring-skills.d.ts +21 -21
- package/src/hiring-skills.js +315 -315
- package/src/hiring-source-aliases.d.ts +32 -32
- package/src/hiring-source-aliases.js +185 -185
- package/src/hiring-source-semantics.d.ts +31 -31
- package/src/hiring-source-semantics.js +293 -293
- package/src/hiring-temporal.d.ts +15 -15
- package/src/hiring-temporal.js +67 -67
- package/src/hiring-vacancy-fields.d.ts +5 -5
- package/src/hiring-vacancy-fields.js +23 -23
- package/src/hiring-work-semantics.d.ts +34 -34
- package/src/hiring-work-semantics.js +72 -72
- package/src/hiring.js +180 -180
- package/src/housing-address.d.ts +18 -18
- package/src/housing-address.js +217 -210
- package/src/housing-commercial.d.ts +1 -0
- package/src/housing-commercial.js +9 -0
- package/src/housing-context.d.ts +36 -36
- package/src/housing-context.js +183 -183
- package/src/housing-features.js +30 -30
- package/src/housing-intent.d.ts +9 -9
- package/src/housing-intent.js +132 -132
- package/src/housing-listing-fields.js +131 -131
- package/src/housing-money.d.ts +7 -7
- package/src/housing-money.js +102 -102
- package/src/housing-source-aliases.d.ts +8 -8
- package/src/housing-source-aliases.js +51 -51
- package/src/housing-structured.d.ts +55 -55
- package/src/housing-structured.js +219 -219
- package/src/housing.js +200 -200
- package/src/index.js +45 -44
- package/src/kz-location-extensions.js +307 -307
- package/src/landmarks.js +21 -21
- package/src/lexicon-core.js +58 -58
- package/src/location-merge.js +106 -106
- package/src/locations.js +456 -456
- package/src/money-core.d.ts +10 -10
- package/src/money-core.js +81 -81
- package/src/money-lexicon.d.ts +5 -5
- package/src/money-lexicon.js +79 -79
- package/src/money.js +154 -154
- package/src/normalization.js +384 -384
- package/src/odesa-metropolitan.js +144 -144
- package/src/romania-geography.js +47 -47
- package/src/tashkent-colloquial.js +80 -72
- package/src/tashkent-housing-geography.d.ts +38 -38
- package/src/tashkent-housing-geography.js +211 -211
- package/src/tashkent-pois.js +215 -215
- package/src/tashkent-residential-complexes.js +272 -272
- package/src/ua-location-extensions-major.js +118 -118
- package/src/ua-location-extensions-metro.js +9 -9
- package/src/ua-location-extensions-regional.js +246 -246
- package/src/ua-secondary-cities.d.ts +2 -2
- package/src/ua-secondary-cities.js +57 -57
- package/src/ukraine.js +75 -75
- package/src/uz-location-extensions.js +259 -259
|
@@ -1,32 +1,32 @@
|
|
|
1
|
-
export interface ExtendedProfessionMatch {
|
|
2
|
-
canonical: string;
|
|
3
|
-
group: string;
|
|
4
|
-
family: string;
|
|
5
|
-
score: number;
|
|
6
|
-
strength: 'strong' | 'weak';
|
|
7
|
-
matched: string;
|
|
8
|
-
index: number;
|
|
9
|
-
label: string;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export interface SourceProfessionAlias {
|
|
13
|
-
canonical: string;
|
|
14
|
-
label: string;
|
|
15
|
-
group: string;
|
|
16
|
-
aliases: readonly string[];
|
|
17
|
-
re: RegExp;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export interface SourceRoleNormalization {
|
|
21
|
-
canonical: string;
|
|
22
|
-
label: string;
|
|
23
|
-
re: RegExp;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export const SOURCE_PROFESSION_ALIASES: readonly SourceProfessionAlias[];
|
|
27
|
-
export const SOURCE_ROLE_NORMALIZATION_RULES: readonly SourceRoleNormalization[];
|
|
28
|
-
export const SOURCE_CANDIDATE_INTENT_ALIASES: readonly string[];
|
|
29
|
-
export function normalizeSourceRole(value: unknown): Readonly<{ canonical: string; label: string }> | null;
|
|
30
|
-
export function matchesSourceCandidateIntent(value: unknown): boolean;
|
|
31
|
-
export function professionDisplayLabel(canonical: string): string;
|
|
32
|
-
export function matchExtendedProfessions(value: unknown, options?: { limit?: number; allowWeak?: boolean }): readonly ExtendedProfessionMatch[];
|
|
1
|
+
export interface ExtendedProfessionMatch {
|
|
2
|
+
canonical: string;
|
|
3
|
+
group: string;
|
|
4
|
+
family: string;
|
|
5
|
+
score: number;
|
|
6
|
+
strength: 'strong' | 'weak';
|
|
7
|
+
matched: string;
|
|
8
|
+
index: number;
|
|
9
|
+
label: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface SourceProfessionAlias {
|
|
13
|
+
canonical: string;
|
|
14
|
+
label: string;
|
|
15
|
+
group: string;
|
|
16
|
+
aliases: readonly string[];
|
|
17
|
+
re: RegExp;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface SourceRoleNormalization {
|
|
21
|
+
canonical: string;
|
|
22
|
+
label: string;
|
|
23
|
+
re: RegExp;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const SOURCE_PROFESSION_ALIASES: readonly SourceProfessionAlias[];
|
|
27
|
+
export const SOURCE_ROLE_NORMALIZATION_RULES: readonly SourceRoleNormalization[];
|
|
28
|
+
export const SOURCE_CANDIDATE_INTENT_ALIASES: readonly string[];
|
|
29
|
+
export function normalizeSourceRole(value: unknown): Readonly<{ canonical: string; label: string }> | null;
|
|
30
|
+
export function matchesSourceCandidateIntent(value: unknown): boolean;
|
|
31
|
+
export function professionDisplayLabel(canonical: string): string;
|
|
32
|
+
export function matchExtendedProfessions(value: unknown, options?: { limit?: number; allowWeak?: boolean }): readonly ExtendedProfessionMatch[];
|
|
@@ -1,186 +1,186 @@
|
|
|
1
|
-
import { aliasesToRegex } from './normalization.js';
|
|
2
|
-
import { matchProfessions } from './hiring-professions.js';
|
|
3
|
-
|
|
4
|
-
const sourceRole = (canonical, label, aliases, group = 'other') => Object.freeze({
|
|
5
|
-
canonical,
|
|
6
|
-
label,
|
|
7
|
-
group,
|
|
8
|
-
aliases: Object.freeze([...new Set(aliases)]),
|
|
9
|
-
re: aliasesToRegex([...new Set(aliases)]),
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Source spellings seen in real CV feeds which are too source-specific or
|
|
14
|
-
* colloquial for the core profession rows. They still live in the shared
|
|
15
|
-
* package so consumers do not grow their own profession regex catalogs.
|
|
16
|
-
*/
|
|
17
|
-
export const SOURCE_PROFESSION_ALIASES = Object.freeze([
|
|
18
|
-
sourceRole('chief_executive_officer', 'Chief Executive Officer', ['ceo', 'chief executive officer', 'генеральный директор', 'гендиректор', 'виконавчий директор'], 'management'),
|
|
19
|
-
sourceRole('chief_technology_officer', 'Chief Technology Officer', ['cto', 'chief technology officer', 'технический директор', 'технічний директор'], 'management'),
|
|
20
|
-
sourceRole('sales_manager', 'Sales Manager', ['sales executive', 'head of sales', 'менеджер экспортных продаж', 'менеджер по экспортным продажам', 'роп', 'sotuv menejer'], 'sales'),
|
|
21
|
-
sourceRole('driver', 'Driver', ['се категория', 'се категория буйича', 'ce категория', 'ce category', 'shafyor'], 'transport'),
|
|
22
|
-
sourceRole('accountant', 'Accountant', ['bugalteriya', 'buxgalteriya', 'buhgalteriya'], 'finance'),
|
|
23
|
-
sourceRole('cashier', 'Cashier', ['kassa xodimi', 'kassa mudiri'], 'retail'),
|
|
24
|
-
sourceRole('notary', 'Notary', ['notary', 'notarius', 'нотариус'], 'legal'),
|
|
25
|
-
sourceRole('metrology_specialist', 'Metrology Specialist', ['metrologiya', 'metrology specialist', 'метролог', 'standartlashtirish'], 'manufacturing'),
|
|
26
|
-
sourceRole('security_guard', 'Security Guard', ['xavfsizlik', 'qoriqlash', 'qo‘riqlash', "qo'riqlash", 'охорона'], 'security'),
|
|
27
|
-
sourceRole('finance_banking_specialist', 'Finance / Banking Specialist', ['finance specialist', 'banking specialist', 'moliya', 'soliq', 'bank'], 'finance'),
|
|
28
|
-
sourceRole('teacher', 'Teacher', ['tyutorlik', 'тьютор', 'titur', "o'qituvchilik", 'o‘qituvchilik', 'oʻqituvchilik', 'ustoz'], 'education'),
|
|
29
|
-
sourceRole('english_teacher', 'English Teacher', ['ingliz tili ustoziman', 'ingliz tili ustoz', 'ingliz tili oqituvchi', "ingliz tili o'qituvchi"], 'education'),
|
|
30
|
-
sourceRole('it_specialist', 'IT Specialist', ['it specialist', 'itishnik', 'it ishnik', 'kompyuter boyicha ish', "kompyuter bo'yicha ish", 'kompyuter bo‘yicha ish'], 'infrastructure'),
|
|
31
|
-
sourceRole('biotechnologist', 'Biotechnologist', ['biotechnologist', 'биотехнолог', 'biotexnolog'], 'medicine'),
|
|
32
|
-
sourceRole('laboratory_technician', 'Laboratory Technician', ['laborant'], 'medicine'),
|
|
33
|
-
sourceRole('media_specialist', 'Media Specialist', ['media specialist', 'специалист по сми', 'matbuot'], 'media_content'),
|
|
34
|
-
sourceRole('engineer', 'Engineer', ['engineer', 'инженер', 'інженер', 'muhandis', 'injiner'], 'engineering'),
|
|
35
|
-
sourceRole('chat_operator', 'Chat Operator', ['chat operatori'], 'customer_support'),
|
|
36
|
-
sourceRole('call_center_operator', 'Call Center Operator', ['koll-markaz operatori', 'koll markaz operatori', 'call-markaz operatori'], 'customer_support'),
|
|
37
|
-
sourceRole('consultant', 'Consultant', ['consultant', 'консультант', 'консультантка'], 'commercial'),
|
|
38
|
-
sourceRole('supervisor', 'Supervisor', ['supervisor', 'супервайзер', 'начальник отряд', 'начальник отряда'], 'management'),
|
|
39
|
-
sourceRole('quality_inspector', 'Quality Inspector', ['quality inspector', 'инспектор по качеству', 'інспектор з якості'], 'manufacturing'),
|
|
40
|
-
sourceRole('oil_gas_worker', 'Oil & Gas Worker', ['oil and gas', 'oil & gas', 'нефть и газ', 'нефтегаз', 'neft va gaz', 'neft vagaz', 'neft vagaz sohasida', 'neft va gaz sohasida'], 'manufacturing'),
|
|
41
|
-
sourceRole('cybersecurity_specialist', 'Cybersecurity Specialist', ['cybersecurity specialist', 'ciso', 'руководитель по информационной безопасности', 'руководитель информационной безопасности'], 'information_security'),
|
|
42
|
-
sourceRole('architect', 'Architect', ['arxitektor loyihachi', 'arxitektor'], 'construction'),
|
|
43
|
-
sourceRole('economist', 'Economist', ['iqtisodchi', 'iqtsodchi', 'iqtisodiy'], 'finance'),
|
|
44
|
-
sourceRole('logistics_manager', 'Logistics Specialist', ['logist', 'logistics specialist', 'логист'], 'logistics'),
|
|
45
|
-
sourceRole('frontend_developer', 'Frontend Developer', ['frontet', 'frontet developer', 'frontet dasturchi'], 'software_development'),
|
|
46
|
-
sourceRole('nanny', 'Nanny', ['bolalarga qarash', 'bolaga qarash'], 'education'),
|
|
47
|
-
sourceRole('loader', 'Loader', ['грузчиком', 'грузчика', 'грузчик'], 'logistics'),
|
|
48
|
-
sourceRole('welder', 'Welder', ['сварщиком', 'сварщица', 'зварювальником'], 'construction'),
|
|
49
|
-
]);
|
|
50
|
-
|
|
51
|
-
const sourceRoleNormalization = (canonical, label, re) => Object.freeze({ canonical, label, re });
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Anchored or strongly contextualized raw-role repairs. These rules are kept
|
|
55
|
-
* separate from SOURCE_PROFESSION_ALIASES so generic values such as `model`,
|
|
56
|
-
* `online`, or `bank` never become profession matches in arbitrary CV prose.
|
|
57
|
-
*/
|
|
58
|
-
export const SOURCE_ROLE_NORMALIZATION_RULES = Object.freeze([
|
|
59
|
-
sourceRoleNormalization('economist', 'Economist', /^iqt(?:i)?sodchi$/iu),
|
|
60
|
-
sourceRoleNormalization('economist', 'Economist', /^iqtisodiy$/iu),
|
|
61
|
-
sourceRoleNormalization('logistics_manager', 'Logistics Specialist', /^logist(?:ika)?(?:\s+updater)?$/iu),
|
|
62
|
-
sourceRoleNormalization('english_teacher', 'English Teacher', /^ingliz\s+tili\s+ustoz(?:iman)?$/iu),
|
|
63
|
-
sourceRoleNormalization('frontend_developer', 'Frontend Developer', /mobilagraf[\s\S]*itishnik[\s\S]*front(?:et|ent|end)/iu),
|
|
64
|
-
sourceRoleNormalization('nanny', 'Nanny', /farqi\s+yo[\s\S]*bolalarga\s+qarash/iu),
|
|
65
|
-
sourceRoleNormalization('sales_manager', 'Sales Manager', /^(?:sales\s+executive(?:\s+ind)?|роп(?:,?\s*sales\s+executive)?)$/iu),
|
|
66
|
-
sourceRoleNormalization('operative_officer', 'Operative Officer', /^(?:оперативник|оперуполномоченн\p{L}*|оперативный\s+уполномоченн\p{L}*)$/iu),
|
|
67
|
-
sourceRoleNormalization('water_supply_specialist', 'Water Supply Specialist', /^(?:suv\s+ta['’ʻʼ‘`]?minoti|водоснабжение)$/iu),
|
|
68
|
-
sourceRoleNormalization('any_role', 'Any Role', /^(?:onlayn(?:\s+ish(?:chi)?)?|online(?:\s+ish(?:chi)?)?|онлайн|удал[её]нно|remote(?:\s+work)?|boshqa\s+ishlar?|farqi\s+(?:yo['’ʻʼ‘`]?q|yuq)|tungi|bilmaym\p{L}*)$/iu),
|
|
69
|
-
sourceRoleNormalization('restaurant_cafe_worker', 'Restaurant / Cafe Worker', /^ищу\s+работу\s+(?:в\s+)?(?:кафе|ресторанах?|кафе\s+или\s+ресторанах)$/iu),
|
|
70
|
-
sourceRoleNormalization('driver', 'Driver', /^(?:xaydovchilik|haydovchilik|shafyorlik|shofyorlik)/iu),
|
|
71
|
-
sourceRoleNormalization('retail_worker', 'Retail Worker', /^do['’ʻʼ‘`]?kon$/iu),
|
|
72
|
-
sourceRoleNormalization('salesperson', 'Salesperson', /^(?:savdo|sotuvchi)$/iu),
|
|
73
|
-
sourceRoleNormalization('pharmacist', 'Pharmacist', /^(?:dorishunos|farmatsevt)$/iu),
|
|
74
|
-
sourceRoleNormalization('notary_assistant', 'Notary Assistant', /^(?:natarus|notarius)\s+yordamchisi/iu),
|
|
75
|
-
sourceRoleNormalization('librarian', 'Librarian', /^kutubxonachi$/iu),
|
|
76
|
-
sourceRoleNormalization('singer_vocalist', 'Singer / Vocalist', /^(?:vokal\s*:\s*)?xonanda$/iu),
|
|
77
|
-
sourceRoleNormalization('model', 'Model', /^model$/iu),
|
|
78
|
-
sourceRoleNormalization('flight_attendant', 'Flight Attendant', /^bortprovodnik$|^бортпроводник$/iu),
|
|
79
|
-
sourceRoleNormalization('hvac_technician', 'HVAC Technician', /^(?:konditsaner|kanditsaner|konditsioner)/iu),
|
|
80
|
-
sourceRoleNormalization('mobile_content_creator', 'Mobile Content Creator', /^mobilografiya(?:\s+bo['’ʻʼ‘`]?yicha)?$/iu),
|
|
81
|
-
sourceRoleNormalization('cctv_intercom_technician', 'CCTV / Intercom Technician', /kamera\s+(?:dama?fon|domofon)|domofon\s+xizmat/iu),
|
|
82
|
-
sourceRoleNormalization('internal_control_specialist', 'Internal Control Specialist', /^ichki\s+nazoratchi$/iu),
|
|
83
|
-
sourceRoleNormalization('brand_ambassador', 'Brand Ambassador', /^(?:бренд\s+фейс|brand\s+face)$/iu),
|
|
84
|
-
sourceRoleNormalization('insurance_specialist', 'Insurance Specialist', /^sug['’ʻʼ‘`]?urta$/iu),
|
|
85
|
-
sourceRoleNormalization('bank_operations_specialist', 'Bank Operations Specialist', /^стаж[её]р\s+операционист|^операционист$/iu),
|
|
86
|
-
sourceRoleNormalization('commercial_director', 'Commercial Director', /^коммерческ\p{L}*\s+директор|\bchief\s+commercial\s+officer\b|\bCCO\b/iu),
|
|
87
|
-
sourceRoleNormalization('security_specialist', 'Security Specialist', /^по\s+безопасност\p{L}*\s+объекта$/iu),
|
|
88
|
-
sourceRoleNormalization('healthcare_specialist', 'Healthcare Specialist', /^mededsina$|^meditsina$|^медицина$/iu),
|
|
89
|
-
sourceRoleNormalization('tourism_hospitality_specialist', 'Tourism / Hospitality Specialist', /^mehmonxona[^\n]*turfirma|^turfirma[^\n]*mehmonxona/iu),
|
|
90
|
-
sourceRoleNormalization('confectioner', 'Confectioner', /qandolat|qandolatchi/iu),
|
|
91
|
-
]);
|
|
92
|
-
|
|
93
|
-
export function normalizeSourceRole(value) {
|
|
94
|
-
const text = String(value || '').trim();
|
|
95
|
-
if (!text) return null;
|
|
96
|
-
const match = SOURCE_ROLE_NORMALIZATION_RULES.find((entry) => entry.re.test(text));
|
|
97
|
-
return match ? Object.freeze({ canonical: match.canonical, label: match.label }) : null;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
export const SOURCE_CANDIDATE_INTENT_ALIASES = Object.freeze([
|
|
101
|
-
'работу ищу',
|
|
102
|
-
'роботу шукаю',
|
|
103
|
-
'срочно работу ищу',
|
|
104
|
-
'терміново роботу шукаю',
|
|
105
|
-
'могу работать',
|
|
106
|
-
'можу працювати',
|
|
107
|
-
]);
|
|
108
|
-
|
|
109
|
-
const SOURCE_CANDIDATE_INTENT_RE = aliasesToRegex(SOURCE_CANDIDATE_INTENT_ALIASES);
|
|
110
|
-
|
|
111
|
-
export function matchesSourceCandidateIntent(value) {
|
|
112
|
-
return SOURCE_CANDIDATE_INTENT_RE.test(String(value || ''));
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
const LABELS = new Map(SOURCE_PROFESSION_ALIASES.map((entry) => [entry.canonical, entry.label]));
|
|
116
|
-
const ACRONYMS = new Map([
|
|
117
|
-
['qa', 'QA'], ['hr', 'HR'], ['ui', 'UI'], ['ux', 'UX'], ['ai', 'AI'], ['ml', 'ML'],
|
|
118
|
-
['seo', 'SEO'], ['sre', 'SRE'], ['dba', 'DBA'], ['crm', 'CRM'], ['erp', 'ERP'], ['pmo', 'PMO'], ['it', 'IT'],
|
|
119
|
-
]);
|
|
120
|
-
|
|
121
|
-
export function professionDisplayLabel(canonical) {
|
|
122
|
-
if (!canonical) return '';
|
|
123
|
-
const explicit = LABELS.get(canonical);
|
|
124
|
-
if (explicit) return explicit;
|
|
125
|
-
return String(canonical).split('_').map((part) => ACRONYMS.get(part) || `${part.charAt(0).toUpperCase()}${part.slice(1)}`).join(' ');
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
function sourceMatches(text) {
|
|
129
|
-
const matches = [];
|
|
130
|
-
for (const entry of SOURCE_PROFESSION_ALIASES) {
|
|
131
|
-
const match = String(text || '').match(entry.re);
|
|
132
|
-
if (!match) continue;
|
|
133
|
-
matches.push({
|
|
134
|
-
canonical: entry.canonical,
|
|
135
|
-
group: entry.group,
|
|
136
|
-
family: entry.group,
|
|
137
|
-
score: 1,
|
|
138
|
-
strength: 'strong',
|
|
139
|
-
matched: match[0].trim(),
|
|
140
|
-
index: match.index ?? 0,
|
|
141
|
-
label: entry.label,
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
return matches;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* Combine the core taxonomy with real-source aliases. More specific matches
|
|
149
|
-
* suppress contained generic matches ("Chief Accountant" must not also become
|
|
150
|
-
* "Accountant"), while separate spans remain separate professions.
|
|
151
|
-
*/
|
|
152
|
-
export function matchExtendedProfessions(value, { limit = 5, allowWeak = true } = {}) {
|
|
153
|
-
const text = String(value || '');
|
|
154
|
-
if (!text) return [];
|
|
155
|
-
const base = matchProfessions(text, { limit: Math.max(limit * 4, 24), allowWeak }).map((match) => {
|
|
156
|
-
const index = text.toLocaleLowerCase().indexOf(String(match.matched || '').toLocaleLowerCase());
|
|
157
|
-
return { ...match, index: index < 0 ? 0 : index, label: professionDisplayLabel(match.canonical) };
|
|
158
|
-
});
|
|
159
|
-
const matches = [...base, ...sourceMatches(text)]
|
|
160
|
-
.sort((a, b) => b.score - a.score || b.matched.length - a.matched.length || a.index - b.index);
|
|
161
|
-
|
|
162
|
-
const selected = [];
|
|
163
|
-
const canonicals = new Set();
|
|
164
|
-
for (const match of matches) {
|
|
165
|
-
if (canonicals.has(match.canonical)) continue;
|
|
166
|
-
const start = match.index;
|
|
167
|
-
const end = start + match.matched.length;
|
|
168
|
-
const contained = selected.some((chosen) => {
|
|
169
|
-
const chosenStart = chosen.index;
|
|
170
|
-
const chosenEnd = chosenStart + chosen.matched.length;
|
|
171
|
-
return chosen.score >= match.score && chosenStart <= start && chosenEnd >= end && chosen.matched.length > match.matched.length;
|
|
172
|
-
});
|
|
173
|
-
if (contained) continue;
|
|
174
|
-
canonicals.add(match.canonical);
|
|
175
|
-
selected.push({ ...match });
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
// A concrete software role outranks a generic "IT specialist" mention in
|
|
179
|
-
// the same role/title text, even when the two aliases occupy separate spans.
|
|
180
|
-
const hasSoftwareRole = selected.some((match) => match.group === 'software_development');
|
|
181
|
-
const filtered = hasSoftwareRole
|
|
182
|
-
? selected.filter((match) => match.canonical !== 'it_specialist')
|
|
183
|
-
: selected;
|
|
184
|
-
|
|
185
|
-
return Object.freeze(filtered.slice(0, limit).map((match) => Object.freeze(match)));
|
|
1
|
+
import { aliasesToRegex } from './normalization.js';
|
|
2
|
+
import { matchProfessions } from './hiring-professions.js';
|
|
3
|
+
|
|
4
|
+
const sourceRole = (canonical, label, aliases, group = 'other') => Object.freeze({
|
|
5
|
+
canonical,
|
|
6
|
+
label,
|
|
7
|
+
group,
|
|
8
|
+
aliases: Object.freeze([...new Set(aliases)]),
|
|
9
|
+
re: aliasesToRegex([...new Set(aliases)]),
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Source spellings seen in real CV feeds which are too source-specific or
|
|
14
|
+
* colloquial for the core profession rows. They still live in the shared
|
|
15
|
+
* package so consumers do not grow their own profession regex catalogs.
|
|
16
|
+
*/
|
|
17
|
+
export const SOURCE_PROFESSION_ALIASES = Object.freeze([
|
|
18
|
+
sourceRole('chief_executive_officer', 'Chief Executive Officer', ['ceo', 'chief executive officer', 'генеральный директор', 'гендиректор', 'виконавчий директор'], 'management'),
|
|
19
|
+
sourceRole('chief_technology_officer', 'Chief Technology Officer', ['cto', 'chief technology officer', 'технический директор', 'технічний директор'], 'management'),
|
|
20
|
+
sourceRole('sales_manager', 'Sales Manager', ['sales executive', 'head of sales', 'менеджер экспортных продаж', 'менеджер по экспортным продажам', 'роп', 'sotuv menejer'], 'sales'),
|
|
21
|
+
sourceRole('driver', 'Driver', ['се категория', 'се категория буйича', 'ce категория', 'ce category', 'shafyor'], 'transport'),
|
|
22
|
+
sourceRole('accountant', 'Accountant', ['bugalteriya', 'buxgalteriya', 'buhgalteriya'], 'finance'),
|
|
23
|
+
sourceRole('cashier', 'Cashier', ['kassa xodimi', 'kassa mudiri'], 'retail'),
|
|
24
|
+
sourceRole('notary', 'Notary', ['notary', 'notarius', 'нотариус'], 'legal'),
|
|
25
|
+
sourceRole('metrology_specialist', 'Metrology Specialist', ['metrologiya', 'metrology specialist', 'метролог', 'standartlashtirish'], 'manufacturing'),
|
|
26
|
+
sourceRole('security_guard', 'Security Guard', ['xavfsizlik', 'qoriqlash', 'qo‘riqlash', "qo'riqlash", 'охорона'], 'security'),
|
|
27
|
+
sourceRole('finance_banking_specialist', 'Finance / Banking Specialist', ['finance specialist', 'banking specialist', 'moliya', 'soliq', 'bank'], 'finance'),
|
|
28
|
+
sourceRole('teacher', 'Teacher', ['tyutorlik', 'тьютор', 'titur', "o'qituvchilik", 'o‘qituvchilik', 'oʻqituvchilik', 'ustoz'], 'education'),
|
|
29
|
+
sourceRole('english_teacher', 'English Teacher', ['ingliz tili ustoziman', 'ingliz tili ustoz', 'ingliz tili oqituvchi', "ingliz tili o'qituvchi"], 'education'),
|
|
30
|
+
sourceRole('it_specialist', 'IT Specialist', ['it specialist', 'itishnik', 'it ishnik', 'kompyuter boyicha ish', "kompyuter bo'yicha ish", 'kompyuter bo‘yicha ish'], 'infrastructure'),
|
|
31
|
+
sourceRole('biotechnologist', 'Biotechnologist', ['biotechnologist', 'биотехнолог', 'biotexnolog'], 'medicine'),
|
|
32
|
+
sourceRole('laboratory_technician', 'Laboratory Technician', ['laborant'], 'medicine'),
|
|
33
|
+
sourceRole('media_specialist', 'Media Specialist', ['media specialist', 'специалист по сми', 'matbuot'], 'media_content'),
|
|
34
|
+
sourceRole('engineer', 'Engineer', ['engineer', 'инженер', 'інженер', 'muhandis', 'injiner'], 'engineering'),
|
|
35
|
+
sourceRole('chat_operator', 'Chat Operator', ['chat operatori'], 'customer_support'),
|
|
36
|
+
sourceRole('call_center_operator', 'Call Center Operator', ['koll-markaz operatori', 'koll markaz operatori', 'call-markaz operatori'], 'customer_support'),
|
|
37
|
+
sourceRole('consultant', 'Consultant', ['consultant', 'консультант', 'консультантка'], 'commercial'),
|
|
38
|
+
sourceRole('supervisor', 'Supervisor', ['supervisor', 'супервайзер', 'начальник отряд', 'начальник отряда'], 'management'),
|
|
39
|
+
sourceRole('quality_inspector', 'Quality Inspector', ['quality inspector', 'инспектор по качеству', 'інспектор з якості'], 'manufacturing'),
|
|
40
|
+
sourceRole('oil_gas_worker', 'Oil & Gas Worker', ['oil and gas', 'oil & gas', 'нефть и газ', 'нефтегаз', 'neft va gaz', 'neft vagaz', 'neft vagaz sohasida', 'neft va gaz sohasida'], 'manufacturing'),
|
|
41
|
+
sourceRole('cybersecurity_specialist', 'Cybersecurity Specialist', ['cybersecurity specialist', 'ciso', 'руководитель по информационной безопасности', 'руководитель информационной безопасности'], 'information_security'),
|
|
42
|
+
sourceRole('architect', 'Architect', ['arxitektor loyihachi', 'arxitektor'], 'construction'),
|
|
43
|
+
sourceRole('economist', 'Economist', ['iqtisodchi', 'iqtsodchi', 'iqtisodiy'], 'finance'),
|
|
44
|
+
sourceRole('logistics_manager', 'Logistics Specialist', ['logist', 'logistics specialist', 'логист'], 'logistics'),
|
|
45
|
+
sourceRole('frontend_developer', 'Frontend Developer', ['frontet', 'frontet developer', 'frontet dasturchi'], 'software_development'),
|
|
46
|
+
sourceRole('nanny', 'Nanny', ['bolalarga qarash', 'bolaga qarash'], 'education'),
|
|
47
|
+
sourceRole('loader', 'Loader', ['грузчиком', 'грузчика', 'грузчик'], 'logistics'),
|
|
48
|
+
sourceRole('welder', 'Welder', ['сварщиком', 'сварщица', 'зварювальником'], 'construction'),
|
|
49
|
+
]);
|
|
50
|
+
|
|
51
|
+
const sourceRoleNormalization = (canonical, label, re) => Object.freeze({ canonical, label, re });
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Anchored or strongly contextualized raw-role repairs. These rules are kept
|
|
55
|
+
* separate from SOURCE_PROFESSION_ALIASES so generic values such as `model`,
|
|
56
|
+
* `online`, or `bank` never become profession matches in arbitrary CV prose.
|
|
57
|
+
*/
|
|
58
|
+
export const SOURCE_ROLE_NORMALIZATION_RULES = Object.freeze([
|
|
59
|
+
sourceRoleNormalization('economist', 'Economist', /^iqt(?:i)?sodchi$/iu),
|
|
60
|
+
sourceRoleNormalization('economist', 'Economist', /^iqtisodiy$/iu),
|
|
61
|
+
sourceRoleNormalization('logistics_manager', 'Logistics Specialist', /^logist(?:ika)?(?:\s+updater)?$/iu),
|
|
62
|
+
sourceRoleNormalization('english_teacher', 'English Teacher', /^ingliz\s+tili\s+ustoz(?:iman)?$/iu),
|
|
63
|
+
sourceRoleNormalization('frontend_developer', 'Frontend Developer', /mobilagraf[\s\S]*itishnik[\s\S]*front(?:et|ent|end)/iu),
|
|
64
|
+
sourceRoleNormalization('nanny', 'Nanny', /farqi\s+yo[\s\S]*bolalarga\s+qarash/iu),
|
|
65
|
+
sourceRoleNormalization('sales_manager', 'Sales Manager', /^(?:sales\s+executive(?:\s+ind)?|роп(?:,?\s*sales\s+executive)?)$/iu),
|
|
66
|
+
sourceRoleNormalization('operative_officer', 'Operative Officer', /^(?:оперативник|оперуполномоченн\p{L}*|оперативный\s+уполномоченн\p{L}*)$/iu),
|
|
67
|
+
sourceRoleNormalization('water_supply_specialist', 'Water Supply Specialist', /^(?:suv\s+ta['’ʻʼ‘`]?minoti|водоснабжение)$/iu),
|
|
68
|
+
sourceRoleNormalization('any_role', 'Any Role', /^(?:onlayn(?:\s+ish(?:chi)?)?|online(?:\s+ish(?:chi)?)?|онлайн|удал[её]нно|remote(?:\s+work)?|boshqa\s+ishlar?|farqi\s+(?:yo['’ʻʼ‘`]?q|yuq)|tungi|bilmaym\p{L}*)$/iu),
|
|
69
|
+
sourceRoleNormalization('restaurant_cafe_worker', 'Restaurant / Cafe Worker', /^ищу\s+работу\s+(?:в\s+)?(?:кафе|ресторанах?|кафе\s+или\s+ресторанах)$/iu),
|
|
70
|
+
sourceRoleNormalization('driver', 'Driver', /^(?:xaydovchilik|haydovchilik|shafyorlik|shofyorlik)/iu),
|
|
71
|
+
sourceRoleNormalization('retail_worker', 'Retail Worker', /^do['’ʻʼ‘`]?kon$/iu),
|
|
72
|
+
sourceRoleNormalization('salesperson', 'Salesperson', /^(?:savdo|sotuvchi)$/iu),
|
|
73
|
+
sourceRoleNormalization('pharmacist', 'Pharmacist', /^(?:dorishunos|farmatsevt)$/iu),
|
|
74
|
+
sourceRoleNormalization('notary_assistant', 'Notary Assistant', /^(?:natarus|notarius)\s+yordamchisi/iu),
|
|
75
|
+
sourceRoleNormalization('librarian', 'Librarian', /^kutubxonachi$/iu),
|
|
76
|
+
sourceRoleNormalization('singer_vocalist', 'Singer / Vocalist', /^(?:vokal\s*:\s*)?xonanda$/iu),
|
|
77
|
+
sourceRoleNormalization('model', 'Model', /^model$/iu),
|
|
78
|
+
sourceRoleNormalization('flight_attendant', 'Flight Attendant', /^bortprovodnik$|^бортпроводник$/iu),
|
|
79
|
+
sourceRoleNormalization('hvac_technician', 'HVAC Technician', /^(?:konditsaner|kanditsaner|konditsioner)/iu),
|
|
80
|
+
sourceRoleNormalization('mobile_content_creator', 'Mobile Content Creator', /^mobilografiya(?:\s+bo['’ʻʼ‘`]?yicha)?$/iu),
|
|
81
|
+
sourceRoleNormalization('cctv_intercom_technician', 'CCTV / Intercom Technician', /kamera\s+(?:dama?fon|domofon)|domofon\s+xizmat/iu),
|
|
82
|
+
sourceRoleNormalization('internal_control_specialist', 'Internal Control Specialist', /^ichki\s+nazoratchi$/iu),
|
|
83
|
+
sourceRoleNormalization('brand_ambassador', 'Brand Ambassador', /^(?:бренд\s+фейс|brand\s+face)$/iu),
|
|
84
|
+
sourceRoleNormalization('insurance_specialist', 'Insurance Specialist', /^sug['’ʻʼ‘`]?urta$/iu),
|
|
85
|
+
sourceRoleNormalization('bank_operations_specialist', 'Bank Operations Specialist', /^стаж[её]р\s+операционист|^операционист$/iu),
|
|
86
|
+
sourceRoleNormalization('commercial_director', 'Commercial Director', /^коммерческ\p{L}*\s+директор|\bchief\s+commercial\s+officer\b|\bCCO\b/iu),
|
|
87
|
+
sourceRoleNormalization('security_specialist', 'Security Specialist', /^по\s+безопасност\p{L}*\s+объекта$/iu),
|
|
88
|
+
sourceRoleNormalization('healthcare_specialist', 'Healthcare Specialist', /^mededsina$|^meditsina$|^медицина$/iu),
|
|
89
|
+
sourceRoleNormalization('tourism_hospitality_specialist', 'Tourism / Hospitality Specialist', /^mehmonxona[^\n]*turfirma|^turfirma[^\n]*mehmonxona/iu),
|
|
90
|
+
sourceRoleNormalization('confectioner', 'Confectioner', /qandolat|qandolatchi/iu),
|
|
91
|
+
]);
|
|
92
|
+
|
|
93
|
+
export function normalizeSourceRole(value) {
|
|
94
|
+
const text = String(value || '').trim();
|
|
95
|
+
if (!text) return null;
|
|
96
|
+
const match = SOURCE_ROLE_NORMALIZATION_RULES.find((entry) => entry.re.test(text));
|
|
97
|
+
return match ? Object.freeze({ canonical: match.canonical, label: match.label }) : null;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export const SOURCE_CANDIDATE_INTENT_ALIASES = Object.freeze([
|
|
101
|
+
'работу ищу',
|
|
102
|
+
'роботу шукаю',
|
|
103
|
+
'срочно работу ищу',
|
|
104
|
+
'терміново роботу шукаю',
|
|
105
|
+
'могу работать',
|
|
106
|
+
'можу працювати',
|
|
107
|
+
]);
|
|
108
|
+
|
|
109
|
+
const SOURCE_CANDIDATE_INTENT_RE = aliasesToRegex(SOURCE_CANDIDATE_INTENT_ALIASES);
|
|
110
|
+
|
|
111
|
+
export function matchesSourceCandidateIntent(value) {
|
|
112
|
+
return SOURCE_CANDIDATE_INTENT_RE.test(String(value || ''));
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const LABELS = new Map(SOURCE_PROFESSION_ALIASES.map((entry) => [entry.canonical, entry.label]));
|
|
116
|
+
const ACRONYMS = new Map([
|
|
117
|
+
['qa', 'QA'], ['hr', 'HR'], ['ui', 'UI'], ['ux', 'UX'], ['ai', 'AI'], ['ml', 'ML'],
|
|
118
|
+
['seo', 'SEO'], ['sre', 'SRE'], ['dba', 'DBA'], ['crm', 'CRM'], ['erp', 'ERP'], ['pmo', 'PMO'], ['it', 'IT'],
|
|
119
|
+
]);
|
|
120
|
+
|
|
121
|
+
export function professionDisplayLabel(canonical) {
|
|
122
|
+
if (!canonical) return '';
|
|
123
|
+
const explicit = LABELS.get(canonical);
|
|
124
|
+
if (explicit) return explicit;
|
|
125
|
+
return String(canonical).split('_').map((part) => ACRONYMS.get(part) || `${part.charAt(0).toUpperCase()}${part.slice(1)}`).join(' ');
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function sourceMatches(text) {
|
|
129
|
+
const matches = [];
|
|
130
|
+
for (const entry of SOURCE_PROFESSION_ALIASES) {
|
|
131
|
+
const match = String(text || '').match(entry.re);
|
|
132
|
+
if (!match) continue;
|
|
133
|
+
matches.push({
|
|
134
|
+
canonical: entry.canonical,
|
|
135
|
+
group: entry.group,
|
|
136
|
+
family: entry.group,
|
|
137
|
+
score: 1,
|
|
138
|
+
strength: 'strong',
|
|
139
|
+
matched: match[0].trim(),
|
|
140
|
+
index: match.index ?? 0,
|
|
141
|
+
label: entry.label,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
return matches;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Combine the core taxonomy with real-source aliases. More specific matches
|
|
149
|
+
* suppress contained generic matches ("Chief Accountant" must not also become
|
|
150
|
+
* "Accountant"), while separate spans remain separate professions.
|
|
151
|
+
*/
|
|
152
|
+
export function matchExtendedProfessions(value, { limit = 5, allowWeak = true } = {}) {
|
|
153
|
+
const text = String(value || '');
|
|
154
|
+
if (!text) return [];
|
|
155
|
+
const base = matchProfessions(text, { limit: Math.max(limit * 4, 24), allowWeak }).map((match) => {
|
|
156
|
+
const index = text.toLocaleLowerCase().indexOf(String(match.matched || '').toLocaleLowerCase());
|
|
157
|
+
return { ...match, index: index < 0 ? 0 : index, label: professionDisplayLabel(match.canonical) };
|
|
158
|
+
});
|
|
159
|
+
const matches = [...base, ...sourceMatches(text)]
|
|
160
|
+
.sort((a, b) => b.score - a.score || b.matched.length - a.matched.length || a.index - b.index);
|
|
161
|
+
|
|
162
|
+
const selected = [];
|
|
163
|
+
const canonicals = new Set();
|
|
164
|
+
for (const match of matches) {
|
|
165
|
+
if (canonicals.has(match.canonical)) continue;
|
|
166
|
+
const start = match.index;
|
|
167
|
+
const end = start + match.matched.length;
|
|
168
|
+
const contained = selected.some((chosen) => {
|
|
169
|
+
const chosenStart = chosen.index;
|
|
170
|
+
const chosenEnd = chosenStart + chosen.matched.length;
|
|
171
|
+
return chosen.score >= match.score && chosenStart <= start && chosenEnd >= end && chosen.matched.length > match.matched.length;
|
|
172
|
+
});
|
|
173
|
+
if (contained) continue;
|
|
174
|
+
canonicals.add(match.canonical);
|
|
175
|
+
selected.push({ ...match });
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// A concrete software role outranks a generic "IT specialist" mention in
|
|
179
|
+
// the same role/title text, even when the two aliases occupy separate spans.
|
|
180
|
+
const hasSoftwareRole = selected.some((match) => match.group === 'software_development');
|
|
181
|
+
const filtered = hasSoftwareRole
|
|
182
|
+
? selected.filter((match) => match.canonical !== 'it_specialist')
|
|
183
|
+
: selected;
|
|
184
|
+
|
|
185
|
+
return Object.freeze(filtered.slice(0, limit).map((match) => Object.freeze(match)));
|
|
186
186
|
}
|
|
@@ -1,31 +1,31 @@
|
|
|
1
|
-
import type { SalaryParseResult } from '../index.d.ts';
|
|
2
|
-
|
|
3
|
-
export type CandidateExperienceMention = Readonly<{ years: number; context: string; approximate?: true }>;
|
|
4
|
-
export type VisaSponsorshipWording = 'offered' | 'notOffered' | null;
|
|
5
|
-
|
|
6
|
-
export function extractCandidateStructuredField(value: unknown, key: string, maxLength?: number): string | null;
|
|
7
|
-
export function extractJobStructuredField(value: unknown, key: string, maxLength?: number): string | null;
|
|
8
|
-
export function extractCandidateDisplayName(value: unknown): string;
|
|
9
|
-
export function extractCandidateExperienceMentions(value: unknown): readonly CandidateExperienceMention[];
|
|
10
|
-
export function parseHiringSourceSalary(value: unknown): SalaryParseResult | null;
|
|
11
|
-
export function parseCandidateSalary(value: unknown, country?: string): SalaryParseResult | null;
|
|
12
|
-
export function detectUsLocation(value: unknown): boolean;
|
|
13
|
-
export function detectVisaSponsorshipWording(value: unknown): VisaSponsorshipWording;
|
|
14
|
-
export const TEMPORARY_WORK_AUTH_RE: RegExp;
|
|
15
|
-
export function detectRecruitmentAgency(value: unknown): boolean;
|
|
16
|
-
export function extractNiceToHaveContext(value: unknown, maxLength?: number): string;
|
|
17
|
-
export type CandidatePostSignals = Readonly<{
|
|
18
|
-
candidateForm: boolean;
|
|
19
|
-
cvMarker: boolean;
|
|
20
|
-
firstPerson: boolean;
|
|
21
|
-
personalProfile: boolean;
|
|
22
|
-
contact: boolean;
|
|
23
|
-
emptyRecommendation: boolean;
|
|
24
|
-
sectionCount: number;
|
|
25
|
-
}>;
|
|
26
|
-
export function detectCandidatePostSignals(value: unknown): CandidatePostSignals;
|
|
27
|
-
export function extractCandidateStructuredBlock(value: unknown, key: string, maxLength?: number): string | null;
|
|
28
|
-
export function defaultHiringCurrency(country: unknown): string | null;
|
|
29
|
-
export function isHiringCharityAppeal(value: unknown): boolean;
|
|
30
|
-
export function isHiringRecruitingOpportunity(value: unknown): boolean;
|
|
31
|
-
export function sameHiringProfessionFamily(a: unknown, b: unknown): boolean;
|
|
1
|
+
import type { SalaryParseResult } from '../index.d.ts';
|
|
2
|
+
|
|
3
|
+
export type CandidateExperienceMention = Readonly<{ years: number; context: string; approximate?: true }>;
|
|
4
|
+
export type VisaSponsorshipWording = 'offered' | 'notOffered' | null;
|
|
5
|
+
|
|
6
|
+
export function extractCandidateStructuredField(value: unknown, key: string, maxLength?: number): string | null;
|
|
7
|
+
export function extractJobStructuredField(value: unknown, key: string, maxLength?: number): string | null;
|
|
8
|
+
export function extractCandidateDisplayName(value: unknown): string;
|
|
9
|
+
export function extractCandidateExperienceMentions(value: unknown): readonly CandidateExperienceMention[];
|
|
10
|
+
export function parseHiringSourceSalary(value: unknown): SalaryParseResult | null;
|
|
11
|
+
export function parseCandidateSalary(value: unknown, country?: string): SalaryParseResult | null;
|
|
12
|
+
export function detectUsLocation(value: unknown): boolean;
|
|
13
|
+
export function detectVisaSponsorshipWording(value: unknown): VisaSponsorshipWording;
|
|
14
|
+
export const TEMPORARY_WORK_AUTH_RE: RegExp;
|
|
15
|
+
export function detectRecruitmentAgency(value: unknown): boolean;
|
|
16
|
+
export function extractNiceToHaveContext(value: unknown, maxLength?: number): string;
|
|
17
|
+
export type CandidatePostSignals = Readonly<{
|
|
18
|
+
candidateForm: boolean;
|
|
19
|
+
cvMarker: boolean;
|
|
20
|
+
firstPerson: boolean;
|
|
21
|
+
personalProfile: boolean;
|
|
22
|
+
contact: boolean;
|
|
23
|
+
emptyRecommendation: boolean;
|
|
24
|
+
sectionCount: number;
|
|
25
|
+
}>;
|
|
26
|
+
export function detectCandidatePostSignals(value: unknown): CandidatePostSignals;
|
|
27
|
+
export function extractCandidateStructuredBlock(value: unknown, key: string, maxLength?: number): string | null;
|
|
28
|
+
export function defaultHiringCurrency(country: unknown): string | null;
|
|
29
|
+
export function isHiringCharityAppeal(value: unknown): boolean;
|
|
30
|
+
export function isHiringRecruitingOpportunity(value: unknown): boolean;
|
|
31
|
+
export function sameHiringProfessionFamily(a: unknown, b: unknown): boolean;
|