From 7f258655f2e6d413d64271668a44fd515de88132 Mon Sep 17 00:00:00 2001 From: afmika Date: Fri, 23 Feb 2024 13:18:25 +0300 Subject: [PATCH 1/3] feat(deno/sdk): native function/lambda support for typescript --- typegate/tests/runtimes/deno/deno_static.ts | 21 ------------- typegate/tests/runtimes/deno/deno_test.ts | 22 ++++++++++--- .../tests/runtimes/deno/deno_typescript.ts | 31 +++++++++++++++++++ typegraph/node/sdk/src/runtimes/deno.ts | 16 +++++++--- website/static/specs/0.0.3.json | 26 ++++++++++++++++ 5 files changed, 86 insertions(+), 30 deletions(-) delete mode 100644 typegate/tests/runtimes/deno/deno_static.ts create mode 100644 typegate/tests/runtimes/deno/deno_typescript.ts diff --git a/typegate/tests/runtimes/deno/deno_static.ts b/typegate/tests/runtimes/deno/deno_static.ts deleted file mode 100644 index 22c81a7ee..000000000 --- a/typegate/tests/runtimes/deno/deno_static.ts +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright Metatype OÜ, licensed under the Elastic License 2.0. -// SPDX-License-Identifier: Elastic-2.0 - -import { Policy, t, typegraph } from "@typegraph/sdk/index.js"; -import { DenoRuntime } from "@typegraph/sdk/runtimes/deno.js"; - -typegraph("test-deno-static", (g: any) => { - const deno = new DenoRuntime(); - const pub = Policy.public(); - - g.expose({ - simpleStatic: deno.static( - t.either([t.string(), t.integer()]), - "One!", - ).withPolicy(pub), - structStatic: deno.static(t.struct({ "a": t.string() }), { - a: "Hello World", - }) - .withPolicy(pub), - }); -}); diff --git a/typegate/tests/runtimes/deno/deno_test.ts b/typegate/tests/runtimes/deno/deno_test.ts index c27f3b30a..927788548 100644 --- a/typegate/tests/runtimes/deno/deno_test.ts +++ b/typegate/tests/runtimes/deno/deno_test.ts @@ -122,22 +122,34 @@ Meta.test("Deno runtime: use local imports", async (t) => { }); Meta.test("Deno runtime with typescript", async (t) => { - const e = await t.engine("runtimes/deno/deno_static.ts"); + const e = await t.engine("runtimes/deno/deno_typescript.ts"); await t.should("work with static values", async () => { await gql` query { - simpleStatic - structStatic { + static { a } } `.expectData({ - simpleStatic: "One!", - structStatic: { + static: { a: "Hello World", }, }).on(e); }); + + await t.should("work with native tyepscript code", async () => { + await gql` + query { + hello(name: "World") + helloFn(name: "World!") + } + ` + .expectData({ + hello: "Hello World", + helloFn: "Hello World!", + }) + .on(e); + }); }); Meta.test("Deno runtime: file name reloading", async (t) => { diff --git a/typegate/tests/runtimes/deno/deno_typescript.ts b/typegate/tests/runtimes/deno/deno_typescript.ts new file mode 100644 index 000000000..5799a7209 --- /dev/null +++ b/typegate/tests/runtimes/deno/deno_typescript.ts @@ -0,0 +1,31 @@ +// Copyright Metatype OÜ, licensed under the Elastic License 2.0. +// SPDX-License-Identifier: Elastic-2.0 + +import { Policy, t, typegraph } from "@typegraph/sdk/index.js"; +import { DenoRuntime } from "@typegraph/sdk/runtimes/deno.js"; + +const hello = ({ name }: any) => `Hello ${name}`; +function helloFn({ name }: any) { + return `Hello ${name}`; +} + +typegraph("test-deno-static", (g: any) => { + const deno = new DenoRuntime(); + const pub = Policy.public(); + + g.expose({ + static: deno.static(t.struct({ a: t.string() }), { + a: "Hello World", + }).withPolicy(pub), + hello: deno.func( + t.struct({ name: t.string() }), + t.string(), + { code: hello }, + ).withPolicy(pub), + helloFn: deno.func( + t.struct({ name: t.string() }), + t.string(), + { code: helloFn }, + ).withPolicy(pub), + }); +}); diff --git a/typegraph/node/sdk/src/runtimes/deno.ts b/typegraph/node/sdk/src/runtimes/deno.ts index 5a784fdc6..605c07e1c 100644 --- a/typegraph/node/sdk/src/runtimes/deno.ts +++ b/typegraph/node/sdk/src/runtimes/deno.ts @@ -26,7 +26,7 @@ interface PredefinedFuncMat extends Materializer { } export interface DenoFunc { - code: string; + code: string | Function; secrets?: Array; effect?: Effect; } @@ -38,6 +38,10 @@ export interface DenoImport { effect?: Effect; } +function stringifyFn(code: string | Function) { + return typeof code == "function" ? code.toString() : code; +} + export class DenoRuntime extends Runtime { constructor() { super(runtimes.getDenoRuntime()); @@ -51,10 +55,11 @@ export class DenoRuntime extends Runtime { out: O, { code, secrets = [], effect = fx.read() }: DenoFunc, ): t.Func { - const matId = runtimes.registerDenoFunc({ code, secrets }, effect); + const source = stringifyFn(code); + const matId = runtimes.registerDenoFunc({ code: source, secrets }, effect); const mat: FunMat = { _id: matId, - code, + code: source, secrets, effect, }; @@ -123,7 +128,10 @@ export class DenoRuntime extends Runtime { return Policy.create( name, - runtimes.registerDenoFunc(params, fx.read()), + runtimes.registerDenoFunc( + { ...params, code: stringifyFn(params.code) }, + fx.read(), + ), ); } diff --git a/website/static/specs/0.0.3.json b/website/static/specs/0.0.3.json index 845a327ca..26c2c3fb7 100644 --- a/website/static/specs/0.0.3.json +++ b/website/static/specs/0.0.3.json @@ -1241,6 +1241,24 @@ "$ref": "#/definitions/InjectionData_for_String" } } + }, + { + "type": "object", + "required": [ + "data", + "source" + ], + "properties": { + "source": { + "type": "string", + "enum": [ + "random" + ] + }, + "data": { + "$ref": "#/definitions/InjectionData_for_String" + } + } } ] }, @@ -2363,6 +2381,14 @@ }, "version": { "type": "string" + }, + "random_seed": { + "type": [ + "integer", + "null" + ], + "format": "uint32", + "minimum": 0.0 } } }, From aa50f6ae43f151ddc89d16eb658e41c8d4627bb1 Mon Sep 17 00:00:00 2001 From: afmika Date: Fri, 23 Feb 2024 20:27:08 +0300 Subject: [PATCH 2/3] feat(deno/sdk): throw on unsupported cases --- typegate/tests/runtimes/deno/deno_test.ts | 4 ++-- .../tests/runtimes/deno/deno_typescript.ts | 4 ++-- typegraph/node/sdk/src/runtimes/deno.ts | 18 +++++++++++++++++- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/typegate/tests/runtimes/deno/deno_test.ts b/typegate/tests/runtimes/deno/deno_test.ts index 927788548..ad365139a 100644 --- a/typegate/tests/runtimes/deno/deno_test.ts +++ b/typegate/tests/runtimes/deno/deno_test.ts @@ -141,12 +141,12 @@ Meta.test("Deno runtime with typescript", async (t) => { await gql` query { hello(name: "World") - helloFn(name: "World!") + helloFn(name: "wOrLd") } ` .expectData({ hello: "Hello World", - helloFn: "Hello World!", + helloFn: "Hello world", }) .on(e); }); diff --git a/typegate/tests/runtimes/deno/deno_typescript.ts b/typegate/tests/runtimes/deno/deno_typescript.ts index 5799a7209..20815d20f 100644 --- a/typegate/tests/runtimes/deno/deno_typescript.ts +++ b/typegate/tests/runtimes/deno/deno_typescript.ts @@ -6,10 +6,10 @@ import { DenoRuntime } from "@typegraph/sdk/runtimes/deno.js"; const hello = ({ name }: any) => `Hello ${name}`; function helloFn({ name }: any) { - return `Hello ${name}`; + return `Hello ${(name as string).toLowerCase()}`; } -typegraph("test-deno-static", (g: any) => { +typegraph("test-deno-tyepscript", (g: any) => { const deno = new DenoRuntime(); const pub = Policy.public(); diff --git a/typegraph/node/sdk/src/runtimes/deno.ts b/typegraph/node/sdk/src/runtimes/deno.ts index 605c07e1c..fd3c17e10 100644 --- a/typegraph/node/sdk/src/runtimes/deno.ts +++ b/typegraph/node/sdk/src/runtimes/deno.ts @@ -39,7 +39,23 @@ export interface DenoImport { } function stringifyFn(code: string | Function) { - return typeof code == "function" ? code.toString() : code; + if (typeof code == "function") { + const source = code.toString(); + const namedFnMatch = source.match(/function\s*(\*?\s*[a-zA-Z0-9_]+)/); + if (namedFnMatch) { + const [, name] = namedFnMatch; + if (name.replace(/s/g, "").startsWith("*")) { + throw new Error(`Generator function "${name}" not supported`); + } + if (/function\s[a-zA-Z0-9_]+\(\) { \[native code\] }/.test(source)) { + throw new Error( + `"${name}" is not supported as it is a native function`, + ); + } + } + return source; + } + return code; } export class DenoRuntime extends Runtime { From 64e21ff75c693adecb1fe7f68198649ba45d5e63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl?= Date: Mon, 26 Feb 2024 21:47:57 +0300 Subject: [PATCH 3/3] fix(sdk): missing slash MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michaël --- typegraph/node/sdk/src/runtimes/deno.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/typegraph/node/sdk/src/runtimes/deno.ts b/typegraph/node/sdk/src/runtimes/deno.ts index fd3c17e10..c9dafe371 100644 --- a/typegraph/node/sdk/src/runtimes/deno.ts +++ b/typegraph/node/sdk/src/runtimes/deno.ts @@ -44,7 +44,7 @@ function stringifyFn(code: string | Function) { const namedFnMatch = source.match(/function\s*(\*?\s*[a-zA-Z0-9_]+)/); if (namedFnMatch) { const [, name] = namedFnMatch; - if (name.replace(/s/g, "").startsWith("*")) { + if (name.replace(/\s/g, "").startsWith("*")) { throw new Error(`Generator function "${name}" not supported`); } if (/function\s[a-zA-Z0-9_]+\(\) { \[native code\] }/.test(source)) {