78db55d499
- Name normalization completed: NICKNAMES table (Matt↔Matthew, Mike↔Michael...)
resolved in nameKey, parenthetical team-tag strip "(STL)", verified accent-fold
(Iván/Ivan, José/Jose). Slate strip now DISPLAYS the normalized de-dotted name
("AJ Ewing" not "A.J. Ewing") via buildPlayerStripsFromProps.
- Complete MLB VYNDR INTELLIGENCE: mlbGameLogFeatures derives rest_days (days off
between latest games; 0=B2B) + ab_per_game (usage). buildIntelFields renders
usage as "X AB/G", rest as B2B/Xd, matchup from bvp_advantage fallback.
- Ticker SCAN dedup: pushTickerItems keeps one SCAN per sport (sport field or
text-prefix parse for legacy); MOVE/GRADE preserved; cap 50.
- BOMBER threshold prorated for mid-season (hr>=15 strong / >=10 mod) so June
sluggers classify BOMBER not FLEX/DRIVER.
Backend 2122 -> 2149 tests (+27), 179 suites. Web build clean (exit 0).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
73 lines
2.9 KiB
JavaScript
73 lines
2.9 KiB
JavaScript
// Session 47 — Phase 1: complete name normalization (accents, nicknames, parens,
|
|
// display de-dotting).
|
|
|
|
const be = require('../../src/utils/playerName');
|
|
const fe = require('../../web/src/lib/playerName');
|
|
const slate = require('../../web/src/lib/slateAdapter');
|
|
|
|
describe('accent folding', () => {
|
|
it('"Iván Herrera" and "Ivan Herrera" share a key', () => {
|
|
expect(be.nameKey('Iván Herrera')).toBe(be.nameKey('Ivan Herrera'));
|
|
expect(be.nameKey('Iván Herrera')).toBe('ivan herrera');
|
|
});
|
|
it('"José Caballero" and "Jose Caballero" share a key', () => {
|
|
expect(be.nameKey('José Caballero')).toBe(be.nameKey('Jose Caballero'));
|
|
});
|
|
it('keeps the accent in display', () => {
|
|
expect(be.normalizeName('Iván Herrera').display).toBe('Iván Herrera');
|
|
});
|
|
});
|
|
|
|
describe('nickname resolution', () => {
|
|
it('"Matt Liberatore" === "Matthew Liberatore"', () => {
|
|
expect(be.nameKey('Matt Liberatore')).toBe(be.nameKey('Matthew Liberatore'));
|
|
expect(be.nameKey('Matt Liberatore')).toBe('matthew liberatore');
|
|
});
|
|
it('"Mike Massey" === "Michael Massey"', () => {
|
|
expect(be.nameKey('Mike Massey')).toBe(be.nameKey('Michael Massey'));
|
|
});
|
|
it('does not touch the last name', () => {
|
|
// "Matt" first name resolves; a player whose LAST name is Matt-like is unaffected
|
|
expect(be.nameKey('John Matthews')).toBe('john matthews');
|
|
});
|
|
});
|
|
|
|
describe('parenthetical team tags', () => {
|
|
it('strips "(STL)" from display and key', () => {
|
|
expect(be.normalizeName('Jose Fermin (STL)').display).toBe('Jose Fermin');
|
|
expect(be.nameKey('Jose Fermin (STL)')).toBe(be.nameKey('Jose Fermin'));
|
|
});
|
|
});
|
|
|
|
describe('display de-dotting', () => {
|
|
it('"A.J. Ewing" display shows "AJ Ewing"', () => {
|
|
expect(be.normalizeName('A.J. Ewing').display).toBe('AJ Ewing');
|
|
});
|
|
});
|
|
|
|
describe('frontend + backend agree', () => {
|
|
it.each(['Iván Herrera', 'Matt Liberatore', 'Jose Fermin (STL)', 'A.J. Ewing', 'Ronald Acuña Jr.', 'Mike Massey'])('%s', (n) => {
|
|
expect(fe.nameKey(n)).toBe(be.nameKey(n));
|
|
expect(fe.normalizeName(n).display).toBe(be.normalizeName(n).display);
|
|
});
|
|
});
|
|
|
|
describe('buildPlayerStripsFromProps merges variants + de-dots display', () => {
|
|
it('merges nickname + accent + period variants into one strip', () => {
|
|
const strips = slate.buildPlayerStripsFromProps([
|
|
{ player: 'Matt Liberatore', stat_type: 'strikeouts', line: 5.5 },
|
|
{ player: 'Matthew Liberatore', stat_type: 'hits_allowed', line: 5.5 },
|
|
{ player: 'Iván Herrera', stat_type: 'hits', line: 1.5 },
|
|
{ player: 'Ivan Herrera', stat_type: 'total_bases', line: 1.5 },
|
|
], {}, {});
|
|
expect(strips).toHaveLength(2);
|
|
expect(strips[0].props).toHaveLength(2);
|
|
});
|
|
it('display name is de-dotted', () => {
|
|
const strips = slate.buildPlayerStripsFromProps([
|
|
{ player: 'A.J. Ewing', stat_type: 'hits', line: 1.5 },
|
|
], {}, {});
|
|
expect(strips[0].player).toBe('AJ Ewing');
|
|
});
|
|
});
|