@tsed/json-mapper 8.11.0 → 8.11.2-rc.1
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/lib/esm/components/DateMapper.js +0 -1
- package/lib/esm/components/PrimitiveMapper.js +0 -1
- package/lib/esm/components/SymbolMapper.js +0 -1
- package/lib/esm/decorators/afterDeserialize.js +0 -1
- package/lib/esm/decorators/beforeDeserialize.js +0 -1
- package/lib/esm/decorators/jsonMapper.js +0 -1
- package/lib/esm/decorators/onDeserialize.js +0 -1
- package/lib/esm/decorators/onSerialize.js +0 -1
- package/lib/esm/domain/JsonDeserializer.js +0 -1
- package/lib/esm/domain/JsonDeserializerOptions.js +0 -1
- package/lib/esm/domain/JsonMapperCompiler.js +0 -1
- package/lib/esm/domain/JsonMapperGlobalOptions.js +0 -1
- package/lib/esm/domain/JsonMapperSettings.js +0 -1
- package/lib/esm/domain/JsonMapperTypesContainer.js +0 -1
- package/lib/esm/domain/JsonSerializer.js +0 -1
- package/lib/esm/domain/JsonSerializerOptions.js +0 -1
- package/lib/esm/domain/Writer.js +0 -1
- package/lib/esm/hooks/alterAfterDeserialize.js +0 -1
- package/lib/esm/hooks/alterBeforeDeserialize.js +0 -1
- package/lib/esm/hooks/alterOnDeserialize.js +0 -1
- package/lib/esm/hooks/alterOnSerialize.js +0 -1
- package/lib/esm/index.js +0 -1
- package/lib/esm/interfaces/JsonMapperMethods.js +0 -1
- package/lib/esm/utils/deserialize.js +0 -1
- package/lib/esm/utils/getObjectProperties.js +0 -1
- package/lib/esm/utils/serialize.js +0 -1
- package/package.json +12 -11
- package/lib/browser/components/DateMapper.js +0 -22
- package/lib/browser/components/DateMapper.js.map +0 -1
- package/lib/browser/components/PrimitiveMapper.js +0 -52
- package/lib/browser/components/PrimitiveMapper.js.map +0 -1
- package/lib/browser/components/SymbolMapper.js +0 -21
- package/lib/browser/components/SymbolMapper.js.map +0 -1
- package/lib/browser/decorators/afterDeserialize.js +0 -10
- package/lib/browser/decorators/afterDeserialize.js.map +0 -1
- package/lib/browser/decorators/beforeDeserialize.js +0 -10
- package/lib/browser/decorators/beforeDeserialize.js.map +0 -1
- package/lib/browser/decorators/jsonMapper.js +0 -12
- package/lib/browser/decorators/jsonMapper.js.map +0 -1
- package/lib/browser/decorators/onDeserialize.js +0 -10
- package/lib/browser/decorators/onDeserialize.js.map +0 -1
- package/lib/browser/decorators/onSerialize.js +0 -10
- package/lib/browser/decorators/onSerialize.js.map +0 -1
- package/lib/browser/domain/JsonDeserializer.js +0 -179
- package/lib/browser/domain/JsonDeserializer.js.map +0 -1
- package/lib/browser/domain/JsonDeserializerOptions.js +0 -2
- package/lib/browser/domain/JsonDeserializerOptions.js.map +0 -1
- package/lib/browser/domain/JsonMapperCompiler.js +0 -110
- package/lib/browser/domain/JsonMapperCompiler.js.map +0 -1
- package/lib/browser/domain/JsonMapperGlobalOptions.js +0 -2
- package/lib/browser/domain/JsonMapperGlobalOptions.js.map +0 -1
- package/lib/browser/domain/JsonMapperSettings.js +0 -9
- package/lib/browser/domain/JsonMapperSettings.js.map +0 -1
- package/lib/browser/domain/JsonMapperTypesContainer.js +0 -12
- package/lib/browser/domain/JsonMapperTypesContainer.js.map +0 -1
- package/lib/browser/domain/JsonSerializer.js +0 -164
- package/lib/browser/domain/JsonSerializer.js.map +0 -1
- package/lib/browser/domain/JsonSerializerOptions.js +0 -2
- package/lib/browser/domain/JsonSerializerOptions.js.map +0 -1
- package/lib/browser/domain/Writer.js +0 -124
- package/lib/browser/domain/Writer.js.map +0 -1
- package/lib/browser/hooks/alterAfterDeserialize.js +0 -8
- package/lib/browser/hooks/alterAfterDeserialize.js.map +0 -1
- package/lib/browser/hooks/alterBeforeDeserialize.js +0 -8
- package/lib/browser/hooks/alterBeforeDeserialize.js.map +0 -1
- package/lib/browser/hooks/alterOnDeserialize.js +0 -7
- package/lib/browser/hooks/alterOnDeserialize.js.map +0 -1
- package/lib/browser/hooks/alterOnSerialize.js +0 -7
- package/lib/browser/hooks/alterOnSerialize.js.map +0 -1
- package/lib/browser/index.js +0 -47
- package/lib/browser/index.js.map +0 -1
- package/lib/browser/utils/deserialize.js +0 -12
- package/lib/browser/utils/deserialize.js.map +0 -1
- package/lib/browser/utils/getObjectProperties.js +0 -8
- package/lib/browser/utils/getObjectProperties.js.map +0 -1
- package/lib/browser/utils/serialize.js +0 -12
- package/lib/browser/utils/serialize.js.map +0 -1
- package/lib/esm/components/DateMapper.js.map +0 -1
- package/lib/esm/components/PrimitiveMapper.js.map +0 -1
- package/lib/esm/components/SymbolMapper.js.map +0 -1
- package/lib/esm/decorators/afterDeserialize.js.map +0 -1
- package/lib/esm/decorators/beforeDeserialize.js.map +0 -1
- package/lib/esm/decorators/jsonMapper.js.map +0 -1
- package/lib/esm/decorators/onDeserialize.js.map +0 -1
- package/lib/esm/decorators/onSerialize.js.map +0 -1
- package/lib/esm/domain/JsonDeserializer.js.map +0 -1
- package/lib/esm/domain/JsonDeserializerOptions.js.map +0 -1
- package/lib/esm/domain/JsonMapperCompiler.js.map +0 -1
- package/lib/esm/domain/JsonMapperGlobalOptions.js.map +0 -1
- package/lib/esm/domain/JsonMapperSettings.js.map +0 -1
- package/lib/esm/domain/JsonMapperTypesContainer.js.map +0 -1
- package/lib/esm/domain/JsonSerializer.js.map +0 -1
- package/lib/esm/domain/JsonSerializerOptions.js.map +0 -1
- package/lib/esm/domain/Writer.js.map +0 -1
- package/lib/esm/hooks/alterAfterDeserialize.js.map +0 -1
- package/lib/esm/hooks/alterBeforeDeserialize.js.map +0 -1
- package/lib/esm/hooks/alterOnDeserialize.js.map +0 -1
- package/lib/esm/hooks/alterOnSerialize.js.map +0 -1
- package/lib/esm/index.js.map +0 -1
- package/lib/esm/interfaces/JsonMapperMethods.js.map +0 -1
- package/lib/esm/utils/deserialize.js.map +0 -1
- package/lib/esm/utils/getObjectProperties.js.map +0 -1
- package/lib/esm/utils/serialize.js.map +0 -1
- package/src/components/DateMapper.spec.ts +0 -43
- package/src/components/DateMapper.ts +0 -29
- package/src/components/PrimitiveMapper.spec.ts +0 -179
- package/src/components/PrimitiveMapper.ts +0 -64
- package/src/components/SymbolMapper.spec.ts +0 -23
- package/src/components/SymbolMapper.ts +0 -19
- package/src/decorators/afterDeserialize.ts +0 -39
- package/src/decorators/beforeDeserialize.ts +0 -39
- package/src/decorators/jsonMapper.ts +0 -16
- package/src/decorators/onDeserialize.ts +0 -29
- package/src/decorators/onSerialize.ts +0 -29
- package/src/domain/JsonDeserializer.spec.ts +0 -1437
- package/src/domain/JsonDeserializer.ts +0 -402
- package/src/domain/JsonDeserializerOptions.ts +0 -31
- package/src/domain/JsonMapperCompiler.ts +0 -247
- package/src/domain/JsonMapperGlobalOptions.ts +0 -14
- package/src/domain/JsonMapperSettings.ts +0 -7
- package/src/domain/JsonMapperTypesContainer.ts +0 -20
- package/src/domain/JsonSerializer.spec.ts +0 -1506
- package/src/domain/JsonSerializer.ts +0 -371
- package/src/domain/JsonSerializerOptions.ts +0 -17
- package/src/domain/Writer.spec.ts +0 -11
- package/src/domain/Writer.ts +0 -181
- package/src/domain/__snapshots__/Writer.spec.ts.snap +0 -10
- package/src/hooks/alterAfterDeserialize.ts +0 -5
- package/src/hooks/alterBeforeDeserialize.ts +0 -5
- package/src/hooks/alterOnDeserialize.ts +0 -5
- package/src/hooks/alterOnSerialize.ts +0 -5
- package/src/index.ts +0 -28
- package/src/interfaces/JsonMapperMethods.ts +0 -32
- package/src/utils/deserialize.spec.ts +0 -33
- package/src/utils/deserialize.ts +0 -12
- package/src/utils/getObjectProperties.ts +0 -5
- package/src/utils/serialize.spec.ts +0 -37
- package/src/utils/serialize.ts +0 -12
- package/vite.config.mts +0 -45
- package/vitest.config.mts +0 -21
|
@@ -1,402 +0,0 @@
|
|
|
1
|
-
import {classOf, isArray, isBoolean, isClass, isEmpty, isNil, nameOf, objectKeys, Type} from "@tsed/core";
|
|
2
|
-
import {getPropertiesStores, JsonClassStore, JsonEntityStore, JsonParameterStore, JsonPropertyStore} from "@tsed/schema";
|
|
3
|
-
|
|
4
|
-
import {alterAfterDeserialize} from "../hooks/alterAfterDeserialize.js";
|
|
5
|
-
import {alterBeforeDeserialize} from "../hooks/alterBeforeDeserialize.js";
|
|
6
|
-
import {alterOnDeserialize} from "../hooks/alterOnDeserialize.js";
|
|
7
|
-
import {JsonDeserializerOptions} from "./JsonDeserializerOptions.js";
|
|
8
|
-
import {CachedJsonMapper, JsonMapperCompiler} from "./JsonMapperCompiler.js";
|
|
9
|
-
import {JsonMapperSettings} from "./JsonMapperSettings.js";
|
|
10
|
-
import {getJsonMapperTypes} from "./JsonMapperTypesContainer.js";
|
|
11
|
-
import {Writer} from "./Writer.js";
|
|
12
|
-
|
|
13
|
-
function isDeserializable(obj: any, options: JsonDeserializerOptions) {
|
|
14
|
-
if ((!!options.collectionType && isNil(obj)) || obj === undefined) {
|
|
15
|
-
return false;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
return !(isEmpty(options.type) || (options.type === Object && !options.collectionType));
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function varKey(k: string) {
|
|
22
|
-
return `__${k}`;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function mapParamStoreOptions(store: JsonParameterStore, options: JsonDeserializerOptions) {
|
|
26
|
-
return {
|
|
27
|
-
...options,
|
|
28
|
-
store: undefined,
|
|
29
|
-
type: store.getBestType(),
|
|
30
|
-
collectionType: store.collectionType,
|
|
31
|
-
groups: store.parameter.groups,
|
|
32
|
-
// genericTypes: store.nestedGenerics[0],
|
|
33
|
-
generics: store.nestedGenerics
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function getGenericIndex(propertyStore: JsonPropertyStore) {
|
|
38
|
-
return propertyStore.parent.schema.genericLabels.indexOf(propertyStore.itemSchema.genericType);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export class JsonDeserializer extends JsonMapperCompiler<JsonDeserializerOptions> {
|
|
42
|
-
/**
|
|
43
|
-
* Cached classes by his id
|
|
44
|
-
* @protected
|
|
45
|
-
*/
|
|
46
|
-
protected constructors: Record<string, Type<any>> = {};
|
|
47
|
-
|
|
48
|
-
constructor() {
|
|
49
|
-
super();
|
|
50
|
-
|
|
51
|
-
this.addGlobal("newInstanceOf", this.newInstanceOf.bind(this));
|
|
52
|
-
this.addGlobal("alterBeforeDeserialize", this.alterBeforeDeserialize.bind(this));
|
|
53
|
-
this.addGlobal("alterAfterDeserialize", this.alterAfterDeserialize.bind(this));
|
|
54
|
-
|
|
55
|
-
this.addTypeMapper(Object, this.mapObject.bind(this));
|
|
56
|
-
this.addTypeMapper(Array, this.mapArray.bind(this));
|
|
57
|
-
this.addTypeMapper(Map, this.mapMap.bind(this));
|
|
58
|
-
this.addTypeMapper(Set, this.mapSet.bind(this));
|
|
59
|
-
this.addTypeMapper("ObjectId", (value: any) => String(value));
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
map<Model = any>(input: any, options: JsonDeserializerOptions = {}): Model {
|
|
63
|
-
options = this.mapOptions(options);
|
|
64
|
-
|
|
65
|
-
if (!isDeserializable(input, options)) {
|
|
66
|
-
return input;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
if (!options.collectionType && isArray(input)) {
|
|
70
|
-
options.collectionType = Array;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const model = options.type || classOf(input);
|
|
74
|
-
|
|
75
|
-
const mapper = this.compile(model, options.groups!);
|
|
76
|
-
|
|
77
|
-
if (options.collectionType) {
|
|
78
|
-
const collectionMapper = this.compile(options.collectionType, options.groups!);
|
|
79
|
-
return collectionMapper.fn(input, {...options, id: mapper.id});
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
return mapper.fn(input, this.createContext(options));
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
compile(model: Type<any>, groups: false | string[]): CachedJsonMapper<JsonDeserializerOptions> {
|
|
86
|
-
if ([WeakMap, WeakSet].includes(model)) {
|
|
87
|
-
throw new Error(`${nameOf(model)} is not supported by JsonMapper.`);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
return super.compile(model, groups);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
eval(
|
|
94
|
-
mapper: string,
|
|
95
|
-
{
|
|
96
|
-
id,
|
|
97
|
-
groupsId,
|
|
98
|
-
model
|
|
99
|
-
}: {
|
|
100
|
-
id: string;
|
|
101
|
-
model: Type<any>;
|
|
102
|
-
groupsId: string;
|
|
103
|
-
}
|
|
104
|
-
): CachedJsonMapper<JsonDeserializerOptions> {
|
|
105
|
-
this.constructors[id] = model;
|
|
106
|
-
|
|
107
|
-
return super.eval(mapper, {id, groupsId, model});
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
protected newInstanceOf(id: string, obj: any, options: any) {
|
|
111
|
-
try {
|
|
112
|
-
return new this.constructors[id](options.disableUnsecureConstructor ? {} : obj);
|
|
113
|
-
} catch (er) {
|
|
114
|
-
return obj;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
protected createMapper(model: Type<any>, id: string, groups: false | string[]): string {
|
|
119
|
-
const entity = JsonEntityStore.from(model);
|
|
120
|
-
const properties = new Set<string>();
|
|
121
|
-
const schemaProperties = [...getPropertiesStores(entity).values()];
|
|
122
|
-
|
|
123
|
-
const writer = new Writer().arrow("input", "options");
|
|
124
|
-
|
|
125
|
-
writer.if("isNil(input)").return("input");
|
|
126
|
-
|
|
127
|
-
if (entity.schema.hasDiscriminator) {
|
|
128
|
-
writer.add(this.mapDiscriminator(entity, groups));
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// pre hook
|
|
132
|
-
if (entity.schema.$hooks?.has("beforeDeserialize")) {
|
|
133
|
-
this.schemes[id] = entity.schema;
|
|
134
|
-
writer.set("input", `alterBeforeDeserialize('${id}', input, options)`);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// generics and options
|
|
138
|
-
writer.const("generics", "options.generics[0]");
|
|
139
|
-
|
|
140
|
-
if (entity.schema.genericLabels?.length) {
|
|
141
|
-
writer.set("options", "{...options, self: input, generics: [...options.generics].slice(1)}");
|
|
142
|
-
} else {
|
|
143
|
-
writer.set("options", "{...options, self: input}");
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
writer.const("obj", `newInstanceOf('${id}', input, options)`);
|
|
147
|
-
|
|
148
|
-
// properties
|
|
149
|
-
writer.add(
|
|
150
|
-
...schemaProperties.flatMap((propertyStore) => {
|
|
151
|
-
const key = propertyStore.propertyName;
|
|
152
|
-
|
|
153
|
-
// TODO V8 add this line: properties.add(key as string);
|
|
154
|
-
properties.add(String(propertyStore.parent.schema.getAliasOf(key) || key));
|
|
155
|
-
|
|
156
|
-
if (
|
|
157
|
-
(propertyStore.schema?.$ignore && isBoolean(propertyStore.schema?.$ignore)) ||
|
|
158
|
-
propertyStore.isGetterOnly() ||
|
|
159
|
-
(propertyStore.schema?.$hooks?.has("groups") && this.alterGroups(propertyStore.schema, groups))
|
|
160
|
-
) {
|
|
161
|
-
return;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
return this.mapProperty(propertyStore, id, groups);
|
|
165
|
-
})
|
|
166
|
-
);
|
|
167
|
-
|
|
168
|
-
// additional properties
|
|
169
|
-
writer.add(this.mapAdditionalProperties(entity, properties, groups));
|
|
170
|
-
|
|
171
|
-
// post hook
|
|
172
|
-
if (entity.schema.$hooks?.has("afterDeserialize")) {
|
|
173
|
-
this.schemes[id] = entity.schema;
|
|
174
|
-
|
|
175
|
-
return writer.return(`alterAfterDeserialize('${id}', obj, options)`).root().toString();
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
return writer.return("obj").root().toString();
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
protected alterValue(schemaId: string, value: any, options: JsonDeserializerOptions): any {
|
|
182
|
-
return alterOnDeserialize(this.schemes[schemaId], value, options as any);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
private mapDiscriminator(entity: JsonClassStore, groups: false | string[]) {
|
|
186
|
-
const writer = new Writer();
|
|
187
|
-
const discriminator = entity.schema.discriminator();
|
|
188
|
-
|
|
189
|
-
const sw = writer.switch(`input['${discriminator.propertyName}']`);
|
|
190
|
-
|
|
191
|
-
discriminator.values.forEach((value, kind) => {
|
|
192
|
-
const nestedMapper = this.compile(value, groups);
|
|
193
|
-
|
|
194
|
-
sw.case(`'${kind}'`).returnCallMapper(nestedMapper.id, "input");
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
return writer;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
private mapProperty(propertyStore: JsonPropertyStore, id: string, groups: false | string[]) {
|
|
201
|
-
const key = String(propertyStore.propertyKey);
|
|
202
|
-
const aliasKey: string = String(propertyStore.parent.schema.getAliasOf(key) || key);
|
|
203
|
-
const schemaId = this.getSchemaId(id, key);
|
|
204
|
-
const format = propertyStore.itemSchema.get("format");
|
|
205
|
-
const formatOpts = format && `options: {format: '${format}'}`;
|
|
206
|
-
|
|
207
|
-
let writer = new Writer().add(`// Map ${key} ${id} ${groups || ""}`);
|
|
208
|
-
const pick = key !== aliasKey ? `options.useAlias ? '${aliasKey}' : '${key}'` : `'${key}'`;
|
|
209
|
-
|
|
210
|
-
// ignore hook (deprecated)
|
|
211
|
-
if (propertyStore.schema?.$hooks?.has("ignore")) {
|
|
212
|
-
this.schemes[schemaId] = propertyStore.schema;
|
|
213
|
-
|
|
214
|
-
writer = writer.if(`!alterIgnore('${schemaId}', {...options, self: input})`);
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
// pre hook
|
|
218
|
-
const hasDeserializer = propertyStore.schema?.$hooks?.has("onDeserialize");
|
|
219
|
-
let getter = `input[${pick}]`;
|
|
220
|
-
|
|
221
|
-
if (hasDeserializer) {
|
|
222
|
-
this.schemes[schemaId] = propertyStore.schema;
|
|
223
|
-
const opts = Writer.options(formatOpts);
|
|
224
|
-
|
|
225
|
-
getter = `alterValue('${schemaId}', input[${pick}], ${opts})`;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
const ifWriter = writer.set(`let ${varKey(key)}`, getter).if(`${varKey(key)} !== undefined`);
|
|
229
|
-
|
|
230
|
-
const fill = this.getPropertyFiller(propertyStore, id, groups, formatOpts);
|
|
231
|
-
|
|
232
|
-
if (hasDeserializer) {
|
|
233
|
-
fill(ifWriter.if(`${varKey(key)} === input.${key}`));
|
|
234
|
-
} else {
|
|
235
|
-
fill(ifWriter);
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
ifWriter.set(`obj.${key}`, varKey(key));
|
|
239
|
-
|
|
240
|
-
if (groups && groups.includes("partial")) {
|
|
241
|
-
ifWriter.else().add(`delete obj.${key}`);
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
return writer.root();
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
private getPropertyFiller(propertyStore: JsonPropertyStore, id: string, groups: false | string[], formatOpts: any) {
|
|
248
|
-
const key = String(propertyStore.propertyKey);
|
|
249
|
-
const schemaId = this.getSchemaId(id, key);
|
|
250
|
-
const generics = propertyStore.itemSchema.nestedGenerics;
|
|
251
|
-
const isGeneric = propertyStore.itemSchema.isGeneric && !generics?.length;
|
|
252
|
-
|
|
253
|
-
if (isGeneric) {
|
|
254
|
-
const index = getGenericIndex(propertyStore);
|
|
255
|
-
const opts = Writer.options(formatOpts, `type: generics[${index}]`);
|
|
256
|
-
|
|
257
|
-
return (writer: Writer) => writer.set(varKey(key), `compileAndMap(${varKey(key)}, ${opts})`);
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
const type = propertyStore.itemSchema.hasDiscriminator ? propertyStore.itemSchema.discriminator().base : propertyStore.getBestType();
|
|
261
|
-
const nestedMapper = this.compile(type, groups);
|
|
262
|
-
|
|
263
|
-
if (propertyStore.isCollection) {
|
|
264
|
-
return (writer: Writer) =>
|
|
265
|
-
writer.callMapper(nameOf(propertyStore.collectionType), varKey(key), `id: '${nestedMapper.id}'`, formatOpts);
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
if (generics?.length) {
|
|
269
|
-
this.schemes[schemaId] = propertyStore.schema;
|
|
270
|
-
|
|
271
|
-
return (writer: Writer) =>
|
|
272
|
-
writer.callMapper(nestedMapper.id, varKey(key), formatOpts, `generics: schemes['${schemaId}'].nestedGenerics`);
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
return (writer: Writer) => writer.callMapper(nestedMapper.id, varKey(key), formatOpts);
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
private mapOptions({groups, useAlias = true, types, ...options}: JsonDeserializerOptions<any, any>): JsonDeserializerOptions {
|
|
279
|
-
if (options.store instanceof JsonParameterStore) {
|
|
280
|
-
return this.mapOptions(mapParamStoreOptions(options.store, options));
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
const customMappers: Record<string, any> = {};
|
|
284
|
-
types = types || getJsonMapperTypes();
|
|
285
|
-
|
|
286
|
-
types.forEach((mapper, model) => {
|
|
287
|
-
if (![Array, Set, Map].includes(model as any)) {
|
|
288
|
-
const typeName = nameOf(model);
|
|
289
|
-
|
|
290
|
-
if (nameOf(model) in mapper) {
|
|
291
|
-
this.addTypeMapper(model as any, (mapper as any)[typeName].bind(mapper));
|
|
292
|
-
} else {
|
|
293
|
-
this.addTypeMapper(model as any, (value: any, options: any) =>
|
|
294
|
-
mapper.deserialize(value, {
|
|
295
|
-
...options,
|
|
296
|
-
type: model
|
|
297
|
-
})
|
|
298
|
-
);
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
});
|
|
302
|
-
|
|
303
|
-
const strictGroups = options.strictGroups ?? JsonMapperSettings.strictGroups;
|
|
304
|
-
|
|
305
|
-
return {
|
|
306
|
-
...options,
|
|
307
|
-
additionalProperties: options.additionalProperties ?? JsonMapperSettings.additionalProperties,
|
|
308
|
-
disableUnsecureConstructor: options.disableUnsecureConstructor ?? JsonMapperSettings.disableUnsecureConstructor,
|
|
309
|
-
groups: groups === undefined ? (strictGroups ? [] : false) : groups || false,
|
|
310
|
-
useAlias,
|
|
311
|
-
customMappers,
|
|
312
|
-
generics: options.generics || []
|
|
313
|
-
};
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
private mapAdditionalProperties(entity: JsonClassStore, properties: Set<string>, groups: string[] | false) {
|
|
317
|
-
const additionalProperties = entity.schema.get("additionalProperties");
|
|
318
|
-
|
|
319
|
-
const exclude = [...properties.values()].map((key) => `'${key}'`).join(", ");
|
|
320
|
-
const writer = new Writer();
|
|
321
|
-
|
|
322
|
-
writer.add("// add additional properties");
|
|
323
|
-
let each = writer.each("objectKeys(input)", ["key"]);
|
|
324
|
-
|
|
325
|
-
if (exclude.length) {
|
|
326
|
-
each = each.if(`![${exclude}].includes(key)`);
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
if (isClass(additionalProperties)) {
|
|
330
|
-
const nestedMapper = this.compile(additionalProperties.getComputedType(), groups);
|
|
331
|
-
|
|
332
|
-
each.set("obj[key]", Writer.mapper(nestedMapper.id, "input[key]", "options"));
|
|
333
|
-
|
|
334
|
-
return writer;
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
if (additionalProperties) {
|
|
338
|
-
each.set("obj[key]", "input[key]");
|
|
339
|
-
|
|
340
|
-
return writer;
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
// dynamic additional properties options
|
|
344
|
-
each.if(`options.additionalProperties && obj[key] === undefined`).set("obj[key]", "input[key]");
|
|
345
|
-
|
|
346
|
-
return writer;
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
private mapObject(input: any, options: JsonDeserializerOptions) {
|
|
350
|
-
return input;
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
private mapSet(input: any, options: JsonDeserializerOptions): Set<any> {
|
|
354
|
-
if (isNil(input)) {
|
|
355
|
-
return input;
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
const obj = new Set<any>();
|
|
359
|
-
|
|
360
|
-
objectKeys(input).forEach((key) => {
|
|
361
|
-
obj.add(this.mapItem(input[key], options));
|
|
362
|
-
});
|
|
363
|
-
|
|
364
|
-
return obj;
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
private mapArray(input: any, options: JsonDeserializerOptions) {
|
|
368
|
-
if (isNil(input)) {
|
|
369
|
-
return input;
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
return [].concat(input).map((item: any) => {
|
|
373
|
-
return this.mapItem(item, options);
|
|
374
|
-
});
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
private mapMap(input: any, options: JsonDeserializerOptions): Map<string, any> {
|
|
378
|
-
if (isNil(input)) {
|
|
379
|
-
return input;
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
const obj = new Map<string, any>();
|
|
383
|
-
|
|
384
|
-
objectKeys(input).forEach((key) => {
|
|
385
|
-
obj.set(key, this.mapItem(input[key], options));
|
|
386
|
-
});
|
|
387
|
-
|
|
388
|
-
return obj;
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
private mapItem(input: any, {id, ...options}: JsonDeserializerOptions) {
|
|
392
|
-
return this.execMapper(id, input, options);
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
private alterBeforeDeserialize(schemaId: string, value: any, options: JsonDeserializerOptions): any {
|
|
396
|
-
return alterBeforeDeserialize(value, this.schemes[schemaId], options);
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
private alterAfterDeserialize(schemaId: string, value: any, options: JsonDeserializerOptions): any {
|
|
400
|
-
return alterAfterDeserialize(value, this.schemes[schemaId], options);
|
|
401
|
-
}
|
|
402
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import {MetadataTypes, Type} from "@tsed/core";
|
|
2
|
-
import {JsonEntityStore} from "@tsed/schema";
|
|
3
|
-
|
|
4
|
-
import {JsonMapperMethods} from "../interfaces/JsonMapperMethods.js";
|
|
5
|
-
import {JsonMapperGlobalOptions} from "./JsonMapperGlobalOptions.js";
|
|
6
|
-
|
|
7
|
-
export interface JsonDeserializerOptions<T = any, C = any> extends MetadataTypes<T, C>, JsonMapperGlobalOptions {
|
|
8
|
-
/**
|
|
9
|
-
* Types used to map complex types (Symbol, Array, Set, Map)
|
|
10
|
-
*/
|
|
11
|
-
types?: Map<Type | Symbol | string, JsonMapperMethods>;
|
|
12
|
-
/**
|
|
13
|
-
* useAlias mapping
|
|
14
|
-
*/
|
|
15
|
-
useAlias?: boolean;
|
|
16
|
-
/**
|
|
17
|
-
* Use the store which have all metadata to deserialize correctly the model. This
|
|
18
|
-
* property is useful when you deal with metadata parameters.
|
|
19
|
-
*/
|
|
20
|
-
store?: JsonEntityStore;
|
|
21
|
-
/**
|
|
22
|
-
*
|
|
23
|
-
*/
|
|
24
|
-
groups?: string[] | false;
|
|
25
|
-
/**
|
|
26
|
-
* Add types to deserialize a module using generics feature.
|
|
27
|
-
*/
|
|
28
|
-
generics?: Type[][];
|
|
29
|
-
|
|
30
|
-
[key: string]: any;
|
|
31
|
-
}
|
|
@@ -1,247 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ancestorsOf,
|
|
3
|
-
classOf,
|
|
4
|
-
getRandomId,
|
|
5
|
-
hasJsonMethod,
|
|
6
|
-
isClass,
|
|
7
|
-
isCollection,
|
|
8
|
-
isDate,
|
|
9
|
-
isMomentObject,
|
|
10
|
-
isMongooseObject,
|
|
11
|
-
isNil,
|
|
12
|
-
isObject,
|
|
13
|
-
isObjectID,
|
|
14
|
-
isString,
|
|
15
|
-
nameOf,
|
|
16
|
-
objectKeys,
|
|
17
|
-
Type
|
|
18
|
-
} from "@tsed/core";
|
|
19
|
-
import {JsonSchema} from "@tsed/schema";
|
|
20
|
-
|
|
21
|
-
export type JsonMapperCallback<Options> = (input: any, options?: Options) => any;
|
|
22
|
-
export type CachedJsonMapper<Options> = {
|
|
23
|
-
id: string;
|
|
24
|
-
fn: JsonMapperCallback<Options>;
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
export type CachedGroupsJsonMapper<Options> = Map<string, CachedJsonMapper<Options>>;
|
|
28
|
-
|
|
29
|
-
export abstract class JsonMapperCompiler<Options extends Record<string, any> = any> {
|
|
30
|
-
/**
|
|
31
|
-
* Cached mappers metadata
|
|
32
|
-
* @protected
|
|
33
|
-
*/
|
|
34
|
-
protected cache = new Map<Type<any> | string, CachedGroupsJsonMapper<Options>>();
|
|
35
|
-
/**
|
|
36
|
-
* Cached executable mappers by his id
|
|
37
|
-
* @protected
|
|
38
|
-
*/
|
|
39
|
-
protected mappers: Record<string, JsonMapperCallback<Options>> = {};
|
|
40
|
-
/**
|
|
41
|
-
* Cached schemas
|
|
42
|
-
* @protected
|
|
43
|
-
*/
|
|
44
|
-
protected schemes: Record<string, any> = {};
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Cached classes by his id
|
|
48
|
-
* @protected
|
|
49
|
-
*/
|
|
50
|
-
protected constructors: Record<string, Type<any>> = {};
|
|
51
|
-
/**
|
|
52
|
-
* Global variables available in the mapper
|
|
53
|
-
* @protected
|
|
54
|
-
*/
|
|
55
|
-
protected globals: Record<string, any> = {
|
|
56
|
-
isCollection,
|
|
57
|
-
isClass,
|
|
58
|
-
isObject,
|
|
59
|
-
classOf,
|
|
60
|
-
nameOf,
|
|
61
|
-
hasJsonMethod,
|
|
62
|
-
isMongooseObject,
|
|
63
|
-
isNil,
|
|
64
|
-
isDate,
|
|
65
|
-
objectKeys,
|
|
66
|
-
isMomentObject
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
constructor() {
|
|
70
|
-
this.addGlobal("alterIgnore", this.alterIgnore.bind(this));
|
|
71
|
-
this.addGlobal("alterValue", this.alterValue.bind(this));
|
|
72
|
-
this.addGlobal("execMapper", this.execMapper.bind(this));
|
|
73
|
-
this.addGlobal("compileAndMap", this.map.bind(this));
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
addTypeMapper(model: Type<any> | string, fn: any) {
|
|
77
|
-
const id = nameOf(model);
|
|
78
|
-
|
|
79
|
-
this.cache.set(
|
|
80
|
-
model,
|
|
81
|
-
new Map().set("typeMapper", {
|
|
82
|
-
id,
|
|
83
|
-
fn
|
|
84
|
-
})
|
|
85
|
-
);
|
|
86
|
-
|
|
87
|
-
this.mappers[id] = fn;
|
|
88
|
-
|
|
89
|
-
return this;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
removeTypeMapper(model: Type<any> | string) {
|
|
93
|
-
const store = this.cache.get(model);
|
|
94
|
-
|
|
95
|
-
if (store) {
|
|
96
|
-
const {id} = store.get("typeMapper")!;
|
|
97
|
-
|
|
98
|
-
delete this.mappers[id];
|
|
99
|
-
this.cache.delete(model);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
addGlobal(key: string, value: any) {
|
|
104
|
-
this.globals[key] = value;
|
|
105
|
-
|
|
106
|
-
return this;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
eval(mapper: string, {id, groupsId, model}: {id: string; model: Type<any> | string; groupsId: string}) {
|
|
110
|
-
this.addGlobal("cache", this.cache);
|
|
111
|
-
|
|
112
|
-
const {globals, schemes} = this;
|
|
113
|
-
|
|
114
|
-
const injectGlobals = Object.keys(globals)
|
|
115
|
-
.map((name) => {
|
|
116
|
-
return `const ${name} = globals.${name};`;
|
|
117
|
-
})
|
|
118
|
-
.join("\n");
|
|
119
|
-
|
|
120
|
-
eval(`${injectGlobals};
|
|
121
|
-
|
|
122
|
-
cache.get(model).set(groupsId, { id: '${id}', fn: ${mapper} })`);
|
|
123
|
-
|
|
124
|
-
const store = this.cache.get(model)!.get(groupsId)!;
|
|
125
|
-
|
|
126
|
-
this.mappers[id] = store.fn;
|
|
127
|
-
|
|
128
|
-
return store;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
createContext(options: Options) {
|
|
132
|
-
const {cache} = this;
|
|
133
|
-
|
|
134
|
-
return {
|
|
135
|
-
...options,
|
|
136
|
-
cache
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
compile(
|
|
141
|
-
model: Type<any> | string,
|
|
142
|
-
groups: false | string[],
|
|
143
|
-
opts: {
|
|
144
|
-
mapper?: any;
|
|
145
|
-
} = {}
|
|
146
|
-
): CachedJsonMapper<Options> {
|
|
147
|
-
const token = isString(model) ? model : this.getType(model);
|
|
148
|
-
|
|
149
|
-
const groupsId = this.getGroupsId(groups);
|
|
150
|
-
let storeGroups = this.cache.get(token) || this.cache.get(nameOf(token));
|
|
151
|
-
|
|
152
|
-
if (!storeGroups) {
|
|
153
|
-
storeGroups = new Map();
|
|
154
|
-
this.cache.set(token, storeGroups);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
if (storeGroups.has("typeMapper")) {
|
|
158
|
-
return storeGroups.get("typeMapper")!;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// generate mapper for the given groups
|
|
162
|
-
if (!storeGroups.has(groupsId)) {
|
|
163
|
-
const id = this.getId(token, groupsId);
|
|
164
|
-
|
|
165
|
-
// prevent circular dependencies
|
|
166
|
-
storeGroups.set(groupsId, {
|
|
167
|
-
id
|
|
168
|
-
} as any);
|
|
169
|
-
|
|
170
|
-
const mapper = opts.mapper ? opts.mapper(id, groups) : this.createMapper(token as Type<any>, id, groups);
|
|
171
|
-
|
|
172
|
-
try {
|
|
173
|
-
return this.eval(mapper, {id, model: token, groupsId});
|
|
174
|
-
} catch (err) {
|
|
175
|
-
throw new Error(`Fail to compile mapper for ${nameOf(model)}. See the error above: ${err.message}.\n${mapper}`);
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
return storeGroups!.get(groupsId)!;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
protected execMapper(id: string, value: any, options: Options) {
|
|
183
|
-
if (isObjectID(value)) {
|
|
184
|
-
return value.toString();
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
return this.mappers[id || nameOf(classOf(value))](value, options);
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
protected abstract map(input: any, options: Options): any;
|
|
191
|
-
|
|
192
|
-
protected abstract alterValue(schemaId: string, value: any, options: Options): any;
|
|
193
|
-
|
|
194
|
-
protected abstract createMapper(model: Type<any>, id: string, groups: false | string[]): string;
|
|
195
|
-
|
|
196
|
-
protected getType(model: Type<any>) {
|
|
197
|
-
if (!model) {
|
|
198
|
-
return Object;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
if (isClass(model) && !isCollection(model)) {
|
|
202
|
-
const type = [Array, Map, Set].find((t) => ancestorsOf(model).includes(t));
|
|
203
|
-
|
|
204
|
-
if (type) {
|
|
205
|
-
return type;
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
return model;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
protected alterIgnore(id: string, options: Options) {
|
|
213
|
-
let result = this.schemes[id]?.$hooks?.alter("ignore", false, [options]);
|
|
214
|
-
|
|
215
|
-
if (result) {
|
|
216
|
-
return result;
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
protected alterGroups(schema: JsonSchema, groups: false | string[]) {
|
|
221
|
-
if (groups !== false) {
|
|
222
|
-
return schema.$hooks.alter("groups", false, [groups]);
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
return false;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
protected getGroupsId(groups: false | string[]) {
|
|
229
|
-
if (groups === false) {
|
|
230
|
-
return "default";
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
if (groups.length === 0) {
|
|
234
|
-
return "-";
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
return groups.join(",");
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
protected getId(model: Type<any> | string, groupsId: string) {
|
|
241
|
-
return `${isString(model) ? model : nameOf(model)}:${getRandomId()}:${groupsId}`;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
protected getSchemaId(id: string, propertyKey: string) {
|
|
245
|
-
return `${id}:${propertyKey}`;
|
|
246
|
-
}
|
|
247
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
export interface JsonMapperGlobalOptions {
|
|
2
|
-
/**
|
|
3
|
-
* JsonMapper additional property policy. (see [JsonMapper](/docs/json-mapper.md))
|
|
4
|
-
*/
|
|
5
|
-
additionalProperties?: boolean;
|
|
6
|
-
/**
|
|
7
|
-
* Disable the unsecure constructor injection when the deserialize function is used (by default: false)
|
|
8
|
-
*/
|
|
9
|
-
disableUnsecureConstructor?: boolean;
|
|
10
|
-
/**
|
|
11
|
-
* Enable strict Groups configuration when the `options.groups` is undefined. (by default: false)
|
|
12
|
-
*/
|
|
13
|
-
strictGroups?: boolean;
|
|
14
|
-
}
|