namespace formgen.input { /** */ export function from_raw( raw : any ) : interface_input { switch (raw.type) { case "checkbox": { return ( new class_input_checkbox( { "label": formgen.helpers.map.read<(null | string)>(raw, "label", null), } ) ); break; } case "number": { return ( new class_input_number( { "label": formgen.helpers.map.read<(null | string)>(raw, "label", null), } ) ); break; } case "text": { return ( new class_input_text( { "label": formgen.helpers.map.read<(null | string)>(raw, "label", null), } ) ); break; } case "color": { return ( new class_input_color( { "label": formgen.helpers.map.read<(null | string)>(raw, "label", null), } ) ); break; } case "select": { return ( new class_input_select( ( raw.options .map( (option_raw : Record) => ({ "value": option_raw["value"], "label": (formgen.helpers.map.read<(null | string)>(option_raw, "label", null) ?? String(option_raw["value"])), }) ) ), { "label": formgen.helpers.map.read<(null | string)>(raw, "label", null), } ) ); } case "list": { return ( new class_input_list( () => from_raw(raw.element), { "label": formgen.helpers.map.read<(null | string)>(raw, "label", null), } ) ); break; } case "group": { return ( new class_input_group( formgen.helpers.list.transform( formgen.helpers.map.to_pairs(raw.members), (pair) => ({ "name": pair.key, "input": from_raw(pair.value), "marked": (pair.value["required"] ?? false), }) ), { "label": formgen.helpers.map.read<(null | string)>(raw, "label", null), } ) ); break; } default: { throw (new Error("unhandled type: " + raw.type)); break; } } } /** * @todo description * @todo if-then-else */ function from_json_schema_inner( defs : Map, root : formgen.helpers.json_schema.type_schema, json_schema : formgen.helpers.json_schema.type_schema, { "fallback_label": fallback_label = null, "map_unhandled_refs_to_empty": map_unhandled_refs_to_empty = false, } : { fallback_label ?: (null | string); map_unhandled_refs_to_empty ?: boolean; } = { } ) : interface_input { const schema_adjusted : formgen.helpers.json_schema.type_schema = (() => { if (! ("$ref" in json_schema)) { return json_schema; } else { const cases = [ { "regexp": new RegExp('^#$'), "handling": (match) => { return root; }, }, { "regexp": new RegExp('^#/\\$defs/(.*)$'), "handling": (match) => { const key : string = match[1]; return defs.get(key); }, }, ]; for (const case_ of cases) { const match = json_schema.$ref.match(case_.regexp); if (match === null) { // do nothing } else { return case_.handling(match); } } if (map_unhandled_refs_to_empty) { /** * @todo warning */ return { "type": "null" }; } else { throw (new Error("unhandled ref: " + json_schema.$ref)); } } }) (); if ("enum" in schema_adjusted) { return ( new class_input_select( schema_adjusted.enum.map( (value, index) => ( { "value": value, // "label": ("Option " + (index+1).toFixed(0)), "label": JSON.stringify(value), } ) ), { "label": (schema_adjusted.title ?? fallback_label ?? null), } ) ); } else if ("type" in schema_adjusted) { switch (schema_adjusted.type) { case "null": { return ( new class_input_empty( ) ); break; } case "boolean": { return ( new class_input_checkbox( { "label": (schema_adjusted.title ?? fallback_label ?? null), "hint": (schema_adjusted.description ?? null), } ) ); break; } /** * @todo minimum * @todo exclusiveMinimum * @todo maximum * @todo exclusiveMaximum * @todo multipleOf */ case "integer": { return ( new class_input_number( { "label": (schema_adjusted.title ?? fallback_label ?? null), "hint": (schema_adjusted.description ?? null), } ) ); break; } /** * @todo minimum * @todo exclusiveMinimum * @todo maximum * @todo exclusiveMaximum * @todo multipleOf */ case "number": { return ( new class_input_number( { "label": (schema_adjusted.title ?? fallback_label ?? null), "hint": (schema_adjusted.description ?? null), } ) ); break; } /** * @todo pattern * @todo minLength * @todo maxLength * @todo more format values */ case "string": { if ("format" in schema_adjusted) { switch (schema_adjusted.format) { case "date": { return ( new class_input_date( { "label": (schema_adjusted.title ?? fallback_label ?? null), "hint": (schema_adjusted.description ?? null), } ) ); break; } case "time": { return ( new class_input_time( { "label": (schema_adjusted.title ?? fallback_label ?? null), "hint": (schema_adjusted.description ?? null), } ) ); break; } default: { /** * @todo warning */ return ( new class_input_text( { "label": (schema_adjusted.title ?? fallback_label ?? null), "hint": (schema_adjusted.description ?? null), } ) ); break; } } } else { return ( new class_input_text( { "label": (schema_adjusted.title ?? fallback_label ?? null), "hint": (schema_adjusted.description ?? null), } ) ); } break; } case "array": { if (! ("items" in schema_adjusted)) { throw (new Error("can not generate array input without 'items' definition")); } else { return ( new class_input_list( () => from_json_schema_inner( defs, root, (schema_adjusted.items as formgen.helpers.json_schema.type_schema), { "map_unhandled_refs_to_empty": map_unhandled_refs_to_empty, } ), { "label": (schema_adjusted.title ?? fallback_label ?? null), } ) ); } break; } /** * @todo required * @todo additionalProperties * @todo required */ case "object": { if ("properties" in schema_adjusted) { return ( new class_input_group( formgen.helpers.list.transform( formgen.helpers.map.to_pairs< formgen.helpers.json_schema.type_schema >(schema_adjusted.properties as Record), (pair : {key : string, value : formgen.helpers.json_schema.type_schema;}) => ({ "name": pair.key, "input": from_json_schema_inner( defs, root, pair.value, { "fallback_label": pair.key, "map_unhandled_refs_to_empty": map_unhandled_refs_to_empty, } ), "marked": (schema_adjusted.required ?? []).includes(pair.key), }) ), { "label": (schema_adjusted.title ?? fallback_label ?? null), } ) ); } else { throw (new Error("unhandled object situation")); } break; } default: { throw (new Error("unhandled json schema type: " + JSON.stringify(schema_adjusted))); break; } } } else if ("not" in schema_adjusted) { throw (new Error("not implemented")); } else if ("oneOf" in schema_adjusted) { return ( new class_input_sum( formgen.helpers.list.transform;}>( formgen.helpers.list.sequence(schema_adjusted.oneOf.length), (index) => { const sub_schema : formgen.helpers.json_schema.type_schema = schema_adjusted.oneOf[index]; return { "input": from_json_schema_inner( defs, root, sub_schema, { "map_unhandled_refs_to_empty": map_unhandled_refs_to_empty, } ), "label": (sub_schema.title ?? fallback_label ?? ("Art " + (index + 1).toFixed(0))), }; } ), { "label": (schema_adjusted.title ?? fallback_label ?? null), } ) ); } else if ("anyOf" in schema_adjusted) { return ( new class_input_sum( formgen.helpers.list.transform;}>( formgen.helpers.list.sequence(schema_adjusted.anyOf.length), (index) => { const sub_schema : formgen.helpers.json_schema.type_schema = schema_adjusted.anyOf[index]; return { "input": from_json_schema_inner( defs, root, sub_schema, { "map_unhandled_refs_to_empty": map_unhandled_refs_to_empty, } ), "label": (sub_schema.title ?? fallback_label ?? ("Art " + (index + 1).toFixed(0))), }; } ), { "label": (schema_adjusted.title ?? fallback_label ?? null), } ) ); } else if ("allOf" in schema_adjusted) { throw (new Error("not implemented")); } else { throw (new Error("unhandled schema: " + JSON.stringify(schema_adjusted))); } } /** */ export function from_json_schema( root : formgen.helpers.json_schema.type_root, { "map_unhandled_refs_to_empty": map_unhandled_refs_to_empty = false, } : { map_unhandled_refs_to_empty ?: boolean; } = { } ) : interface_input { let defs : Map = new Map(); if ("$defs" in root) { for (const [name, value] of Object.entries(root.$defs)) { defs.set(name, value); } } return from_json_schema_inner( defs, root, root, { "map_unhandled_refs_to_empty": map_unhandled_refs_to_empty, } ); } }