change-case
change-case copied to clipboard
Consider extending functionality to allow changing case of object keys
Hey there! Great package and i love the api you've exposed.
Have you considered expanding the scope of this project to expose a utility to recursively change the case of keys of an object?
For example:
const user = {
firstName: 'foo',
lastName: 'bar',
};
const snakeCaseUser = snakeCaseKeys(user);
/*
{
first_name: 'foo',
last_name: 'bar',
}
*/
@uladkasach It's not something I've wanted to maintain before, but I could see it being useful as a package that takes changeKeys(obj, renameFn)
instead of wrapping each module independently.
Would you be comfortable with me adding that function to this package?
e.g.:
import { snakeCase, changeKeys } from 'change-case';
const user = {
firstName: 'foo',
lastName: 'bar',
};
const snakeCaseUser = changeKeys(user, snakeCase);
/*
{
first_name: 'foo',
last_name: 'bar',
}
*/
@uladkasach It's not something I've wanted to maintain before, but I could see it being useful as a package that takes
changeKeys(obj, renameFn)
instead of wrapping each module independently.
This could be highly appreciated by all developers who need to work with API in Python. It's simpler to make the conversion on a client side than to explain them why do we need this.
We at BStock.com needed and wanted this code described in this issue so @yury-herlovich and myself pitched in to create the functionality desired
We have done the work with testing and would like to request @uladkasach to review and implement as a pull request. If weeks go by and no movement then we will make the official pull request.
It is note worthy, as with most all looping of objects, that a cyclic reference would cause an endless loop. A developer can use cyclic detection if needed to prevent endless looping of an object as seen here
The code needed:
export function changeKeys(
obj: any,
casing: (v: string, ops?: any) => string
): any {
if (!obj || obj.constructor !== Object) {
return obj
}
return Object.keys(obj).reduce((all: any, key) => {
const newKey = casing(key)
all[newKey] = obj[key] && obj[key].constructor === Object ?
changeKeys(obj[key], casing) : obj[key]
return all
}, {})
}
The unit test like code we used to verify our functionality:
import { camelCase } from 'change-case'
describe('toCamelCase', () => {
it('should convert 1 level object', () => {
const obj = {some_thing: 'test-item', another_thing: 'test-entity-id'}
const res = changeKeys(obj, camelCase)
expect(res).toStrictEqual({someThing: 'test-item', anotherThing: 'test-entity-id'})
})
it('should convert multi level object', () => {
const obj = {
card: {
exp_month: 11,
exp_year: 2023,
brand: 'Visa',
address_line1_check: 'unchecked',
address_zip_check: 'unchecked',
field1: null,
test_field2: null,
},
owner: {
address: {
postal_code: '33066',
state: 'FL',
},
},
}
const expected = {
card: {
expMonth: 11,
expYear: 2023,
brand: 'Visa',
addressLine1Check: 'unchecked',
addressZipCheck: 'unchecked',
field1: null,
testField2: null,
},
owner: {
address: {
postalCode: '33066',
state: 'FL',
},
},
}
const res = changeKeys(obj, camelCase)
expect(res).toStrictEqual(expected)
})
it('should not fail if it got not an object', () => {
expect(changeKeys(null, camelCase)).toBe(null)
expect(changeKeys(undefined, camelCase)).toBe(undefined)
expect(changeKeys(1, camelCase)).toBe(1)
expect(changeKeys('abc', camelCase)).toBe('abc')
expect(changeKeys(['a', 'b', 'c'], camelCase)).toStrictEqual(['a', 'b', 'c'])
})
})
Finally got around to contributing this :sweat_smile:
bumping this up again, i think its ready to merge: https://github.com/blakeembrey/change-case/pull/240
Bump 😸
This has been added to change-case@5
as an ESM import of change-case/keys
, based on the work in https://github.com/blakeembrey/change-case/pull/240.