sindresorhus / lowercase-keys

Lowercase the keys of an object
MIT License
41 stars 12 forks source link

Duplicate keys with different casings #13

Open palashmon opened 5 months ago

palashmon commented 5 months ago

I recently found a potential bug in this code related to duplicate keys with different casings. When the lowercaseKeys function encounters objects with keys like "Key" and "key", it only retains one of them due to the transformation to lowercase keys. This could lead to unexpected behavior and data loss in certain scenarios.

To illustrate, here is a code example:

const obj = { "Key": "value1", "key": "value2" };
console.log(lowercaseKeys(obj)); 
//=> { "key": "value2" }

Thank you!

sindresorhus commented 5 months ago

That is expected behavior. The package does exactly what it says.

What did you expect it to do in this case?

palashmon commented 5 months ago

Thank you for the prompt response and clarification on the behavior of the function.

But I was thinking that instead of directly altering the function's behavior, we could consider enhancing error messaging to gracefully inform users about the presence of duplicate keys with different casings in the input object. This approach empowers users with knowledge about potential data loss scenarios while maintaining the function's core functionality.

Also, we can give the option to merge values like:

// Possible API extension
function lowercaseKeys(object, { mergeDuplicates = false } = {}) {
    // Implementation that merges duplicate keys
}

So, we can either show a message to users about "presence of duplicate keys with different casings"

or we can merge the keys like this so that there is no data loss based on mergeDuplicates option:

const obj = { "Key": "value1", "key": "value2" };
console.log(lowercaseKeys(obj, { mergeDuplicates: true })); 
//=> { "key_1": "value1", "key": "value2" }

Thank you!

sindresorhus commented 5 months ago

I think the easiest solution is to add an option that accepts a function that gets called when there are duplicates. It would receive the existing key and the duplicate before lowercasing it, and let you decide how to handle it. Either overwrite, rename, or throw an error. By default, it should just overwrite.