class-transformer
class-transformer copied to clipboard
feature: ship common transforms in subdirectory
Description
Due to the deprecation of the class-sanitizer package, release common transformations will improve new users experience.
Proposed solution
I've imagined something like:
import { Trim, ToLowerCase } from 'class-transformer/common'
class Person {
@Trim()
@ToLowerCase()
public email!: string;
}
Thus this can be achieved with this piece of code:
import { Trim } from 'class-transformer'
export function Trim() {
return (target: any, key: string) => {
return Transform((value: string) => value.trim())(target, key);
};
}
Or in a more customizable way:
export function Trim(only?: "left" | "right") {
return (target: any, key: string) => {
return Transform((value: string) => {
if (only) {
if (only === "left") {
return value.trimLeft();
}
return value.trimRight();
}
return value.trim();
})(target, key);
};
}
If the solution can't be shipped, encourage new users to create your own decorators to avoid mismatch between yours dtos.
Thanks for pay attention, awesome work!
Yes, this is on the roadmap but we need to figure out what is the best way to ship this. In the meantime feel free to use class-sanitizer the latest version is not deprecated just new development is halted. (I will deprecate only if a security bug arise.)
ping, want this too.
Better solution
import { Transform, TransformOptions } from 'class-transformer';
export interface TrimOptions {
/** @default 'both' */
strategy?: 'start' | 'end' | 'both';
}
export function Trim(options?: TrimOptions, transformOptions?: TransformOptions): (target: any, key: string) => void {
return Transform((value: unknown) => {
if ('string' !== typeof value) {
return value;
}
switch (options?.strategy) {
case 'start':
return value.trimLeft();
case 'end':
return value.trimRight();
default:
return value.trim();
}
}, transformOptions);
}
Test
import { plainToClass } from 'class-transformer';
describe('#Trim', () => {
class TestModel {
@Trim()
withDefault: string;
@Trim({ strategy: 'start' })
trimStart: string;
@Trim({ strategy: 'end' })
trimEnd: string;
@Trim({ strategy: 'both' })
trimBoth: string;
}
it('should transform with success', async () => {
return plainToClass(TestModel, {
withDefault: ' withDefault ',
trimStart: ' trimStart ',
trimEnd: ' trimEnd ',
trimBoth: ' trimBoth ',
}).should.eql({
withDefault: 'withDefault',
trimStart: 'trimStart ',
trimEnd: ' trimEnd',
trimBoth: 'trimBoth',
});
});
});
I'm using NestJs, and we love decorators. This is working so good :
import {
Transform,
TransformFnParams,
TransformOptions,
} from "class-transformer";
export interface TrimOptions {
/** @default 'both' */
strategy?: "start" | "end" | "both";
}
export function TrimOrNull(
options?: TrimOptions,
transformOptions?: TransformOptions
): (target: any, key: string) => void {
return Transform((sourceData: TransformFnParams) => {
if ("string" !== typeof sourceData.value) {
return null;
}
switch (options?.strategy) {
case "start":
return sourceData.value.trimStart();
case "end":
return sourceData.value.trimEnd();
default:
return sourceData.value.trim();
}
}, transformOptions);
}
Any update on this?
Would love to see common transform decorators!
Better solution for version >= v0.4.0
- return Transform((value: unknown) => {
+ return Transform(({ value }: any) => {
import { Transform, TransformOptions } from 'class-transformer';
export interface TrimOptions {
/** @default 'both' */
strategy?: 'start' | 'end' | 'both';
}
export function Trim(options?: TrimOptions, transformOptions?: TransformOptions): (target: any, key: string) => void {
return Transform(({ value }: any) => {
if ('string' !== typeof value) {
return value;
}
switch (options?.strategy) {
case 'start':
return value.trimLeft();
case 'end':
return value.trimRight();
default:
return value.trim();
}
}, transformOptions);
}