From 4e947978c01ba206155c8e7d0d48df4eb5ca0f8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samy=20Pess=C3=A9?= Date: Thu, 28 Nov 2024 16:42:19 +0100 Subject: [PATCH] Allow stringFormats to transform value (#6) --- src/compileValidateRequest.ts | 2 +- src/compileValueSchema.ts | 14 +++ .../compileValueSchema.test.ts.snap | 93 ++++++++++++++----- src/tests/__snapshots__/compiler.test.ts.snap | 4 +- src/tests/compileValueSchema.test.ts | 9 ++ 5 files changed, 98 insertions(+), 24 deletions(-) diff --git a/src/compileValidateRequest.ts b/src/compileValidateRequest.ts index 123b5d3..d6da624 100644 --- a/src/compileValidateRequest.ts +++ b/src/compileValidateRequest.ts @@ -10,7 +10,7 @@ import { annotateWithJSDocComment } from './comments'; const COMMENT = ` Validate a request against the OpenAPI spec @param {{ method: string; path: string; body?: any; query: Record; headers: Record; }} request - Input request to validate -@param {{ stringFormats?: { [format: string]: (value: string, path: string[]) => ValidationError | null } }} [context] - Context object to pass to validation functions +@param {{ stringFormats?: { [format: string]: (value: string, path: string[]) => ValidationError | string | null } }} [context] - Context object to pass to validation functions @returns {{ operationId?: string; params: Record; query: Record; body?: any; headers: Record; }} `; diff --git a/src/compileValueSchema.ts b/src/compileValueSchema.ts index 3c24c66..6b39d20 100644 --- a/src/compileValueSchema.ts +++ b/src/compileValueSchema.ts @@ -814,6 +814,20 @@ function compileStringSchema(compiler: Compiler, schema: OpenAPIStringSchema) { builders.blockStatement([builders.returnStatement(formatResult)]), ), ); + nodes.push( + builders.ifStatement( + builders.binaryExpression( + '===', + builders.unaryExpression('typeof', formatResult), + builders.literal('string'), + ), + builders.blockStatement([ + builders.expressionStatement( + builders.assignmentExpression('=', value, formatResult), + ), + ]), + ), + ); } if (schema.minLength) { diff --git a/src/tests/__snapshots__/compileValueSchema.test.ts.snap b/src/tests/__snapshots__/compileValueSchema.test.ts.snap index 22a9f87..f44bae8 100644 --- a/src/tests/__snapshots__/compileValueSchema.test.ts.snap +++ b/src/tests/__snapshots__/compileValueSchema.test.ts.snap @@ -4,7 +4,7 @@ exports[`Number basic 1`] = ` "/** Validate a request against the OpenAPI spec @param {{ method: string; path: string; body?: any; query: Record; headers: Record; }} request - Input request to validate -@param {{ stringFormats?: { [format: string]: (value: string, path: string[]) => ValidationError | null } }} [context] - Context object to pass to validation functions +@param {{ stringFormats?: { [format: string]: (value: string, path: string[]) => ValidationError | string | null } }} [context] - Context object to pass to validation functions @returns {{ operationId?: string; params: Record; query: Record; body?: any; headers: Record; }} */ export function validateRequest(request, context) { @@ -48,7 +48,7 @@ exports[`Number maximum 1`] = ` "/** Validate a request against the OpenAPI spec @param {{ method: string; path: string; body?: any; query: Record; headers: Record; }} request - Input request to validate -@param {{ stringFormats?: { [format: string]: (value: string, path: string[]) => ValidationError | null } }} [context] - Context object to pass to validation functions +@param {{ stringFormats?: { [format: string]: (value: string, path: string[]) => ValidationError | string | null } }} [context] - Context object to pass to validation functions @returns {{ operationId?: string; params: Record; query: Record; body?: any; headers: Record; }} */ export function validateRequest(request, context) { @@ -95,7 +95,7 @@ exports[`Number maximum exclusiveMaximum 1`] = ` "/** Validate a request against the OpenAPI spec @param {{ method: string; path: string; body?: any; query: Record; headers: Record; }} request - Input request to validate -@param {{ stringFormats?: { [format: string]: (value: string, path: string[]) => ValidationError | null } }} [context] - Context object to pass to validation functions +@param {{ stringFormats?: { [format: string]: (value: string, path: string[]) => ValidationError | string | null } }} [context] - Context object to pass to validation functions @returns {{ operationId?: string; params: Record; query: Record; body?: any; headers: Record; }} */ export function validateRequest(request, context) { @@ -142,7 +142,7 @@ exports[`Number minimum 1`] = ` "/** Validate a request against the OpenAPI spec @param {{ method: string; path: string; body?: any; query: Record; headers: Record; }} request - Input request to validate -@param {{ stringFormats?: { [format: string]: (value: string, path: string[]) => ValidationError | null } }} [context] - Context object to pass to validation functions +@param {{ stringFormats?: { [format: string]: (value: string, path: string[]) => ValidationError | string | null } }} [context] - Context object to pass to validation functions @returns {{ operationId?: string; params: Record; query: Record; body?: any; headers: Record; }} */ export function validateRequest(request, context) { @@ -189,7 +189,7 @@ exports[`Number minimim exclusiveMinimum 1`] = ` "/** Validate a request against the OpenAPI spec @param {{ method: string; path: string; body?: any; query: Record; headers: Record; }} request - Input request to validate -@param {{ stringFormats?: { [format: string]: (value: string, path: string[]) => ValidationError | null } }} [context] - Context object to pass to validation functions +@param {{ stringFormats?: { [format: string]: (value: string, path: string[]) => ValidationError | string | null } }} [context] - Context object to pass to validation functions @returns {{ operationId?: string; params: Record; query: Record; body?: any; headers: Record; }} */ export function validateRequest(request, context) { @@ -236,7 +236,7 @@ exports[`Integer basic 1`] = ` "/** Validate a request against the OpenAPI spec @param {{ method: string; path: string; body?: any; query: Record; headers: Record; }} request - Input request to validate -@param {{ stringFormats?: { [format: string]: (value: string, path: string[]) => ValidationError | null } }} [context] - Context object to pass to validation functions +@param {{ stringFormats?: { [format: string]: (value: string, path: string[]) => ValidationError | string | null } }} [context] - Context object to pass to validation functions @returns {{ operationId?: string; params: Record; query: Record; body?: any; headers: Record; }} */ export function validateRequest(request, context) { @@ -280,7 +280,7 @@ exports[`Nullable nullable: true 1`] = ` "/** Validate a request against the OpenAPI spec @param {{ method: string; path: string; body?: any; query: Record; headers: Record; }} request - Input request to validate -@param {{ stringFormats?: { [format: string]: (value: string, path: string[]) => ValidationError | null } }} [context] - Context object to pass to validation functions +@param {{ stringFormats?: { [format: string]: (value: string, path: string[]) => ValidationError | string | null } }} [context] - Context object to pass to validation functions @returns {{ operationId?: string; params: Record; query: Record; body?: any; headers: Record; }} */ export function validateRequest(request, context) { @@ -327,7 +327,7 @@ exports[`String with enum 1`] = ` "/** Validate a request against the OpenAPI spec @param {{ method: string; path: string; body?: any; query: Record; headers: Record; }} request - Input request to validate -@param {{ stringFormats?: { [format: string]: (value: string, path: string[]) => ValidationError | null } }} [context] - Context object to pass to validation functions +@param {{ stringFormats?: { [format: string]: (value: string, path: string[]) => ValidationError | string | null } }} [context] - Context object to pass to validation functions @returns {{ operationId?: string; params: Record; query: Record; body?: any; headers: Record; }} */ export function validateRequest(request, context) { @@ -368,7 +368,7 @@ exports[`String with pattern 1`] = ` "/** Validate a request against the OpenAPI spec @param {{ method: string; path: string; body?: any; query: Record; headers: Record; }} request - Input request to validate -@param {{ stringFormats?: { [format: string]: (value: string, path: string[]) => ValidationError | null } }} [context] - Context object to pass to validation functions +@param {{ stringFormats?: { [format: string]: (value: string, path: string[]) => ValidationError | string | null } }} [context] - Context object to pass to validation functions @returns {{ operationId?: string; params: Record; query: Record; body?: any; headers: Record; }} */ export function validateRequest(request, context) { @@ -413,7 +413,7 @@ exports[`String with pattern 2`] = ` "/** Validate a request against the OpenAPI spec @param {{ method: string; path: string; body?: any; query: Record; headers: Record; }} request - Input request to validate -@param {{ stringFormats?: { [format: string]: (value: string, path: string[]) => ValidationError | null } }} [context] - Context object to pass to validation functions +@param {{ stringFormats?: { [format: string]: (value: string, path: string[]) => ValidationError | string | null } }} [context] - Context object to pass to validation functions @returns {{ operationId?: string; params: Record; query: Record; body?: any; headers: Record; }} */ export function validateRequest(request, context) { @@ -450,6 +450,57 @@ function obj0(path, value, context) { if (formatResult instanceof ValidationError) { return formatResult; } + if (typeof formatResult === 'string') { + value = formatResult; + } + return value; +}" +`; + +exports[`String with format 1`] = ` +"/** +Validate a request against the OpenAPI spec +@param {{ method: string; path: string; body?: any; query: Record; headers: Record; }} request - Input request to validate +@param {{ stringFormats?: { [format: string]: (value: string, path: string[]) => ValidationError | string | null } }} [context] - Context object to pass to validation functions +@returns {{ operationId?: string; params: Record; query: Record; body?: any; headers: Record; }} +*/ +export function validateRequest(request, context) { + return new RequestError(404, 'no operation match path'); +} +/** +Map of all components defined in the spec to their validation functions. +{Object.(path: string[], value: T, context: any) => (T | ValidationError)>} +*/ +export const componentSchemas = {}; +export class RequestError extends Error { + /** @param {number} code HTTP code for the error +@param {string} message The error message*/ + constructor(code, message) { + super(message); + /** @type {number} HTTP code for the error*/ + this.code = code; + } +} +export class ValidationError extends RequestError { + /** @param {string[]} path The path that failed validation +@param {string} message The error message*/ + constructor(path, message) { + super(409, message); + /** @type {string[]} The path that failed validation*/ + this.path = path; + } +} +function obj0(path, value, context) { + if (typeof value !== 'string') { + return new ValidationError(path, 'expected a string'); + } + const formatResult = context?.stringFormats?.['uri']?.(value, path); + if (formatResult instanceof ValidationError) { + return formatResult; + } + if (typeof formatResult === 'string') { + value = formatResult; + } return value; }" `; @@ -458,7 +509,7 @@ exports[`Objects with a required prop 1`] = ` "/** Validate a request against the OpenAPI spec @param {{ method: string; path: string; body?: any; query: Record; headers: Record; }} request - Input request to validate -@param {{ stringFormats?: { [format: string]: (value: string, path: string[]) => ValidationError | null } }} [context] - Context object to pass to validation functions +@param {{ stringFormats?: { [format: string]: (value: string, path: string[]) => ValidationError | string | null } }} [context] - Context object to pass to validation functions @returns {{ operationId?: string; params: Record; query: Record; body?: any; headers: Record; }} */ export function validateRequest(request, context) { @@ -541,7 +592,7 @@ exports[`Objects with a default value 1`] = ` "/** Validate a request against the OpenAPI spec @param {{ method: string; path: string; body?: any; query: Record; headers: Record; }} request - Input request to validate -@param {{ stringFormats?: { [format: string]: (value: string, path: string[]) => ValidationError | null } }} [context] - Context object to pass to validation functions +@param {{ stringFormats?: { [format: string]: (value: string, path: string[]) => ValidationError | string | null } }} [context] - Context object to pass to validation functions @returns {{ operationId?: string; params: Record; query: Record; body?: any; headers: Record; }} */ export function validateRequest(request, context) { @@ -606,7 +657,7 @@ exports[`Objects as free form object 1`] = ` "/** Validate a request against the OpenAPI spec @param {{ method: string; path: string; body?: any; query: Record; headers: Record; }} request - Input request to validate -@param {{ stringFormats?: { [format: string]: (value: string, path: string[]) => ValidationError | null } }} [context] - Context object to pass to validation functions +@param {{ stringFormats?: { [format: string]: (value: string, path: string[]) => ValidationError | string | null } }} [context] - Context object to pass to validation functions @returns {{ operationId?: string; params: Record; query: Record; body?: any; headers: Record; }} */ export function validateRequest(request, context) { @@ -648,7 +699,7 @@ exports[`Objects with additionalProperties: true 1`] = ` "/** Validate a request against the OpenAPI spec @param {{ method: string; path: string; body?: any; query: Record; headers: Record; }} request - Input request to validate -@param {{ stringFormats?: { [format: string]: (value: string, path: string[]) => ValidationError | null } }} [context] - Context object to pass to validation functions +@param {{ stringFormats?: { [format: string]: (value: string, path: string[]) => ValidationError | string | null } }} [context] - Context object to pass to validation functions @returns {{ operationId?: string; params: Record; query: Record; body?: any; headers: Record; }} */ export function validateRequest(request, context) { @@ -713,7 +764,7 @@ exports[`Objects with additionalProperties: {} 1`] = ` "/** Validate a request against the OpenAPI spec @param {{ method: string; path: string; body?: any; query: Record; headers: Record; }} request - Input request to validate -@param {{ stringFormats?: { [format: string]: (value: string, path: string[]) => ValidationError | null } }} [context] - Context object to pass to validation functions +@param {{ stringFormats?: { [format: string]: (value: string, path: string[]) => ValidationError | string | null } }} [context] - Context object to pass to validation functions @returns {{ operationId?: string; params: Record; query: Record; body?: any; headers: Record; }} */ export function validateRequest(request, context) { @@ -794,7 +845,7 @@ exports[`Objects with minProperties/maxProperties 1`] = ` "/** Validate a request against the OpenAPI spec @param {{ method: string; path: string; body?: any; query: Record; headers: Record; }} request - Input request to validate -@param {{ stringFormats?: { [format: string]: (value: string, path: string[]) => ValidationError | null } }} [context] - Context object to pass to validation functions +@param {{ stringFormats?: { [format: string]: (value: string, path: string[]) => ValidationError | string | null } }} [context] - Context object to pass to validation functions @returns {{ operationId?: string; params: Record; query: Record; body?: any; headers: Record; }} */ export function validateRequest(request, context) { @@ -842,7 +893,7 @@ exports[`Array minItems / maxItems 1`] = ` "/** Validate a request against the OpenAPI spec @param {{ method: string; path: string; body?: any; query: Record; headers: Record; }} request - Input request to validate -@param {{ stringFormats?: { [format: string]: (value: string, path: string[]) => ValidationError | null } }} [context] - Context object to pass to validation functions +@param {{ stringFormats?: { [format: string]: (value: string, path: string[]) => ValidationError | string | null } }} [context] - Context object to pass to validation functions @returns {{ operationId?: string; params: Record; query: Record; body?: any; headers: Record; }} */ export function validateRequest(request, context) { @@ -905,7 +956,7 @@ exports[`Array uniqueItems 1`] = ` "/** Validate a request against the OpenAPI spec @param {{ method: string; path: string; body?: any; query: Record; headers: Record; }} request - Input request to validate -@param {{ stringFormats?: { [format: string]: (value: string, path: string[]) => ValidationError | null } }} [context] - Context object to pass to validation functions +@param {{ stringFormats?: { [format: string]: (value: string, path: string[]) => ValidationError | string | null } }} [context] - Context object to pass to validation functions @returns {{ operationId?: string; params: Record; query: Record; body?: any; headers: Record; }} */ export function validateRequest(request, context) { @@ -967,7 +1018,7 @@ exports[`anyOf 1`] = ` "/** Validate a request against the OpenAPI spec @param {{ method: string; path: string; body?: any; query: Record; headers: Record; }} request - Input request to validate -@param {{ stringFormats?: { [format: string]: (value: string, path: string[]) => ValidationError | null } }} [context] - Context object to pass to validation functions +@param {{ stringFormats?: { [format: string]: (value: string, path: string[]) => ValidationError | string | null } }} [context] - Context object to pass to validation functions @returns {{ operationId?: string; params: Record; query: Record; body?: any; headers: Record; }} */ export function validateRequest(request, context) { @@ -1028,7 +1079,7 @@ exports[`oneOf 1`] = ` "/** Validate a request against the OpenAPI spec @param {{ method: string; path: string; body?: any; query: Record; headers: Record; }} request - Input request to validate -@param {{ stringFormats?: { [format: string]: (value: string, path: string[]) => ValidationError | null } }} [context] - Context object to pass to validation functions +@param {{ stringFormats?: { [format: string]: (value: string, path: string[]) => ValidationError | string | null } }} [context] - Context object to pass to validation functions @returns {{ operationId?: string; params: Record; query: Record; body?: any; headers: Record; }} */ export function validateRequest(request, context) { @@ -1108,7 +1159,7 @@ exports[`allOf 1`] = ` "/** Validate a request against the OpenAPI spec @param {{ method: string; path: string; body?: any; query: Record; headers: Record; }} request - Input request to validate -@param {{ stringFormats?: { [format: string]: (value: string, path: string[]) => ValidationError | null } }} [context] - Context object to pass to validation functions +@param {{ stringFormats?: { [format: string]: (value: string, path: string[]) => ValidationError | string | null } }} [context] - Context object to pass to validation functions @returns {{ operationId?: string; params: Record; query: Record; body?: any; headers: Record; }} */ export function validateRequest(request, context) { diff --git a/src/tests/__snapshots__/compiler.test.ts.snap b/src/tests/__snapshots__/compiler.test.ts.snap index b30687f..d409c42 100644 --- a/src/tests/__snapshots__/compiler.test.ts.snap +++ b/src/tests/__snapshots__/compiler.test.ts.snap @@ -4,7 +4,7 @@ exports[`components ref 1`] = ` "/** Validate a request against the OpenAPI spec @param {{ method: string; path: string; body?: any; query: Record; headers: Record; }} request - Input request to validate -@param {{ stringFormats?: { [format: string]: (value: string, path: string[]) => ValidationError | null } }} [context] - Context object to pass to validation functions +@param {{ stringFormats?: { [format: string]: (value: string, path: string[]) => ValidationError | string | null } }} [context] - Context object to pass to validation functions @returns {{ operationId?: string; params: Record; query: Record; body?: any; headers: Record; }} */ export function validateRequest(request, context) { @@ -88,7 +88,7 @@ exports[`recursive refs 1`] = ` "/** Validate a request against the OpenAPI spec @param {{ method: string; path: string; body?: any; query: Record; headers: Record; }} request - Input request to validate -@param {{ stringFormats?: { [format: string]: (value: string, path: string[]) => ValidationError | null } }} [context] - Context object to pass to validation functions +@param {{ stringFormats?: { [format: string]: (value: string, path: string[]) => ValidationError | string | null } }} [context] - Context object to pass to validation functions @returns {{ operationId?: string; params: Record; query: Record; body?: any; headers: Record; }} */ export function validateRequest(request, context) { diff --git a/src/tests/compileValueSchema.test.ts b/src/tests/compileValueSchema.test.ts index 07b4a13..a86bef1 100644 --- a/src/tests/compileValueSchema.test.ts +++ b/src/tests/compileValueSchema.test.ts @@ -99,6 +99,15 @@ describe('String', () => { }); expect(compiler.compile()).toMatchSnapshot(); }); + + test('with format', () => { + const compiler = new Compiler(); + compileValueSchema(compiler, { + type: 'string', + format: 'uri', + }); + expect(compiler.compile()).toMatchSnapshot(); + }); }); describe('Objects', () => {