@eventvisor/core 0.14.0 → 0.15.0
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/CHANGELOG.md +11 -0
- package/lib/cli/plugins.js +2 -0
- package/lib/cli/plugins.js.map +1 -1
- package/lib/generate-code/index.d.ts +9 -0
- package/lib/generate-code/index.js +90 -0
- package/lib/generate-code/index.js.map +1 -0
- package/lib/generate-code/typescript/generateInterface.d.ts +2 -0
- package/lib/generate-code/typescript/generateInterface.js +80 -0
- package/lib/generate-code/typescript/generateInterface.js.map +1 -0
- package/lib/generate-code/typescript/generateInterface.spec.d.ts +1 -0
- package/lib/generate-code/typescript/generateInterface.spec.js +792 -0
- package/lib/generate-code/typescript/generateInterface.spec.js.map +1 -0
- package/lib/generate-code/typescript/index.d.ts +3 -0
- package/lib/generate-code/typescript/index.js +172 -0
- package/lib/generate-code/typescript/index.js.map +1 -0
- package/package.json +4 -4
- package/src/cli/plugins.ts +2 -0
- package/src/generate-code/index.ts +79 -0
- package/src/generate-code/typescript/generateInterface.spec.ts +847 -0
- package/src/generate-code/typescript/generateInterface.ts +89 -0
- package/src/generate-code/typescript/index.ts +199 -0
|
@@ -0,0 +1,847 @@
|
|
|
1
|
+
import { generateInterface } from "./generateInterface";
|
|
2
|
+
import { JSONSchema } from "@eventvisor/types";
|
|
3
|
+
|
|
4
|
+
describe("generateInterface", () => {
|
|
5
|
+
describe("Primitive Types", () => {
|
|
6
|
+
it("should generate type for string type", () => {
|
|
7
|
+
const schema: JSONSchema = { type: "string" };
|
|
8
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
9
|
+
expect(result).toBe("export type GeneratedInterface = string");
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it("should generate type for number type", () => {
|
|
13
|
+
const schema: JSONSchema = { type: "number" };
|
|
14
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
15
|
+
expect(result).toBe("export type GeneratedInterface = number");
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it("should generate type for integer type", () => {
|
|
19
|
+
const schema: JSONSchema = { type: "integer" };
|
|
20
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
21
|
+
expect(result).toBe("export type GeneratedInterface = number");
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("should generate type for boolean type", () => {
|
|
25
|
+
const schema: JSONSchema = { type: "boolean" };
|
|
26
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
27
|
+
expect(result).toBe("export type GeneratedInterface = boolean");
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("should generate type for null type", () => {
|
|
31
|
+
const schema: JSONSchema = { type: "null" };
|
|
32
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
33
|
+
expect(result).toBe("export type GeneratedInterface = null");
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("should generate type for schema without type (defaults to any)", () => {
|
|
37
|
+
const schema: JSONSchema = {};
|
|
38
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
39
|
+
expect(result).toBe("export type GeneratedInterface = any");
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
describe("Objects", () => {
|
|
44
|
+
it("should generate interface for simple object", () => {
|
|
45
|
+
const schema: JSONSchema = {
|
|
46
|
+
type: "object",
|
|
47
|
+
properties: {
|
|
48
|
+
name: { type: "string" },
|
|
49
|
+
age: { type: "number" },
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
53
|
+
expect(result).toContain("export interface GeneratedInterface");
|
|
54
|
+
expect(result).toContain("name?: string;");
|
|
55
|
+
expect(result).toContain("age?: number;");
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("should generate interface for object with required properties", () => {
|
|
59
|
+
const schema: JSONSchema = {
|
|
60
|
+
type: "object",
|
|
61
|
+
properties: {
|
|
62
|
+
name: { type: "string" },
|
|
63
|
+
age: { type: "number" },
|
|
64
|
+
email: { type: "string" },
|
|
65
|
+
},
|
|
66
|
+
required: ["name", "email"],
|
|
67
|
+
};
|
|
68
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
69
|
+
expect(result).toContain("name: string;");
|
|
70
|
+
expect(result).toContain("age?: number;");
|
|
71
|
+
expect(result).toContain("email: string;");
|
|
72
|
+
expect(result).not.toContain("name?:");
|
|
73
|
+
expect(result).not.toContain("email?:");
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("should generate interface for object with all optional properties", () => {
|
|
77
|
+
const schema: JSONSchema = {
|
|
78
|
+
type: "object",
|
|
79
|
+
properties: {
|
|
80
|
+
name: { type: "string" },
|
|
81
|
+
age: { type: "number" },
|
|
82
|
+
},
|
|
83
|
+
required: [],
|
|
84
|
+
};
|
|
85
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
86
|
+
expect(result).toContain("name?: string;");
|
|
87
|
+
expect(result).toContain("age?: number;");
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it("should generate type for empty object", () => {
|
|
91
|
+
const schema: JSONSchema = {
|
|
92
|
+
type: "object",
|
|
93
|
+
properties: {},
|
|
94
|
+
};
|
|
95
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
96
|
+
expect(result).toContain("Record<string, any>");
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it("should generate type for object without properties", () => {
|
|
100
|
+
const schema: JSONSchema = {
|
|
101
|
+
type: "object",
|
|
102
|
+
};
|
|
103
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
104
|
+
expect(result).toContain("Record<string, any>");
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it("should generate interface for object inferred from properties", () => {
|
|
108
|
+
const schema: JSONSchema = {
|
|
109
|
+
properties: {
|
|
110
|
+
name: { type: "string" },
|
|
111
|
+
},
|
|
112
|
+
};
|
|
113
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
114
|
+
expect(result).toContain("name?: string;");
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it("should generate interface for object with mixed property types", () => {
|
|
118
|
+
const schema: JSONSchema = {
|
|
119
|
+
type: "object",
|
|
120
|
+
properties: {
|
|
121
|
+
name: { type: "string" },
|
|
122
|
+
age: { type: "integer" },
|
|
123
|
+
active: { type: "boolean" },
|
|
124
|
+
score: { type: "null" },
|
|
125
|
+
},
|
|
126
|
+
required: ["name"],
|
|
127
|
+
};
|
|
128
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
129
|
+
expect(result).toContain("name: string;");
|
|
130
|
+
expect(result).toContain("age?: number;");
|
|
131
|
+
expect(result).toContain("active?: boolean;");
|
|
132
|
+
expect(result).toContain("score?: null;");
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
describe("Nested Objects", () => {
|
|
137
|
+
it("should generate interface for nested object", () => {
|
|
138
|
+
const schema: JSONSchema = {
|
|
139
|
+
type: "object",
|
|
140
|
+
properties: {
|
|
141
|
+
user: {
|
|
142
|
+
type: "object",
|
|
143
|
+
properties: {
|
|
144
|
+
name: { type: "string" },
|
|
145
|
+
age: { type: "number" },
|
|
146
|
+
},
|
|
147
|
+
required: ["name"],
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
};
|
|
151
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
152
|
+
expect(result).toContain("user?: {");
|
|
153
|
+
expect(result).toContain("name: string;");
|
|
154
|
+
expect(result).toContain("age?: number;");
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it("should generate interface for deeply nested object", () => {
|
|
158
|
+
const schema: JSONSchema = {
|
|
159
|
+
type: "object",
|
|
160
|
+
properties: {
|
|
161
|
+
level1: {
|
|
162
|
+
type: "object",
|
|
163
|
+
properties: {
|
|
164
|
+
level2: {
|
|
165
|
+
type: "object",
|
|
166
|
+
properties: {
|
|
167
|
+
level3: {
|
|
168
|
+
type: "object",
|
|
169
|
+
properties: {
|
|
170
|
+
value: { type: "string" },
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
};
|
|
179
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
180
|
+
expect(result).toContain("level1?: {");
|
|
181
|
+
expect(result).toContain("level2?: {");
|
|
182
|
+
expect(result).toContain("level3?: {");
|
|
183
|
+
expect(result).toContain("value?: string;");
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
it("should generate interface for object with multiple nested objects", () => {
|
|
187
|
+
const schema: JSONSchema = {
|
|
188
|
+
type: "object",
|
|
189
|
+
properties: {
|
|
190
|
+
address: {
|
|
191
|
+
type: "object",
|
|
192
|
+
properties: {
|
|
193
|
+
street: { type: "string" },
|
|
194
|
+
city: { type: "string" },
|
|
195
|
+
},
|
|
196
|
+
required: ["street"],
|
|
197
|
+
},
|
|
198
|
+
contact: {
|
|
199
|
+
type: "object",
|
|
200
|
+
properties: {
|
|
201
|
+
email: { type: "string" },
|
|
202
|
+
phone: { type: "string" },
|
|
203
|
+
},
|
|
204
|
+
},
|
|
205
|
+
},
|
|
206
|
+
};
|
|
207
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
208
|
+
expect(result).toContain("address?: {");
|
|
209
|
+
expect(result).toContain("street: string;");
|
|
210
|
+
expect(result).toContain("city?: string;");
|
|
211
|
+
expect(result).toContain("contact?: {");
|
|
212
|
+
expect(result).toContain("email?: string;");
|
|
213
|
+
expect(result).toContain("phone?: string;");
|
|
214
|
+
});
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
describe("Arrays", () => {
|
|
218
|
+
it("should generate type for array of strings", () => {
|
|
219
|
+
const schema: JSONSchema = {
|
|
220
|
+
type: "array",
|
|
221
|
+
items: { type: "string" },
|
|
222
|
+
};
|
|
223
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
224
|
+
expect(result).toBe("export type GeneratedInterface = string[]");
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
it("should generate type for array of numbers", () => {
|
|
228
|
+
const schema: JSONSchema = {
|
|
229
|
+
type: "array",
|
|
230
|
+
items: { type: "number" },
|
|
231
|
+
};
|
|
232
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
233
|
+
expect(result).toBe("export type GeneratedInterface = number[]");
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
it("should generate type for array of booleans", () => {
|
|
237
|
+
const schema: JSONSchema = {
|
|
238
|
+
type: "array",
|
|
239
|
+
items: { type: "boolean" },
|
|
240
|
+
};
|
|
241
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
242
|
+
expect(result).toBe("export type GeneratedInterface = boolean[]");
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
it("should generate type for array without items", () => {
|
|
246
|
+
const schema: JSONSchema = {
|
|
247
|
+
type: "array",
|
|
248
|
+
};
|
|
249
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
250
|
+
expect(result).toBe("export type GeneratedInterface = any[]");
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
it("should generate type for array of objects", () => {
|
|
254
|
+
const schema: JSONSchema = {
|
|
255
|
+
type: "array",
|
|
256
|
+
items: {
|
|
257
|
+
type: "object",
|
|
258
|
+
properties: {
|
|
259
|
+
name: { type: "string" },
|
|
260
|
+
age: { type: "number" },
|
|
261
|
+
},
|
|
262
|
+
},
|
|
263
|
+
};
|
|
264
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
265
|
+
expect(result).toContain("export type GeneratedInterface =");
|
|
266
|
+
expect(result).toContain("name?: string;");
|
|
267
|
+
expect(result).toContain("age?: number;");
|
|
268
|
+
expect(result).toContain("[]");
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
it("should generate type for array of nested objects", () => {
|
|
272
|
+
const schema: JSONSchema = {
|
|
273
|
+
type: "array",
|
|
274
|
+
items: {
|
|
275
|
+
type: "object",
|
|
276
|
+
properties: {
|
|
277
|
+
user: {
|
|
278
|
+
type: "object",
|
|
279
|
+
properties: {
|
|
280
|
+
name: { type: "string" },
|
|
281
|
+
},
|
|
282
|
+
},
|
|
283
|
+
},
|
|
284
|
+
},
|
|
285
|
+
};
|
|
286
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
287
|
+
expect(result).toContain("user?: {");
|
|
288
|
+
expect(result).toContain("name?: string;");
|
|
289
|
+
expect(result).toContain("[]");
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
it("should generate type for nested arrays", () => {
|
|
293
|
+
const schema: JSONSchema = {
|
|
294
|
+
type: "array",
|
|
295
|
+
items: {
|
|
296
|
+
type: "array",
|
|
297
|
+
items: { type: "string" },
|
|
298
|
+
},
|
|
299
|
+
};
|
|
300
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
301
|
+
expect(result).toBe("export type GeneratedInterface = string[][]");
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
it("should generate type for deeply nested arrays", () => {
|
|
305
|
+
const schema: JSONSchema = {
|
|
306
|
+
type: "array",
|
|
307
|
+
items: {
|
|
308
|
+
type: "array",
|
|
309
|
+
items: {
|
|
310
|
+
type: "array",
|
|
311
|
+
items: { type: "number" },
|
|
312
|
+
},
|
|
313
|
+
},
|
|
314
|
+
};
|
|
315
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
316
|
+
expect(result).toBe("export type GeneratedInterface = number[][][]");
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
it("should generate type for array of arrays of objects", () => {
|
|
320
|
+
const schema: JSONSchema = {
|
|
321
|
+
type: "array",
|
|
322
|
+
items: {
|
|
323
|
+
type: "array",
|
|
324
|
+
items: {
|
|
325
|
+
type: "object",
|
|
326
|
+
properties: {
|
|
327
|
+
id: { type: "string" },
|
|
328
|
+
},
|
|
329
|
+
},
|
|
330
|
+
},
|
|
331
|
+
};
|
|
332
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
333
|
+
expect(result).toContain("id?: string;");
|
|
334
|
+
expect(result).toContain("[][]");
|
|
335
|
+
});
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
describe("Tuples", () => {
|
|
339
|
+
it("should generate type for tuple type", () => {
|
|
340
|
+
const schema: JSONSchema = {
|
|
341
|
+
type: "array",
|
|
342
|
+
items: [{ type: "string" }, { type: "number" }],
|
|
343
|
+
};
|
|
344
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
345
|
+
expect(result).toBe("export type GeneratedInterface = [string, number]");
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
it("should generate type for tuple with multiple types", () => {
|
|
349
|
+
const schema: JSONSchema = {
|
|
350
|
+
type: "array",
|
|
351
|
+
items: [{ type: "string" }, { type: "number" }, { type: "boolean" }],
|
|
352
|
+
};
|
|
353
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
354
|
+
expect(result).toBe("export type GeneratedInterface = [string, number, boolean]");
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
it("should generate type for tuple with objects", () => {
|
|
358
|
+
const schema: JSONSchema = {
|
|
359
|
+
type: "array",
|
|
360
|
+
items: [
|
|
361
|
+
{ type: "string" },
|
|
362
|
+
{
|
|
363
|
+
type: "object",
|
|
364
|
+
properties: {
|
|
365
|
+
name: { type: "string" },
|
|
366
|
+
},
|
|
367
|
+
},
|
|
368
|
+
],
|
|
369
|
+
};
|
|
370
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
371
|
+
expect(result).toContain("[string, {");
|
|
372
|
+
expect(result).toContain("name?: string;");
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
it("should generate type for tuple with nested arrays", () => {
|
|
376
|
+
const schema: JSONSchema = {
|
|
377
|
+
type: "array",
|
|
378
|
+
items: [
|
|
379
|
+
{ type: "string" },
|
|
380
|
+
{
|
|
381
|
+
type: "array",
|
|
382
|
+
items: { type: "number" },
|
|
383
|
+
},
|
|
384
|
+
],
|
|
385
|
+
};
|
|
386
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
387
|
+
expect(result).toBe("export type GeneratedInterface = [string, number[]]");
|
|
388
|
+
});
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
describe("Enums", () => {
|
|
392
|
+
it("should generate type for enum of strings", () => {
|
|
393
|
+
const schema: JSONSchema = {
|
|
394
|
+
enum: ["red", "green", "blue"],
|
|
395
|
+
};
|
|
396
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
397
|
+
expect(result).toBe('export type GeneratedInterface = "red" | "green" | "blue"');
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
it("should generate type for enum of numbers", () => {
|
|
401
|
+
const schema: JSONSchema = {
|
|
402
|
+
enum: [1, 2, 3],
|
|
403
|
+
};
|
|
404
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
405
|
+
expect(result).toBe("export type GeneratedInterface = 1 | 2 | 3");
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
it("should generate type for enum of booleans", () => {
|
|
409
|
+
const schema: JSONSchema = {
|
|
410
|
+
enum: [true, false],
|
|
411
|
+
};
|
|
412
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
413
|
+
expect(result).toBe("export type GeneratedInterface = true | false");
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
it("should generate type for enum with mixed types", () => {
|
|
417
|
+
const schema: JSONSchema = {
|
|
418
|
+
enum: ["string", 42, true, null],
|
|
419
|
+
};
|
|
420
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
421
|
+
expect(result).toContain('"string"');
|
|
422
|
+
expect(result).toContain("42");
|
|
423
|
+
expect(result).toContain("true");
|
|
424
|
+
expect(result).toContain("null");
|
|
425
|
+
expect(result).toContain(" | ");
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
it("should generate type for enum with single value", () => {
|
|
429
|
+
const schema: JSONSchema = {
|
|
430
|
+
enum: ["single"],
|
|
431
|
+
};
|
|
432
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
433
|
+
expect(result).toBe('export type GeneratedInterface = "single"');
|
|
434
|
+
});
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
describe("Const Values", () => {
|
|
438
|
+
it("should generate type for const string", () => {
|
|
439
|
+
const schema: JSONSchema = {
|
|
440
|
+
const: "fixed-value",
|
|
441
|
+
};
|
|
442
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
443
|
+
expect(result).toBe('export type GeneratedInterface = "fixed-value"');
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
it("should generate type for const number", () => {
|
|
447
|
+
const schema: JSONSchema = {
|
|
448
|
+
const: 42,
|
|
449
|
+
};
|
|
450
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
451
|
+
expect(result).toBe("export type GeneratedInterface = 42");
|
|
452
|
+
});
|
|
453
|
+
|
|
454
|
+
it("should generate type for const boolean", () => {
|
|
455
|
+
const schema: JSONSchema = {
|
|
456
|
+
const: true,
|
|
457
|
+
};
|
|
458
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
459
|
+
expect(result).toBe("export type GeneratedInterface = true");
|
|
460
|
+
});
|
|
461
|
+
|
|
462
|
+
it("should generate type for const null", () => {
|
|
463
|
+
const schema: JSONSchema = {
|
|
464
|
+
const: null,
|
|
465
|
+
};
|
|
466
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
467
|
+
expect(result).toBe("export type GeneratedInterface = null");
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
it("should generate type for const object", () => {
|
|
471
|
+
const schema: JSONSchema = {
|
|
472
|
+
const: { key: "value" },
|
|
473
|
+
};
|
|
474
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
475
|
+
expect(result).toContain('{"key":"value"}');
|
|
476
|
+
});
|
|
477
|
+
});
|
|
478
|
+
|
|
479
|
+
describe("Complex Nested Structures", () => {
|
|
480
|
+
it("should generate interface for object with array of objects", () => {
|
|
481
|
+
const schema: JSONSchema = {
|
|
482
|
+
type: "object",
|
|
483
|
+
properties: {
|
|
484
|
+
users: {
|
|
485
|
+
type: "array",
|
|
486
|
+
items: {
|
|
487
|
+
type: "object",
|
|
488
|
+
properties: {
|
|
489
|
+
id: { type: "string" },
|
|
490
|
+
name: { type: "string" },
|
|
491
|
+
},
|
|
492
|
+
required: ["id"],
|
|
493
|
+
},
|
|
494
|
+
},
|
|
495
|
+
},
|
|
496
|
+
};
|
|
497
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
498
|
+
expect(result).toContain("users?: {");
|
|
499
|
+
expect(result).toContain("id: string;");
|
|
500
|
+
expect(result).toContain("name?: string;");
|
|
501
|
+
expect(result).toContain("[]");
|
|
502
|
+
});
|
|
503
|
+
|
|
504
|
+
it("should generate interface for object with nested arrays and objects", () => {
|
|
505
|
+
const schema: JSONSchema = {
|
|
506
|
+
type: "object",
|
|
507
|
+
properties: {
|
|
508
|
+
data: {
|
|
509
|
+
type: "array",
|
|
510
|
+
items: {
|
|
511
|
+
type: "object",
|
|
512
|
+
properties: {
|
|
513
|
+
items: {
|
|
514
|
+
type: "array",
|
|
515
|
+
items: {
|
|
516
|
+
type: "object",
|
|
517
|
+
properties: {
|
|
518
|
+
value: { type: "string" },
|
|
519
|
+
},
|
|
520
|
+
},
|
|
521
|
+
},
|
|
522
|
+
},
|
|
523
|
+
},
|
|
524
|
+
},
|
|
525
|
+
},
|
|
526
|
+
};
|
|
527
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
528
|
+
expect(result).toContain("data?: {");
|
|
529
|
+
expect(result).toContain("items?: {");
|
|
530
|
+
expect(result).toContain("value?: string;");
|
|
531
|
+
expect(result).toContain("[]");
|
|
532
|
+
});
|
|
533
|
+
|
|
534
|
+
it("should generate interface for complex user profile schema", () => {
|
|
535
|
+
const schema: JSONSchema = {
|
|
536
|
+
type: "object",
|
|
537
|
+
properties: {
|
|
538
|
+
id: { type: "string" },
|
|
539
|
+
name: { type: "string" },
|
|
540
|
+
age: { type: "integer" },
|
|
541
|
+
active: { type: "boolean" },
|
|
542
|
+
tags: {
|
|
543
|
+
type: "array",
|
|
544
|
+
items: { type: "string" },
|
|
545
|
+
},
|
|
546
|
+
address: {
|
|
547
|
+
type: "object",
|
|
548
|
+
properties: {
|
|
549
|
+
street: { type: "string" },
|
|
550
|
+
city: { type: "string" },
|
|
551
|
+
coordinates: {
|
|
552
|
+
type: "object",
|
|
553
|
+
properties: {
|
|
554
|
+
lat: { type: "number" },
|
|
555
|
+
lng: { type: "number" },
|
|
556
|
+
},
|
|
557
|
+
},
|
|
558
|
+
},
|
|
559
|
+
required: ["street"],
|
|
560
|
+
},
|
|
561
|
+
contacts: {
|
|
562
|
+
type: "array",
|
|
563
|
+
items: {
|
|
564
|
+
type: "object",
|
|
565
|
+
properties: {
|
|
566
|
+
type: { type: "string" },
|
|
567
|
+
value: { type: "string" },
|
|
568
|
+
},
|
|
569
|
+
required: ["type"],
|
|
570
|
+
},
|
|
571
|
+
},
|
|
572
|
+
},
|
|
573
|
+
required: ["id", "name"],
|
|
574
|
+
};
|
|
575
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
576
|
+
expect(result).toContain("id: string;");
|
|
577
|
+
expect(result).toContain("name: string;");
|
|
578
|
+
expect(result).toContain("age?: number;");
|
|
579
|
+
expect(result).toContain("active?: boolean;");
|
|
580
|
+
expect(result).toContain("tags?: string[];");
|
|
581
|
+
expect(result).toContain("address?: {");
|
|
582
|
+
expect(result).toContain("street: string;");
|
|
583
|
+
expect(result).toContain("city?: string;");
|
|
584
|
+
expect(result).toContain("coordinates?: {");
|
|
585
|
+
expect(result).toContain("lat?: number;");
|
|
586
|
+
expect(result).toContain("lng?: number;");
|
|
587
|
+
expect(result).toContain("contacts?: {");
|
|
588
|
+
expect(result).toContain("type: string;");
|
|
589
|
+
expect(result).toContain("value?: string;");
|
|
590
|
+
});
|
|
591
|
+
});
|
|
592
|
+
|
|
593
|
+
describe("Descriptions", () => {
|
|
594
|
+
it("should include description in generated interface", () => {
|
|
595
|
+
const schema: JSONSchema = {
|
|
596
|
+
description: "A user schema",
|
|
597
|
+
type: "object",
|
|
598
|
+
properties: {
|
|
599
|
+
name: { type: "string" },
|
|
600
|
+
},
|
|
601
|
+
};
|
|
602
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
603
|
+
expect(result).toContain("/** A user schema */");
|
|
604
|
+
expect(result).toContain("export interface GeneratedInterface");
|
|
605
|
+
});
|
|
606
|
+
|
|
607
|
+
it("should not include description comment when description is missing", () => {
|
|
608
|
+
const schema: JSONSchema = {
|
|
609
|
+
type: "object",
|
|
610
|
+
properties: {
|
|
611
|
+
name: { type: "string" },
|
|
612
|
+
},
|
|
613
|
+
};
|
|
614
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
615
|
+
expect(result).not.toContain("/**");
|
|
616
|
+
expect(result).toContain("export interface GeneratedInterface");
|
|
617
|
+
});
|
|
618
|
+
|
|
619
|
+
it("should include description for simple type", () => {
|
|
620
|
+
const schema: JSONSchema = {
|
|
621
|
+
description: "A string value",
|
|
622
|
+
type: "string",
|
|
623
|
+
};
|
|
624
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
625
|
+
expect(result).toContain("/** A string value */");
|
|
626
|
+
expect(result).toContain("export type GeneratedInterface = string");
|
|
627
|
+
});
|
|
628
|
+
});
|
|
629
|
+
|
|
630
|
+
describe("Edge Cases", () => {
|
|
631
|
+
it("should handle object with properties but no type specified", () => {
|
|
632
|
+
const schema: JSONSchema = {
|
|
633
|
+
properties: {
|
|
634
|
+
name: { type: "string" },
|
|
635
|
+
},
|
|
636
|
+
};
|
|
637
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
638
|
+
expect(result).toContain("name?: string;");
|
|
639
|
+
});
|
|
640
|
+
|
|
641
|
+
it("should handle const with higher priority than enum", () => {
|
|
642
|
+
const schema: JSONSchema = {
|
|
643
|
+
const: "fixed",
|
|
644
|
+
enum: ["fixed", "other"],
|
|
645
|
+
};
|
|
646
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
647
|
+
expect(result).toBe('export type GeneratedInterface = "fixed"');
|
|
648
|
+
});
|
|
649
|
+
|
|
650
|
+
it("should handle const with higher priority than type", () => {
|
|
651
|
+
const schema: JSONSchema = {
|
|
652
|
+
const: "fixed",
|
|
653
|
+
type: "string",
|
|
654
|
+
};
|
|
655
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
656
|
+
expect(result).toBe('export type GeneratedInterface = "fixed"');
|
|
657
|
+
});
|
|
658
|
+
|
|
659
|
+
it("should handle enum with higher priority than type", () => {
|
|
660
|
+
const schema: JSONSchema = {
|
|
661
|
+
enum: ["a", "b"],
|
|
662
|
+
type: "string",
|
|
663
|
+
};
|
|
664
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
665
|
+
expect(result).toBe('export type GeneratedInterface = "a" | "b"');
|
|
666
|
+
});
|
|
667
|
+
|
|
668
|
+
it("should handle object with numeric property names", () => {
|
|
669
|
+
const schema: JSONSchema = {
|
|
670
|
+
type: "object",
|
|
671
|
+
properties: {
|
|
672
|
+
"0": { type: "string" },
|
|
673
|
+
"1": { type: "number" },
|
|
674
|
+
},
|
|
675
|
+
};
|
|
676
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
677
|
+
expect(result).toContain("0?: string;");
|
|
678
|
+
expect(result).toContain("1?: number;");
|
|
679
|
+
});
|
|
680
|
+
|
|
681
|
+
it("should handle object with special character property names", () => {
|
|
682
|
+
const schema: JSONSchema = {
|
|
683
|
+
type: "object",
|
|
684
|
+
properties: {
|
|
685
|
+
"my-property": { type: "string" },
|
|
686
|
+
"another.property": { type: "number" },
|
|
687
|
+
},
|
|
688
|
+
};
|
|
689
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
690
|
+
expect(result).toContain("my-property?: string;");
|
|
691
|
+
expect(result).toContain("another.property?: number;");
|
|
692
|
+
});
|
|
693
|
+
|
|
694
|
+
it("should handle required array with properties not in properties object", () => {
|
|
695
|
+
const schema: JSONSchema = {
|
|
696
|
+
type: "object",
|
|
697
|
+
properties: {
|
|
698
|
+
name: { type: "string" },
|
|
699
|
+
},
|
|
700
|
+
required: ["name", "missing"],
|
|
701
|
+
};
|
|
702
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
703
|
+
expect(result).toContain("name: string;");
|
|
704
|
+
expect(result).not.toContain("missing");
|
|
705
|
+
});
|
|
706
|
+
|
|
707
|
+
it("should handle empty enum array", () => {
|
|
708
|
+
const schema: JSONSchema = {
|
|
709
|
+
enum: [],
|
|
710
|
+
};
|
|
711
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
712
|
+
// Should fall through to default type handling
|
|
713
|
+
expect(result).toContain("export type GeneratedInterface =");
|
|
714
|
+
});
|
|
715
|
+
|
|
716
|
+
it("should handle array with empty items array", () => {
|
|
717
|
+
const schema: JSONSchema = {
|
|
718
|
+
type: "array",
|
|
719
|
+
items: [],
|
|
720
|
+
};
|
|
721
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
722
|
+
// Empty array becomes empty tuple
|
|
723
|
+
expect(result).toContain("[]");
|
|
724
|
+
});
|
|
725
|
+
});
|
|
726
|
+
|
|
727
|
+
describe("Real-world Scenarios", () => {
|
|
728
|
+
it("should generate interface for event tracking schema", () => {
|
|
729
|
+
const schema: JSONSchema = {
|
|
730
|
+
type: "object",
|
|
731
|
+
properties: {
|
|
732
|
+
eventName: { type: "string" },
|
|
733
|
+
userId: { type: "string" },
|
|
734
|
+
timestamp: { type: "number" },
|
|
735
|
+
properties: {
|
|
736
|
+
type: "object",
|
|
737
|
+
properties: {
|
|
738
|
+
page: { type: "string" },
|
|
739
|
+
referrer: { type: "string" },
|
|
740
|
+
},
|
|
741
|
+
},
|
|
742
|
+
tags: {
|
|
743
|
+
type: "array",
|
|
744
|
+
items: { type: "string" },
|
|
745
|
+
},
|
|
746
|
+
},
|
|
747
|
+
required: ["eventName", "userId"],
|
|
748
|
+
};
|
|
749
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
750
|
+
expect(result).toContain("eventName: string;");
|
|
751
|
+
expect(result).toContain("userId: string;");
|
|
752
|
+
expect(result).toContain("timestamp?: number;");
|
|
753
|
+
expect(result).toContain("properties?: {");
|
|
754
|
+
expect(result).toContain("tags?: string[];");
|
|
755
|
+
});
|
|
756
|
+
|
|
757
|
+
it("should generate interface for API response schema", () => {
|
|
758
|
+
const schema: JSONSchema = {
|
|
759
|
+
type: "object",
|
|
760
|
+
properties: {
|
|
761
|
+
success: { type: "boolean" },
|
|
762
|
+
data: {
|
|
763
|
+
type: "object",
|
|
764
|
+
properties: {
|
|
765
|
+
items: {
|
|
766
|
+
type: "array",
|
|
767
|
+
items: {
|
|
768
|
+
type: "object",
|
|
769
|
+
properties: {
|
|
770
|
+
id: { type: "string" },
|
|
771
|
+
name: { type: "string" },
|
|
772
|
+
},
|
|
773
|
+
required: ["id"],
|
|
774
|
+
},
|
|
775
|
+
},
|
|
776
|
+
total: { type: "integer" },
|
|
777
|
+
},
|
|
778
|
+
},
|
|
779
|
+
errors: {
|
|
780
|
+
type: "array",
|
|
781
|
+
items: {
|
|
782
|
+
type: "object",
|
|
783
|
+
properties: {
|
|
784
|
+
code: { type: "string" },
|
|
785
|
+
message: { type: "string" },
|
|
786
|
+
},
|
|
787
|
+
},
|
|
788
|
+
},
|
|
789
|
+
},
|
|
790
|
+
required: ["success"],
|
|
791
|
+
};
|
|
792
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
793
|
+
expect(result).toContain("success: boolean;");
|
|
794
|
+
expect(result).toContain("data?: {");
|
|
795
|
+
expect(result).toContain("items?: {");
|
|
796
|
+
expect(result).toContain("id: string;");
|
|
797
|
+
expect(result).toContain("total?: number;");
|
|
798
|
+
expect(result).toContain("errors?: {");
|
|
799
|
+
});
|
|
800
|
+
|
|
801
|
+
it("should generate interface for configuration schema", () => {
|
|
802
|
+
const schema: JSONSchema = {
|
|
803
|
+
description: "Application configuration",
|
|
804
|
+
type: "object",
|
|
805
|
+
properties: {
|
|
806
|
+
environment: {
|
|
807
|
+
enum: ["development", "staging", "production"],
|
|
808
|
+
},
|
|
809
|
+
apiUrl: { type: "string" },
|
|
810
|
+
timeout: { type: "integer" },
|
|
811
|
+
features: {
|
|
812
|
+
type: "object",
|
|
813
|
+
properties: {
|
|
814
|
+
enabled: {
|
|
815
|
+
type: "array",
|
|
816
|
+
items: { type: "string" },
|
|
817
|
+
},
|
|
818
|
+
disabled: {
|
|
819
|
+
type: "array",
|
|
820
|
+
items: { type: "string" },
|
|
821
|
+
},
|
|
822
|
+
},
|
|
823
|
+
},
|
|
824
|
+
retry: {
|
|
825
|
+
type: "object",
|
|
826
|
+
properties: {
|
|
827
|
+
maxAttempts: { type: "integer" },
|
|
828
|
+
backoff: { type: "number" },
|
|
829
|
+
},
|
|
830
|
+
required: ["maxAttempts"],
|
|
831
|
+
},
|
|
832
|
+
},
|
|
833
|
+
required: ["environment", "apiUrl"],
|
|
834
|
+
};
|
|
835
|
+
const result = generateInterface(schema, "GeneratedInterface");
|
|
836
|
+
expect(result).toContain("/** Application configuration */");
|
|
837
|
+
expect(result).toContain('environment: "development" | "staging" | "production";');
|
|
838
|
+
expect(result).toContain("apiUrl: string;");
|
|
839
|
+
expect(result).toContain("timeout?: number;");
|
|
840
|
+
expect(result).toContain("features?: {");
|
|
841
|
+
expect(result).toContain("enabled?: string[];");
|
|
842
|
+
expect(result).toContain("retry?: {");
|
|
843
|
+
expect(result).toContain("maxAttempts: number;");
|
|
844
|
+
expect(result).toContain("backoff?: number;");
|
|
845
|
+
});
|
|
846
|
+
});
|
|
847
|
+
});
|