[mod] code structure [add] support for templating
This commit is contained in:
parent
e0daa85c88
commit
40f6550246
127
source/base.ts
Normal file
127
source/base.ts
Normal file
|
|
@ -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<string, any>;
|
||||||
|
}
|
||||||
|
>;
|
||||||
|
}
|
||||||
|
>;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
export type type_output = {
|
||||||
|
render : ((input_data : type_input) => Promise<string>);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
export enum enum_realm {
|
||||||
|
database = "database",
|
||||||
|
backend = "backend",
|
||||||
|
frontend = "frontend",
|
||||||
|
other = "other",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
var _outputs : Record<enum_realm, Record<string, _sindri.type_output>> = {
|
||||||
|
[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<string>
|
||||||
|
{
|
||||||
|
return lib_plankton.file.read(
|
||||||
|
[__dirname, "templates", realm, implementation, name].join("/")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
334
source/conf.ts
334
source/conf.ts
|
|
@ -1,48 +1,31 @@
|
||||||
|
namespace _sindri
|
||||||
/**
|
|
||||||
* @todo generate generic
|
|
||||||
*/
|
|
||||||
function input_schema(
|
|
||||||
) : any
|
|
||||||
{
|
{
|
||||||
return {
|
|
||||||
"type": "object",
|
/**
|
||||||
"additionalProperties": false,
|
* @todo generate generic
|
||||||
"properties": {
|
*/
|
||||||
"domains": {
|
export function input_schema(
|
||||||
"type": "array",
|
) : any
|
||||||
"items": {
|
{
|
||||||
"type": "object",
|
return {
|
||||||
"additionalProperties": false,
|
"type": "object",
|
||||||
"properties": {
|
"additionalProperties": false,
|
||||||
"name": {
|
"properties": {
|
||||||
"type": "string"
|
"domains": {
|
||||||
},
|
"type": "array",
|
||||||
"description": {
|
"items": {
|
||||||
"type": ["null", "string"],
|
"type": "object",
|
||||||
"default": null
|
"additionalProperties": false,
|
||||||
},
|
"properties": {
|
||||||
"key_field": {
|
"name": {
|
||||||
"type": ["null","object"],
|
"type": "string"
|
||||||
"additionalProperties": false,
|
|
||||||
"properties": {
|
|
||||||
"name": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"description": {
|
|
||||||
"type": ["null", "string"],
|
|
||||||
"default": null
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"required": [
|
"description": {
|
||||||
"name"
|
"type": ["null", "string"],
|
||||||
],
|
"default": null
|
||||||
"default": null
|
},
|
||||||
},
|
"key_field": {
|
||||||
"data_fields": {
|
"type": ["null","object"],
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"properties": {
|
"properties": {
|
||||||
"name": {
|
"name": {
|
||||||
|
|
@ -51,135 +34,156 @@ function input_schema(
|
||||||
"description": {
|
"description": {
|
||||||
"type": ["null", "string"],
|
"type": ["null", "string"],
|
||||||
"default": null
|
"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": [
|
"required": [
|
||||||
"name",
|
"name"
|
||||||
"type"
|
],
|
||||||
]
|
"default": null
|
||||||
},
|
},
|
||||||
"default": []
|
"data_fields": {
|
||||||
},
|
"type": "array",
|
||||||
"constraints": {
|
"items": {
|
||||||
"type": "array",
|
"type": "object",
|
||||||
"items": {
|
"additionalProperties": false,
|
||||||
"type": "object",
|
"properties": {
|
||||||
"additionalProperties": false,
|
"name": {
|
||||||
"properties": {
|
"type": "string"
|
||||||
"kind": {
|
|
||||||
"type": "string",
|
|
||||||
"enum": [
|
|
||||||
"unique",
|
|
||||||
"foreign_key"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"parameters": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": "string",
|
|
||||||
"properties": {
|
|
||||||
},
|
},
|
||||||
"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": [
|
"default": []
|
||||||
"kind"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"default": []
|
"constraints": {
|
||||||
}
|
"type": "array",
|
||||||
},
|
"items": {
|
||||||
"required": [
|
"type": "object",
|
||||||
"name"
|
"additionalProperties": false,
|
||||||
]
|
"properties": {
|
||||||
}
|
"kind": {
|
||||||
}
|
"type": "string",
|
||||||
},
|
"enum": [
|
||||||
"required": [
|
"unique",
|
||||||
"domains"
|
"foreign_key"
|
||||||
]
|
]
|
||||||
}
|
},
|
||||||
}
|
"parameters": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": "string",
|
||||||
/**
|
"properties": {
|
||||||
*/
|
},
|
||||||
function input_normalize(
|
"required": [
|
||||||
input_raw : any
|
]
|
||||||
) : type_input
|
}
|
||||||
{
|
},
|
||||||
// validate
|
"required": [
|
||||||
if (! input_raw.hasOwnProperty("domains")) {
|
"kind"
|
||||||
throw (new Error("input node is missing mandatory field 'domains'"));
|
]
|
||||||
}
|
},
|
||||||
else {
|
"default": []
|
||||||
// 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
|
},
|
||||||
),
|
"required": [
|
||||||
"data_fields": (
|
"name"
|
||||||
(domain_raw.hasOwnProperty("data_fields") && (domain_raw["data_fields"] !== null))
|
]
|
||||||
? (
|
}
|
||||||
domain_raw["data_fields"]
|
}
|
||||||
.map(
|
},
|
||||||
data_field_raw => ({
|
"required": [
|
||||||
"name": data_field_raw["name"],
|
"domains"
|
||||||
"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"] ?? {}),
|
|
||||||
})
|
|
||||||
)
|
|
||||||
)
|
|
||||||
: []
|
|
||||||
),
|
|
||||||
})
|
|
||||||
)
|
|
||||||
),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
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"] ?? {}),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
)
|
||||||
|
: []
|
||||||
|
),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
198
source/main.ts
198
source/main.ts
|
|
@ -1,91 +1,135 @@
|
||||||
/**
|
namespace _sindri
|
||||||
*/
|
|
||||||
async function main(
|
|
||||||
args_raw : Array<string>
|
|
||||||
) : Promise<void>
|
|
||||||
{
|
{
|
||||||
const outputs : Record<string, type_output> = {
|
|
||||||
"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({
|
export async function main(
|
||||||
"name": "format",
|
args_raw : Array<string>
|
||||||
"type": lib_plankton.args.enum_type.string,
|
) : Promise<void>
|
||||||
"kind": lib_plankton.args.enum_kind.volatile,
|
{
|
||||||
"mode": lib_plankton.args.enum_mode.replace,
|
const arg_handler = new lib_plankton.args.class_handler(
|
||||||
"default": "database-sqlite",
|
{
|
||||||
"parameters": {
|
"format": new lib_plankton.args.class_argument({
|
||||||
"indicators_long": ["format"],
|
"name": "format",
|
||||||
"indicators_short": ["f"],
|
"type": lib_plankton.args.enum_type.string,
|
||||||
},
|
"kind": lib_plankton.args.enum_kind.volatile,
|
||||||
"info": "output format",
|
"mode": lib_plankton.args.enum_mode.replace,
|
||||||
}),
|
"default": "database:sqlite",
|
||||||
"schema": new lib_plankton.args.class_argument({
|
"parameters": {
|
||||||
"name": "schema",
|
"indicators_long": ["format"],
|
||||||
"type": lib_plankton.args.enum_type.boolean,
|
"indicators_short": ["f"],
|
||||||
"kind": lib_plankton.args.enum_kind.volatile,
|
},
|
||||||
"mode": lib_plankton.args.enum_mode.replace,
|
"info": "output format",
|
||||||
"default": false,
|
}),
|
||||||
"parameters": {
|
"list": new lib_plankton.args.class_argument({
|
||||||
"indicators_long": ["schema"],
|
"name": "list",
|
||||||
"indicators_short": ["s"],
|
"type": lib_plankton.args.enum_type.boolean,
|
||||||
},
|
"kind": lib_plankton.args.enum_kind.volatile,
|
||||||
"info": "print sindri JSON schema to stdout and exit",
|
"mode": lib_plankton.args.enum_mode.replace,
|
||||||
}),
|
"default": false,
|
||||||
"help": new lib_plankton.args.class_argument({
|
"parameters": {
|
||||||
"name": "help",
|
"indicators_long": ["list"],
|
||||||
"type": lib_plankton.args.enum_type.boolean,
|
"indicators_short": ["l"],
|
||||||
"kind": lib_plankton.args.enum_kind.volatile,
|
},
|
||||||
"mode": lib_plankton.args.enum_mode.replace,
|
"info": "list available output formats",
|
||||||
"default": false,
|
}),
|
||||||
"parameters": {
|
"schema": new lib_plankton.args.class_argument({
|
||||||
"indicators_long": ["help"],
|
"name": "schema",
|
||||||
"indicators_short": ["h"],
|
"type": lib_plankton.args.enum_type.boolean,
|
||||||
},
|
"kind": lib_plankton.args.enum_kind.volatile,
|
||||||
"info": "print help to stdout and exit",
|
"mode": lib_plankton.args.enum_mode.replace,
|
||||||
}),
|
"default": false,
|
||||||
}
|
"parameters": {
|
||||||
);
|
"indicators_long": ["schema"],
|
||||||
const args : Record<string, any> = arg_handler.read(lib_plankton.args.enum_environment.cli, args_raw.join(" "));
|
"indicators_short": ["s"],
|
||||||
|
},
|
||||||
if (args["help"]) {
|
"info": "print sindri JSON schema to stdout and exit",
|
||||||
process.stdout.write(
|
}),
|
||||||
arg_handler.generate_help(
|
"help": new lib_plankton.args.class_argument({
|
||||||
{
|
"name": "help",
|
||||||
"programname": "sindri",
|
"type": lib_plankton.args.enum_type.boolean,
|
||||||
"author": "Christian Fraß <frass@greenscale.de>",
|
"kind": lib_plankton.args.enum_kind.volatile,
|
||||||
"description": "create data model scripts in different output formats (MySQL, SQLite, …) on basis of an abstract description; feed with .sindri.json file via stdin!",
|
"mode": lib_plankton.args.enum_mode.replace,
|
||||||
"executable": "sindri",
|
"default": false,
|
||||||
}
|
"parameters": {
|
||||||
)
|
"indicators_long": ["help"],
|
||||||
|
"indicators_short": ["h"],
|
||||||
|
},
|
||||||
|
"info": "print help to stdout and exit",
|
||||||
|
}),
|
||||||
|
}
|
||||||
);
|
);
|
||||||
}
|
const args : Record<string, any> = arg_handler.read(lib_plankton.args.enum_environment.cli, args_raw.join(" "));
|
||||||
else {
|
|
||||||
if (args["schema"]) {
|
if (args["help"]) {
|
||||||
process.stdout.write(
|
process.stdout.write(
|
||||||
JSON.stringify(input_schema(), undefined, "\t")
|
arg_handler.generate_help(
|
||||||
|
{
|
||||||
|
"programname": "sindri",
|
||||||
|
"author": "Christian Fraß <frass@greenscale.de>",
|
||||||
|
"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 {
|
else {
|
||||||
const input_content : string = await lib_plankton.file.read_stdin();
|
if (args["schema"]) {
|
||||||
const input_data_raw : any = lib_plankton.json.decode(input_content);
|
process.stdout.write(
|
||||||
const input_data : type_input = input_normalize(input_data_raw);
|
JSON.stringify(_sindri.input_schema(), undefined, "\t")
|
||||||
|
);
|
||||||
if (! outputs.hasOwnProperty(args["format"])) {
|
|
||||||
throw (new Error("unhandled output format: " + args["format"]));
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const output_content : string = outputs[args["format"]].render(input_data);
|
if (args["list"]) {
|
||||||
process.stdout.write(output_content);
|
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<string> = 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));
|
||||||
|
|
|
||||||
|
|
@ -1437,6 +1437,10 @@ namespace _sindri.outputs.backend.typescript
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const output_backend_typescript : type_output = {
|
_sindri.add_output(
|
||||||
"render": _sindri.outputs.backend.typescript.render,
|
_sindri.enum_realm.backend,
|
||||||
};
|
"typescript",
|
||||||
|
{
|
||||||
|
"render": (x) => Promise.resolve<string>(_sindri.outputs.backend.typescript.render(x)),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
@ -212,6 +212,10 @@ namespace _sindri.outputs.database.mysql
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
const output_database_mysql : type_output = {
|
_sindri.add_output(
|
||||||
"render": _sindri.outputs.database.mysql.render,
|
_sindri.enum_realm.database,
|
||||||
};
|
"mysql",
|
||||||
|
{
|
||||||
|
"render": (x) => Promise.resolve<string>(_sindri.outputs.backend.typescript.render(x)),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
@ -174,6 +174,10 @@ namespace _sindri.outputs.database.sqlite
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const output_database_sqlite : type_output = {
|
_sindri.add_output(
|
||||||
"render": _sindri.outputs.database.sqlite.render,
|
_sindri.enum_realm.database,
|
||||||
};
|
"sqlite",
|
||||||
|
{
|
||||||
|
"render": (x) => Promise.resolve<string>(_sindri.outputs.backend.typescript.render(x)),
|
||||||
|
}
|
||||||
|
);
|
||||||
36
source/outputs/frontend/typescript/logic.ts
Normal file
36
source/outputs/frontend/typescript/logic.ts
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
namespace _sindri.outputs.frontend.typescript
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
async function get_template(
|
||||||
|
name : string
|
||||||
|
) : Promise<string>
|
||||||
|
{
|
||||||
|
return _sindri.get_template(_sindri.enum_realm.frontend, "typescript", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
export async function render(
|
||||||
|
input_data
|
||||||
|
) : Promise<string>
|
||||||
|
{
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
);
|
||||||
251
source/outputs/frontend/typescript/templates/core.ts.tpl
Normal file
251
source/outputs/frontend/typescript/templates/core.ts.tpl
Normal file
|
|
@ -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<any>
|
||||||
|
{
|
||||||
|
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<int, any>) => void))
|
||||||
|
) : lib_plankton.zoo_editor.type_editor<int, any>
|
||||||
|
{
|
||||||
|
return lib_plankton.zoo_editor.make<int, any>(
|
||||||
|
// store
|
||||||
|
{
|
||||||
|
"setup": () => Promise.resolve<void>(undefined),
|
||||||
|
"search": (term) => (
|
||||||
|
api_call(
|
||||||
|
"GET",
|
||||||
|
lib_plankton.string.coin(
|
||||||
|
"/{{name}}",
|
||||||
|
{
|
||||||
|
"name": domain_description.name,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
null
|
||||||
|
)
|
||||||
|
.then(
|
||||||
|
(entries) => Promise.resolve<Array<{key : int; preview : any}>>(
|
||||||
|
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<any>(
|
||||||
|
// 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<int, any>(
|
||||||
|
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<void>
|
||||||
|
{
|
||||||
|
abstract.domains.forEach(
|
||||||
|
domain_description => {
|
||||||
|
register_editor_page_for_domain(domain_description);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return Promise.resolve<void>(undefined);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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,
|
|
||||||
};
|
|
||||||
|
|
@ -1,5 +1,12 @@
|
||||||
const output_jsonschema : type_output = {
|
namespace _sindri.outputs.other.jsonschema
|
||||||
"render": function (input_data) {
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
export function render(
|
||||||
|
input_data
|
||||||
|
) : string
|
||||||
|
{
|
||||||
return lib_plankton.json.encode(
|
return lib_plankton.json.encode(
|
||||||
Object.fromEntries(
|
Object.fromEntries(
|
||||||
input_data.domains.map(
|
input_data.domains.map(
|
||||||
|
|
@ -78,5 +85,17 @@ const output_jsonschema : type_output = {
|
||||||
),
|
),
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
};
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
_sindri.add_output(
|
||||||
|
_sindri.enum_realm.other,
|
||||||
|
"jsonschema",
|
||||||
|
{
|
||||||
|
"render": (x) => Promise.resolve<string>(_sindri.outputs.backend.typescript.render(x)),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
@ -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<string, any>;
|
|
||||||
}
|
|
||||||
>;
|
|
||||||
}
|
|
||||||
>;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
type type_output = {
|
|
||||||
render : ((input_data : type_input) => string);
|
|
||||||
};
|
|
||||||
|
|
@ -13,16 +13,16 @@ cmd_copy := cp -r -u -v
|
||||||
## rules
|
## rules
|
||||||
|
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
all: build/sindri
|
all: build/sindri templates
|
||||||
|
|
||||||
temp/sindri-unlinked.js: \
|
temp/sindri-unlinked.js: \
|
||||||
lib/plankton/plankton.d.ts \
|
lib/plankton/plankton.d.ts \
|
||||||
source/types.ts \
|
source/base.ts \
|
||||||
source/outputs/jsonschema.ts \
|
source/outputs/other/jsonschema/logic.ts \
|
||||||
source/outputs/database_sqlite.ts \
|
source/outputs/database/sqlite/logic.ts \
|
||||||
source/outputs/database_mysql.ts \
|
source/outputs/database/mysql/logic.ts \
|
||||||
source/outputs/backend_typescript.ts \
|
source/outputs/backend/typescript/logic.ts \
|
||||||
source/outputs/frontend_typescript.ts \
|
source/outputs/frontend/typescript/logic.ts \
|
||||||
source/conf.ts \
|
source/conf.ts \
|
||||||
source/main.ts
|
source/main.ts
|
||||||
@ ${cmd_log} "compiling …"
|
@ ${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_echox} "#!/usr/bin/env node" > temp/head.js
|
||||||
@ ${cmd_concatenate} temp/head.js $^ > $@
|
@ ${cmd_concatenate} temp/head.js $^ > $@
|
||||||
@ ${cmd_chmod} +x $@
|
@ ${cmd_chmod} +x $@
|
||||||
|
|
||||||
|
.PHONY: templates
|
||||||
|
templates: \
|
||||||
|
source/outputs/frontend/typescript/templates/core.ts.tpl
|
||||||
|
@ ${cmd_log} "placing templates …"
|
||||||
|
@ tools/place-templates
|
||||||
|
|
|
||||||
17
tools/place-templates
Executable file
17
tools/place-templates
Executable file
|
|
@ -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
|
||||||
Loading…
Reference in a new issue