Skip to content

Commit

Permalink
Merge branch 'master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
mrjono1 authored May 2, 2021
2 parents c72fdbb + 36a9ebe commit 2df577e
Show file tree
Hide file tree
Showing 13 changed files with 337 additions and 62 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "joi-to-typescript",
"description": "Convert Joi Schemas to TypeScript interfaces",
"version": "1.13.0",
"version": "1.14.0",
"author": "Jono Clarnette",
"keywords": [
"joi",
Expand Down
169 changes: 169 additions & 0 deletions src/__tests__/primitiveTypes/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
import { existsSync, readFileSync, rmdirSync } from 'fs';

import { convertFromDirectory } from '../../index';

describe('Primitive Types', () => {
const typeOutputDirectory = './src/__tests__/primitiveTypes/interfaces';
beforeAll(async () => {
if (existsSync(typeOutputDirectory)) {
rmdirSync(typeOutputDirectory, { recursive: true });
}
const result = await convertFromDirectory({
schemaDirectory: './src/__tests__/primitiveTypes/schemas',
typeOutputDirectory
});

expect(result).toBe(true);
});

test('String base schema', async () => {
const readmeContent = readFileSync(`${typeOutputDirectory}/Email.ts`).toString();

expect(readmeContent).toBe(`/**
* This file was automatically generated by joi-to-typescript
* Do not modify this file manually
*/
export interface CompanySchema {
email?: Email;
}
export type Email = string;
export interface UserSchema {
email: Email;
}
`);
});

test('number base schema', async () => {
const readmeContent = readFileSync(`${typeOutputDirectory}/Counter.ts`).toString();

expect(readmeContent).toBe(`/**
* This file was automatically generated by joi-to-typescript
* Do not modify this file manually
*/
export interface CompanySchema {
counter?: Counter;
}
export type Counter = number;
export interface UserSchema {
counter: Counter;
}
`);
});

test('Date base schema', async () => {
const readmeContent = readFileSync(`${typeOutputDirectory}/DateField.ts`).toString();

expect(readmeContent).toBe(`/**
* This file was automatically generated by joi-to-typescript
* Do not modify this file manually
*/
export interface CompanySchema {
counter?: DateField;
}
export type DateField = Date;
export interface UserSchema {
counter: DateField;
}
`);
});

test('boolean base schema', async () => {
const readmeContent = readFileSync(`${typeOutputDirectory}/Boolean.ts`).toString();

expect(readmeContent).toBe(`/**
* This file was automatically generated by joi-to-typescript
* Do not modify this file manually
*/
export type Boolean = boolean;
export interface CompanySchema {
counter?: Boolean;
}
export interface UserSchema {
counter: Boolean;
}
`);
});

test('allow on base schema', async () => {
const readmeContent = readFileSync(`${typeOutputDirectory}/Allow.ts`).toString();

expect(readmeContent).toBe(`/**
* This file was automatically generated by joi-to-typescript
* Do not modify this file manually
*/
export type Blank = string;
export type BlankNull = string | null | '';
/**
* This is date
*/
export type DateOptions = Date | null;
/**
* Test Schema Name
*/
export type Name = string;
export type NormalList = 'red' | 'green' | 'blue';
export type NormalRequiredList = 'red' | 'green' | 'blue';
/**
* nullable
*/
export type NullName = string | null;
export type NullNumber = number | null;
export type Numbers = 1 | 2 | 3 | 4 | 5;
`);
});

test('ensure primitive types are exported/imported correctly', async () => {
const readmeContent = readFileSync(`${typeOutputDirectory}/Using.ts`).toString();

expect(readmeContent).toBe(`/**
* This file was automatically generated by joi-to-typescript
* Do not modify this file manually
*/
export interface UsingOtherTypesSchema {
property?: string | null | '';
}
`);
});

test('union/alternative primitive types', async () => {
const readmeContent = readFileSync(`${typeOutputDirectory}/Union.ts`).toString();

expect(readmeContent).toBe(`/**
* This file was automatically generated by joi-to-typescript
* Do not modify this file manually
*/
export interface CompanySchema {
counter?: Union;
}
export type Union = string | number;
export interface UserSchema {
counter: Union;
}
`);
});
});
11 changes: 11 additions & 0 deletions src/__tests__/primitiveTypes/schemas/AllowSchema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import Joi from 'joi';

export const Name = Joi.string().optional().description('Test Schema Name').allow('').label('Name');
export const NullName = Joi.string().optional().description('nullable').allow(null);
export const BlankNull = Joi.string().optional().allow(null, '');
export const Blank = Joi.string().allow('');
export const NormalList = Joi.string().allow('red', 'green', 'blue');
export const NormalRequiredList = Joi.string().allow('red', 'green', 'blue').required();
export const Numbers = Joi.number().optional().allow(1, 2, 3, 4, 5);
export const NullNumber = Joi.number().optional().allow(null);
export const DateOptions = Joi.date().allow(null).description('This is date');
11 changes: 11 additions & 0 deletions src/__tests__/primitiveTypes/schemas/BooleanSchema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import Joi from 'joi';

export const BooleanSchema = Joi.boolean().label('Boolean');

export const CompanySchema = Joi.object({
counter: BooleanSchema
});

export const UserSchema = Joi.object({
counter: BooleanSchema.required()
});
11 changes: 11 additions & 0 deletions src/__tests__/primitiveTypes/schemas/CounterSchema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import Joi from 'joi';

export const CounterSchema = Joi.number().label('Counter');

export const CompanySchema = Joi.object({
counter: CounterSchema
});

export const UserSchema = Joi.object({
counter: CounterSchema.required()
});
11 changes: 11 additions & 0 deletions src/__tests__/primitiveTypes/schemas/DateFieldSchema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import Joi from 'joi';

export const DateFieldSchema = Joi.date().label('DateField');

export const CompanySchema = Joi.object({
counter: DateFieldSchema
});

export const UserSchema = Joi.object({
counter: DateFieldSchema.required()
});
13 changes: 13 additions & 0 deletions src/__tests__/primitiveTypes/schemas/EmailSchema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import Joi from 'joi';

export const EmailSchema = Joi.string()
.email({ tlds: { allow: false } })
.label('Email');

export const CompanySchema = Joi.object({
email: EmailSchema
});

export const UserSchema = Joi.object({
email: EmailSchema.required()
});
11 changes: 11 additions & 0 deletions src/__tests__/primitiveTypes/schemas/UnionSchema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import Joi from 'joi';

export const UnionSchema = Joi.alternatives([Joi.string(), Joi.number()]).label('Union');

export const CompanySchema = Joi.object({
counter: UnionSchema
});

export const UserSchema = Joi.object({
counter: UnionSchema.required()
});
6 changes: 6 additions & 0 deletions src/__tests__/primitiveTypes/schemas/UsingSchema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import Joi from 'joi';
import { BlankNull } from './AllowSchema';

export const UsingOtherTypesSchema = Joi.object({
property: BlankNull
});
10 changes: 6 additions & 4 deletions src/analyseSchemaFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ import Path from 'path';

import { Settings, ConvertedType, GenerateTypeFile } from './types';
import { getTypeFileNameFromSchema } from './index';
import { Describe, getAllCustomTypes, parseSchema, typeContentToTs } from './parse';
import { getAllCustomTypes, parseSchema, typeContentToTs } from './parse';
import { Describe } from 'joiDescribeTypes';

export function convertSchemaInternal(
settings: Settings,
joi: AnySchema,
exportedName?: string
exportedName?: string,
rootSchema?: boolean
): ConvertedType | undefined {
const details = joi.describe() as Describe;
const name = details?.flags?.label || exportedName;
Expand All @@ -35,7 +37,7 @@ export function convertSchemaInternal(
details.flags.label = name;
}

const parsedSchema = parseSchema(details, settings, false);
const parsedSchema = parseSchema(details, settings, false, undefined, rootSchema);
if (parsedSchema) {
const customTypes = getAllCustomTypes(parsedSchema);
const content = typeContentToTs(settings, parsedSchema, true);
Expand Down Expand Up @@ -77,7 +79,7 @@ export async function analyseSchemaFile(
if (!Joi.isSchema(joiSchema)) {
continue;
}
const convertedType = convertSchemaInternal(settings, joiSchema, exportedName);
const convertedType = convertSchemaInternal(settings, joiSchema, exportedName, true);
if (convertedType) {
allConvertedTypes.push({ ...convertedType, location: fullOutputFilePath });
}
Expand Down
42 changes: 42 additions & 0 deletions src/joiDescribeTypes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import Joi from 'joi';

/**
* This file extends the TypeScript Types that are packaged as part of joi
*/

export interface BaseDescribe extends Joi.Description {
flags?: {
label?: string;
description?: string;
presence?: 'optional' | 'required';
unknown?: boolean;
};
}

export interface ArrayDescribe extends BaseDescribe {
type: 'array';
items: Describe[];
}

export interface ObjectDescribe extends BaseDescribe {
type: 'object';
keys: Record<'string', Describe>;
}

export interface AlternativesDescribe extends BaseDescribe {
// Joi.alt and Joi.alternatives both output as 'alternatives'
type: 'alternatives';
matches: { schema: Describe }[];
}

export interface StringDescribe extends BaseDescribe {
type: 'string';
allow?: string[];
}

export interface BasicDescribe extends BaseDescribe {
// Joi.bool an Joi.boolean both output as 'boolean'
type: 'any' | 'boolean' | 'date' | 'number';
}

export type Describe = ArrayDescribe | BasicDescribe | ObjectDescribe | AlternativesDescribe | StringDescribe;
Loading

0 comments on commit 2df577e

Please sign in to comment.