UNPKG

joi-extract-type

Version:

Provides native type extraction from Joi schemas for Typescript

304 lines (265 loc) 10.7 kB
/** @format */ import * as Joi from '@hapi/joi'; import './index'; const extJoi = Joi.extend({} as Joi.Extension); // Unknown types or AnySchema defaults to type any const any_schema = Joi.any(); type extractAny = Joi.extractType<typeof any_schema>; export const extractedAny: extractAny = 'anything'; const is_enabled = Joi.boolean(); type extractBoolean = Joi.extractType<typeof is_enabled>; export const extractedBoolean: extractBoolean = true; const full_name = extJoi.string(); type extractString = Joi.extractType<typeof full_name>; export const extractedString: extractString = 'string'; const created_at = Joi.date(); type extractDate = Joi.extractType<typeof created_at>; export const extractedDate: extractDate = new Date(); const priority = extJoi.number(); type extractNumber = Joi.extractType<typeof priority>; export const extractedNumber: extractNumber = 5; const userAsObject = { full_name: full_name.required(), short_desc: extJoi.string(), is_enabled, has_credentials: Joi.boolean().valid(true).required(), created_at, priority, }; const user = Joi.object(userAsObject); type extractObject = Joi.extractType<typeof userAsObject>; type extractObjectSchema = Joi.extractType<typeof user>; export const extractedObject: extractObject = { created_at: extractedDate, full_name: extractedString, is_enabled: extractedBoolean, priority: extractedNumber, has_credentials: true, }; export const extractedObjectSchema: extractObjectSchema = extractedObject; const roles = extJoi .array() .items(extJoi.string().valid(['admin', 'member', 'guest'])) .items(extJoi.number()); type extractArray = Joi.extractType<typeof roles>; export const extactedArray: extractArray = ['admin', 2]; const uuid_exp = `[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}`; const uuid_pattern = new RegExp(uuid_exp, 'i'); const uuid = extJoi.string().regex(uuid_pattern); type extractUuid = Joi.extractType<typeof uuid>; export const extractedUuid: extractUuid = '123e4567-e89b-12d3-a456-426655440000'; const apply = extJoi.array().items(Joi.object({ id: uuid.required() })); type extractApply = Joi.extractType<typeof apply>; const anyApply = [{ id: '3' }, { id: undefined }]; export const extractedApply: extractApply = anyApply; const rule_flat = extJoi .array() .items(extJoi.string()) .items(Joi.object({ id: uuid.required() })); type extractRuleFlat = Joi.extractType<typeof rule_flat>; export const extractedRuleFlat: extractRuleFlat = [{ id: 'string' }, 'test']; const rule = Joi.object().keys({ apply, id: uuid.required() }); type extractRule = Joi.extractType<typeof rule>; export const extractedRule: extractRule = { apply: extractedApply, id: 'string', }; export const ruleMap = Joi.object().pattern(/\w+/, rule); type extractRuleMap = Joi.extractType<typeof ruleMap>; export const extractedRuleMap: extractRuleMap = { somekey: extractedRule }; export const jobOperatorRoleSchema = Joi.object({ id: extJoi.string().required(), user_id: extJoi.string().required(), job_id: extJoi.string(), index: extJoi.number(), parent_index: extJoi.number().required(), role: extJoi.string().valid('recruiter', 'requester'), pipeline_rules: extJoi.array().items(rule).required(), }); type extractComplexType = Joi.extractType<typeof jobOperatorRoleSchema>; export const extractedComplexType: extractComplexType = { id: '2015', user_id: '102', job_id: '52', role: 'requester', parent_index: 5, pipeline_rules: [extractedRule], }; export const usingDefaultWithProps = Joi.object({ number_prop_with_default: extJoi.number().default(2), string_prop_with_default: extJoi.string().default('string'), boolean_prop_with_default: Joi.boolean().default(false), date_prop_with_default: Joi.date().default(new Date()), array_prop_with_default: extJoi.array().default([5]), object_prop_with_default: Joi.object({ number: extJoi.number() }).default({ string: extJoi.string(), }), }); type usingDefaultWithPropsType = Joi.extractType<typeof usingDefaultWithProps>; export const extractedUsingDefaultWithProps: usingDefaultWithPropsType = { number_prop_with_default: 20, string_prop_with_default: 'string', boolean_prop_with_default: true, date_prop_with_default: new Date(), array_prop_with_default: [1, 2], object_prop_with_default: { number: 5 }, }; export const extractedComplexTypeValidationResponse = Joi.validate({}, jobOperatorRoleSchema); const appendedJobOperatorRoleSchema = jobOperatorRoleSchema.append({ excluded: Joi.boolean(), }); type extractAppendedSchema = Joi.extractType<typeof appendedJobOperatorRoleSchema>; export const extractedAppended: extractAppendedSchema = { ...extractedComplexType, excluded: true, }; function someFunction() { return someFunction; } const createUserSchema = Joi.func<typeof someFunction>(); type extractFunction = Joi.extractType<typeof createUserSchema>; export const extractedFunction: extractFunction = someFunction; const number_string = Joi.alt().try(extJoi.number().valid(1, 2, 3), extJoi.string()); type extractNumberString = Joi.extractType<typeof number_string>; export const extractNumberStringNumber: extractNumberString = 2; export const extractNumberStringString: extractNumberString = '2'; const date_time1 = Joi.alternatives([Joi.date(), extJoi.number(), extJoi.string()]); type extractDateTime1 = Joi.extractType<typeof date_time1>; export const extractDateTimeDate1: extractDateTime1 = new Date(); export const extractDateTimeTime1: extractDateTime1 = +new Date(); export const extractDateTimeString1: extractDateTime1 = new Date().toISOString(); const when = Joi.alt().when('x', { is: 'a', then: extJoi.string(), otherwise: extJoi.number() }); type extractedWhen = Joi.extractType<typeof when>; export const extractWhen1: extractedWhen = 2; export const extractWhen2: extractedWhen = '2'; const required_alt = Joi.object({ required: Joi.object({ start_date: date_time1.required(), end_date: date_time1, value: when.required(), }).required(), }); type extractedRequiredAlt = Joi.extractType<typeof required_alt>; export const extractRequiredAlt: extractedRequiredAlt = { required: { start_date: new Date(), value: '2' }, }; const required_alt_augmented = required_alt.keys({ required2: Joi.object({ value: extJoi.number(), }) .required() .pattern(/\w+/, extJoi.number()) .pattern(extJoi.string(), extJoi.number()) .pattern(extJoi.string().valid('pattern_key'), extJoi.number()), }); type extractedRequiredAltAugmented = Joi.extractType<typeof required_alt_augmented>; export const extractRequiredAltAugmented: extractedRequiredAltAugmented = { required: { start_date: new Date(), value: 2, }, required2: {}, }; const string_array_schema = [ extJoi.string().default('test' as 'test'), extJoi.array().items([extJoi.string(), extJoi.number()]).valid('string', 2), // TODO overwrite valid on ArraySchema ]; type extractStringArray = Joi.extractType<typeof string_array_schema>; export const extractStringArrayString: extractStringArray = 'string'; export const extractStringArrayArray: extractStringArray = ['string', 2]; // A extends B type guard type numberExtendsAny = Joi.extendsGuard<any, extractNumber>; export const asNumber: numberExtendsAny = 2; type stringNotNumber = Joi.extendsGuard<string, extractNumber>; export const asString: stringNotNumber = 'string'; // Validation methods type priorityValidationResponse = { error: any; value: extractNumber }; export const validationExtractedNumber1: priorityValidationResponse = Joi.validate( extractedNumber, priority ); export const validationExtractedNumber2: priorityValidationResponse = Joi.validate( extractedNumber, priority, {} ); export const validatedNumber: number = validationExtractedNumber2.value || validationExtractedNumber1.value; type strictEnum = 'tag'; export const validationOverwrittenReturn: strictEnum = Joi.validate( extractedNumber, priority, (_err, value: extractNumber) => { if (typeof value === 'number') return 'tag' as 'tag'; } ); const nullableString = extJoi.string().valid('string').allow(null, 0); type extractNullableString = Joi.extractType<typeof nullableString>; export const extactedNullableStringNull: extractNullableString = null; export const extactedNullableStringZero: extractNullableString = 0; export const extactedNullableString: extractNullableString = 'string'; const nullableNumber = extJoi .number() .allow(null as null) .default(5); type extractNullableNumber = Joi.extractType<typeof nullableNumber>; export const extactedNullableNumberNull: extractNullableNumber = null; export const extactedNullableNumber: extractNullableNumber = 15; const nullType = null as null; const allNullable = { nullableString, nullableNumber, nullableBoolean: Joi.boolean().required().allow(nullType), nullableFunc: Joi.func().required().allow(nullType), nullableDate: Joi.date().required().allow(nullType), nullableArray: extJoi.array().items(extJoi.string()).allow(nullType), nullableObject: Joi.object({ nullableString }).allow(nullType), nullableAlt: Joi.alt(nullableString, nullableNumber).allow(nullType), }; type extractAllNullable = Joi.extractType<typeof allNullable>; export const extractedAllNullable: extractAllNullable = { nullableString: null, nullableNumber: null, nullableBoolean: null, nullableFunc: null, nullableDate: null, nullableArray: null, nullableObject: null, nullableAlt: null, }; export const anyRequired = Joi.any().required(); export const anyOptional = Joi.any(); export const anyTestSchema = { anyRequired, anyOptional }; type extractedAnyTest = Joi.extractType<typeof anyTestSchema>; export let anyTests: extractedAnyTest; anyTests = { anyRequired: 'test', anyOptional: 'test' }; anyTests = { anyRequired: 'test' }; anyTests = { anyRequired: 123, anyOptional: 123 }; // Test for issue #27 const nestedObjSchema = Joi.object() .required() .keys({ nested: Joi.object().required().keys({ foo: Joi.string().required(), }), opt: Joi.object().keys({ bar: Joi.string().required(), }), }); type extractNestedObjSchema = Joi.extractType<typeof nestedObjSchema>; export const extractedNestedObjSchema: extractNestedObjSchema = { nested: { foo: 'string', }, }; // Test for issue #36 export const stdSchemaMethods = [ Joi.any().tags('tags').label('any'), Joi.string().tags('tags').label('string'), Joi.boolean().tags('tags').label('boolean'), Joi.number().tags('tags').label('number'), Joi.date().tags('tags').label('date'), Joi.object().tags('tags').label('object'), Joi.array().tags('tags').label('array'), Joi.alt().tags('tags').label('alt'), ];