Feature snake_case to camelCase conversion option
I went through docs i couldn't find anything that let me convert snake_case to CamelCase using plainToClass
In many cases json returning from API's are mostly snake_case but my classes contain CamelCase properties. it would be nice to have something like below.
Just a thought can be implement in @f decorator as well to be able to covert in both plainToClass and classToPlain.
e.g const post = plainToClass(Post, postJson, {snakeToCamel: true});
Found
class Test {
constructor(
@f.asName('alias_field')
field: string;
) {}
}
But it works only with constructor, why it not works with class directly?
class Test {
@f.asName('alias_field')
field: string;
}
asName is only for necessary when code is minimized (constructor argument names are usually changed then, which would make getting fields as constructor args impossible, and thus strict mode impossible).
However, I agree that a mapping of field names is a good feature, but I don't know yet how to change the API and the serialize engine to keep everything performant.
@darky @marcj thanks, yes it's working with constructor, @marcj totally agree with keeping performance up, FYI i recently moved from class-transformer for my recent project, this is the only missing piece for now i will go with constructor way.
Constructor with asName is not a great replacement for your need. Better is to way for the weekend, then I think we figured something out.
I thought about that and I think that this feature pretty much makes the whole codebase of converting, validation, property definition way too complex. It's probably easier to write a converter yourself, simply because if you do it in your code directly, its code is quite simple compared to the complexity it would bring to Marshal as a whole (when deeply integrated in the classToPlain/plainToClass API and decorators).
Code that covers all data structures could look like that:
function underscoreToCamelCase(name: string): string {
return name.replace(/_([a-z])/g, c => c[1].toUpperCase());
}
function camelCaseToUnderscore(name: string): string {
return name.replace(/([A-Z])/g, '_$1').toLowerCase();
}
function isObject(obj: any): obj is { [name: string]: any } {
if (obj === null) return false;
return ((typeof obj === 'function') || (typeof obj === 'object' && !Array.isArray(obj)));
}
function convertNames(item: any, nameStrategy: (v: string) => string): any {
if (Array.isArray(item)) return item.map((v: any) => convertNames(v, nameStrategy));
if (!isObject(item)) return item;
const res: { [name: string]: any } = {};
for (const i in item) {
if (!item.hasOwnProperty(i)) continue;
res[nameStrategy(i)] = convertNames(item[i], nameStrategy);
}
return res;
}
const plain = {
id: 123,
first_name: 'Peter',
sub: {
my_other_name: 'Guschdl'
},
items: [
'string', 'another'
],
childs: [
{its_name: 'a'},
{its_name: 'b'}
]
};
console.log(convertNames(plain, underscoreToCamelCase));
/*
{
id: 123,
firstName: 'Peter',
sub: { myOtherName: 'Guschdl' },
items: [ 'string', 'another' ],
childs: [ { itsName: 'a' }, { itsName: 'b' } ]
}
*/
//and convert back again
console.log(convertNames(convertNames(plain, underscoreToCamelCase), camelCaseToUnderscore));
/*
{
id: 123,
first_name: 'Peter',
sub: { my_other_name: 'Guschdl' },
items: [ 'string', 'another' ],
childs: [ { its_name: 'a' }, { its_name: 'b' } ]
}
*/
//how to work with plainToClass/classToPlain
plainToClass(MyClass, convertNames(plain, underscoreToCamelCase));
const item = new MyClass;
convertNames(classToPlain(MyClass, item), camelCaseToUnderscore);
This API makes it easy to include exceptions or your own naming strategy.
We could add those utility methods in Marshal, but only as an addition to classToPlain/plainToClass, like shown in the code above.
I was looking through the tickets and maybe what I wrote in the past can help. I once wrote an ultra-fast snakeCase, camelize etc. conversion library https://github.com/encharm/xcase - it has pretty much a close to native performance.
Naming strategy was implemented a long time ago. I'm going to close this, but feel free to reopen if anything else needs to be addressed.