Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions src/lib/heuristics/extract/education.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -947,3 +947,59 @@ describe("extractEducation — cleanField strips leftover edge middot and bullet
expect(value[0].field).toBeUndefined();
});
});

describe("extractEducation — parseDegreeAndField strips middot/bullet before in/of connective (#839)", () => {
it("strips middot then in connective from degree field", () => {
const { value } = extractEducation(
mkEduSection([
"Springfield State University",
"B.S. · in Computer Science",
]),
);
expect(value).toHaveLength(1);
expect(value[0].degree).toBe("B.S.");
expect(value[0].field).toBe("Computer Science");
});

it("strips bullet then of connective from degree field", () => {
const { value } = extractEducation(
mkEduSection([
"Springfield State University",
"B.S. • of Computer Science",
]),
);
expect(value).toHaveLength(1);
expect(value[0].degree).toBe("B.S.");
expect(value[0].field).toBe("Computer Science");
});

it("still strips hyphen and em dash before in connective", () => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit — this test and the interior-middot one below it pass identically before and after the change. I confirmed by reverting education.ts to origin/main and running just this describe block: the two middot/bullet cases fail, these two pass. That is correct — AC 3 and AC 4 of #839 asked for them precisely so the fix is pinned as a widening rather than a rewrite — but a later reader scanning a #839 describe block will reasonably read all four as evidence the fix works. One line of comment saying these two are regression guards ("unchanged by #839; here so a future narrowing of the class is caught") would carry that.

Second, smaller: expect(hyphen[0].field) and expect(emDash[0].field) index into the array without an expect(...).toHaveLength(1) first, unlike the two tests above. If a future change split this header into two entries, [0] would still satisfy the assertion and the test would stay green on a real regression.

const { value: hyphen } = extractEducation(
mkEduSection([
"Springfield State University",
"B.S. - in Computer Science",
]),
);
expect(hyphen[0].field).toBe("Computer Science");

const { value: emDash } = extractEducation(
mkEduSection([
"Springfield State University",
"B.S. — in Computer Science",
]),
);
expect(emDash[0].field).toBe("Computer Science");
});

it("preserves interior middot in a two-part field name", () => {
const { value } = extractEducation(
mkEduSection([
"Springfield State University",
"B.S. Mathematics · Statistics",
]),
);
expect(value).toHaveLength(1);
expect(value[0].degree).toBe("B.S.");
expect(value[0].field).toBe("Mathematics · Statistics");
});
});
9 changes: 7 additions & 2 deletions src/lib/heuristics/extract/education.ts
Original file line number Diff line number Diff line change
Expand Up @@ -533,9 +533,14 @@ function parseDegreeAndField(line: string): {
}
const fieldRaw = line
.slice(fieldStart)
// Drop a leading "in "/"of " connective or a "-"/"—"/":"/"," separator.
// Drop a leading "in "/"of " connective or a "-"/"–"/"—"/","/":"/"·"/"•"
// separator. The middot/bullet live here, not only in `cleanField`, because
// this strip runs FIRST — `cleanField`'s edge strip accepted them already but
// runs after the connective strips, too late to rescue a "· in <field>"
// header (#839). The two classes still differ (`cleanField` also takes ";");
// unifying the separator vocabulary repo-wide is #653.
.replace(/^\s*(?:in|of)\s+/i, "")
.replace(/^\s*[-–—,:]\s*/, "")
.replace(/^\s*[-–—,:·•]\s*/, "")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Secondary — the two classes still disagree, one glyph over. cleanField's edge strip is [\s,;:·•–\-—]; this one is [-–—,:·•]. The ; is in the first and not the second, and the ordering that caused #839 is unchanged — this strip runs before the two connective strips, cleanField runs after. Verified on the pushed head by probing extractEducation directly:

"B.S. ; in Computer Science"  → degree "B.S.", field "in Computer Science"    ← still leaks
"B.S. · in Computer Science"  → degree "B.S.", field "Computer Science"       ← fixed by this PR
"B.S. ‣ in Computer Science"  → degree "B.S.", field "‣ in Computer Science"  ← in neither class

Not blocking: ; is outside #839's acceptance criteria, the issue explicitly hands separator-vocabulary unification to #653, and a Degree ; in Field header is rarer still than the middot one. Flagging it because it is exactly the class of finding #839 was, and the next reader of these two strips will again assume they agree. If you want to close it here rather than leave it to #653, the issue's own step 3 is the shape: one module-level const EDGE_SEPARATOR_CLASS consumed by both strips, which makes the drift impossible instead of merely unlikely. Either way this PR is approved as-is.

.replace(/^\s*(?:in|of)\s+/i, "");
return { degree, field: cleanField(fieldRaw) };
}
Expand Down
Loading