@router-cli/react-router
Version:
File based routing cli for react-router-dom. Types and components. see @router-cli/react-router-dev for the cli and plugins.
88 lines (73 loc) • 2.81 kB
text/typescript
import type { LoaderFunctionArgs } from 'react-router-dom';
import searchParamUtilities from "./searchParams";
import { ParamSchema } from '../types';
import { parseSchema } from './schemaParser';
import { createErrorResponse } from './errors';
type Params = LoaderFunctionArgs['params'];
type Options<Parser = SearchParamsParser> = {
message?: string;
status?: number;
parser?: Parser;
};
export function parseParams<TShape, T extends ParamSchema<TShape> = ParamSchema<TShape>>(
params: Params,
schema: T,
options?: Options
): TShape {
try {
return parseSchema(params, schema);
} catch (error) {
throw createErrorResponse(options);
}
}
export function parseQuery<TShape, T extends ParamSchema<TShape> = ParamSchema<TShape>>(
request: Request | URLSearchParams,
schema: T,
options?: Options
): TShape {
try {
const searchParams = isURLSearchParams(request)
? request
: getSearchParamsFromRequest(request);
const params = parseSearchParams(searchParams, options?.parser);
return parseSchema(params, schema);
} catch (error) {
throw createErrorResponse(options);
}
}
type ParsedSearchParamsTypes = string | number | boolean;
type ParsedSearchParams<T = ParsedSearchParamsTypes> = Record<string, T | null | Array<T | null>>
type SearchParamsParser<T = ParsedSearchParams> = (
searchParams: URLSearchParams
) => T;
function isObjectEntry([, value]: [string, FormDataEntryValue]) {
return value instanceof Object;
}
function parseFormData(formData: FormData, customParser?: SearchParamsParser) {
const objectEntries = [...formData.entries()].filter(isObjectEntry);
objectEntries.forEach(([key, value]) => {
formData.set(key, JSON.stringify(value));
});
// Context on `as any` usage: https://github.com/microsoft/TypeScript/issues/30584
return parseSearchParams(new URLSearchParams(formData as any), customParser);
}
function parseSearchParams(
searchParams: URLSearchParams,
customParser?: SearchParamsParser
): ParsedSearchParams {
const parser = customParser || parseSearchParamsDefault;
return parser(searchParams);
}
const parseSearchParamsDefault: SearchParamsParser = (searchParams) => {
return searchParamUtilities.parse(searchParams);
};
function getSearchParamsFromRequest(request: Request): URLSearchParams {
const url = new URL(request.url);
return url.searchParams;
}
function isURLSearchParams(value: unknown): value is URLSearchParams {
return getObjectTypeName(value) === 'URLSearchParams';
}
function getObjectTypeName(value: unknown): string {
return toString.call(value).slice(8, -1);
}