Add Array support to functions

This commit is contained in:
K35 2022-01-02 20:51:45 +00:00
parent a8f49d117d
commit db21c1c42e
7 changed files with 143 additions and 40 deletions

View File

@ -42,4 +42,7 @@ service TestService {
@Description("Just sends an Event with a String") @Description("Just sends an Event with a String")
@Param("param1", "Parameter with some string for event") @Param("param1", "Parameter with some string for event")
notification OnEvent(param1: string); notification OnEvent(param1: string);
FunctionWithArrayAsParamAndReturn(values1: number[], values2: number[]): number[];
} }

View File

@ -39,6 +39,10 @@ class TestService extends Server.TestService<undefined> {
OnEvent(param1: string, ctx: undefined): void { OnEvent(param1: string, ctx: undefined): void {
console.log("Received notification", param1); console.log("Received notification", param1);
} }
async FunctionWithArrayAsParamAndReturn(vals1, vals2) {
return [...vals1, ...vals2];
}
} }
server.addService(new TestService()); server.addService(new TestService());
@ -70,6 +74,22 @@ async function run() {
.catch((err) => { .catch((err) => {
console.log("Found expected error!", err.message); console.log("Found expected error!", err.message);
}); });
console.log("Test with arrays:");
console.log(await test
//@ts-ignore
.FunctionWithArrayAsParamAndReturn([1,2,3], [4,5,6]));
console.log("Let with Array fail!");
await test
//@ts-ignore
.FunctionWithArrayAsParamAndReturn([1,2,3], [4,"asd",6])
.then(() => {
console.log("!!!!This should have failed!!!!");
})
.catch((err) => {
console.log("Found expected error!", err.message);
});
} }
run(); run();

View File

