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.

119 lines
2.5 KiB
TypeScript

import { unreachable } from "../../../common/lib/dev.ts";
import { push, setIdx, setProp } from "../../../common/lib/imm.ts";
import {
Field,
FieldKind,
FieldOptions,
MaybePersistedSchema,
defaultOptionsForFieldKind,
validateSchema,
} from "../../../common/schema.ts";
import { Const, ReturnTypes } from "../../../common/utils.ts";
import { Reduce } from "../../state/lib/store.ts";
import { State } from "./view.ts";
export const setName = (name: string) => ({ setName: name });
export const addField = () => "addField" as const;
export const setFieldProp = <P extends keyof Field>(
index: number,
prop: P,
value: Field[P],
) => ({
index,
prop,
value,
});
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
k: infer I,
) => void
? I
: never;
export type AllOptions = UnionToIntersection<FieldOptions[FieldKind]>;
export const setFieldOptionProp = <P extends keyof AllOptions>(
index: number,
optionProp: P,
value: Required<AllOptions[P]>,
) => ({
index,
optionProp,
value,
});
export type Action = ReturnTypes<
[
typeof setName,
typeof addField,
typeof setFieldProp,
typeof setFieldOptionProp,
]
>;
const reduceSchema = (
schema: Const<MaybePersistedSchema>,
action: Action,
): Const<MaybePersistedSchema> => {
console.debug(action);
if (action == "addField") {
return setProp(
schema,
"fields",
push(schema.fields, {
kind: "string",
name: "New field",
options: defaultOptionsForFieldKind("string"),
required: false,
}),
);
}
if ("setName" in action) {
return setProp(schema, "name", action.setName);
}
if ("prop" in action) {
let field = setProp(schema.fields[action.index], action.prop, action.value);
if (action.prop == "kind") {
field = setProp(field, "options", {
...defaultOptionsForFieldKind(action.value as Field["kind"]),
...field.options,
});
}
return setProp(
schema,
"fields",
setIdx(schema.fields, action.index, field),
);
}
if ("optionProp" in action) {
return setProp(
schema,
"fields",
setIdx(
schema.fields,
action.index,
setProp(
schema.fields[action.index],
"options",
setProp(
schema.fields[action.index].options as any,
action.optionProp as never,
action.value as never,
),
),
),
);
}
return unreachable();
};
export const reduce: Reduce<State, Action> = (state, action) => {
const schema = reduceSchema(state.schema, action);
const errors = validateSchema(schema);
return { schema, errors };
};