Skip to content

Commit afadef7

Browse files
author
Matej Szendi
committed
* Add skipArray, skipDate, skipNumber, and skipString options to toNull()
* Add `skipArray`, `skipDate`, `skipNumber`, and `skipString` options to `toUndefined()` * Add tests for `toNull()` * Add tests for `toUndefined()`
1 parent 628f0be commit afadef7

File tree

5 files changed

+361
-17
lines changed

5 files changed

+361
-17
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "transformbot",
33
"description": "The modular and type-safe schema library for transforming values",
4-
"version": "0.15.0",
4+
"version": "0.16.0",
55
"license": "MIT",
66
"author": "Matej Szendi",
77
"repository": {

src/actions/toNull.ts

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,50 @@ import type { Action } from "../types.ts";
22

33
export type ToNullAction<TInput, TOutput> = Action<TInput, TOutput>;
44

5-
export function toNull<
6-
TInput,
7-
TOutput = TInput,
8-
>(): ToNullAction<TInput, TOutput | null> {
5+
export interface ToNullOptions {
6+
skipArray?: boolean;
7+
skipDate?: boolean;
8+
skipNumber?: boolean;
9+
skipString?: boolean;
10+
}
11+
12+
export function toNull<TInput, TOutput = TInput>(
13+
options?: ToNullOptions,
14+
): ToNullAction<TInput, TOutput | null> {
915
return (input) => {
1016
if (input === null) {
1117
return null;
1218
}
1319

14-
if (input instanceof Date && input.getTime() === 0) {
20+
if (
21+
true !== options?.skipDate &&
22+
input instanceof Date &&
23+
input.getTime() === 0
24+
) {
1525
return null;
1626
}
1727

18-
if (typeof input === "number" && (input === 0 || input === 0.0)) {
28+
if (
29+
true !== options?.skipNumber &&
30+
typeof input === "number" &&
31+
(input === 0 || input === 0.0)
32+
) {
1933
return null;
2034
}
2135

22-
if (typeof input === "string" && input === "") {
36+
if (
37+
true !== options?.skipString &&
38+
typeof input === "string" &&
39+
input === ""
40+
) {
2341
return null;
2442
}
2543

26-
if (Array.isArray(input) && input.length === 0) {
44+
if (
45+
true !== options?.skipArray &&
46+
Array.isArray(input) &&
47+
input.length === 0
48+
) {
2749
return null;
2850
}
2951

src/actions/toUndefined.ts

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,50 @@ import type { Action } from "../types.ts";
22

33
export type ToUndefinedAction<TInput, TOutput> = Action<TInput, TOutput>;
44

5-
export function toUndefined<
6-
TInput,
7-
TOutput = NonNullable<TInput>,
8-
>(): ToUndefinedAction<TInput, TOutput | undefined> {
5+
export interface ToUndefinedOptions {
6+
skipArray?: boolean;
7+
skipDate?: boolean;
8+
skipNumber?: boolean;
9+
skipString?: boolean;
10+
}
11+
12+
export function toUndefined<TInput, TOutput = NonNullable<TInput>>(
13+
options?: ToUndefinedOptions,
14+
): ToUndefinedAction<TInput, TOutput | undefined> {
915
return (input) => {
1016
if (input === null) {
1117
return undefined;
1218
}
1319

14-
if (input instanceof Date && input.getTime() === 0) {
20+
if (
21+
true !== options?.skipDate &&
22+
input instanceof Date &&
23+
input.getTime() === 0
24+
) {
1525
return undefined;
1626
}
1727

18-
if (typeof input === "number" && (input === 0 || input === 0.0)) {
28+
if (
29+
true !== options?.skipNumber &&
30+
typeof input === "number" &&
31+
(input === 0 || input === 0.0)
32+
) {
1933
return undefined;
2034
}
2135

22-
if (typeof input === "string" && input === "") {
36+
if (
37+
true !== options?.skipString &&
38+
typeof input === "string" &&
39+
input === ""
40+
) {
2341
return undefined;
2442
}
2543

26-
if (Array.isArray(input) && input.length === 0) {
44+
if (
45+
true !== options?.skipArray &&
46+
Array.isArray(input) &&
47+
input.length === 0
48+
) {
2749
return undefined;
2850
}
2951

test/actions/toNull.test.ts

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
import { describe, expect, it } from "vitest";
2+
import { toNull } from "../../src/actions/toNull.ts";
3+
4+
describe("toNull conversions", () => {
5+
// Test without options
6+
describe("default behavior", () => {
7+
const convert = toNull();
8+
9+
it("should convert array `[]` to `null`", () => {
10+
expect(convert([])).toBeNull();
11+
});
12+
13+
it("should keep non-empty array", () => {
14+
const arr = [1, 2, 3];
15+
expect(convert(arr)).toBe(arr);
16+
});
17+
18+
it("should keep bigint `100`", () => {
19+
const val = BigInt(100);
20+
expect(convert(val)).toBe(val);
21+
});
22+
23+
it("should keep boolean `true`", () => {
24+
expect(convert(true)).toBe(true);
25+
});
26+
27+
it("should keep boolean `false`", () => {
28+
expect(convert(false)).toBe(false);
29+
});
30+
31+
it("should convert Date with time 0 to `null`", () => {
32+
const zeroDate = new Date(0);
33+
expect(convert(zeroDate)).toBeNull();
34+
});
35+
36+
it("should keep regular Date", () => {
37+
const date = new Date();
38+
expect(convert(date)).toBe(date);
39+
});
40+
41+
it("should keep null as `null`", () => {
42+
expect(convert(null)).toBeNull();
43+
});
44+
45+
it("should convert number `0` to `null`", () => {
46+
expect(convert(0)).toBeNull();
47+
});
48+
49+
it("should keep number `1`", () => {
50+
expect(convert(1)).toBe(1);
51+
});
52+
53+
it("should keep number `123`", () => {
54+
expect(convert(123)).toBe(123);
55+
});
56+
57+
it("should keep object `{}`", () => {
58+
const obj = {};
59+
expect(convert(obj)).toBe(obj);
60+
});
61+
62+
it("should convert empty string `` to `null`", () => {
63+
expect(convert("")).toBeNull();
64+
});
65+
66+
it("should keep string `0`", () => {
67+
expect(convert("0")).toBe("0");
68+
});
69+
70+
it("should keep string `1`", () => {
71+
expect(convert("1")).toBe("1");
72+
});
73+
74+
it("should keep string `1,23`", () => {
75+
expect(convert("1,23")).toBe("1,23");
76+
});
77+
78+
it("should keep string `456`", () => {
79+
expect(convert("456")).toBe("456");
80+
});
81+
82+
it("should keep string ` 789 `", () => {
83+
expect(convert(" 789 ")).toBe(" 789 ");
84+
});
85+
86+
it("should keep string `abc`", () => {
87+
expect(convert("abc")).toBe("abc");
88+
});
89+
90+
it("should keep string `false`", () => {
91+
expect(convert("false")).toBe("false");
92+
});
93+
94+
it("should keep string `no`", () => {
95+
expect(convert("no")).toBe("no");
96+
});
97+
98+
it("should keep string `true`", () => {
99+
expect(convert("true")).toBe("true");
100+
});
101+
102+
it("should keep string `yes`", () => {
103+
expect(convert("yes")).toBe("yes");
104+
});
105+
106+
it("should keep undefined as undefined", () => {
107+
expect(convert(undefined)).toBe(undefined);
108+
});
109+
});
110+
111+
// Test with options
112+
describe("with options", () => {
113+
it("should keep empty array when skipArray is true", () => {
114+
const convert = toNull({ skipArray: true });
115+
const arr: string[] = [];
116+
expect(convert(arr)).toBe(arr);
117+
});
118+
119+
it("should keep Date with time 0 when skipDate is true", () => {
120+
const convert = toNull({ skipDate: true });
121+
const zeroDate = new Date(0);
122+
expect(convert(zeroDate)).toBe(zeroDate);
123+
});
124+
125+
it("should keep number `0` when skipNumber is true", () => {
126+
const convert = toNull({ skipNumber: true });
127+
expect(convert(0)).toBe(0);
128+
});
129+
130+
it("should keep empty string when skipString is true", () => {
131+
const convert = toNull({ skipString: true });
132+
expect(convert("")).toBe("");
133+
});
134+
135+
it("should keep all normally-converted values when all skip options are true", () => {
136+
const convert = toNull({
137+
skipArray: true,
138+
skipDate: true,
139+
skipNumber: true,
140+
skipString: true,
141+
});
142+
143+
expect(convert([])).toEqual([]);
144+
expect(convert(new Date(0))).toEqual(new Date(0));
145+
expect(convert(0)).toBe(0);
146+
expect(convert("")).toBe("");
147+
expect(convert(null)).toBeNull();
148+
});
149+
});
150+
});

0 commit comments

Comments
 (0)