change-case icon indicating copy to clipboard operation
change-case copied to clipboard

Consider extending functionality to allow changing case of object keys

Open uladkasach opened this issue 4 years ago • 5 comments

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 avatar Apr 03 '20 13:04 uladkasach

@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.

blakeembrey avatar Apr 05 '20 01:04 blakeembrey

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 avatar Apr 05 '20 15:04 uladkasach

@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.

dmytro-shchurov avatar May 02 '20 13:05 dmytro-shchurov

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'])
  })
})

AckerApple avatar Dec 30 '20 15:12 AckerApple

Finally got around to contributing this :sweat_smile:

uladkasach avatar Aug 06 '21 10:08 uladkasach

bumping this up again, i think its ready to merge: https://github.com/blakeembrey/change-case/pull/240

uladkasach avatar Dec 16 '22 18:12 uladkasach

Bump 😸

austinbiggs avatar Feb 27 '23 19:02 austinbiggs

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.

blakeembrey avatar Sep 30 '23 02:09 blakeembrey