@whiteslove/parsing-lexicon 0.5.3 → 0.5.5
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
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@whiteslove/parsing-lexicon",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.5",
|
|
4
4
|
"description": "Shared deterministic multilingual parsing lexicon for WhitesLove housing and hiring services",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -176,6 +176,10 @@
|
|
|
176
176
|
"import": "./src/housing-money.js"
|
|
177
177
|
},
|
|
178
178
|
"./hiring-professions": "./src/hiring-professions.js",
|
|
179
|
+
"./hiring-profession-display": {
|
|
180
|
+
"types": "./src/hiring-profession-display.d.ts",
|
|
181
|
+
"import": "./src/hiring-profession-display.js"
|
|
182
|
+
},
|
|
179
183
|
"./hiring-skills": {
|
|
180
184
|
"types": "./src/hiring-skills.d.ts",
|
|
181
185
|
"import": "./src/hiring-skills.js"
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { matchProfession, professionByCanonical } from './hiring-professions.js';
|
|
2
|
+
|
|
3
|
+
const PROFESSION_ACRONYMS = Object.freeze(new Map([
|
|
4
|
+
['ai', 'AI'],
|
|
5
|
+
['api', 'API'],
|
|
6
|
+
['bi', 'BI'],
|
|
7
|
+
['crm', 'CRM'],
|
|
8
|
+
['dba', 'DBA'],
|
|
9
|
+
['erp', 'ERP'],
|
|
10
|
+
['grc', 'GRC'],
|
|
11
|
+
['hr', 'HR'],
|
|
12
|
+
['ios', 'iOS'],
|
|
13
|
+
['ml', 'ML'],
|
|
14
|
+
['pmo', 'PMO'],
|
|
15
|
+
['qa', 'QA'],
|
|
16
|
+
['seo', 'SEO'],
|
|
17
|
+
['sre', 'SRE'],
|
|
18
|
+
['ui', 'UI'],
|
|
19
|
+
['ux', 'UX'],
|
|
20
|
+
]));
|
|
21
|
+
|
|
22
|
+
function titleCaseCanonical(canonical) {
|
|
23
|
+
return String(canonical || '')
|
|
24
|
+
.split('_')
|
|
25
|
+
.filter(Boolean)
|
|
26
|
+
.map((part) => PROFESSION_ACRONYMS.get(part) || `${part.charAt(0).toUpperCase()}${part.slice(1)}`)
|
|
27
|
+
.join(' ');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Return one deterministic display label for a profession owned by this package.
|
|
32
|
+
*
|
|
33
|
+
* This is intentionally not a search transliteration API. Search folding and
|
|
34
|
+
* alias matching remain separate concerns. Unknown values are returned trimmed
|
|
35
|
+
* instead of being locally transliterated or guessed by consumers.
|
|
36
|
+
*/
|
|
37
|
+
export function professionDisplayName(value) {
|
|
38
|
+
const raw = String(value ?? '').trim();
|
|
39
|
+
if (!raw) return '';
|
|
40
|
+
|
|
41
|
+
const exact = professionByCanonical(raw);
|
|
42
|
+
if (exact) return titleCaseCanonical(exact.canonical);
|
|
43
|
+
|
|
44
|
+
const match = matchProfession(raw, { allowWeak: false });
|
|
45
|
+
return match ? titleCaseCanonical(match.canonical) : raw;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function professionCanonicalDisplayName(canonical) {
|
|
49
|
+
const entry = professionByCanonical(String(canonical ?? '').trim());
|
|
50
|
+
return entry ? titleCaseCanonical(entry.canonical) : '';
|
|
51
|
+
}
|
|
@@ -3,6 +3,7 @@ import type { SalaryParseResult } from '../index.d.ts';
|
|
|
3
3
|
export type CandidateExperienceMention = Readonly<{ years: number; context: string; approximate?: true }>;
|
|
4
4
|
export type VisaSponsorshipWording = 'offered' | 'notOffered' | null;
|
|
5
5
|
|
|
6
|
+
export function cleanHiringSourceText(value: unknown): string;
|
|
6
7
|
export function extractCandidateStructuredField(value: unknown, key: string, maxLength?: number): string | null;
|
|
7
8
|
export function extractJobStructuredField(value: unknown, key: string, maxLength?: number): string | null;
|
|
8
9
|
export function extractCandidateDisplayName(value: unknown): string;
|
|
@@ -21,6 +21,18 @@ const FIELD_EXTRA_ALIASES = Object.freeze({
|
|
|
21
21
|
}),
|
|
22
22
|
});
|
|
23
23
|
|
|
24
|
+
const APPLICATION_MODAL_RE = /(?:отправить\s+резюме\s+)?пол\s+мужской\s+женский\s+образование[\s\S]{0,500}?выберите\s+вакансию[\s\S]*/iu;
|
|
25
|
+
const LEAKED_CSS_RULE_RE = /\s*[.#][\w\\-]+(?:\s+[.#][\w\\-]+)?(?::[\w-]+)?\s*\{\s*(?:[\w-]+\s*:\s*[^;{}]+;?\s*)+\}\s*/gu;
|
|
26
|
+
|
|
27
|
+
/** Remove source-page controls and stylesheet fragments copied into vacancy text. */
|
|
28
|
+
export function cleanHiringSourceText(value) {
|
|
29
|
+
return String(value || '')
|
|
30
|
+
.replace(APPLICATION_MODAL_RE, '')
|
|
31
|
+
.replace(LEAKED_CSS_RULE_RE, ' ')
|
|
32
|
+
.replace(/[ \t]+(?=\n)/g, '')
|
|
33
|
+
.trim();
|
|
34
|
+
}
|
|
35
|
+
|
|
24
36
|
function entryAliases(entry, extras = []) {
|
|
25
37
|
return [...new Set([entry?.canonical, ...aliasesOf(entry || {}), ...extras].filter(Boolean))];
|
|
26
38
|
}
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import { detectDegreeLevel } from './hiring-requirements.js';
|
|
2
|
+
import { cleanHiringSourceText } from './hiring-source-semantics.js';
|
|
2
3
|
import { normalizeUnicode } from './normalization.js';
|
|
3
4
|
|
|
4
5
|
export function detectHiringEducation(value) {
|
|
5
|
-
|
|
6
|
+
// Some vacancy pages append the fields of their application modal to the
|
|
7
|
+
// vacancy body. Degree choices in that UI describe the applicant form, not
|
|
8
|
+
// the vacancy requirement (for example: "Пол Мужской Женский Образование
|
|
9
|
+
// ... Высшее специалитет, магистратура Выберите вакансию").
|
|
10
|
+
const text = cleanHiringSourceText(value);
|
|
6
11
|
// Vacancy requirements often state "Bachelor's or Master's degree". That is
|
|
7
12
|
// an accepted-alternative list, not a Master's minimum; expose the least
|
|
8
13
|
// restrictive accepted level so filters do not hide valid Bachelor holders.
|