Skip to content

Commit 318c6bb

Browse files
authored
chore: Allow non-object type items in arrays in createJsonSchema (#1104)
1 parent ad4b646 commit 318c6bb

File tree

2 files changed

+86
-22
lines changed

2 files changed

+86
-22
lines changed

builder/src/utils.ts

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -265,24 +265,34 @@ export function createJsonSchema(
265265
case "object":
266266
if (Array.isArray(value)) {
267267
schema.type = "array";
268-
if (value.length > 0) {
269-
const properties: { [key: string]: any } = {};
270-
for (let i = 0; i < value.length; i++) {
271-
const item = value?.[i];
272-
if (typeof item === "object" && item !== null) {
273-
Object.keys(item).forEach((key) => {
274-
if (!(key in properties)) {
275-
properties[key] = analyzeType(
276-
value?.[i]?.[key],
277-
);
278-
}
279-
});
268+
// Check the array type. The array type is determined by the first element
269+
// of the array, or if objects, a superset of all properties of the object elements.
270+
// If array is empty, `items` is `{}`.
271+
if (value.length === 0) {
272+
schema.items = {};
273+
} else {
274+
const first = value[0];
275+
if (first && typeof first === "object" && !Array.isArray(first)) {
276+
const properties: { [key: string]: any } = {};
277+
for (let i = 0; i < value.length; i++) {
278+
const item = value?.[i];
279+
if (typeof item === "object" && item !== null) {
280+
Object.keys(item).forEach((key) => {
281+
if (!(key in properties)) {
282+
properties[key] = analyzeType(
283+
value?.[i]?.[key],
284+
);
285+
}
286+
});
287+
}
280288
}
289+
schema.items = {
290+
type: "object",
291+
properties,
292+
};
293+
} else {
294+
schema.items = analyzeType(first) as JSONSchemaMutable;
281295
}
282-
schema.items = {
283-
type: "object",
284-
properties,
285-
};
286296
}
287297
} else if (value !== null) {
288298
schema.type = "object";

builder/test/utils.test.ts

Lines changed: 60 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -151,8 +151,7 @@ describe("createJsonSchema", () => {
151151
expect(arraySchema).toEqual({
152152
type: "array",
153153
items: {
154-
type: "object",
155-
properties: {},
154+
type: "string",
156155
},
157156
});
158157

@@ -195,8 +194,7 @@ describe("createJsonSchema", () => {
195194
array: {
196195
type: "array",
197196
items: {
198-
type: "object",
199-
properties: {},
197+
type: "integer",
200198
},
201199
},
202200
value: { type: "null" },
@@ -214,6 +212,7 @@ describe("createJsonSchema", () => {
214212

215213
expect(createJsonSchema([])).toEqual({
216214
type: "array",
215+
items: {},
217216
});
218217
});
219218

@@ -308,8 +307,7 @@ describe("createJsonSchema", () => {
308307
expect(schema).toEqual({
309308
type: "array",
310309
items: {
311-
type: "object",
312-
properties: {},
310+
type: "integer",
313311
},
314312
});
315313
});
@@ -360,4 +358,60 @@ describe("createJsonSchema", () => {
360358
},
361359
});
362360
});
361+
362+
it("should handle multidimensional array of numbers", () => {
363+
const data = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
364+
expect(createJsonSchema(data)).toEqual({
365+
type: "array",
366+
items: {
367+
type: "array",
368+
items: {
369+
type: "integer",
370+
},
371+
},
372+
});
373+
});
374+
375+
it("should handle nested array of strings", () => {
376+
const data = {
377+
"recipes": [{
378+
"name": "Pasta Carbonara",
379+
"ingredients": [
380+
"200g spaghetti",
381+
"100g pancetta",
382+
"2 eggs",
383+
"50g pecorino cheese",
384+
"50g parmesan",
385+
"black pepper",
386+
],
387+
"instructions":
388+
"Cook pasta. Fry pancetta. Mix eggs and cheese. Combine all ingredients while pasta is hot.",
389+
}],
390+
};
391+
expect(createJsonSchema(data)).toEqual({
392+
"type": "object",
393+
"properties": {
394+
"recipes": {
395+
"type": "array",
396+
"items": {
397+
"type": "object",
398+
"properties": {
399+
"name": {
400+
"type": "string",
401+
},
402+
"ingredients": {
403+
"type": "array",
404+
"items": {
405+
"type": "string",
406+
},
407+
},
408+
"instructions": {
409+
"type": "string",
410+
},
411+
},
412+
},
413+
},
414+
},
415+
});
416+
});
363417
});

0 commit comments

Comments
 (0)