Skip to content

Commit 81ac3c1

Browse files
committed
refactor: enhance documentation for methods in Serializable class and related functions
1 parent 6b7c61f commit 81ac3c1

File tree

7 files changed

+342
-77
lines changed

7 files changed

+342
-77
lines changed

src/classes/Serializable.ts

Lines changed: 138 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,31 @@ import {fromJSON} from "../functions/FromJSON.js";
1010
import {toJSON} from "../functions/ToJSON.js";
1111

1212
/**
13-
* Class that helps you deserialize objects to classes.
13+
* Base class that provides serialization and deserialization functionality for converting
14+
* objects to and from JSON format. This class uses decorators to define how properties
15+
* should be serialized and deserialized.
1416
*
1517
* @export
1618
* @class Serializable
19+
* @example
20+
* ```typescript
21+
* class User extends Serializable {
22+
* @JsonProperty()
23+
* name: string;
24+
*
25+
* @JsonProperty()
26+
* age: number;
27+
* }
28+
*
29+
* const user = User.fromJSON({ name: "John", age: 30 });
30+
* const json = user.toJSON();
31+
* ```
1732
*/
1833
export class Serializable {
1934

2035
/**
21-
* Global settings for serialization and deserialization.
36+
* Global default settings for all serialization and deserialization operations.
37+
* These settings can be overridden per operation by passing custom settings.
2238
*
2339
* @static
2440
* @type {SerializationSettings}
@@ -27,15 +43,19 @@ export class Serializable {
2743
public static defaultSettings: SerializationSettings = new SerializationSettings();
2844

2945
/**
30-
* Deserialize an object using a static method.
31-
*
32-
* Example:
33-
* const obj: MyObject = MyObject.fromJSON({...data});
46+
* Creates a new instance of the class and deserializes JSON data into it.
47+
* This is a convenient static method that combines instantiation and deserialization.
3448
*
3549
* @static
36-
* @param {object} json
37-
* @returns {object}
50+
* @template T - The type of the Serializable class
51+
* @param {object} json - The JSON object to deserialize
52+
* @param {Partial<SerializationSettings>} [settings] - Optional settings to override default serialization behavior
53+
* @returns {T} A new instance of the class with properties populated from the JSON
3854
* @memberof Serializable
55+
* @example
56+
* ```typescript
57+
* const user = User.fromJSON({ name: "John", age: 30 });
58+
* ```
3959
*/
4060
public static fromJSON<T extends Serializable>(
4161
this: new () => T,
@@ -46,15 +66,20 @@ export class Serializable {
4666
}
4767

4868
/**
49-
* Deserialize an object from a string using a static method.
50-
*
51-
* Example:
52-
* const obj: MyObject = MyObject.fromString("{...data}");
69+
* Creates a new instance of the class and deserializes JSON string data into it.
70+
* Automatically parses the JSON string before deserialization.
5371
*
5472
* @static
55-
* @param {string} str
56-
* @returns {object}
73+
* @template T - The type of the Serializable class
74+
* @param {string} str - The JSON string to parse and deserialize
75+
* @param {Partial<SerializationSettings>} [settings] - Optional settings to override default serialization behavior
76+
* @returns {T} A new instance of the class with properties populated from the parsed JSON
5777
* @memberof Serializable
78+
* @throws {SyntaxError} If the string is not valid JSON
79+
* @example
80+
* ```typescript
81+
* const user = User.fromString('{"name":"John","age":30}');
82+
* ```
5883
*/
5984
public static fromString<T extends Serializable>(
6085
this: new () => T,
@@ -65,94 +90,138 @@ export class Serializable {
6590
}
6691

6792
/**
68-
* Fill properties of the current model with data from JSON.
93+
* Populates the current instance's properties with data from a JSON object.
94+
* Uses metadata from decorators to determine how to deserialize each property.
6995
*
70-
* Example:
71-
* const obj: MyObject = new MyObject().fromJSON({...data});
72-
*
73-
* @param {object} json
74-
* @returns {this}
96+
* @param {object} json - The JSON object containing data to populate the instance
97+
* @param {Partial<SerializationSettings>} [settings] - Optional settings to override default serialization behavior
98+
* @returns {this} The current instance for method chaining
7599
* @memberof Serializable
100+
* @example
101+
* ```typescript
102+
* const user = new User();
103+
* user.fromJSON({ name: "John", age: 30 });
104+
* ```
76105
*/
77106
public fromJSON (json: object, settings?: Partial<SerializationSettings>): this {
78107
return fromJSON<this>(this, json, settings);
79108
}
80109

81110
/**
82-
* Fill properties of the current model with data from a string.
83-
*
84-
* Example:
85-
* const obj: MyObject = new MyObject().fromString("{...data}");
111+
* Populates the current instance's properties with data from a JSON string.
112+
* Automatically parses the JSON string before populating properties.
86113
*
87-
* @param {string} str
88-
* @returns {this}
114+
* @param {string} str - The JSON string to parse and use for populating the instance
115+
* @param {Partial<SerializationSettings>} [settings] - Optional settings to override default serialization behavior
116+
* @returns {this} The current instance for method chaining
89117
* @memberof Serializable
118+
* @throws {SyntaxError} If the string is not valid JSON
119+
* @example
120+
* ```typescript
121+
* const user = new User();
122+
* user.fromString('{"name":"John","age":30}');
123+
* ```
90124
*/
91125
public fromString (str: string, settings?: Partial<SerializationSettings>): this {
92126
return this.fromJSON(JSON.parse(str), settings);
93127
}
94128

95129
/**
96-
* Process serialization for the @jsonIgnore decorator.
130+
* Serializes the current instance to a plain JavaScript object.
131+
* Respects @JsonIgnore decorators to exclude specific properties from serialization.
132+
* Applies naming strategies and @JsonName decorators for property name transformation.
97133
*
98-
* @returns {object}
134+
* @returns {Record<string, unknown>} A plain object representation of the instance
99135
* @memberof Serializable
136+
* @example
137+
* ```typescript
138+
* const user = new User();
139+
* user.name = "John";
140+
* user.age = 30;
141+
* const json = user.toJSON(); // { name: "John", age: 30 }
142+
* ```
100143
*/
101144
public toJSON (): Record<string, unknown> {
102145
return toJSON(this);
103146
}
104147

105148
/**
106-
* Serialize the class to FormData.
149+
* Serializes the current instance to FormData format, suitable for multipart/form-data requests.
150+
* This is particularly useful for AJAX form submissions that include file uploads.
151+
* Unlike JSON serialization with base64-encoded files, FormData provides better performance
152+
* and avoids UI freezing when handling large files.
107153
*
108-
* Can be used to prepare an AJAX form with files.
109-
* Sending files via AJAX JSON is a heavy task because it requires converting files to base64 format.
110-
* The user interface can freeze for several seconds during this operation if the file is too large.
111-
* AJAX forms are a lightweight alternative.
112-
*
113-
* @param {string} formPrefix Prefix for form property names
114-
* @param {FormData} formData Can update an existing FormData
115-
* @returns {FormData}
154+
* @param {string} [formPrefix] - Optional prefix to prepend to all form field names
155+
* @param {FormData} [formData] - Optional existing FormData instance to append to
156+
* @returns {FormData} A FormData instance containing the serialized data
116157
* @memberof Serializable
158+
* @example
159+
* ```typescript
160+
* const user = new User();
161+
* user.name = "John";
162+
* user.avatar = fileInput.files[0];
163+
* const formData = user.toFormData();
164+
* // Use with fetch: fetch('/api/users', { method: 'POST', body: formData });
165+
* ```
117166
*/
118167
public toFormData (formPrefix?: string, formData?: FormData): FormData {
119168
return classToFormData(this, formPrefix, formData);
120169
}
121170

122171
/**
123-
* Process serialization for the @jsonIgnore decorator.
172+
* Serializes the current instance to a JSON string.
173+
* This is a convenience method that combines toJSON() with JSON.stringify().
124174
*
125-
* @returns {string}
175+
* @returns {string} A JSON string representation of the instance
126176
* @memberof Serializable
177+
* @example
178+
* ```typescript
179+
* const user = new User();
180+
* user.name = "John";
181+
* user.age = 30;
182+
* const jsonString = user.toString(); // '{"name":"John","age":30}'
183+
* ```
127184
*/
128185
public toString (): string {
129186
return JSON.stringify(this.toJSON());
130187
}
131188

132189
/**
133-
* Process exceptions for incorrect types.
134-
* By default, it just prints a warning in the console, but it can be overridden to throw exceptions or log to the backend.
190+
* Handles type mismatch errors during deserialization.
191+
* By default, logs an error to the console. Can be overridden in subclasses to implement
192+
* custom error handling such as throwing exceptions, logging to external services, or
193+
* collecting validation errors.
135194
*
136-
* @protected
137-
* @param {string} prop
138-
* @param {string} message
139-
* @param {(unknown)} jsonValue
195+
* @public
196+
* @param {string} prop - The name of the property that has a type mismatch
197+
* @param {string} message - A description of the type error
198+
* @param {unknown} jsonValue - The actual value that caused the type mismatch
140199
* @memberof Serializable
200+
* @example
201+
* ```typescript
202+
* class User extends Serializable {
203+
* onWrongType(prop: string, message: string, jsonValue: unknown): void {
204+
* throw new Error(`Invalid ${prop}: ${message}`);
205+
* }
206+
* }
207+
* ```
141208
*/
142209
public onWrongType (prop: string, message: string, jsonValue: unknown): void {
143210
// eslint-disable-next-line no-console
144211
console.error(`${this.constructor.name}.fromJSON: json.${prop} ${message}:`, jsonValue);
145212
}
146213

147214
/**
148-
* Deserialize one property.
215+
* Deserializes a single property value based on its accepted types.
216+
* This method is used internally during deserialization to convert JSON values
217+
* to the appropriate TypeScript types defined by decorators.
149218
*
150-
* @private
151-
* @param {object} object
152-
* @param {string} prop
153-
* @param {AcceptedTypes[]} acceptedTypes
154-
* @param {(unknown)} jsonValue
155-
* @returns {(Object | null | void)}
219+
* @public
220+
* @param {string} prop - The name of the property being deserialized
221+
* @param {AcceptedTypes[]} acceptedTypes - Array of allowed types for this property
222+
* @param {unknown} jsonValue - The JSON value to deserialize
223+
* @param {Partial<SerializationSettings>} [settings] - Optional settings to override default behavior
224+
* @returns {unknown} The deserialized value matching one of the accepted types
156225
* @memberof Serializable
157226
*/
158227
// eslint-disable-next-line max-params
@@ -166,12 +235,24 @@ export class Serializable {
166235
}
167236

168237
/**
169-
* Extract the correct name for a property.
170-
* Considers decorators for transforming the property name.
238+
* Determines the JSON property name for a given class property.
239+
* Takes into account @JsonName decorators and naming strategies (camelCase, snake_case, etc.)
240+
* defined in the serialization settings.
171241
*
172-
* @param {string} property Source name of the property
173-
* @param {Partial<SerializationSettings>} settings Serialization settings
174-
* @returns
242+
* @public
243+
* @param {string} property - The source property name as defined in the class
244+
* @param {Partial<SerializationSettings>} [settings] - Optional settings to override default naming behavior
245+
* @returns {string} The transformed property name to use in JSON
246+
* @memberof Serializable
247+
* @example
248+
* ```typescript
249+
* // With @JsonName decorator
250+
* class User extends Serializable {
251+
* @JsonName("user_name")
252+
* userName: string;
253+
* }
254+
* // user.getJsonPropertyName("userName") returns "user_name"
255+
* ```
175256
*/
176257
public getJsonPropertyName (property: string, settings?: Partial<SerializationSettings>): string {
177258
return getPropertyName(this, property, settings);

src/functions/ClassToFormData.ts

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,37 @@
33
import {getPropertyName} from "./GetPropertyName.js";
44

55
/**
6-
* Converts a class instance to FormData for use in AJAX forms.
6+
* Converts a class instance to FormData format for multipart/form-data HTTP requests.
7+
* This function recursively processes nested objects, arrays, and handles special types like File and Date.
8+
* Properties marked with @JsonIgnore decorator are excluded from the conversion.
79
*
8-
* @param {object} obj - The class instance to convert.
9-
* @param {string} [formPrefix] - Optional prefix for form property names.
10-
* @param {FormData} [formData] - Optional existing FormData to update.
11-
* @returns {FormData} - The resulting FormData object.
10+
* @param {object} obj - The class instance or object to convert to FormData
11+
* @param {string} [formPrefix] - Optional prefix for form property names (used for nested objects, e.g., "user.address")
12+
* @param {FormData} [formData] - Optional existing FormData instance to append to. If not provided, creates a new one
13+
* @returns {FormData} The FormData object containing all serialized properties
14+
*
15+
* @example
16+
* ```typescript
17+
* const user = {
18+
* name: "John",
19+
* age: 30,
20+
* avatar: fileInput.files[0],
21+
* address: { city: "New York" }
22+
* };
23+
* const formData = classToFormData(user);
24+
* // Results in FormData with entries:
25+
* // name: "John"
26+
* // age: "30"
27+
* // avatar: [File object]
28+
* // address.city: "New York"
29+
* ```
30+
*
31+
* @remarks
32+
* - File objects are appended directly to FormData
33+
* - Date objects are converted to ISO strings
34+
* - Null values are skipped
35+
* - Arrays are processed recursively with indices for nested objects
36+
* - Nested objects use dot notation for property names
1237
*/
1338
export const classToFormData = (obj: object, formPrefix?: string, formData?: FormData) => {
1439
const newFormData = formData ?? new FormData();

src/functions/DeserializeProperty.ts

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,39 @@ import {fromJSON} from "./FromJSON";
55
import {onWrongType} from "./OnWrongType";
66

77
/**
8-
* Deserializes a property value from JSON based on the accepted types.
9-
* This function attempts to convert the provided JSON value into one of the specified accepted types,
10-
* handling primitives, arrays, dates, and serializable objects.
8+
* Deserializes a single property value from JSON data based on accepted type definitions.
9+
* This function iterates through accepted types and attempts to match and convert the JSON value
10+
* to the appropriate TypeScript type. Supports primitives, arrays, dates, and complex object types.
1111
*
12-
* @param obj - The object instance to which the property belongs.
13-
* @param prop - The name of the property being deserialized.
14-
* @param acceptedTypes - An array of accepted types for the property.
15-
* @param jsonValue - The JSON value to deserialize.
16-
* @param settings - Optional serialization settings to customize the deserialization process.
17-
* @returns The deserialized value matching one of the accepted types, or the original property value if deserialization fails.
12+
* @param {object} obj - The object instance to which the property belongs
13+
* @param {string} prop - The name of the property being deserialized
14+
* @param {AcceptedTypes[]} acceptedTypes - Array of type constructors or type definitions that the property can accept
15+
* @param {unknown} jsonValue - The raw JSON value to deserialize and convert
16+
* @param {Partial<SerializationSettings>} [settings] - Optional settings to customize deserialization behavior
17+
* @returns {unknown} The deserialized and typed value, or the original property value if no type match is found
18+
*
19+
* @remarks
20+
* Supported type conversions:
21+
* - `null` - Preserves null values
22+
* - `undefined` (void 0) - For deep copy operations
23+
* - `Boolean` - Converts boolean values and Boolean objects
24+
* - `Number` - Converts numeric values and Number objects
25+
* - `String` - Converts string values and String objects
26+
* - `Object` - Converts plain objects
27+
* - `Date` - Parses ISO strings, Date objects, and validates date values
28+
* - `Array` - Recursively deserializes array elements
29+
* - `Serializable` subclasses - Creates instances and calls fromJSON
30+
* - Custom classes - Creates instances and applies fromJSON for non-Serializable classes
31+
* - Instance checks - Validates existing instances of specific classes
32+
*
33+
* If no type matches, calls `onWrongType` error handler and returns the original property value.
34+
*
35+
* @example
36+
* ```typescript
37+
* const acceptedTypes = [String, Number];
38+
* const result = deserializeProperty(obj, "age", acceptedTypes, "30");
39+
* // Returns the string "30" since String is checked first
40+
* ```
1841
*/
1942
// eslint-disable-next-line max-lines-per-function, max-statements, complexity
2043
export const deserializeProperty = (

0 commit comments

Comments
 (0)