111 lines
2.7 KiB
TypeScript
111 lines
2.7 KiB
TypeScript
/**
|
|
* Type coercion utilities for query parameters
|
|
* Converts string values from query params to proper types based on JSON Schema
|
|
*/
|
|
|
|
import type { TJsonSchema, IOpenApiParamMeta } from '../decorators/decorators.types.js';
|
|
|
|
/**
|
|
* Coerce a single value based on JSON Schema type
|
|
*/
|
|
export function coerceValue(value: string | undefined, schema: TJsonSchema): unknown {
|
|
if (value === undefined || value === '') {
|
|
// Return default if available
|
|
if (schema.default !== undefined) {
|
|
return schema.default;
|
|
}
|
|
return undefined;
|
|
}
|
|
|
|
const type = Array.isArray(schema.type) ? schema.type[0] : schema.type;
|
|
|
|
switch (type) {
|
|
case 'integer': {
|
|
const num = parseInt(value, 10);
|
|
return isNaN(num) ? value : num;
|
|
}
|
|
|
|
case 'number': {
|
|
const num = parseFloat(value);
|
|
return isNaN(num) ? value : num;
|
|
}
|
|
|
|
case 'boolean': {
|
|
if (value === 'true' || value === '1') return true;
|
|
if (value === 'false' || value === '0' || value === '') return false;
|
|
return value;
|
|
}
|
|
|
|
case 'array': {
|
|
// Handle comma-separated values
|
|
const items = value.split(',').map(item => item.trim());
|
|
if (schema.items) {
|
|
return items.map(item => coerceValue(item, schema.items as TJsonSchema));
|
|
}
|
|
return items;
|
|
}
|
|
|
|
case 'null': {
|
|
if (value === 'null' || value === '') return null;
|
|
return value;
|
|
}
|
|
|
|
case 'object': {
|
|
// Attempt to parse JSON
|
|
try {
|
|
return JSON.parse(value);
|
|
} catch {
|
|
return value;
|
|
}
|
|
}
|
|
|
|
case 'string':
|
|
default:
|
|
return value;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Coerce all query parameters based on their schemas
|
|
*/
|
|
export function coerceQueryParams(
|
|
query: Record<string, string>,
|
|
schemas: Map<string, IOpenApiParamMeta>
|
|
): Record<string, unknown> {
|
|
const result: Record<string, unknown> = { ...query };
|
|
|
|
for (const [name, meta] of schemas) {
|
|
if (meta.schema) {
|
|
const rawValue = query[name];
|
|
const coercedValue = coerceValue(rawValue, meta.schema);
|
|
|
|
if (coercedValue !== undefined) {
|
|
result[name] = coercedValue;
|
|
} else if (meta.schema.default !== undefined) {
|
|
// Apply default when value is missing
|
|
result[name] = meta.schema.default;
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Coerce path parameters based on their schemas
|
|
*/
|
|
export function coercePathParams(
|
|
params: Record<string, string>,
|
|
schemas: Map<string, IOpenApiParamMeta>
|
|
): Record<string, unknown> {
|
|
const result: Record<string, unknown> = { ...params };
|
|
|
|
for (const [name, meta] of schemas) {
|
|
if (meta.schema && params[name] !== undefined) {
|
|
result[name] = coerceValue(params[name], meta.schema);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|