Skip to content

Commit

Permalink
Fix name parser to not use "last, first" format when not using comma …
Browse files Browse the repository at this point in the history
…separators. Adds unit tests #3940
  • Loading branch information
advplyr committed Feb 5, 2025
1 parent 201e12e commit 5e5a604
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 6 deletions.
20 changes: 14 additions & 6 deletions server/utils/parsers/parseNameString.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,18 @@ module.exports.nameToLastFirst = (firstLast) => {
return `${nameObj.last_name}, ${nameObj.first_name}`
}

// Handle any name string
/**
* Parses a name string into an array of names
*
* @param {string} nameString - The name string to parse
* @returns {{ names: string[] }} Array of names
*/
module.exports.parse = (nameString) => {
if (!nameString) return null

var splitNames = []
let splitNames = []
const isCommaSeparated = nameString.includes(',')

// Example &LF: Friedman, Milton & Friedman, Rose
if (nameString.includes('&')) {
nameString.split('&').forEach((asa) => (splitNames = splitNames.concat(asa.split(','))))
Expand All @@ -59,17 +66,18 @@ module.exports.parse = (nameString) => {
}
}

var names = []
let names = []

// 1 name FIRST LAST
if (splitNames.length === 1) {
names.push(parseName(nameString))
} else {
var firstChunkIsALastName = checkIsALastName(splitNames[0])
var isEvenNum = splitNames.length % 2 === 0
// Determines whether this is formatted as last, first or first last (only if using comma separator)
// Example: "Smith; James Jones" -> ["Smith", "James Jones"]
let firstChunkIsALastName = !isCommaSeparated ? false : checkIsALastName(splitNames[0])
let isEvenNum = splitNames.length % 2 === 0

if (!isEvenNum && firstChunkIsALastName) {
// console.error('Multi-name LAST,FIRST entry has a straggler (could be roman numerals or a suffix), ignore it')
splitNames = splitNames.slice(0, splitNames.length - 1)
}

Expand Down
99 changes: 99 additions & 0 deletions test/server/utils/parsers/parseNameString.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
const chai = require('chai')
const expect = chai.expect
const { parse, nameToLastFirst } = require('../../../../server/utils/parsers/parseNameString')

describe('parseNameString', () => {
describe('parse', () => {
it('returns null if nameString is empty', () => {
const result = parse('')
expect(result).to.be.null
})

it('parses single name in First Last format', () => {
const result = parse('John Smith')
expect(result.names).to.deep.equal(['John Smith'])
})

it('parses single name in Last, First format', () => {
const result = parse('Smith, John')
expect(result.names).to.deep.equal(['John Smith'])
})

it('parses multiple names separated by &', () => {
const result = parse('John Smith & Jane Doe')
expect(result.names).to.deep.equal(['John Smith', 'Jane Doe'])
})

it('parses multiple names separated by "and"', () => {
const result = parse('John Smith and Jane Doe')
expect(result.names).to.deep.equal(['John Smith', 'Jane Doe'])
})

it('parses multiple names separated by comma and "and"', () => {
const result = parse('John Smith, Jane Doe and John Doe')
expect(result.names).to.deep.equal(['John Smith', 'Jane Doe', 'John Doe'])
})

it('parses multiple names separated by semicolon', () => {
const result = parse('John Smith; Jane Doe')
expect(result.names).to.deep.equal(['John Smith', 'Jane Doe'])
})

it('parses multiple names in Last, First format', () => {
const result = parse('Smith, John, Doe, Jane')
expect(result.names).to.deep.equal(['John Smith', 'Jane Doe'])
})

it('parses multiple names with single word name', () => {
const result = parse('John Smith, Jones, James Doe, Ludwig von Mises')
expect(result.names).to.deep.equal(['John Smith', 'Jones', 'James Doe', 'Ludwig von Mises'])
})

it('parses multiple names with single word name listed first (semicolon separator)', () => {
const result = parse('Jones; John Smith; James Doe; Ludwig von Mises')
expect(result.names).to.deep.equal(['Jones', 'John Smith', 'James Doe', 'Ludwig von Mises'])
})

it('handles names with suffixes', () => {
const result = parse('Smith, John Jr.')
expect(result.names).to.deep.equal(['John Jr. Smith'])
})

it('handles compound last names', () => {
const result = parse('von Mises, Ludwig')
expect(result.names).to.deep.equal(['Ludwig von Mises'])
})

it('handles Chinese/Japanese/Korean names', () => {
const result = parse('张三, 李四')
expect(result.names).to.deep.equal(['张三', '李四'])
})

it('removes duplicate names', () => {
const result = parse('John Smith & John Smith')
expect(result.names).to.deep.equal(['John Smith'])
})

it('filters out empty names', () => {
const result = parse('John Smith,')
expect(result.names).to.deep.equal(['John Smith'])
})
})

describe('nameToLastFirst', () => {
it('converts First Last to Last, First format', () => {
const result = nameToLastFirst('John Smith')
expect(result).to.equal('Smith, John')
})

it('returns last name only when no first name', () => {
const result = nameToLastFirst('Smith')
expect(result).to.equal('Smith')
})

it('handles names with middle names', () => {
const result = nameToLastFirst('John Middle Smith')
expect(result).to.equal('Smith, John Middle')
})
})
})

0 comments on commit 5e5a604

Please sign in to comment.