From 6cef29f47f99b5a5895fbd004b7a4c30f88e69f4 Mon Sep 17 00:00:00 2001 From: Tom Elliott Date: Tue, 21 Jan 2025 16:05:47 +1300 Subject: [PATCH] demo working using typescript; some type issues picked up --- R/compile.R | 8 +- R/types.R | 8 +- tests/testthat/app.R | 5 +- tests/testthat/app.rserve.R | 5 +- tests/testthat/sampler/app.js | 25 --- .../{app.d.ts => sampler/app.schema.ts} | 13 +- tests/testthat/sampler/app.ts | 33 ++++ tests/testthat/sampler/index.js | 0 tests/testthat/sampler/package.json | 7 +- tests/testthat/sampler/pnpm-lock.yaml | 167 ++++++++++++++++++ tests/testthat/sampler/tsconfig.json | 15 ++ 11 files changed, 250 insertions(+), 36 deletions(-) delete mode 100644 tests/testthat/sampler/app.js rename tests/testthat/{app.d.ts => sampler/app.schema.ts} (51%) create mode 100644 tests/testthat/sampler/app.ts create mode 100644 tests/testthat/sampler/index.js create mode 100644 tests/testthat/sampler/tsconfig.json diff --git a/R/compile.R b/R/compile.R index 0cbb8f4..dcc4c02 100644 --- a/R/compile.R +++ b/R/compile.R @@ -45,9 +45,15 @@ ts_compile.character <- function( "import { Robj } from 'rserve-ts';", "import { z } from 'zod';", "\n", - x + x, + "\n", + sprintf("export default {\n %s\n};", paste(ls(e), collapse = ",\n ")) ) + # if (file != "" && file.exists(file)) { + # stop(sprintf("File exists: %s", file)) + # return() + # } cat(src, file = file, sep = "\n") invisible() diff --git a/R/types.R b/R/types.R index 4485440..5bef6c0 100644 --- a/R/types.R +++ b/R/types.R @@ -120,7 +120,7 @@ ts_array <- function(type = c("z.number()", "z.boolean()", "z.string()")) { if (type == "z.boolean()") { return("z.instanceof(Uint8Array)") } - return("Robj.character(0)") + return("z.array(z.string())") } n_type <- function(n, type, pl = ts_array(type)) { @@ -173,7 +173,11 @@ ts_integer <- function(n = -1L) { n_type(n, "z.number()", "z.instanceof(Int32Array)"), n_type_fun(n, "Robj.integer"), check = function(x) { - if (!is.integer(x)) stop("Expected an integer") + if (!is.numeric(x)) stop("Expected a number") + if (!all.equal(x, as.integer(x))) { + # javascript only has one number type + stop("Expected an integer") + } if (n > 0 && length(x) != n) { stop("Expected an integer of length ", n) } diff --git a/tests/testthat/app.R b/tests/testthat/app.R index 2e208a8..ebac7d5 100644 --- a/tests/testthat/app.R +++ b/tests/testthat/app.R @@ -1,12 +1,13 @@ library(ts) fn_mean <- ts_function(mean, x = ts_numeric(), result = ts_numeric(1)) -fn_first <- ts_function(function(x = ts_character(-1)) x[1], +fn_first <- ts_function(function(x = ts_character()) x[1], result = ts_character(1) ) sample_num <- ts_function( sample, x = ts_numeric(0), - result = ts_numeric(1) + size = ts_integer(1), + result = ts_numeric() ) diff --git a/tests/testthat/app.rserve.R b/tests/testthat/app.rserve.R index 602d3f7..3817154 100644 --- a/tests/testthat/app.rserve.R +++ b/tests/testthat/app.rserve.R @@ -4,14 +4,15 @@ library(ts) library(ts) fn_mean <- ts_function(mean, x = ts_numeric(), result = ts_numeric(1)) -fn_first <- ts_function(function(x = ts_character(-1)) x[1], +fn_first <- ts_function(function(x = ts_character()) x[1], result = ts_character(1) ) sample_num <- ts_function( sample, x = ts_numeric(0), - result = ts_numeric(1) + size = ts_integer(1), + result = ts_numeric() ) first.fns <- function() ts_app(list( fn_first = fn_first, diff --git a/tests/testthat/sampler/app.js b/tests/testthat/sampler/app.js deleted file mode 100644 index d184429..0000000 --- a/tests/testthat/sampler/app.js +++ /dev/null @@ -1,25 +0,0 @@ -var R = require("./node_modules/rserve-ts/dist/index.js").default; -global.WebSocket = require("ws"); - -async function main() { - const con = await R.create({ - host: "http://127.0.0.1:6311", - }); - - const app = await con.ocap(); - - console.log(app); - console.log(app.fn_mean); - - app.fn_mean(new Float64Array([1, 2, 3, 4, 5]), (err, res) => { - if (err) { - console.error(err); - process.exit(1); - } - console.log("Mean:", res); - process.exit(0); - }); - // console.log("Mean:", m); -} -console.log("Running sampler script...\n"); -main(); diff --git a/tests/testthat/app.d.ts b/tests/testthat/sampler/app.schema.ts similarity index 51% rename from tests/testthat/app.d.ts rename to tests/testthat/sampler/app.schema.ts index 3a7ec01..7387d09 100644 --- a/tests/testthat/app.d.ts +++ b/tests/testthat/sampler/app.schema.ts @@ -2,13 +2,20 @@ import { Robj } from "rserve-ts"; import { z } from "zod"; const fn_first = Robj.ocap( - [z.union([z.string(), Robj.character(0)])], + [z.union([z.string(), z.array(z.string())])], Robj.character(1) ); - const fn_mean = Robj.ocap( [z.union([z.number(), z.instanceof(Float64Array)])], Robj.numeric(1) ); +const sample_num = Robj.ocap( + [z.instanceof(Float64Array), z.number()], + Robj.numeric() +); -const sample_num = Robj.ocap([z.instanceof(Float64Array)], Robj.numeric(1)); +export default { + fn_first, + fn_mean, + sample_num, +}; diff --git a/tests/testthat/sampler/app.ts b/tests/testthat/sampler/app.ts new file mode 100644 index 0000000..42280ab --- /dev/null +++ b/tests/testthat/sampler/app.ts @@ -0,0 +1,33 @@ +// var R = require("./node_modules/rserve-ts/dist/index.js").default; +// global.WebSocket = require("ws"); + +import RserveClient from "rserve-ts"; +import WebSocket from "ws"; + +interface global { + WebSocket: typeof WebSocket; +} + +global.WebSocket = WebSocket as any; + +import appFuns from "./app.schema"; + +async function main() { + const con = await RserveClient.create({ + host: "http://127.0.0.1:6311", + }); + const app = await con.ocap(appFuns); + + const m = await app.fn_mean(new Float64Array([1, 2, 3, 4, 5])); + console.log("Mean:", m); + + const f = await app.fn_first(["hello", "world"]); + console.log("First char:", f); + + const s = await app.sample_num(new Float64Array([1, 2, 3, 4, 5]), 2); + console.log("Sample num:", s); + + process.exit(0); +} +console.log("Running sampler script...\n"); +main(); diff --git a/tests/testthat/sampler/index.js b/tests/testthat/sampler/index.js new file mode 100644 index 0000000..e69de29 diff --git a/tests/testthat/sampler/package.json b/tests/testthat/sampler/package.json index 64f079b..c2a0d57 100644 --- a/tests/testthat/sampler/package.json +++ b/tests/testthat/sampler/package.json @@ -10,7 +10,12 @@ "author": "", "license": "ISC", "dependencies": { + "@types/node": "^22.10.7", + "@types/ws": "^8.5.13", "rserve-ts": "^0.6.1", - "ws": "^8.18.0" + "ts-node": "^10.9.2", + "typescript": "^5.7.3", + "ws": "^8.18.0", + "zod": "^3.24.1" } } diff --git a/tests/testthat/sampler/pnpm-lock.yaml b/tests/testthat/sampler/pnpm-lock.yaml index 4c5fc69..7adf9d8 100644 --- a/tests/testthat/sampler/pnpm-lock.yaml +++ b/tests/testthat/sampler/pnpm-lock.yaml @@ -8,21 +8,115 @@ importers: .: dependencies: + '@types/node': + specifier: ^22.10.7 + version: 22.10.7 + '@types/ws': + specifier: ^8.5.13 + version: 8.5.13 rserve-ts: specifier: ^0.6.1 version: 0.6.1 + ts-node: + specifier: ^10.9.2 + version: 10.9.2(@types/node@22.10.7)(typescript@5.7.3) + typescript: + specifier: ^5.7.3 + version: 5.7.3 ws: specifier: ^8.18.0 version: 8.18.0 + zod: + specifier: ^3.24.1 + version: 3.24.1 packages: + '@cspotcode/source-map-support@0.8.1': + resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} + engines: {node: '>=12'} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.0': + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + + '@jridgewell/trace-mapping@0.3.9': + resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + + '@tsconfig/node10@1.0.11': + resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} + + '@tsconfig/node12@1.0.11': + resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} + + '@tsconfig/node14@1.0.3': + resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} + + '@tsconfig/node16@1.0.4': + resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} + + '@types/node@22.10.7': + resolution: {integrity: sha512-V09KvXxFiutGp6B7XkpaDXlNadZxrzajcY50EuoLIpQ6WWYCSvf19lVIazzfIzQvhUN2HjX12spLojTnhuKlGg==} + + '@types/ws@8.5.13': + resolution: {integrity: sha512-osM/gWBTPKgHV8XkTunnegTRIsvF6owmf5w+JtAfOw472dptdm0dlGv4xCt6GwQRcC2XVOvvRE/0bAoQcL2QkA==} + + acorn-walk@8.3.4: + resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} + engines: {node: '>=0.4.0'} + + acorn@8.14.0: + resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==} + engines: {node: '>=0.4.0'} + hasBin: true + + arg@4.1.3: + resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} + + create-require@1.1.1: + resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} + + diff@4.0.2: + resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} + engines: {node: '>=0.3.1'} + + make-error@1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + rserve-ts@0.6.1: resolution: {integrity: sha512-oxT5ZttA/IExReAjZzKc80f8ug/y/xeIi2YhKSqvy9Hf7nQaQTmmtmDLfJ+vxqLuPRnhxHwjqhsjN2NpxDtLRw==} + ts-node@10.9.2: + resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} + hasBin: true + peerDependencies: + '@swc/core': '>=1.2.50' + '@swc/wasm': '>=1.2.50' + '@types/node': '*' + typescript: '>=2.7' + peerDependenciesMeta: + '@swc/core': + optional: true + '@swc/wasm': + optional: true + + typescript@5.7.3: + resolution: {integrity: sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==} + engines: {node: '>=14.17'} + hasBin: true + underscore@1.13.7: resolution: {integrity: sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g==} + undici-types@6.20.0: + resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} + + v8-compile-cache-lib@3.0.1: + resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} + ws@8.18.0: resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} engines: {node: '>=10.0.0'} @@ -35,18 +129,91 @@ packages: utf-8-validate: optional: true + yn@3.1.1: + resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} + engines: {node: '>=6'} + zod@3.24.1: resolution: {integrity: sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==} snapshots: + '@cspotcode/source-map-support@0.8.1': + dependencies: + '@jridgewell/trace-mapping': 0.3.9 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.0': {} + + '@jridgewell/trace-mapping@0.3.9': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.0 + + '@tsconfig/node10@1.0.11': {} + + '@tsconfig/node12@1.0.11': {} + + '@tsconfig/node14@1.0.3': {} + + '@tsconfig/node16@1.0.4': {} + + '@types/node@22.10.7': + dependencies: + undici-types: 6.20.0 + + '@types/ws@8.5.13': + dependencies: + '@types/node': 22.10.7 + + acorn-walk@8.3.4: + dependencies: + acorn: 8.14.0 + + acorn@8.14.0: {} + + arg@4.1.3: {} + + create-require@1.1.1: {} + + diff@4.0.2: {} + + make-error@1.3.6: {} + rserve-ts@0.6.1: dependencies: underscore: 1.13.7 zod: 3.24.1 + ts-node@10.9.2(@types/node@22.10.7)(typescript@5.7.3): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.11 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 22.10.7 + acorn: 8.14.0 + acorn-walk: 8.3.4 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 5.7.3 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + + typescript@5.7.3: {} + underscore@1.13.7: {} + undici-types@6.20.0: {} + + v8-compile-cache-lib@3.0.1: {} + ws@8.18.0: {} + yn@3.1.1: {} + zod@3.24.1: {} diff --git a/tests/testthat/sampler/tsconfig.json b/tests/testthat/sampler/tsconfig.json new file mode 100644 index 0000000..0622f1a --- /dev/null +++ b/tests/testthat/sampler/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "es2018", + "module": "commonjs", + "allowJs": true, + "noEmit": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true + }, + "ts-node": { + "files": true + } +}