From 3daa6730faca766bcebe65ff02ee6734f022b850 Mon Sep 17 00:00:00 2001 From: toddtarsi Date: Sat, 7 Oct 2023 19:36:42 -0500 Subject: [PATCH 1/3] add handling for sparse arrays --- src/__tests__/array/array.ts | 26 +++++++++++++++++++ .../array/schemas/OneSparseSchema.ts | 8 ++++++ src/parse.ts | 20 ++++++++++++-- 3 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 src/__tests__/array/schemas/OneSparseSchema.ts diff --git a/src/__tests__/array/array.ts b/src/__tests__/array/array.ts index bef2080e..6d77adfe 100644 --- a/src/__tests__/array/array.ts +++ b/src/__tests__/array/array.ts @@ -2,6 +2,7 @@ import { existsSync, readFileSync, rmdirSync } from 'fs'; import Joi from 'joi'; import { convertFromDirectory, convertSchema } from '../../index'; +import { SparseTestListSchema } from './schemas/OneSparseSchema'; describe('Array types', () => { const typeOutputDirectory = './src/__tests__/array/interfaces'; @@ -70,4 +71,29 @@ export type TestList = Test[]; */ export type TestList = string[];`); }); + + test('test to ensure sparse arrays have undefined as a possible type', () => { + // this tests this code + // if (isSparse) { + // return makeTypeContentRoot({ + // joinOperation: 'list', + // children: [ + // makeTypeContentRoot({ + // joinOperation: 'union', + // children: [child, makeTypeContentChild({ content: 'undefined' })], + // interfaceOrTypeName, + // jsDoc + // }) + // ], + // interfaceOrTypeName, + // jsDoc + // }); + // } + const result = convertSchema({ sortPropertiesByName: true }, SparseTestListSchema); + expect(result).not.toBeUndefined; + expect(result?.content).toBe(`/** + * A sparse list of Item object + */ +export type SparseTestList = (Item | undefined)[];`); + }); }); diff --git a/src/__tests__/array/schemas/OneSparseSchema.ts b/src/__tests__/array/schemas/OneSparseSchema.ts new file mode 100644 index 00000000..031690b1 --- /dev/null +++ b/src/__tests__/array/schemas/OneSparseSchema.ts @@ -0,0 +1,8 @@ +import Joi from 'joi'; +import {ItemSchema} from './OneSchema' + +export const SparseTestListSchema = Joi.array() + .items(ItemSchema) + .sparse() + .meta({ className: 'SparseTestList' }) + .description('A sparse list of Item object'); \ No newline at end of file diff --git a/src/parse.ts b/src/parse.ts index f63d5776..e523f27e 100644 --- a/src/parse.ts +++ b/src/parse.ts @@ -410,6 +410,8 @@ function parseStringSchema(details: StringDescribe, settings: Settings, rootSche function parseArray(details: ArrayDescribe, settings: Settings): TypeContent | undefined { const { interfaceOrTypeName, jsDoc } = getCommonDetails(details, settings); + // @ts-expect-error Idk why but the sparse flag is not in the type + const isSparse = details.flags?.sparse; if (details.ordered && !details.items) { const parsedChildren = details.ordered.map(item => parseSchema(item, settings)).filter(Boolean) as TypeContent[]; @@ -439,7 +441,6 @@ function parseArray(details: ArrayDescribe, settings: Settings): TypeContent | u // TODO: handle multiple things in the items arr const item = details.items && !details.ordered ? details.items[0] : ({ type: 'any' } as Describe); - const child = parseSchema(item, settings); if (!child) { return undefined; @@ -454,6 +455,21 @@ function parseArray(details: ArrayDescribe, settings: Settings): TypeContent | u return makeTypeContentRoot({ joinOperation: 'union', children: allowedValues, interfaceOrTypeName, jsDoc }); } + if (isSparse) { + return makeTypeContentRoot({ + joinOperation: 'list', + children: [ + makeTypeContentRoot({ + joinOperation: 'union', + children: [child, makeTypeContentChild({ content: 'undefined' })], + interfaceOrTypeName, + jsDoc + }) + ], + interfaceOrTypeName, + jsDoc + }); + } return makeTypeContentRoot({ joinOperation: 'list', children: [child], interfaceOrTypeName, jsDoc }); } @@ -481,7 +497,7 @@ function parseAlternatives(details: AlternativesDescribe, settings: Settings): T joinOperation: 'union', children: [...children, ...allowedValues], interfaceOrTypeName, - jsDoc, + jsDoc }); } From 87a008b0403f18c26a8cb19b72fca84a10292081 Mon Sep 17 00:00:00 2001 From: toddtarsi Date: Fri, 13 Oct 2023 00:13:53 -0500 Subject: [PATCH 2/3] dropping test comment --- src/__tests__/array/array.ts | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/__tests__/array/array.ts b/src/__tests__/array/array.ts index 6d77adfe..54db4d03 100644 --- a/src/__tests__/array/array.ts +++ b/src/__tests__/array/array.ts @@ -73,22 +73,6 @@ export type TestList = string[];`); }); test('test to ensure sparse arrays have undefined as a possible type', () => { - // this tests this code - // if (isSparse) { - // return makeTypeContentRoot({ - // joinOperation: 'list', - // children: [ - // makeTypeContentRoot({ - // joinOperation: 'union', - // children: [child, makeTypeContentChild({ content: 'undefined' })], - // interfaceOrTypeName, - // jsDoc - // }) - // ], - // interfaceOrTypeName, - // jsDoc - // }); - // } const result = convertSchema({ sortPropertiesByName: true }, SparseTestListSchema); expect(result).not.toBeUndefined; expect(result?.content).toBe(`/** From 768d10e5ffbe8b000378831fbc940671fb6786ba Mon Sep 17 00:00:00 2001 From: toddtarsi Date: Fri, 13 Oct 2023 00:15:51 -0500 Subject: [PATCH 3/3] add sparse to flags --- src/joiDescribeTypes.ts | 4 ++++ src/parse.ts | 1 - 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/joiDescribeTypes.ts b/src/joiDescribeTypes.ts index 20faf041..ad430196 100644 --- a/src/joiDescribeTypes.ts +++ b/src/joiDescribeTypes.ts @@ -29,6 +29,10 @@ export interface BaseDescribe extends Joi.Description { * Default object value */ default?: unknown; + /** + * Allow undefined values in array + */ + sparse?: boolean; /** * https://joi.dev/api/#objectunknownallow */ diff --git a/src/parse.ts b/src/parse.ts index e523f27e..a5f985c4 100644 --- a/src/parse.ts +++ b/src/parse.ts @@ -410,7 +410,6 @@ function parseStringSchema(details: StringDescribe, settings: Settings, rootSche function parseArray(details: ArrayDescribe, settings: Settings): TypeContent | undefined { const { interfaceOrTypeName, jsDoc } = getCommonDetails(details, settings); - // @ts-expect-error Idk why but the sparse flag is not in the type const isSparse = details.flags?.sparse; if (details.ordered && !details.items) {