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
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 };
|
|
};
|