From 028ea7a7b14594172649921b99d7aecdca3e1c23 Mon Sep 17 00:00:00 2001 From: Alberto Marchetti Date: Wed, 18 Oct 2023 10:17:44 +0300 Subject: [PATCH] Introduce the defaultInterfaceSuffix setting --- README.md | 6 +++ .../defaultInterfaceSuffix.ts | 43 +++++++++++++++++++ .../schemas/OneSchema.ts | 11 +++++ src/joiUtils.ts | 15 ++++--- src/types.ts | 6 +++ 5 files changed, 76 insertions(+), 5 deletions(-) create mode 100644 src/__tests__/defaultInterfaceSuffix/defaultInterfaceSuffix.ts create mode 100644 src/__tests__/defaultInterfaceSuffix/schemas/OneSchema.ts diff --git a/README.md b/README.md index 49c9ca0d..ff424486 100644 --- a/README.md +++ b/README.md @@ -173,6 +173,12 @@ export interface Settings { * Use .label('InterfaceName') instead of .meta({className:'InterfaceName'}) for interface names */ useLabelAsInterfaceName: boolean; + /** + * If defined, when a schema name ends with "schema", replaces the ending in the generated type by default + * with this string. + * E.g. when this setting is "Interface", a `TestSchema` object generates a `TestInterface` type + */ + defaultInterfaceSuffix?: string; /** * Should interface properties be defaulted to optional or required * @default false diff --git a/src/__tests__/defaultInterfaceSuffix/defaultInterfaceSuffix.ts b/src/__tests__/defaultInterfaceSuffix/defaultInterfaceSuffix.ts new file mode 100644 index 00000000..fa6084cd --- /dev/null +++ b/src/__tests__/defaultInterfaceSuffix/defaultInterfaceSuffix.ts @@ -0,0 +1,43 @@ +import { existsSync, readFileSync, rmdirSync } from 'fs'; + +import { convertFromDirectory } from '../../index'; + +const typeOutputDirectory = './src/__tests__/defaultInterfaceSuffix/interfaces'; + +describe('Create interfaces from schema files and applies a default interface suffix', () => { + beforeAll(() => { + if (existsSync(typeOutputDirectory)) { + rmdirSync(typeOutputDirectory, { recursive: true }); + } + }); + + test('generates interfaces', async () => { + const result = await convertFromDirectory({ + schemaDirectory: './src/__tests__/defaultInterfaceSuffix/schemas', + typeOutputDirectory, + defaultInterfaceSuffix: 'Interface' + }); + + expect(result).toBe(true); + + const oneContent = readFileSync(`${typeOutputDirectory}/One.ts`).toString(); + expect(oneContent).toBe( + `/** + * This file was automatically generated by joi-to-typescript + * Do not modify this file manually + */ + +/** + * a test schema definition + */ +export interface TestInterface { + name?: string; +} + +export interface TestWithMetaInterface { + name?: string; +} +` + ); + }); +}); diff --git a/src/__tests__/defaultInterfaceSuffix/schemas/OneSchema.ts b/src/__tests__/defaultInterfaceSuffix/schemas/OneSchema.ts new file mode 100644 index 00000000..ae3081b8 --- /dev/null +++ b/src/__tests__/defaultInterfaceSuffix/schemas/OneSchema.ts @@ -0,0 +1,11 @@ +import Joi from 'joi'; + +export const TestSchema = Joi.object({ + name: Joi.string().optional() +}).description('a test schema definition'); + +export const TestWithMetaSchema = Joi.object({ + name: Joi.string().optional() +}).meta({ + myMeta: 'Hello' +}); diff --git a/src/joiUtils.ts b/src/joiUtils.ts index 016a7aa6..c833bf7f 100644 --- a/src/joiUtils.ts +++ b/src/joiUtils.ts @@ -67,13 +67,18 @@ export function ensureInterfaceorTypeName(settings: Settings, details: Describe, details.flags.label = interfaceOrTypeName; } } else { - // Set the meta[].className from the exportedName if missing if (!details.metas || details.metas.length === 0) { - details.metas = [{ className: interfaceOrTypeName }]; - } else { - const className = details.metas.find(meta => meta.className)?.className; + details.metas = []; + } - if (!className) { + const className = details.metas.find(meta => meta.className)?.className; + + // Set the meta[].className from the exportedName if missing + if (!className) { + if (settings.defaultInterfaceSuffix && interfaceOrTypeName.toLowerCase().endsWith('schema')) { + const nameWithNewSuffix = interfaceOrTypeName.slice(0, -6) + settings.defaultInterfaceSuffix; + details.metas.push({ className: nameWithNewSuffix }); + } else { details.metas.push({ className: interfaceOrTypeName }); } } diff --git a/src/types.ts b/src/types.ts index c2b893a7..3c1b3e1d 100644 --- a/src/types.ts +++ b/src/types.ts @@ -16,6 +16,12 @@ export interface Settings { * Use .label('InterfaceName') instead of .meta({className:'InterfaceName'}) for interface names */ readonly useLabelAsInterfaceName: boolean; + /** + * If defined, when a schema name ends with "schema", replaces the ending in the generated type by default + * with this string. + * E.g. when this setting is "Interface", a `TestSchema` object generates a `TestInterface` type + */ + readonly defaultInterfaceSuffix?: string; /** * Should interface properties be defaulted to optional or required * @default false