adorn-api 1.1.1 → 1.1.2
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.
|
@@ -121,7 +121,15 @@ function isPlainObject(value) {
|
|
|
121
121
|
!(value instanceof Date));
|
|
122
122
|
}
|
|
123
123
|
function toPlainObject(value) {
|
|
124
|
-
// 1.
|
|
124
|
+
// 1. Check if value has custom toJSON method (e.g., metal-orm entities)
|
|
125
|
+
if (value !== null &&
|
|
126
|
+
typeof value === "object" &&
|
|
127
|
+
typeof value.toJSON === "function") {
|
|
128
|
+
// Use the custom toJSON which handles circular refs and includes properly
|
|
129
|
+
const jsonResult = value.toJSON();
|
|
130
|
+
return jsonResult;
|
|
131
|
+
}
|
|
132
|
+
// 2. Handle lazy-load wrappers (BelongsToReference)
|
|
125
133
|
if (typeof value === "object" && typeof value.load === "function") {
|
|
126
134
|
const wrapper = value;
|
|
127
135
|
if (wrapper.current !== undefined && wrapper.current !== null) {
|
|
@@ -132,11 +140,11 @@ function toPlainObject(value) {
|
|
|
132
140
|
}
|
|
133
141
|
return null;
|
|
134
142
|
}
|
|
135
|
-
//
|
|
143
|
+
// 3. Handle plain objects
|
|
136
144
|
if (isPlainObject(value)) {
|
|
137
145
|
return value;
|
|
138
146
|
}
|
|
139
|
-
//
|
|
147
|
+
// 4. Convert class instances to plain objects
|
|
140
148
|
if (typeof value === "object") {
|
|
141
149
|
const result = {};
|
|
142
150
|
for (const key of Object.getOwnPropertyNames(value)) {
|
package/package.json
CHANGED
|
@@ -138,7 +138,16 @@ function isPlainObject(value: unknown): value is Record<string, unknown> {
|
|
|
138
138
|
}
|
|
139
139
|
|
|
140
140
|
function toPlainObject(value: unknown): Record<string, unknown> | null {
|
|
141
|
-
// 1.
|
|
141
|
+
// 1. Check if value has custom toJSON method (e.g., metal-orm entities)
|
|
142
|
+
if (value !== null &&
|
|
143
|
+
typeof value === "object" &&
|
|
144
|
+
typeof (value as { toJSON?: () => unknown }).toJSON === "function") {
|
|
145
|
+
// Use the custom toJSON which handles circular refs and includes properly
|
|
146
|
+
const jsonResult = (value as { toJSON: () => unknown }).toJSON();
|
|
147
|
+
return jsonResult as Record<string, unknown>;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// 2. Handle lazy-load wrappers (BelongsToReference)
|
|
142
151
|
if (typeof value === "object" && typeof (value as Record<string, unknown>).load === "function") {
|
|
143
152
|
const wrapper = value as { current: unknown; loaded: boolean; load: () => unknown };
|
|
144
153
|
if (wrapper.current !== undefined && wrapper.current !== null) {
|
|
@@ -149,11 +158,11 @@ function toPlainObject(value: unknown): Record<string, unknown> | null {
|
|
|
149
158
|
}
|
|
150
159
|
return null;
|
|
151
160
|
}
|
|
152
|
-
//
|
|
161
|
+
// 3. Handle plain objects
|
|
153
162
|
if (isPlainObject(value)) {
|
|
154
163
|
return value;
|
|
155
164
|
}
|
|
156
|
-
//
|
|
165
|
+
// 4. Convert class instances to plain objects
|
|
157
166
|
if (typeof value === "object") {
|
|
158
167
|
const result: Record<string, unknown> = {};
|
|
159
168
|
for (const key of Object.getOwnPropertyNames(value)) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { describe, it, expect } from "vitest";
|
|
2
2
|
import { serializeResponse } from "../../src/adapter/express/response-serializer";
|
|
3
3
|
import { t } from "../../src/core/schema";
|
|
4
|
+
import { Dto, Field } from "../../src/core/decorators";
|
|
4
5
|
|
|
5
6
|
describe("serializeResponse", () => {
|
|
6
7
|
describe("Buffer with format: byte", () => {
|
|
@@ -145,3 +146,49 @@ describe("t.bytes() helper", () => {
|
|
|
145
146
|
});
|
|
146
147
|
});
|
|
147
148
|
});
|
|
149
|
+
|
|
150
|
+
describe("serializeResponse with toJSON", () => {
|
|
151
|
+
it("should use toJSON method when available", () => {
|
|
152
|
+
// Create an object with non-enumerable properties and custom toJSON
|
|
153
|
+
const entity = {
|
|
154
|
+
id: 1,
|
|
155
|
+
name: "Test",
|
|
156
|
+
// toJSON is the standard way to customize JSON serialization
|
|
157
|
+
toJSON() {
|
|
158
|
+
return {
|
|
159
|
+
id: this.id,
|
|
160
|
+
name: this.name,
|
|
161
|
+
nested: { value: "included" } // This is non-enumerable in real entity
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
// Make nested non-enumerable to simulate metal-orm
|
|
167
|
+
Object.defineProperty(entity, 'nested', {
|
|
168
|
+
value: { value: "included" },
|
|
169
|
+
enumerable: false,
|
|
170
|
+
writable: true,
|
|
171
|
+
configurable: true
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
@Dto({})
|
|
175
|
+
class TestDto {
|
|
176
|
+
@Field(t.integer())
|
|
177
|
+
id!: number;
|
|
178
|
+
|
|
179
|
+
@Field(t.string())
|
|
180
|
+
name!: string;
|
|
181
|
+
|
|
182
|
+
@Field(t.object({}))
|
|
183
|
+
nested!: { value: string };
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const result = serializeResponse(entity, TestDto);
|
|
187
|
+
|
|
188
|
+
expect(result).toEqual({
|
|
189
|
+
id: 1,
|
|
190
|
+
name: "Test",
|
|
191
|
+
nested: { value: "included" }
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
});
|