From 40f65502460b08f8b7bbc466981d5e532550fe83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Fra=C3=9F?= Date: Tue, 8 Aug 2023 14:39:21 +0200 Subject: [PATCH] [mod] code structure [add] support for templating --- source/base.ts | 127 +++++++ source/conf.ts | 334 +++++++++--------- source/main.ts | 198 +++++++---- .../typescript/logic.ts} | 10 +- .../mysql/logic.ts} | 10 +- .../sqlite/logic.ts} | 10 +- source/outputs/frontend/typescript/logic.ts | 36 ++ .../frontend/typescript/templates/core.ts.tpl | 251 +++++++++++++ source/outputs/frontend_typescript.ts | 22 -- .../jsonschema/logic.ts} | 27 +- source/types.ts | 40 --- tools/makefile | 20 +- tools/place-templates | 17 + 13 files changed, 778 insertions(+), 324 deletions(-) create mode 100644 source/base.ts rename source/outputs/{backend_typescript.ts => backend/typescript/logic.ts} (99%) rename source/outputs/{database_mysql.ts => database/mysql/logic.ts} (96%) rename source/outputs/{database_sqlite.ts => database/sqlite/logic.ts} (96%) create mode 100644 source/outputs/frontend/typescript/logic.ts create mode 100644 source/outputs/frontend/typescript/templates/core.ts.tpl delete mode 100644 source/outputs/frontend_typescript.ts rename source/outputs/{jsonschema.ts => other/jsonschema/logic.ts} (85%) delete mode 100644 source/types.ts create mode 100755 tools/place-templates diff --git a/source/base.ts b/source/base.ts new file mode 100644 index 0000000..560bc1a --- /dev/null +++ b/source/base.ts @@ -0,0 +1,127 @@ +declare var __dirname; + +namespace _sindri +{ + + /** + */ + export type type_input = { + domains : Array< + { + name : string; + description : (null | string); + key_field : ( + null + | + { + name : string; + description ?: (null | string); + } + ); + data_fields : Array< + { + name : string; + description : (null | string); + type : ("boolean" | "integer" | "float" | "string_short" | "string_medium" | "string_long"); + nullable : boolean; + default : (null | boolean | int | float | string); + } + >; + constraints ?: Array< + { + kind : ("unique" | "foreign_key"); + parameters : Record; + } + >; + } + >; + }; + + + /** + */ + export type type_output = { + render : ((input_data : type_input) => Promise); + }; + + + /** + */ + export enum enum_realm { + database = "database", + backend = "backend", + frontend = "frontend", + other = "other", + } + + + /** + */ + var _outputs : Record> = { + [enum_realm.database]: {}, + [enum_realm.backend]: {}, + [enum_realm.frontend]: {}, + [enum_realm.other]: {}, + }; + + + /** + */ + export function add_output( + realm : enum_realm, + implementation : string, + output : _sindri.type_output + ) : void + { + _outputs[realm][implementation] = output; + } + + + /** + */ + export function get_output( + realm : enum_realm, + implementation : string + ) : _sindri.type_output + { + return _outputs[realm][implementation]; + } + + + /** + */ + export function list_outputs( + ) : Array<{realm : enum_realm; implementation : string;}> + { + return ( + Object.entries(_outputs) + .map( + ([realm, group]) => ( + Object.keys(group) + .map( + implementation => ({"realm": (realm as enum_realm), "implementation": implementation}) + ) + ) + ) + .reduce( + (x, y) => x.concat(y), + [] + ) + ); + } + + + /** + */ + export function get_template( + realm : enum_realm, + implementation : string, + name : string + ) : Promise + { + return lib_plankton.file.read( + [__dirname, "templates", realm, implementation, name].join("/") + ); + } + +} diff --git a/source/conf.ts b/source/conf.ts index f73f4b0..b7d4215 100644 --- a/source/conf.ts +++ b/source/conf.ts @@ -1,48 +1,31 @@ - -/** - * @todo generate generic - */ -function input_schema( -) : any +namespace _sindri { - return { - "type": "object", - "additionalProperties": false, - "properties": { - "domains": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": false, - "properties": { - "name": { - "type": "string" - }, - "description": { - "type": ["null", "string"], - "default": null - }, - "key_field": { - "type": ["null","object"], - "additionalProperties": false, - "properties": { - "name": { - "type": "string" - }, - "description": { - "type": ["null", "string"], - "default": null - } + + /** + * @todo generate generic + */ + export function input_schema( + ) : any + { + return { + "type": "object", + "additionalProperties": false, + "properties": { + "domains": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "name": { + "type": "string" }, - "required": [ - "name" - ], - "default": null - }, - "data_fields": { - "type": "array", - "items": { - "type": "object", + "description": { + "type": ["null", "string"], + "default": null + }, + "key_field": { + "type": ["null","object"], "additionalProperties": false, "properties": { "name": { @@ -51,135 +34,156 @@ function input_schema( "description": { "type": ["null", "string"], "default": null - }, - "type": { - "type": "string", - "enum": [ - "boolean", - "integer", - "float", - "string_short", - "string_medium", - "string_long" - ] - }, - "nullable": { - "type": "boolean", - "default": true - }, - "default": { - "type": ["null", "boolean", "integer", "float", "string"], - "default": null } }, "required": [ - "name", - "type" - ] + "name" + ], + "default": null }, - "default": [] - }, - "constraints": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": false, - "properties": { - "kind": { - "type": "string", - "enum": [ - "unique", - "foreign_key" - ] - }, - "parameters": { - "type": "object", - "additionalProperties": "string", - "properties": { + "data_fields": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "name": { + "type": "string" }, - "required": [ - ] - } + "description": { + "type": ["null", "string"], + "default": null + }, + "type": { + "type": "string", + "enum": [ + "boolean", + "integer", + "float", + "string_short", + "string_medium", + "string_long" + ] + }, + "nullable": { + "type": "boolean", + "default": true + }, + "default": { + "type": ["null", "boolean", "integer", "float", "string"], + "default": null + } + }, + "required": [ + "name", + "type" + ] }, - "required": [ - "kind" - ] + "default": [] }, - "default": [] - } - }, - "required": [ - "name" - ] - } - } - }, - "required": [ - "domains" - ] - } -} - - -/** - */ -function input_normalize( - input_raw : any -) : type_input -{ - // validate - if (! input_raw.hasOwnProperty("domains")) { - throw (new Error("input node is missing mandatory field 'domains'")); - } - else { - // sanitize - return { - "domains": ( - input_raw["domains"] - .map( - domain_raw => ({ - "name": domain_raw["name"], - "description": (domain_raw["description"] ?? null), - "key_field": ( - (domain_raw.hasOwnProperty("key_field") && (domain_raw["key_field"] !== null)) - ? { - "name": domain_raw["key_field"]["name"], - "description": (domain_raw["key_field"]["description"] ?? null), + "constraints": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "kind": { + "type": "string", + "enum": [ + "unique", + "foreign_key" + ] + }, + "parameters": { + "type": "object", + "additionalProperties": "string", + "properties": { + }, + "required": [ + ] + } + }, + "required": [ + "kind" + ] + }, + "default": [] } - : null - ), - "data_fields": ( - (domain_raw.hasOwnProperty("data_fields") && (domain_raw["data_fields"] !== null)) - ? ( - domain_raw["data_fields"] - .map( - data_field_raw => ({ - "name": data_field_raw["name"], - "description": (data_field_raw["description"] ?? null), - "type": data_field_raw["type"], - "nullable": (data_field_raw["nullable"] ?? true), - "default": data_field_raw["default"], - }) - ) - ) - : [] - ), - "constraints": ( - (domain_raw.hasOwnProperty("constraints") && (domain_raw["constraints"] !== null)) - ? ( - domain_raw["constraints"] - .map( - constraint_raw => ({ - "kind": constraint_raw["kind"], - "parameters": (constraint_raw["parameters"] ?? {}), - }) - ) - ) - : [] - ), - }) - ) - ), - }; + }, + "required": [ + "name" + ] + } + } + }, + "required": [ + "domains" + ] + } } + + + /** + */ + export function input_normalize( + input_raw : any + ) : type_input + { + // validate + if (! input_raw.hasOwnProperty("domains")) { + throw (new Error("input node is missing mandatory field 'domains'")); + } + else { + // sanitize + return { + "domains": ( + input_raw["domains"] + .map( + domain_raw => ({ + "name": domain_raw["name"], + "description": (domain_raw["description"] ?? null), + "key_field": ( + (domain_raw.hasOwnProperty("key_field") && (domain_raw["key_field"] !== null)) + ? { + "name": domain_raw["key_field"]["name"], + "description": (domain_raw["key_field"]["description"] ?? null), + } + : null + ), + "data_fields": ( + (domain_raw.hasOwnProperty("data_fields") && (domain_raw["data_fields"] !== null)) + ? ( + domain_raw["data_fields"] + .map( + data_field_raw => ({ + "name": data_field_raw["name"], + "description": (data_field_raw["description"] ?? null), + "type": data_field_raw["type"], + "nullable": (data_field_raw["nullable"] ?? true), + "default": data_field_raw["default"], + }) + ) + ) + : [] + ), + "constraints": ( + (domain_raw.hasOwnProperty("constraints") && (domain_raw["constraints"] !== null)) + ? ( + domain_raw["constraints"] + .map( + constraint_raw => ({ + "kind": constraint_raw["kind"], + "parameters": (constraint_raw["parameters"] ?? {}), + }) + ) + ) + : [] + ), + }) + ) + ), + }; + } + } + } diff --git a/source/main.ts b/source/main.ts index 45ca69a..ebba866 100644 --- a/source/main.ts +++ b/source/main.ts @@ -1,91 +1,135 @@ -/** - */ -async function main( - args_raw : Array -) : Promise +namespace _sindri { - const outputs : Record = { - "jsonschema": output_jsonschema, - "database-sqlite": output_database_sqlite, - "database-mysql": output_database_mysql, - "backend-typescript": output_backend_typescript, - "frontend-typescript": output_frontend_typescript, - }; - const arg_handler = new lib_plankton.args.class_handler( - { - "format": new lib_plankton.args.class_argument({ - "name": "format", - "type": lib_plankton.args.enum_type.string, - "kind": lib_plankton.args.enum_kind.volatile, - "mode": lib_plankton.args.enum_mode.replace, - "default": "database-sqlite", - "parameters": { - "indicators_long": ["format"], - "indicators_short": ["f"], - }, - "info": "output format", - }), - "schema": new lib_plankton.args.class_argument({ - "name": "schema", - "type": lib_plankton.args.enum_type.boolean, - "kind": lib_plankton.args.enum_kind.volatile, - "mode": lib_plankton.args.enum_mode.replace, - "default": false, - "parameters": { - "indicators_long": ["schema"], - "indicators_short": ["s"], - }, - "info": "print sindri JSON schema to stdout and exit", - }), - "help": new lib_plankton.args.class_argument({ - "name": "help", - "type": lib_plankton.args.enum_type.boolean, - "kind": lib_plankton.args.enum_kind.volatile, - "mode": lib_plankton.args.enum_mode.replace, - "default": false, - "parameters": { - "indicators_long": ["help"], - "indicators_short": ["h"], - }, - "info": "print help to stdout and exit", - }), - } - ); - const args : Record = arg_handler.read(lib_plankton.args.enum_environment.cli, args_raw.join(" ")); - - if (args["help"]) { - process.stdout.write( - arg_handler.generate_help( - { - "programname": "sindri", - "author": "Christian Fraß ", - "description": "create data model scripts in different output formats (MySQL, SQLite, …) on basis of an abstract description; feed with .sindri.json file via stdin!", - "executable": "sindri", - } - ) + /** + */ + export async function main( + args_raw : Array + ) : Promise + { + const arg_handler = new lib_plankton.args.class_handler( + { + "format": new lib_plankton.args.class_argument({ + "name": "format", + "type": lib_plankton.args.enum_type.string, + "kind": lib_plankton.args.enum_kind.volatile, + "mode": lib_plankton.args.enum_mode.replace, + "default": "database:sqlite", + "parameters": { + "indicators_long": ["format"], + "indicators_short": ["f"], + }, + "info": "output format", + }), + "list": new lib_plankton.args.class_argument({ + "name": "list", + "type": lib_plankton.args.enum_type.boolean, + "kind": lib_plankton.args.enum_kind.volatile, + "mode": lib_plankton.args.enum_mode.replace, + "default": false, + "parameters": { + "indicators_long": ["list"], + "indicators_short": ["l"], + }, + "info": "list available output formats", + }), + "schema": new lib_plankton.args.class_argument({ + "name": "schema", + "type": lib_plankton.args.enum_type.boolean, + "kind": lib_plankton.args.enum_kind.volatile, + "mode": lib_plankton.args.enum_mode.replace, + "default": false, + "parameters": { + "indicators_long": ["schema"], + "indicators_short": ["s"], + }, + "info": "print sindri JSON schema to stdout and exit", + }), + "help": new lib_plankton.args.class_argument({ + "name": "help", + "type": lib_plankton.args.enum_type.boolean, + "kind": lib_plankton.args.enum_kind.volatile, + "mode": lib_plankton.args.enum_mode.replace, + "default": false, + "parameters": { + "indicators_long": ["help"], + "indicators_short": ["h"], + }, + "info": "print help to stdout and exit", + }), + } ); - } - else { - if (args["schema"]) { + const args : Record = arg_handler.read(lib_plankton.args.enum_environment.cli, args_raw.join(" ")); + + if (args["help"]) { process.stdout.write( - JSON.stringify(input_schema(), undefined, "\t") + arg_handler.generate_help( + { + "programname": "sindri", + "author": "Christian Fraß ", + "description": "create data model scripts in different output formats (MySQL, SQLite, …) on basis of an abstract description; feed with .sindri.json file via stdin!", + "executable": "sindri", + } + ) ); } else { - const input_content : string = await lib_plankton.file.read_stdin(); - const input_data_raw : any = lib_plankton.json.decode(input_content); - const input_data : type_input = input_normalize(input_data_raw); - - if (! outputs.hasOwnProperty(args["format"])) { - throw (new Error("unhandled output format: " + args["format"])); + if (args["schema"]) { + process.stdout.write( + JSON.stringify(_sindri.input_schema(), undefined, "\t") + ); } else { - const output_content : string = outputs[args["format"]].render(input_data); - process.stdout.write(output_content); + if (args["list"]) { + process.stdout.write( + _sindri.list_outputs() + .map( + entry => lib_plankton.string.coin( + "{{realm}}:{{implementation}}\n", + { + "realm": entry.realm, + "implementation": entry.implementation, + } + ) + ) + .join("") + ); + } + else { + const input_content : string = await lib_plankton.file.read_stdin(); + const input_data_raw : any = lib_plankton.json.decode(input_content); + const input_data : type_input = _sindri.input_normalize(input_data_raw); + + const format_parts : Array = args["format"].split(":"); + const realm_encoded : string = format_parts[0]; + const realm : _sindri.enum_realm = { + "database": _sindri.enum_realm.database, + "backend": _sindri.enum_realm.backend, + "frontend": _sindri.enum_realm.frontend, + "other": _sindri.enum_realm.other, + }[realm_encoded]; + const name : string = format_parts.slice(1).join(":"); + + let output : (null | _sindri.type_output); + try { + output = _sindri.get_output(realm, name); + } + catch (error) { + output = null; + } + if (output === null) { + throw (new Error("unhandled output format: " + args["format"])); + } + else { + const output_content : string = await output.render(input_data); + process.stdout.write(output_content); + } + } } } } + } -main(process.argv.slice(2)); + +_sindri.main(process.argv.slice(2)); diff --git a/source/outputs/backend_typescript.ts b/source/outputs/backend/typescript/logic.ts similarity index 99% rename from source/outputs/backend_typescript.ts rename to source/outputs/backend/typescript/logic.ts index f47464a..0f69a30 100644 --- a/source/outputs/backend_typescript.ts +++ b/source/outputs/backend/typescript/logic.ts @@ -1437,6 +1437,10 @@ namespace _sindri.outputs.backend.typescript } -const output_backend_typescript : type_output = { - "render": _sindri.outputs.backend.typescript.render, -}; +_sindri.add_output( + _sindri.enum_realm.backend, + "typescript", + { + "render": (x) => Promise.resolve(_sindri.outputs.backend.typescript.render(x)), + } +); diff --git a/source/outputs/database_mysql.ts b/source/outputs/database/mysql/logic.ts similarity index 96% rename from source/outputs/database_mysql.ts rename to source/outputs/database/mysql/logic.ts index 0f1f0b3..caf5bdc 100644 --- a/source/outputs/database_mysql.ts +++ b/source/outputs/database/mysql/logic.ts @@ -212,6 +212,10 @@ namespace _sindri.outputs.database.mysql /** */ -const output_database_mysql : type_output = { - "render": _sindri.outputs.database.mysql.render, -}; +_sindri.add_output( + _sindri.enum_realm.database, + "mysql", + { + "render": (x) => Promise.resolve(_sindri.outputs.backend.typescript.render(x)), + } +); diff --git a/source/outputs/database_sqlite.ts b/source/outputs/database/sqlite/logic.ts similarity index 96% rename from source/outputs/database_sqlite.ts rename to source/outputs/database/sqlite/logic.ts index f4b1351..1b18957 100644 --- a/source/outputs/database_sqlite.ts +++ b/source/outputs/database/sqlite/logic.ts @@ -174,6 +174,10 @@ namespace _sindri.outputs.database.sqlite } -const output_database_sqlite : type_output = { - "render": _sindri.outputs.database.sqlite.render, -}; +_sindri.add_output( + _sindri.enum_realm.database, + "sqlite", + { + "render": (x) => Promise.resolve(_sindri.outputs.backend.typescript.render(x)), + } +); diff --git a/source/outputs/frontend/typescript/logic.ts b/source/outputs/frontend/typescript/logic.ts new file mode 100644 index 0000000..1654382 --- /dev/null +++ b/source/outputs/frontend/typescript/logic.ts @@ -0,0 +1,36 @@ +namespace _sindri.outputs.frontend.typescript +{ + + /** + */ + async function get_template( + name : string + ) : Promise + { + return _sindri.get_template(_sindri.enum_realm.frontend, "typescript", name); + } + + + /** + */ + export async function render( + input_data + ) : Promise + { + return lib_plankton.string.coin( + await get_template("core.ts.tpl"), + { + "value": JSON.stringify(input_data, undefined, "\t"), + } + ); + } + +} + +_sindri.add_output( + _sindri.enum_realm.frontend, + "typescript", + { + "render": _sindri.outputs.frontend.typescript.render, + } +); diff --git a/source/outputs/frontend/typescript/templates/core.ts.tpl b/source/outputs/frontend/typescript/templates/core.ts.tpl new file mode 100644 index 0000000..c065713 --- /dev/null +++ b/source/outputs/frontend/typescript/templates/core.ts.tpl @@ -0,0 +1,251 @@ +namespace _sindri +{ + + /** + */ + const abstract = {{value}}; + + + /** + * @todo headers + * @todo query + */ + export function api_call( + method : string, + path : string, + input : any = null + ) : Promise + { + return ( + fetch( + (conf.backend.scheme + "://" + conf.backend.host + ":" + conf.backend.port.toFixed() + path), + { + "method": method, + "headers": { + "Content-Type": "application/json", + }, + "body": ( + (input === null) + ? undefined + : /*Buffer.from*/(JSON.stringify(input)) + ), + } + ) + .then( + x => x.json() + ) + ); + } + + + /** + */ + export function editor( + domain_description : any, + hook_switch : (null | ((state : lib_plankton.zoo_editor.type_state) => void)) + ) : lib_plankton.zoo_editor.type_editor + { + return lib_plankton.zoo_editor.make( + // store + { + "setup": () => Promise.resolve(undefined), + "search": (term) => ( + api_call( + "GET", + lib_plankton.string.coin( + "/{{name}}", + { + "name": domain_description.name, + } + ), + null + ) + .then( + (entries) => Promise.resolve>( + entries + .filter( + entry => ( + entry.key.toFixed().includes(term.toLowerCase()) + || + ( + /* + (term.length >= 3) + && + */ + domain_description.data_fields + .some( + data_field => JSON.stringify(entry.value[data_field.name]).toLowerCase().includes(term.toLowerCase()) + ) + ) + ) + ) + .map( + entry => ({ + "key": entry.key, + "preview": entry.value, + }) + ) + ) + ) + ), + "read": (id) => api_call( + "GET", + lib_plankton.string.coin( + "/{{name}}/{{id}}", + { + "name": domain_description.name, + "id": id.toFixed(0), + } + ), + null + ), + "create": (object) => api_call( + "POST", + lib_plankton.string.coin( + "/{{name}}", + { + "name": domain_description.name, + } + ), + object + ), + "update": (id, object) => api_call( + "PATCH", + lib_plankton.string.coin( + "/{{name}}/{{id}}", + { + "name": domain_description.name, + "id": id.toFixed(0), + } + ), + object + ), + "delete": (id) => api_call( + "DELETE", + lib_plankton.string.coin( + "/{{name}}/{{id}}", + { + "name": domain_description.name, + "id": id.toFixed(0), + } + ), + null + ), + }, + // form + lib_plankton.zoo_form.make( + // method + "GET", + // fields + ( + domain_description.data_fields.map( + data_field => ({ + "name": data_field.name, + "type": { + "string_short": "text", + "string_medium": "text", + "string_long": "text", + "integer": "number", + "float": "number", + }[data_field.type], + }) + ) + ), + // encode + (object) => object, + // decode + (object_encoded) => object_encoded, + ), + // options + { + "hook_switch": hook_switch, + } + ); + } + + + /** + */ + export function edit_location_name( + domain_description + ) : string + { + return lib_plankton.string.coin( + "edit_{{name}}", + { + "name": domain_description.name, + } + ); + } + + + /** + */ + export function register_editor_page_for_domain( + domain_description + ) : void + { + const location_name : string = edit_location_name(domain_description); + lib_plankton.zoo_page.register( + location_name, + async (parameters, element_main) => { + const id : (null | int) = ((! ("id" in parameters)) ? null : parseInt(parameters["id"])); + const mode : lib_plankton.zoo_editor.enum_mode = editor_decode_mode(parameters["mode"], id); + const search_term : (null | string) = (parameters["search"] ?? null); + lib_plankton.zoo_editor.render( + editor( + domain_description, + (state) => { + lib_plankton.zoo_page.set( + { + "name": location_name, + "parameters": { + "mode": state.mode, + "id": ((state.key === null) ? null : state.key.toFixed(0)), + "search": state.search_state.term, + }, + } + ); + } + ), + element_main, + { + "state": { + "mode": mode, + "key": id, + "search_state": {"term": search_term}, + } + } + ); + } + ); + lib_plankton.zoo_page.add_nav_entry( + { + "name": location_name, + "parameters": { + "mode": "find", + "key": null, + "search": "" + } + }, + { + "label": (domain_description.name + "s"), + } + ); + } + + + /** + */ + export function init( + ) : Promise + { + abstract.domains.forEach( + domain_description => { + register_editor_page_for_domain(domain_description); + } + ); + return Promise.resolve(undefined); + } + +} diff --git a/source/outputs/frontend_typescript.ts b/source/outputs/frontend_typescript.ts deleted file mode 100644 index 9003ee5..0000000 --- a/source/outputs/frontend_typescript.ts +++ /dev/null @@ -1,22 +0,0 @@ -namespace _sindri.outputs.frontend.typescript -{ - - /** - */ - export function render( - input_data - ) : string - { - return lib_plankton.string.coin( - "const sindri_abstract = {{value}};", - { - "value": JSON.stringify(input_data, undefined, "\t"), - } - ); - } - -} - -const output_frontend_typescript : type_output = { - "render": _sindri.outputs.frontend.typescript.render, -}; diff --git a/source/outputs/jsonschema.ts b/source/outputs/other/jsonschema/logic.ts similarity index 85% rename from source/outputs/jsonschema.ts rename to source/outputs/other/jsonschema/logic.ts index f869ee0..490d0cc 100644 --- a/source/outputs/jsonschema.ts +++ b/source/outputs/other/jsonschema/logic.ts @@ -1,5 +1,12 @@ -const output_jsonschema : type_output = { - "render": function (input_data) { +namespace _sindri.outputs.other.jsonschema +{ + + /** + */ + export function render( + input_data + ) : string + { return lib_plankton.json.encode( Object.fromEntries( input_data.domains.map( @@ -78,5 +85,17 @@ const output_jsonschema : type_output = { ), true ); - }, -}; + } + +} + + +/** + */ +_sindri.add_output( + _sindri.enum_realm.other, + "jsonschema", + { + "render": (x) => Promise.resolve(_sindri.outputs.backend.typescript.render(x)), + } +); diff --git a/source/types.ts b/source/types.ts deleted file mode 100644 index 307f3b4..0000000 --- a/source/types.ts +++ /dev/null @@ -1,40 +0,0 @@ -/** - */ -type type_input = { - domains : Array< - { - name : string; - description : (null | string); - key_field : ( - null - | - { - name : string; - description ?: (null | string); - } - ); - data_fields : Array< - { - name : string; - description : (null | string); - type : ("boolean" | "integer" | "float" | "string_short" | "string_medium" | "string_long"); - nullable : boolean; - default : (null | boolean | int | float | string); - } - >; - constraints ?: Array< - { - kind : ("unique" | "foreign_key"); - parameters : Record; - } - >; - } - >; -}; - - -/** - */ -type type_output = { - render : ((input_data : type_input) => string); -}; diff --git a/tools/makefile b/tools/makefile index 013367e..ca02d17 100644 --- a/tools/makefile +++ b/tools/makefile @@ -13,16 +13,16 @@ cmd_copy := cp -r -u -v ## rules .PHONY: all -all: build/sindri +all: build/sindri templates temp/sindri-unlinked.js: \ lib/plankton/plankton.d.ts \ -source/types.ts \ -source/outputs/jsonschema.ts \ -source/outputs/database_sqlite.ts \ -source/outputs/database_mysql.ts \ -source/outputs/backend_typescript.ts \ -source/outputs/frontend_typescript.ts \ +source/base.ts \ +source/outputs/other/jsonschema/logic.ts \ +source/outputs/database/sqlite/logic.ts \ +source/outputs/database/mysql/logic.ts \ +source/outputs/backend/typescript/logic.ts \ +source/outputs/frontend/typescript/logic.ts \ source/conf.ts \ source/main.ts @ ${cmd_log} "compiling …" @@ -35,3 +35,9 @@ build/sindri: lib/plankton/plankton.js temp/sindri-unlinked.js @ ${cmd_echox} "#!/usr/bin/env node" > temp/head.js @ ${cmd_concatenate} temp/head.js $^ > $@ @ ${cmd_chmod} +x $@ + +.PHONY: templates +templates: \ + source/outputs/frontend/typescript/templates/core.ts.tpl + @ ${cmd_log} "placing templates …" + @ tools/place-templates diff --git a/tools/place-templates b/tools/place-templates new file mode 100755 index 0000000..3c844e8 --- /dev/null +++ b/tools/place-templates @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +## consts + +dir_from=source/outputs +dir_to=build/templates + + +## exec + +paths=$(find ${dir_from} -type d -name templates) +for path in ${paths} +do + type=$(echo ${path} | cut --delimiter='/' --fields='3-' | cut --delimiter='/' --fields='-2') + mkdir --parents ${dir_to}/${type} + cp --update --verbose ${path}/* ${dir_to}/${type}/ +done