@tsed/json-mapper 8.0.1 → 8.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +8 -7
- package/readme.md +1 -1
- package/src/components/DateMapper.spec.ts +43 -0
- package/src/components/DateMapper.ts +29 -0
- package/src/components/PrimitiveMapper.spec.ts +179 -0
- package/src/components/PrimitiveMapper.ts +64 -0
- package/src/components/SymbolMapper.spec.ts +23 -0
- package/src/components/SymbolMapper.ts +19 -0
- package/src/decorators/afterDeserialize.ts +39 -0
- package/src/decorators/beforeDeserialize.ts +39 -0
- package/src/decorators/jsonMapper.ts +16 -0
- package/src/decorators/onDeserialize.ts +29 -0
- package/src/decorators/onSerialize.ts +29 -0
- package/src/domain/JsonDeserializer.spec.ts +1437 -0
- package/src/domain/JsonDeserializer.ts +402 -0
- package/src/domain/JsonDeserializerOptions.ts +31 -0
- package/src/domain/JsonMapperCompiler.ts +247 -0
- package/src/domain/JsonMapperGlobalOptions.ts +14 -0
- package/src/domain/JsonMapperSettings.ts +7 -0
- package/src/domain/JsonMapperTypesContainer.ts +20 -0
- package/src/domain/JsonSerializer.spec.ts +1505 -0
- package/src/domain/JsonSerializer.ts +371 -0
- package/src/domain/JsonSerializerOptions.ts +17 -0
- package/src/domain/Writer.spec.ts +11 -0
- package/src/domain/Writer.ts +181 -0
- package/src/domain/__snapshots__/Writer.spec.ts.snap +10 -0
- package/src/hooks/alterAfterDeserialize.ts +5 -0
- package/src/hooks/alterBeforeDeserialize.ts +5 -0
- package/src/hooks/alterOnDeserialize.ts +5 -0
- package/src/hooks/alterOnSerialize.ts +5 -0
- package/src/index.ts +28 -0
- package/src/interfaces/JsonMapperMethods.ts +32 -0
- package/src/utils/deserialize.spec.ts +33 -0
- package/src/utils/deserialize.ts +12 -0
- package/src/utils/getObjectProperties.ts +5 -0
- package/src/utils/serialize.spec.ts +37 -0
- package/src/utils/serialize.ts +12 -0
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@tsed/json-mapper",
|
|
3
3
|
"description": "Json mapper module for Ts.ED Framework",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"version": "8.0.
|
|
5
|
+
"version": "8.0.3",
|
|
6
6
|
"source": "./src/index.ts",
|
|
7
7
|
"main": "./lib/esm/index.js",
|
|
8
8
|
"module": "./lib/esm/index.js",
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"browser": "./lib/browser/json-mapper.umd.min.js",
|
|
11
11
|
"exports": {
|
|
12
12
|
".": {
|
|
13
|
+
"@tsed/source": "./src/index.ts",
|
|
13
14
|
"types": "./lib/types/index.d.ts",
|
|
14
15
|
"browser": "./lib/browser/json-mapper.umd.min.js",
|
|
15
16
|
"import": "./lib/esm/index.js",
|
|
@@ -41,18 +42,18 @@
|
|
|
41
42
|
"tslib": "2.7.0"
|
|
42
43
|
},
|
|
43
44
|
"devDependencies": {
|
|
44
|
-
"@tsed/barrels": "8.0.
|
|
45
|
-
"@tsed/core": "8.0.
|
|
46
|
-
"@tsed/schema": "8.0.
|
|
47
|
-
"@tsed/typescript": "8.0.
|
|
45
|
+
"@tsed/barrels": "8.0.3",
|
|
46
|
+
"@tsed/core": "8.0.3",
|
|
47
|
+
"@tsed/schema": "8.0.3",
|
|
48
|
+
"@tsed/typescript": "8.0.3",
|
|
48
49
|
"eslint": "9.12.0",
|
|
49
50
|
"typescript": "5.4.5",
|
|
50
51
|
"vitest": "2.1.2",
|
|
51
52
|
"webpack": "^5.75.0"
|
|
52
53
|
},
|
|
53
54
|
"peerDependencies": {
|
|
54
|
-
"@tsed/core": "8.0.
|
|
55
|
-
"@tsed/schema": "8.0.
|
|
55
|
+
"@tsed/core": "8.0.3",
|
|
56
|
+
"@tsed/schema": "8.0.3"
|
|
56
57
|
},
|
|
57
58
|
"peerDependenciesMeta": {
|
|
58
59
|
"@tsed/core": {
|
package/readme.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<p style="text-align: center" align="center">
|
|
2
|
-
<a href="https://tsed.
|
|
2
|
+
<a href="https://tsed.dev" target="_blank"><img src="https://tsed.io/tsed-og.png" width="200" alt="Ts.ED logo"/></a>
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
5
|
<div align="center">
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import {DateMapper} from "./DateMapper.js";
|
|
2
|
+
|
|
3
|
+
describe("DateMapper", () => {
|
|
4
|
+
describe("deserialize()", () => {
|
|
5
|
+
it("should return a Date when the data is a string", () => {
|
|
6
|
+
const date = new Date();
|
|
7
|
+
const mapper = new DateMapper();
|
|
8
|
+
|
|
9
|
+
const value = mapper.deserialize(date.toISOString());
|
|
10
|
+
|
|
11
|
+
expect(value).toEqual(date);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it("should return a Date when the data is a number", () => {
|
|
15
|
+
const date = new Date();
|
|
16
|
+
const mapper = new DateMapper();
|
|
17
|
+
|
|
18
|
+
const value = mapper.deserialize(date.getTime());
|
|
19
|
+
|
|
20
|
+
expect(value).toEqual(date);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("should return value when the data is a boolean/null/undefined", () => {
|
|
24
|
+
const date = new Date();
|
|
25
|
+
const mapper = new DateMapper();
|
|
26
|
+
|
|
27
|
+
expect(mapper.deserialize(false)).toEqual(false);
|
|
28
|
+
expect(mapper.deserialize(true)).toEqual(true);
|
|
29
|
+
expect(mapper.deserialize(null)).toEqual(null);
|
|
30
|
+
expect(mapper.deserialize(undefined)).toBeUndefined();
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
describe("serialize()", () => {
|
|
34
|
+
it("should return value", () => {
|
|
35
|
+
const date = new Date();
|
|
36
|
+
const mapper = new DateMapper();
|
|
37
|
+
|
|
38
|
+
const value = mapper.serialize(date);
|
|
39
|
+
|
|
40
|
+
expect(value).toEqual(date.toISOString());
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import {isBoolean} from "@tsed/core";
|
|
2
|
+
|
|
3
|
+
import {JsonMapper} from "../decorators/jsonMapper.js";
|
|
4
|
+
import {JsonMapperMethods} from "../interfaces/JsonMapperMethods.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Mapper for `Date` type.
|
|
8
|
+
* @jsonmapper
|
|
9
|
+
* @component
|
|
10
|
+
*/
|
|
11
|
+
@JsonMapper(Date)
|
|
12
|
+
export class DateMapper implements JsonMapperMethods {
|
|
13
|
+
deserialize(data: string | number): Date;
|
|
14
|
+
deserialize(data: boolean | null | undefined): boolean | null | undefined;
|
|
15
|
+
deserialize(data: any): any {
|
|
16
|
+
// don't convert unexpected data. In normal case, Ajv reject unexpected data.
|
|
17
|
+
// But by default, we have to skip data deserialization and let user to apply
|
|
18
|
+
// the right mapping
|
|
19
|
+
if (isBoolean(data) || data === null || data === undefined) {
|
|
20
|
+
return data;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return new Date(data);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
serialize(object: Date): any {
|
|
27
|
+
return object ? new Date(object).toISOString() : object;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import {catchError} from "@tsed/core";
|
|
2
|
+
|
|
3
|
+
import {PrimitiveMapper} from "./PrimitiveMapper.js";
|
|
4
|
+
|
|
5
|
+
describe("PrimitiveMapper", () => {
|
|
6
|
+
describe("deserialize()", () => {
|
|
7
|
+
it("should return value (number => string)", () => {
|
|
8
|
+
const mapper = new PrimitiveMapper();
|
|
9
|
+
const data = 1;
|
|
10
|
+
const ctx = {
|
|
11
|
+
type: String,
|
|
12
|
+
collectionType: undefined,
|
|
13
|
+
next: vi.fn()
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const value = mapper.deserialize(data, ctx as never);
|
|
17
|
+
|
|
18
|
+
expect(value).toEqual("1");
|
|
19
|
+
});
|
|
20
|
+
it("should return value (string => string)", () => {
|
|
21
|
+
const mapper = new PrimitiveMapper();
|
|
22
|
+
const data = "1";
|
|
23
|
+
const ctx = {
|
|
24
|
+
type: String,
|
|
25
|
+
collectionType: undefined,
|
|
26
|
+
next: vi.fn()
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const value = mapper.deserialize(data, ctx as never);
|
|
30
|
+
|
|
31
|
+
expect(value).toEqual("1");
|
|
32
|
+
});
|
|
33
|
+
it("should return value (null => number)", () => {
|
|
34
|
+
const mapper = new PrimitiveMapper();
|
|
35
|
+
const data = null;
|
|
36
|
+
const ctx = {
|
|
37
|
+
type: Number,
|
|
38
|
+
collectionType: undefined,
|
|
39
|
+
next: vi.fn()
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const value = mapper.deserialize(data, ctx as never);
|
|
43
|
+
|
|
44
|
+
expect(value).toEqual(null);
|
|
45
|
+
});
|
|
46
|
+
it("should return value ('null' => number)", () => {
|
|
47
|
+
const mapper = new PrimitiveMapper();
|
|
48
|
+
const data = "null";
|
|
49
|
+
const ctx = {
|
|
50
|
+
type: Number,
|
|
51
|
+
collectionType: undefined,
|
|
52
|
+
next: vi.fn()
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const value = mapper.deserialize(data, ctx as never);
|
|
56
|
+
|
|
57
|
+
expect(value).toEqual(null);
|
|
58
|
+
});
|
|
59
|
+
it("should return value (string => number)", () => {
|
|
60
|
+
const mapper = new PrimitiveMapper();
|
|
61
|
+
const data = "1";
|
|
62
|
+
const ctx = {
|
|
63
|
+
type: Number,
|
|
64
|
+
collectionType: undefined,
|
|
65
|
+
next: vi.fn()
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const value = mapper.deserialize(data, ctx as never);
|
|
69
|
+
|
|
70
|
+
expect(value).toEqual(1);
|
|
71
|
+
});
|
|
72
|
+
it("should return value (number => number)", () => {
|
|
73
|
+
const mapper = new PrimitiveMapper();
|
|
74
|
+
const data = 1;
|
|
75
|
+
const ctx = {
|
|
76
|
+
type: Number,
|
|
77
|
+
collectionType: undefined,
|
|
78
|
+
next: vi.fn()
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const value = mapper.deserialize(data, ctx as never);
|
|
82
|
+
|
|
83
|
+
expect(value).toEqual(1);
|
|
84
|
+
});
|
|
85
|
+
it("should return value (wrong number => number)", () => {
|
|
86
|
+
const mapper = new PrimitiveMapper();
|
|
87
|
+
const data = "t1";
|
|
88
|
+
const ctx = {
|
|
89
|
+
type: Number,
|
|
90
|
+
collectionType: undefined,
|
|
91
|
+
next: vi.fn()
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
let actualError: any = catchError(() => mapper.deserialize(data, ctx as never));
|
|
95
|
+
|
|
96
|
+
expect(actualError.message).toEqual("Cast error. Expression value is not a number.");
|
|
97
|
+
});
|
|
98
|
+
it("should return value (truthy => boolean)", () => {
|
|
99
|
+
const mapper = new PrimitiveMapper();
|
|
100
|
+
const ctx: any = {
|
|
101
|
+
type: Boolean,
|
|
102
|
+
collectionType: undefined,
|
|
103
|
+
next: vi.fn()
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
expect(mapper.deserialize(1, ctx)).toEqual(true);
|
|
107
|
+
expect(mapper.deserialize("1", ctx)).toEqual(true);
|
|
108
|
+
expect(mapper.deserialize("true", ctx)).toEqual(true);
|
|
109
|
+
expect(mapper.deserialize(true, ctx)).toEqual(true);
|
|
110
|
+
});
|
|
111
|
+
it("should return value (falsy => boolean)", () => {
|
|
112
|
+
const mapper = new PrimitiveMapper();
|
|
113
|
+
const ctx: any = {
|
|
114
|
+
type: Boolean,
|
|
115
|
+
collectionType: undefined,
|
|
116
|
+
next: vi.fn()
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
expect(mapper.deserialize(0, ctx)).toEqual(false);
|
|
120
|
+
expect(mapper.deserialize("0", ctx)).toEqual(false);
|
|
121
|
+
expect(mapper.deserialize("", ctx)).toEqual(false);
|
|
122
|
+
expect(mapper.deserialize("false", ctx)).toEqual(false);
|
|
123
|
+
expect(mapper.deserialize(false, ctx)).toEqual(false);
|
|
124
|
+
expect(mapper.deserialize(undefined, ctx)).toBeUndefined();
|
|
125
|
+
});
|
|
126
|
+
it("should return value (null => boolean)", () => {
|
|
127
|
+
const mapper = new PrimitiveMapper();
|
|
128
|
+
const ctx: any = {
|
|
129
|
+
type: Boolean,
|
|
130
|
+
collectionType: undefined,
|
|
131
|
+
next: vi.fn()
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
expect(mapper.deserialize(null, ctx)).toEqual(null);
|
|
135
|
+
expect(mapper.deserialize("null", ctx)).toEqual(null);
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
describe("serialize()", () => {
|
|
139
|
+
it("should return value (string to string)", () => {
|
|
140
|
+
const mapper = new PrimitiveMapper();
|
|
141
|
+
|
|
142
|
+
const value = mapper.serialize("1", {type: String} as any);
|
|
143
|
+
|
|
144
|
+
expect(value).toEqual("1");
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it("should return value (string to number)", () => {
|
|
148
|
+
const mapper = new PrimitiveMapper();
|
|
149
|
+
|
|
150
|
+
const value = mapper.serialize("1", {type: Number} as any);
|
|
151
|
+
|
|
152
|
+
expect(value).toEqual(1);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it("should return value (object)", () => {
|
|
156
|
+
const mapper = new PrimitiveMapper();
|
|
157
|
+
|
|
158
|
+
// in this case it's probably intended to be an object (or an error but we can decide for the developer and we can broke the code)
|
|
159
|
+
// TODO: for the major version, we can return undefined or throw an error?
|
|
160
|
+
const value = mapper.serialize({"1": "1"} as any, {type: Number} as any);
|
|
161
|
+
|
|
162
|
+
expect(value).toEqual({"1": "1"});
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it("should return value (null)", () => {
|
|
166
|
+
const mapper = new PrimitiveMapper();
|
|
167
|
+
const value = mapper.serialize(null as any, {type: Number} as any);
|
|
168
|
+
|
|
169
|
+
expect(value).toEqual(null);
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it("should return value (undefined)", () => {
|
|
173
|
+
const mapper = new PrimitiveMapper();
|
|
174
|
+
const value = mapper.serialize(undefined as any, {type: Number} as any);
|
|
175
|
+
|
|
176
|
+
expect(value).toEqual(undefined);
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
});
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import {nameOf} from "@tsed/core";
|
|
2
|
+
|
|
3
|
+
import {JsonMapper} from "../decorators/jsonMapper.js";
|
|
4
|
+
import {JsonMapperCtx, JsonMapperMethods} from "../interfaces/JsonMapperMethods.js";
|
|
5
|
+
|
|
6
|
+
function isNullish(data: any) {
|
|
7
|
+
return [null, "null"].includes(data);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export class CastError extends Error {
|
|
11
|
+
name = "CAST_ERROR";
|
|
12
|
+
|
|
13
|
+
constructor(message: string) {
|
|
14
|
+
super(`Cast error. ${message}`);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Mapper for the `String`, `Number`, `BigInt` and `Boolean` types.
|
|
20
|
+
* @jsonmapper
|
|
21
|
+
* @component
|
|
22
|
+
*/
|
|
23
|
+
@JsonMapper(String, Number, Boolean, BigInt)
|
|
24
|
+
export class PrimitiveMapper implements JsonMapperMethods {
|
|
25
|
+
deserialize<T>(data: any, ctx: JsonMapperCtx): string | number | boolean | void | null | BigInt {
|
|
26
|
+
return (this as any)[nameOf(ctx.type)] ? (this as any)[nameOf(ctx.type)](data, ctx) : undefined;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
serialize(object: string | number | boolean | BigInt, ctx: JsonMapperCtx): string | number | boolean | BigInt {
|
|
30
|
+
return (this as any)[nameOf(ctx?.type)] && typeof object !== "object" ? (this as any)[nameOf(ctx.type)](object, ctx) : object;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
protected String(data: any) {
|
|
34
|
+
return data === null ? null : "" + data;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
protected Boolean(data: any) {
|
|
38
|
+
if (["true", "1", true].includes(data)) return true;
|
|
39
|
+
if (["false", "0", false].includes(data)) return false;
|
|
40
|
+
if (isNullish(data)) return null;
|
|
41
|
+
if (data === undefined) return undefined;
|
|
42
|
+
|
|
43
|
+
return !!data;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
protected Number(data: any) {
|
|
47
|
+
if (isNullish(data)) return null;
|
|
48
|
+
if (data === undefined) return data;
|
|
49
|
+
|
|
50
|
+
const n = +data;
|
|
51
|
+
|
|
52
|
+
if (isNaN(n)) {
|
|
53
|
+
throw new CastError("Expression value is not a number.");
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return n;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
protected BigInt(data: any) {
|
|
60
|
+
if (isNullish(data)) return null;
|
|
61
|
+
|
|
62
|
+
return BigInt(data);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import {SymbolMapper} from "./SymbolMapper.js";
|
|
2
|
+
|
|
3
|
+
describe("SymbolMapper", () => {
|
|
4
|
+
describe("deserialize()", () => {
|
|
5
|
+
it("should return value", () => {
|
|
6
|
+
const mapper = new SymbolMapper();
|
|
7
|
+
|
|
8
|
+
const value = mapper.deserialize("SYMBOL");
|
|
9
|
+
|
|
10
|
+
expect(typeof value).toEqual("symbol");
|
|
11
|
+
expect(value.toString()).toEqual("Symbol(SYMBOL)");
|
|
12
|
+
});
|
|
13
|
+
});
|
|
14
|
+
describe("serialize()", () => {
|
|
15
|
+
it("should return value", () => {
|
|
16
|
+
const mapper = new SymbolMapper();
|
|
17
|
+
|
|
18
|
+
const value = mapper.serialize(Symbol.for("SYMBOL"));
|
|
19
|
+
|
|
20
|
+
expect(value).toEqual("SYMBOL");
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import {JsonMapper} from "../decorators/jsonMapper.js";
|
|
2
|
+
import {JsonMapperMethods} from "../interfaces/JsonMapperMethods.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Mapper for the `Symbol` type.
|
|
6
|
+
*
|
|
7
|
+
* @jsonmapper
|
|
8
|
+
* @component
|
|
9
|
+
*/
|
|
10
|
+
@JsonMapper(Symbol)
|
|
11
|
+
export class SymbolMapper implements JsonMapperMethods {
|
|
12
|
+
deserialize(data: string): symbol {
|
|
13
|
+
return Symbol.for(data);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
serialize(object: Symbol): any {
|
|
17
|
+
return object.toString().replace("Symbol(", "").replace(")", "");
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import {JsonEntityFn, JsonHookContext} from "@tsed/schema";
|
|
2
|
+
|
|
3
|
+
export interface AfterDeserializeCallback {
|
|
4
|
+
(value: any, ctx: JsonHookContext): any;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Call the function after JsonMapper.
|
|
9
|
+
*
|
|
10
|
+
* ## Example
|
|
11
|
+
*
|
|
12
|
+
* ```typescript
|
|
13
|
+
* @AfterDeserialize((data: Model) => { // After deserialize get the instance class
|
|
14
|
+
* if (data.prop1 === 'VALUE' && data.prop2 !== 'VALUE2') {
|
|
15
|
+
* throw BadRequest('MyMessage'); // or throw a ValidationError
|
|
16
|
+
* } else {
|
|
17
|
+
* data.prop2 = 'VALUE2';
|
|
18
|
+
* return data;
|
|
19
|
+
* }
|
|
20
|
+
* })
|
|
21
|
+
* class Model {
|
|
22
|
+
* @Property()
|
|
23
|
+
* prop1: string;
|
|
24
|
+
* @Property()
|
|
25
|
+
* prop2: string;
|
|
26
|
+
* }
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* @returns {Function}
|
|
30
|
+
* @decorator
|
|
31
|
+
* @schema
|
|
32
|
+
* @property
|
|
33
|
+
* @param cb
|
|
34
|
+
*/
|
|
35
|
+
export function AfterDeserialize(cb: AfterDeserializeCallback): ClassDecorator {
|
|
36
|
+
return JsonEntityFn((storedJson) => {
|
|
37
|
+
storedJson.schema.$hooks.on("afterDeserialize", cb);
|
|
38
|
+
});
|
|
39
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import {JsonEntityFn, JsonHookContext} from "@tsed/schema";
|
|
2
|
+
|
|
3
|
+
export interface BeforeDeserializeCallback {
|
|
4
|
+
(value: any, ctx: JsonHookContext): any;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Call the function before JsonMapper.
|
|
9
|
+
*
|
|
10
|
+
* ## Example
|
|
11
|
+
*
|
|
12
|
+
* ```typescript
|
|
13
|
+
* @BeforeDeserialize((data: Record<string, unknown>) => { // Before deserialize get the data
|
|
14
|
+
* if (data.prop1 === 'VALUE' && data.prop2 !== 'VALUE2') {
|
|
15
|
+
* throw BadRequest('MyMessage'); // or throw a ValidationError
|
|
16
|
+
* } else {
|
|
17
|
+
* data.prop2 = 'VALUE2';
|
|
18
|
+
* return data;
|
|
19
|
+
* }
|
|
20
|
+
* })
|
|
21
|
+
* class Model {
|
|
22
|
+
* @Property()
|
|
23
|
+
* prop1: string;
|
|
24
|
+
* @Property()
|
|
25
|
+
* prop2: string;
|
|
26
|
+
* }
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* @returns {Function}
|
|
30
|
+
* @decorator
|
|
31
|
+
* @schema
|
|
32
|
+
* @property
|
|
33
|
+
* @param cb
|
|
34
|
+
*/
|
|
35
|
+
export function BeforeDeserialize(cb: BeforeDeserializeCallback): ClassDecorator {
|
|
36
|
+
return JsonEntityFn((storedJson) => {
|
|
37
|
+
storedJson.schema.$hooks.on("beforeDeserialize", cb);
|
|
38
|
+
});
|
|
39
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import {Type} from "@tsed/core";
|
|
2
|
+
|
|
3
|
+
import {registerJsonTypeMapper} from "../domain/JsonMapperTypesContainer.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Register a new JsonMapper Type
|
|
7
|
+
* @param types
|
|
8
|
+
* @constructor
|
|
9
|
+
*/
|
|
10
|
+
export function JsonMapper(...types: (any | Type)[]): ClassDecorator {
|
|
11
|
+
return (target) => {
|
|
12
|
+
types.forEach((type) => {
|
|
13
|
+
registerJsonTypeMapper(type, target as any);
|
|
14
|
+
});
|
|
15
|
+
};
|
|
16
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import {JsonEntityFn, JsonHookContext} from "@tsed/schema";
|
|
2
|
+
|
|
3
|
+
export interface OnDeserializeCallback {
|
|
4
|
+
(value: any, ctx: JsonHookContext): any;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Call the function before property deserialization.
|
|
9
|
+
*
|
|
10
|
+
* ## Example
|
|
11
|
+
*
|
|
12
|
+
* ```typescript
|
|
13
|
+
* class Model {
|
|
14
|
+
* @OnDeserialize(v => v + 1)
|
|
15
|
+
* property: string;
|
|
16
|
+
* }
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* @returns {Function}
|
|
20
|
+
* @decorator
|
|
21
|
+
* @schema
|
|
22
|
+
* @property
|
|
23
|
+
* @param cb
|
|
24
|
+
*/
|
|
25
|
+
export function OnDeserialize(cb: OnDeserializeCallback): PropertyDecorator {
|
|
26
|
+
return JsonEntityFn((storedJson) => {
|
|
27
|
+
storedJson.schema.$hooks.on("onDeserialize", cb);
|
|
28
|
+
});
|
|
29
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import {JsonEntityFn, JsonHookContext} from "@tsed/schema";
|
|
2
|
+
|
|
3
|
+
export interface OnSerializeCallback {
|
|
4
|
+
(value: any, ctx: JsonHookContext): any;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Call the function before property serialization.
|
|
9
|
+
*
|
|
10
|
+
* ## Example
|
|
11
|
+
*
|
|
12
|
+
* ```typescript
|
|
13
|
+
* class Model {
|
|
14
|
+
* @OnSerialize(v => v + 1)
|
|
15
|
+
* property: string;
|
|
16
|
+
* }
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* @returns {Function}
|
|
20
|
+
* @decorator
|
|
21
|
+
* @schema
|
|
22
|
+
* @property
|
|
23
|
+
* @param cb
|
|
24
|
+
*/
|
|
25
|
+
export function OnSerialize(cb: OnSerializeCallback): PropertyDecorator {
|
|
26
|
+
return JsonEntityFn((storedJson) => {
|
|
27
|
+
storedJson.schema.$hooks.on("onSerialize", cb);
|
|
28
|
+
});
|
|
29
|
+
}
|