You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

82 lines
2.5 KiB
TypeScript

import { hasShape, predicates, Shape, ShapeToType } from "@sealcode/ts-predicates";
import { BaseContext } from "koa";
import merge from "merge";
import { BasePageProps } from "./list";
export type EncodedProps = Record<string, unknown>;
// the intention here is to sometime in the future be able to store multiple frames on one document, so props for each frame will be in a different namespace, and parsers are going to help with that
function parseStringValues<TheShape extends Shape>(
shape: TheShape,
values: Record<string, string>
): ShapeToType<TheShape> {
const result: Record<string, unknown> = {};
for (const [key, value] of Object.entries(values)) {
if (!(key in shape)) {
continue;
}
const predicate = shape[key];
if (predicate == predicates.number) {
result[key] = parseFloat(value);
} else {
result[key] = value;
}
}
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
return result as ShapeToType<TheShape>;
}
export abstract class PagePropsParser<PropsType extends BasePageProps> {
abstract decode(ctx: BaseContext): PropsType;
abstract encode(props: PropsType): EncodedProps;
abstract getHTMLInputName(prop_name: string): string;
constructor(public propsShape: Shape, public defaultValues: Partial<PropsType>) {}
overwriteProp(ctx: BaseContext, new_props: Partial<PropsType>): EncodedProps {
const result = {};
merge.recursive(result, this.decode(ctx), new_props);
return result;
}
makeHiddenInputs(values: PropsType, fields_to_skip: string[]): string {
return Object.entries(values)
.filter(([key]) => !fields_to_skip.includes(key))
.map(
([key, value]: [string, string | number]) =>
/* HTML */ `<input type="hidden" name="${key}" value="${value}" />`
)
.join(" ");
}
getDefaultValue<Key extends keyof PropsType>(key: Key): PropsType[Key] | undefined {
return this.defaultValues[key];
}
}
export class AllQueryParams<
PropsType extends BasePageProps
> extends PagePropsParser<PropsType> {
decode(ctx: BaseContext): PropsType {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
const query = parseStringValues(this.propsShape, {
...this.defaultValues,
...ctx.query,
} as unknown as Record<string, string>);
if (!hasShape(this.propsShape, query)) {
throw new Error("Wrong props shape");
}
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
return query as PropsType;
}
encode(props: PropsType): Record<string, unknown> {
return props;
}
getHTMLInputName(prop_name: string): string {
return prop_name;
}
}