-
Notifications
You must be signed in to change notification settings - Fork 4
fix(parser): ignore language proficiency rows #865
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | |||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -304,6 +304,25 @@ const SUBLABEL_PREFIX_RE = new RegExp(`^(${SUBLABEL_BODY}):\\s*`); | ||||||||||||||||
| * tore off its body. See the rejoin in `splitColumnCells`. */ | |||||||||||||||||
| const BARE_SUBLABEL_RE = new RegExp(`^${SUBLABEL_BODY}:$`); | |||||||||||||||||
|
|
|||||||||||||||||
| /** A Skills sub-label that MAY head a spoken-language row. Deliberately NOT | |||||||||||||||||
| * added to NON_SKILL_SUBLABEL_RE: on most engineering résumés `Languages:` | |||||||||||||||||
| * heads the programming-language row, so the label is ambiguous and the body | |||||||||||||||||
| * must decide whether this is a proficiency statement. */ | |||||||||||||||||
| const LANGUAGE_LABEL_RE = /^languages?$/i; | |||||||||||||||||
|
|
|||||||||||||||||
| /** A spoken-language proficiency predication, distinguished from a delimited | |||||||||||||||||
| * programming-language list by its proficiency wording rather than by the | |||||||||||||||||
| * label. */ | |||||||||||||||||
| const LANGUAGE_PROFICIENCY_BODY_RE = | |||||||||||||||||
| /\b(fluent|native|bilingual|conversational|proficient|intermediate|beginner|basic|working\s+proficiency|mother\s+tongue)\b/i; | |||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Secondary. The vocabulary misses the standard scale wordings:
The last is drawn by two committed fixtures — Adding |
|||||||||||||||||
|
|
|||||||||||||||||
| function isLanguageProficiencyCell(cell: string): boolean { | |||||||||||||||||
| const debulleted = stripBullet(cell); | |||||||||||||||||
| const match = debulleted.match(SUBLABEL_PREFIX_RE); | |||||||||||||||||
| if (!match || !LANGUAGE_LABEL_RE.test(match[1])) return false; | |||||||||||||||||
| return LANGUAGE_PROFICIENCY_BODY_RE.test(debulleted.slice(match[0].length)); | |||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Blocking. This tests the proficiency vocabulary against the whole body, so a delimited programming-language row containing one matching word is dropped entirely — and Measured on this branch vs
#833 step 1 specifies the body conjunct as "a proficiency predication rather than a delimited list" — the delimited-list half is missing. Requiring every delimited fragment to be a proficiency predication satisfies all four ACs and rejects all four rows above: const fragments = debulleted
.slice(match[0].length)
.split(SKILL_SPLIT_RE)
.map((f) => f.trim())
.filter((f) => f !== "");
return fragments.length > 0 && fragments.every((f) => LANGUAGE_PROFICIENCY_BODY_RE.test(f));( |
|||||||||||||||||
| } | |||||||||||||||||
|
|
|||||||||||||||||
| /** | |||||||||||||||||
| * Tokenizes a single column cell into valid skill tokens and adds them to | |||||||||||||||||
| * `out`. Drops the cell entirely when it looks like a contact/profile link — | |||||||||||||||||
|
|
@@ -317,7 +336,11 @@ function tokenizeCell(cell: string, out: Set<string>): void { | ||||||||||||||||
| // leading `Label:` prefix and drop the whole cell when it names a | |||||||||||||||||
| // hobbies/interests list — before the label is stripped and the items split. | |||||||||||||||||
| const labelMatch = debulleted.match(SUBLABEL_PREFIX_RE); | |||||||||||||||||
| if (labelMatch && NON_SKILL_SUBLABEL_RE.test(labelMatch[1])) return; | |||||||||||||||||
| if ( | |||||||||||||||||
| labelMatch && | |||||||||||||||||
| (NON_SKILL_SUBLABEL_RE.test(labelMatch[1]) || isLanguageProficiencyCell(debulleted)) | |||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Blocking. Returning here yields zero tokens, so
Note the all-fragments fix for the other blocker does not resolve this: |
|||||||||||||||||
| ) | |||||||||||||||||
| return; | |||||||||||||||||
| const clean = debulleted.replace(SUBLABEL_PREFIX_RE, ""); | |||||||||||||||||
| // A whole cell that is a profile link ("github.com/janesmith") must be | |||||||||||||||||
| // dropped before splitting — a path slash would otherwise leave the path | |||||||||||||||||
|
|
@@ -616,7 +639,12 @@ function upcomingContinuationTexts(lineCells: string[][], from: number): string[ | ||||||||||||||||
| */ | |||||||||||||||||
| function matchCellLabel(cell: string): string | undefined { | |||||||||||||||||
| const m = stripBullet(cell).match(SUBLABEL_PREFIX_RE); | |||||||||||||||||
| if (!m || NON_SKILL_SUBLABEL_RE.test(m[1])) return undefined; | |||||||||||||||||
| if ( | |||||||||||||||||
| !m || | |||||||||||||||||
| NON_SKILL_SUBLABEL_RE.test(m[1]) || | |||||||||||||||||
| isLanguageProficiencyCell(cell) | |||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit. Unreachable: Related: this passes the raw |
|||||||||||||||||
| ) | |||||||||||||||||
| return undefined; | |||||||||||||||||
| return m[1].trim(); | |||||||||||||||||
| } | |||||||||||||||||
|
|
|||||||||||||||||
|
|
|||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Secondary. Stricter than its sibling
NON_SKILL_SUBLABEL_RE, so #833's defect survives on common variants. All still admitted on this branch:Foreign Languages: Fluent in Spanish→["Fluent in Spanish"]Spoken Languages: Native German, conversational French→["Native German","conversational French"]Languages : Fluent in Spanish→["Fluent in Spanish"]The third is a capture artifact:
SUBLABEL_BODY([A-Z][A-Za-z &/]+) admits a space, so the capture is"Languages ".NON_SKILL_SUBLABEL_REcarries a deliberate\s*$for exactly this andmatchCellLabel.trim()s the capture — this regex does neither, soInterests : Tennisis dropped whileLanguages : Fluent in Spanishescapes./^(?:foreign\s+|spoken\s+|other\s+)?languages?\s*$/imirrors the sibling's leading-qualifier tolerance and covers all three.