@ -7193,7 +7193,12 @@ function parse(tokens, file) {
const [name2] = eatText(); const [name2] = eatText();
eatToken(":"); eatToken(":");
const [type] = eatText(); const [type] = eatText();
inputs.push({ name: name2, type }); let array = false;
if (currentToken.type === "array") {
array = true;
eatToken("[]");
}
inputs.push({ name: name2, type, array });
if (currentToken.value !== ",") if (currentToken.value !== ",")
break; break;
eatToken(","); eatToken(",");
@ -7203,7 +7208,16 @@ function parse(tokens, file) {
let return_type = void 0; let return_type = void 0;
if (!notification) { if (!notification) {
eatToken(":"); eatToken(":");
return_type = eatText()[0]; let [type] = eatText();
let array = false;
if (currentToken.type === "array") {
array = true;
eatToken("[]");
}
return_type = {
type,
array
};
} }
eatToken(";"); eatToken(";");
return { return {
@ -7365,11 +7379,11 @@ function get_ir(parsed) {
throw new IRError(fnc, `Function with name ${fnc.name} already defined!`); throw new IRError(fnc, `Function with name ${fnc.name} already defined!`);
alreadyFoundFunctions.add(fnc.name); alreadyFoundFunctions.add(fnc.name);
if (fnc.return_type) { if (fnc.return_type) {
if (defined.indexOf(fnc.return_type) >= 0) { if (defined.indexOf(fnc.return_type.type) >= 0) {
if (!depends.some((a) => a === fnc.return_type)) if (!depends.some((a) => a === fnc.return_type.type))
depends.push(fnc.return_type); depends.push(fnc.return_type.type);
} else { } else {
if (fnc.return_type !== "void" && builtin.indexOf(fnc.return_type) < 0) { if (fnc.return_type.type !== "void" && builtin.indexOf(fnc.return_type.type) < 0) {
throw new IRError(fnc, `Type ${fnc.return_type} is not defined`); throw new IRError(fnc, `Type ${fnc.return_type} is not defined`);
} }
} }
@ -7642,7 +7656,7 @@ var TypescriptTarget = class extends CompileTarget {
a(2, `super(provider, "${def.name}");`); a(2, `super(provider, "${def.name}");`);
a(1, `}`); a(1, `}`);
for (const fnc of def.functions) { for (const fnc of def.functions) {
const params = fnc.inputs.map((e) => `${e.name}: ${toJSType(e.type)}`).join(","); const params = fnc.inputs.map((e) => `${e.name}: ${toJSType(e.type) + (e.array ? "[]" : "")}`).join(", ");
if (!fnc.return) { if (!fnc.return) {
a(1, `${fnc.name}(${params}): void {`); a(1, `${fnc.name}(${params}): void {`);
a(2, `this._provider.sendMessage({`); a(2, `this._provider.sendMessage({`);
@ -7652,7 +7666,7 @@ var TypescriptTarget = class extends CompileTarget {
a(2, `});`); a(2, `});`);
a(1, `}`); a(1, `}`);
} else { } else {
const retType = fnc.return ? toJSType(fnc.return) : "void"; const retType = fnc.return ? toJSType(fnc.return.type) + (fnc.return.array ? "[]" : "") : "void";
a(1, `${fnc.name}(${params}): Promise<${retType}> {`); a(1, `${fnc.name}(${params}): Promise<${retType}> {`);
a(2, `return new Promise<${retType}>((ok, err) => {`); a(2, `return new Promise<${retType}>((ok, err) => {`);
a(3, `this._provider.sendMessage({`); a(3, `this._provider.sendMessage({`);
@ -7664,7 +7678,13 @@ var TypescriptTarget = class extends CompileTarget {
a(4, `ok, err`); a(4, `ok, err`);
a(3, `});`); a(3, `});`);
a(2, `}).then(result => {`); a(2, `}).then(result => {`);
a(3, `if(!verify_${fnc.return}(result)) throw new Error("Invalid result data!");`); if (fnc.return.array) {
a(2, `for(const elm of result) {`);
a(3, `if(!verify_${fnc.return.type}(elm)) throw new Error("Invalid result data!");`);
a(2, `}`);
} else {
a(3, `if(!verify_${fnc.return.type}(result)) throw new Error("Invalid result data!");`);
}
a(3, `return result;`); a(3, `return result;`);
a(2, `});`); a(2, `});`);
a(1, `}`); a(1, `}`);
@ -7675,6 +7695,7 @@ var TypescriptTarget = class extends CompileTarget {
this.writeFormattedFile(this.getFileName(def.name + "_client"), lines.join("\n")); this.writeFormattedFile(this.getFileName(def.name + "_client"), lines.join("\n"));
} }
generateServiceServer(def) { generateServiceServer(def) {
var _a;
let lines = []; let lines = [];
const a = (i, t) => { const a = (i, t) => {
if (!Array.isArray(t)) { if (!Array.isArray(t)) {
@ -7703,10 +7724,10 @@ var TypescriptTarget = class extends CompileTarget {
a(0, ``); a(0, ``);
for (const fnc of def.functions) { for (const fnc of def.functions) {
const params = [ const params = [
...fnc.inputs.map((e) => `${e.name}: ${toJSType(e.type)}`), ...fnc.inputs.map((e) => `${e.name}: ${toJSType(e.type) + (e.array ? "[]" : "")}`),
`ctx: T` `ctx: T`
].join(", "); ].join(", ");
const retVal = fnc.return ? `Promise<${toJSType(fnc.return)}>` : `void`; const retVal = fnc.return ? `Promise<${toJSType(fnc.return.type) + (fnc.return.array ? "[]" : "")}>` : `void`;
a(1, `abstract ${fnc.name}(${params}): ${retVal};`); a(1, `abstract ${fnc.name}(${params}): ${retVal};`);
a(1, `_${fnc.name}(params: any[] | any, ctx: T): ${retVal} {`); a(1, `_${fnc.name}(params: any[] | any, ctx: T): ${retVal} {`);
a(2, `let p: any[] = [];`); a(2, `let p: any[] = [];`);
@ -7720,12 +7741,18 @@ var TypescriptTarget = class extends CompileTarget {
a(2, ``); a(2, ``);
for (let i = 0; i < fnc.inputs.length; i++) { for (let i = 0; i < fnc.inputs.length; i++) {
a(2, `if(p[${i}] !== null && p[${i}] !== undefined) {`); a(2, `if(p[${i}] !== null && p[${i}] !== undefined) {`);
if (fnc.inputs[i].array) {
a(2, `for(const elm of p[${i}]) {`);
a(3, `if(!verify_${fnc.inputs[i].type}(elm)) throw new Error("Parameter verification failed!")`);
a(2, `}`);
} else {
a(2, `if(!verify_${fnc.inputs[i].type}(p[${i}])) throw new Error("Parameter verification failed!")`); a(2, `if(!verify_${fnc.inputs[i].type}(p[${i}])) throw new Error("Parameter verification failed!")`);
}
a(2, `}`); a(2, `}`);
} }
a(2, ``); a(2, ``);
a(2, `p.push(ctx);`); a(2, `p.push(ctx);`);
a(2, `return this.${fnc.name}.call(this, ...p)${fnc.return == "void" ? ".then(res => undefined)" : ""};`); a(2, `return this.${fnc.name}.call(this, ...p)${((_a = fnc.return) == null ? void 0 : _a.type) == "void" ? ".then(res => undefined)" : ""};`);
a(1, `}`); a(1, `}`);
a(0, ``); a(0, ``);
} }

View File

@ -1,6 +1,6 @@
{ {
"name": "@hibas123/jrpcgen", "name": "@hibas123/jrpcgen",
"version": "1.0.4", "version": "1.0.5",
"main": "lib/index.js", "main": "lib/index.js",
"license": "MIT", "license": "MIT",
"packageManager": "yarn@3.1.1", "packageManager": "yarn@3.1.1",

View File

@ -44,8 +44,8 @@ export type ServiceFunctionDecorators = {
export interface ServiceFunctionParamsDefinition { export interface ServiceFunctionParamsDefinition {
name: string; name: string;
inputs: { type: string; name: string }[]; inputs: { type: string; name: string, array: boolean }[];
return: string | undefined; return: { type: string, array: boolean } | undefined;
decorators: ServiceFunctionDecorators decorators: ServiceFunctionDecorators
} }
export type ServiceFunctionDefinition = ServiceFunctionParamsDefinition; export type ServiceFunctionDefinition = ServiceFunctionParamsDefinition;
@ -191,11 +191,11 @@ export default function get_ir(parsed: Parsed): IR {
); );
alreadyFoundFunctions.add(fnc.name); alreadyFoundFunctions.add(fnc.name);
if (fnc.return_type) { if (fnc.return_type) {
if (defined.indexOf(fnc.return_type) >= 0) { if (defined.indexOf(fnc.return_type.type) >= 0) {
if (!depends.some((a) => a === fnc.return_type)) if (!depends.some((a) => a === fnc.return_type.type))
depends.push(fnc.return_type); depends.push(fnc.return_type.type);
} else { } else {
if (fnc.return_type !== "void" && builtin.indexOf(fnc.return_type) < 0) { if (fnc.return_type.type !== "void" && builtin.indexOf(fnc.return_type.type) < 0) {
throw new IRError( throw new IRError(
fnc, fnc,
`Type ${fnc.return_type} is not defined` `Type ${fnc.return_type} is not defined`

View File

@ -42,6 +42,12 @@ export interface TypeStatement extends DefinitionNode {
export interface IServiceFunctionInput { export interface IServiceFunctionInput {
name: string; name: string;
type: string; type: string;
array: boolean;
}
export interface IServiceFunctionReturn {
type: string;
array: boolean;
} }
@ -51,7 +57,7 @@ export interface ServiceFunctionStatement extends DefinitionNode {
type: "service_function"; type: "service_function";
inputs: IServiceFunctionInput[]; inputs: IServiceFunctionInput[];
name: string; name: string;
return_type: string | undefined; // Makes it a notification return_type: IServiceFunctionReturn | undefined; // Makes it a notification
decorators: Decorators; decorators: Decorators;
} }
@ -334,7 +340,12 @@ export default function parse(tokens: Token[], file: string): Parsed {
const [name] = eatText(); const [name] = eatText();
eatToken(":"); eatToken(":");
const [type] = eatText(); const [type] = eatText();
inputs.push({ name, type }); let array = false;
if (currentToken.type === "array") {
array = true;
eatToken("[]");
}
inputs.push({ name, type, array });
if (currentToken.value !== ",") break; if (currentToken.value !== ",") break;
eatToken(","); eatToken(",");
} }
@ -342,11 +353,20 @@ export default function parse(tokens: Token[], file: string): Parsed {
eatToken(")"); eatToken(")");
let return_type = undefined; let return_type: IServiceFunctionReturn | undefined = undefined;
if (!notification) { if (!notification) {
eatToken(":"); eatToken(":");
return_type = eatText()[0]; let [type] = eatText();
let array = false;
if (currentToken.type === "array") {
array = true;
eatToken("[]");
}
return_type = {
type,
array
}
} }
eatToken(";"); eatToken(";");

View File

@ -15,7 +15,7 @@ const conversion = {
boolean: "boolean", boolean: "boolean",
number: "number", number: "number",
string: "string", string: "string",
void: "void" void: "void",
}; };
function toJSType(type: string): string { function toJSType(type: string): string {
@ -196,7 +196,6 @@ export class TypescriptTarget extends CompileTarget {
this.getTemplate("ts_service_client.ts") this.getTemplate("ts_service_client.ts")
); );
let lines: string[] = []; let lines: string[] = [];
const a: lineAppender = (i, t) => { const a: lineAppender = (i, t) => {
if (!Array.isArray(t)) { if (!Array.isArray(t)) {
@ -238,8 +237,10 @@ export class TypescriptTarget extends CompileTarget {
for (const fnc of def.functions) { for (const fnc of def.functions) {
const params = fnc.inputs const params = fnc.inputs
.map((e) => `${e.name}: ${toJSType(e.type)}`) .map(
.join(","); (e) => `${e.name}: ${toJSType(e.type) + (e.array ? "[]" : "")}`
)
.join(", ");
//TODO: Prio 2 : Add optional parameters to this and the declaration file //TODO: Prio 2 : Add optional parameters to this and the declaration file
if (!fnc.return) { if (!fnc.return) {
a(1, `${fnc.name}(${params}): void {`); a(1, `${fnc.name}(${params}): void {`);
@ -250,7 +251,9 @@ export class TypescriptTarget extends CompileTarget {
a(2, `});`); a(2, `});`);
a(1, `}`); a(1, `}`);
} else { } else {
const retType = fnc.return ? toJSType(fnc.return) : "void"; const retType = fnc.return
? toJSType(fnc.return.type) + (fnc.return.array ? "[]" : "")
: "void";
a(1, `${fnc.name}(${params}): Promise<${retType}> {`); a(1, `${fnc.name}(${params}): Promise<${retType}> {`);
a(2, `return new Promise<${retType}>((ok, err) => {`); a(2, `return new Promise<${retType}>((ok, err) => {`);
a(3, `this._provider.sendMessage({`); a(3, `this._provider.sendMessage({`);
@ -262,10 +265,19 @@ export class TypescriptTarget extends CompileTarget {
a(4, `ok, err`); a(4, `ok, err`);
a(3, `});`); a(3, `});`);
a(2, `}).then(result => {`); a(2, `}).then(result => {`);
if (fnc.return.array) {
a(2, `for(const elm of result) {`);
a( a(
3, 3,
`if(!verify_${fnc.return}(result)) throw new Error("Invalid result data!");` `if(!verify_${fnc.return.type}(elm)) throw new Error("Invalid result data!");`
); );
a(2, `}`);
} else {
a(
3,
`if(!verify_${fnc.return.type}(result)) throw new Error("Invalid result data!");`
);
}
a(3, `return result;`); a(3, `return result;`);
a(2, `});`); a(2, `});`);
a(1, `}`); a(1, `}`);
@ -332,11 +344,15 @@ export class TypescriptTarget extends CompileTarget {
for (const fnc of def.functions) { for (const fnc of def.functions) {
const params = [ const params = [
...fnc.inputs.map((e) => `${e.name}: ${toJSType(e.type)}`), ...fnc.inputs.map(
(e) => `${e.name}: ${toJSType(e.type) + (e.array ? "[]" : "")}`
),
`ctx: T`, `ctx: T`,
].join(", "); ].join(", ");
const retVal = fnc.return const retVal = fnc.return
? `Promise<${toJSType(fnc.return)}>` ? `Promise<${
toJSType(fnc.return.type) + (fnc.return.array ? "[]" : "")
}>`
: `void`; : `void`;
a(1, `abstract ${fnc.name}(${params}): ${retVal};`); a(1, `abstract ${fnc.name}(${params}): ${retVal};`);
@ -353,15 +369,32 @@ export class TypescriptTarget extends CompileTarget {
a(2, `}`); a(2, `}`);
a(2, ``); a(2, ``);
for(let i = 0; i < fnc.inputs.length; i++) { for (let i = 0; i < fnc.inputs.length; i++) {
a(2, `if(p[${i}] !== null && p[${i}] !== undefined) {`); a(2, `if(p[${i}] !== null && p[${i}] !== undefined) {`);
a(2, `if(!verify_${fnc.inputs[i].type}(p[${i}])) throw new Error("Parameter verification failed!")`); if (fnc.inputs[i].array) {
a(2, `for(const elm of p[${i}]) {`);
a(
3,
`if(!verify_${fnc.inputs[i].type}(elm)) throw new Error("Parameter verification failed!")`
);
a(2, `}`);
} else {
a(
2,
`if(!verify_${fnc.inputs[i].type}(p[${i}])) throw new Error("Parameter verification failed!")`
);
}
a(2, `}`); a(2, `}`);
} }
a(2, ``); a(2, ``);
a(2, `p.push(ctx);`); a(2, `p.push(ctx);`);
a(2, `return this.${fnc.name}.call(this, ...p)${fnc.return == "void" ? ".then(res => undefined)" : ""};`); a(
2,
`return this.${fnc.name}.call(this, ...p)${
fnc.return?.type == "void" ? ".then(res => undefined)" : ""
};`
);
a(1, `}`); a(1, `}`);
a(0, ``); a(0, ``);
} }