updating API
This commit is contained in:
parent
b2e62d757f
commit
7a4f649e70
@ -8,10 +8,10 @@ ts_compile.ts_function <- function(f, name = deparse(substitute(f)), ...) {
|
||||
inputs <- attr(f, "args")
|
||||
result <- attr(f, "result")
|
||||
|
||||
inputs <- sapply(inputs, \(x) x$type)
|
||||
inputs <- sapply(inputs, \(x) x$zod_type)
|
||||
fn_args <- paste(inputs) |>
|
||||
paste(collapse = ", ")
|
||||
sprintf("const %s = R.ocap([%s], %s]);", name, fn_args, result$type_fn)
|
||||
sprintf("const %s = R.ocap([%s], %s]);", name, fn_args, result$r_type)
|
||||
}
|
||||
|
||||
# #' @export
|
||||
|
||||
28
R/types.R
28
R/types.R
@ -9,8 +9,8 @@
|
||||
#' @param generic logical, if `TRUE` then the object is a generic type.
|
||||
#'
|
||||
#' @md
|
||||
object <- function(type = "any",
|
||||
type_fn = "any",
|
||||
object <- function(zod_type = "any",
|
||||
r_type = "any",
|
||||
default = NULL,
|
||||
check = function() stop("Not implemented"),
|
||||
generic = FALSE) {
|
||||
@ -27,21 +27,21 @@ object <- function(type = "any",
|
||||
#' @export
|
||||
print.ts_object <- function(x, ...) {
|
||||
# name <- deparse(substitute(x))
|
||||
cat(sprintf("Input (ts) type: %s\n", x$type))
|
||||
cat(sprintf("Output (R) type: %s\n", x$type_fn))
|
||||
cat(sprintf("Zod type: %s\n", x$zod_type))
|
||||
cat(sprintf(" R type: %s\n", x$r_type))
|
||||
}
|
||||
|
||||
is_object <- function(x) {
|
||||
inherits(x, "ts_object")
|
||||
}
|
||||
|
||||
ts_union <- function(...) paste(..., sep = " | ")
|
||||
ts_array <- function(type = c("number", "boolean", "string")) {
|
||||
if (type == "number") {
|
||||
return("Float64Array")
|
||||
ts_union <- function(...) sprintf("z.union([%s])", paste(..., sep = ", "))
|
||||
ts_array <- function(type = c("z.number()", "z.boolean()", "z.string()")) {
|
||||
if (type == "z.number()") {
|
||||
return("z.instanceof(Float64Array)")
|
||||
}
|
||||
if (type == "boolean") {
|
||||
return("Uint8Array")
|
||||
if (type == "z.boolean()") {
|
||||
return("z.instanceof(Uint8Array)")
|
||||
}
|
||||
return("RTYPE.stringArray")
|
||||
}
|
||||
@ -65,7 +65,7 @@ n_type_fun <- function(n, type) {
|
||||
#' @export
|
||||
ts_logical <- function(n = -1L) {
|
||||
object(
|
||||
n_type(n, "boolean"),
|
||||
n_type(n, "z.boolean()"),
|
||||
n_type_fun(n, "RTYPE.logical"),
|
||||
check = function(x) {
|
||||
if (!is.logical(x)) stop("Expected a boolean")
|
||||
@ -78,7 +78,7 @@ ts_logical <- function(n = -1L) {
|
||||
#' @export
|
||||
ts_integer <- function(n = -1L) {
|
||||
object(
|
||||
n_type(n, "number"),
|
||||
n_type(n, "z.number()"),
|
||||
n_type_fun(n, "RTYPE.integer"),
|
||||
check = function(x) {
|
||||
if (!is.integer(x)) stop("Expected an integer")
|
||||
@ -91,7 +91,7 @@ ts_integer <- function(n = -1L) {
|
||||
#' @export
|
||||
ts_numeric <- function(n = -1L) {
|
||||
object(
|
||||
n_type(n, "number"),
|
||||
n_type(n, "z.number()"),
|
||||
n_type_fun(n, "RTYPE.numeric"),
|
||||
check = function(x) {
|
||||
if (!is.numeric(x)) stop("Expected a number", call. = FALSE)
|
||||
@ -106,7 +106,7 @@ ts_numeric <- function(n = -1L) {
|
||||
#' @export
|
||||
ts_character <- function(n = -1L) {
|
||||
object(
|
||||
n_type(n, "string"),
|
||||
n_type(n, "z.string()"),
|
||||
n_type_fun(n, "RTYPE.character"),
|
||||
check = function(x) {
|
||||
if (!is.character(x)) stop("Expected a string")
|
||||
|
||||
26
README.Rmd
26
README.Rmd
@ -36,27 +36,24 @@ Writing functions is easy, just use the `ts_*()` functions to define formals and
|
||||
|
||||
```r
|
||||
library(ts)
|
||||
app <- ts_app(
|
||||
app <- ts_list(
|
||||
add = ts_fun(
|
||||
function(x, y) {
|
||||
x + y
|
||||
},
|
||||
x = ts_number(),
|
||||
y = ts_number(),
|
||||
x = ts_number(1),
|
||||
y = ts_number(1),
|
||||
# ideally this will use a generic type where x OR y can be vectors
|
||||
# and, if one is a vector, the return type will be a vector too...
|
||||
result = ts_number()
|
||||
result = r_numeric(1)
|
||||
),
|
||||
sample = ts_fun(
|
||||
function(x, n) {
|
||||
sample(x, n)
|
||||
},
|
||||
x = ts_character_vector(),
|
||||
n = ts_integer(),
|
||||
result = ts_condition(n,
|
||||
1 = ts_character(),
|
||||
ts_character_vector()
|
||||
)
|
||||
x = ts_string(),
|
||||
n = ts_number(1),
|
||||
result = r_character()
|
||||
)
|
||||
)
|
||||
|
||||
@ -73,7 +70,7 @@ export const app = {
|
||||
z.promise(R.numeric(1))
|
||||
),
|
||||
sample: z.function(
|
||||
z.tuple([z.character_vector(), z.integer()]),
|
||||
z.tuple([z.array(z.string()), z.integer()]),
|
||||
z.promise(R.character())
|
||||
)
|
||||
};
|
||||
@ -82,11 +79,8 @@ export const app = {
|
||||
which will generate the following types:
|
||||
```typescript
|
||||
type App = {
|
||||
add: (x: number, y: number) => Promise<{ data: number }>;
|
||||
sample: (x: string[], n: number) => Promise<{ data: string | string[] }>;
|
||||
// or, if possible, even better:
|
||||
sample: <N extends number>(x: string[], n: N) =>
|
||||
Promise<{ data: N extends 1 ? string : string[] }>;
|
||||
add: (x: number, y: number) => Promise<Robj.Numeric<1>>;
|
||||
sample: (x: string[], n: number) => Promise<Robj.Character>;
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
32
README.md
32
README.md
@ -28,27 +28,24 @@ formals and return types.
|
||||
|
||||
``` r
|
||||
library(ts)
|
||||
app <- ts_app(
|
||||
app <- ts_list(
|
||||
add = ts_fun(
|
||||
function(x, y) {
|
||||
x + y
|
||||
},
|
||||
x = ts_number(),
|
||||
y = ts_number(),
|
||||
x = ts_number(1),
|
||||
y = ts_number(1),
|
||||
# ideally this will use a generic type where x OR y can be vectors
|
||||
# and, if one is a vector, the return type will be a vector too...
|
||||
result = ts_number()
|
||||
result = r_numeric(1)
|
||||
),
|
||||
sample = ts_fun(
|
||||
function(x, n) {
|
||||
sample(x, n)
|
||||
},
|
||||
x = ts_character_vector(),
|
||||
n = ts_integer(),
|
||||
result = ts_condition(n,
|
||||
1 = ts_character(),
|
||||
ts_character_vector()
|
||||
)
|
||||
x = ts_string(),
|
||||
n = ts_number(1),
|
||||
result = r_character()
|
||||
)
|
||||
)
|
||||
|
||||
@ -66,7 +63,7 @@ export const app = {
|
||||
z.promise(R.numeric(1))
|
||||
),
|
||||
sample: z.function(
|
||||
z.tuple([z.character_vector(), z.integer()]),
|
||||
z.tuple([z.array(z.string()), z.integer()]),
|
||||
z.promise(R.character())
|
||||
)
|
||||
};
|
||||
@ -76,11 +73,8 @@ which will generate the following types:
|
||||
|
||||
``` typescript
|
||||
type App = {
|
||||
add: (x: number, y: number) => Promise<{ data: number }>;
|
||||
sample: (x: string[], n: number) => Promise<{ data: string | string[] }>;
|
||||
// or, if possible, even better:
|
||||
sample: <N extends number>(x: string[], n: N) =>
|
||||
Promise<{ data: N extends 1 ? string : string[] }>;
|
||||
add: (x: number, y: number) => Promise<Robj.Numeric<1>>;
|
||||
sample: (x: string[], n: number) => Promise<Robj.Character>;
|
||||
};
|
||||
```
|
||||
|
||||
@ -113,7 +107,11 @@ cat(readLines("tests/testthat/app.R"), sep = "\n")
|
||||
#> )
|
||||
|
||||
ts_compile("tests/testthat/app.R", file = "")
|
||||
#> Error in ts_compile.ts_function(e[[x]], file = file, name = x): unused argument (file = file)
|
||||
#> import { stringArray, character, numeric } from 'rserve-ts';
|
||||
#>
|
||||
#> const fn_first = R.ocap([z.union([z.string(), stringArray])], character(1)]);
|
||||
#> const fn_mean = R.ocap([z.union([z.number(), z.instanceof(Float64Array)])], numeric(1)]);
|
||||
#> const sample_num = R.ocap([z.instanceof(Float64Array)], numeric(1)]);
|
||||
```
|
||||
|
||||
## TODO
|
||||
|
||||
@ -5,23 +5,23 @@
|
||||
\title{Typed object}
|
||||
\usage{
|
||||
object(
|
||||
type = "any",
|
||||
type_fn = "any",
|
||||
zod_type = "any",
|
||||
r_type = "any",
|
||||
default = NULL,
|
||||
check = function() stop("Not implemented"),
|
||||
generic = FALSE
|
||||
)
|
||||
}
|
||||
\arguments{
|
||||
\item{type}{The type of the object that Typescript expect to send to R.}
|
||||
|
||||
\item{type_fn}{The type of the object that Typescript expects to recieve from R.}
|
||||
|
||||
\item{default}{The default value of the object.}
|
||||
|
||||
\item{check}{A function that checks the object and returns it if it is valid. This operates on the R side and is mostly for development and debugging purposes. It is up to the developer to ensure that all functions return the correct type of object always.}
|
||||
|
||||
\item{generic}{logical, if \code{TRUE} then the object is a generic type.}
|
||||
|
||||
\item{type}{The type of the object that Typescript expect to send to R.}
|
||||
|
||||
\item{type_fn}{The type of the object that Typescript expects to recieve from R.}
|
||||
}
|
||||
\description{
|
||||
This is the base type for all typed objects. It is not meant to be used directly.
|
||||
|
||||
@ -4,9 +4,24 @@ sample_num <- ts_function(
|
||||
x = ts_numeric(0),
|
||||
result = ts_numeric(1)
|
||||
)
|
||||
ts_compile(sample_num)
|
||||
|
||||
sampler <- ts_function(
|
||||
function() {
|
||||
list(
|
||||
sample_one = sample_num(0)
|
||||
)
|
||||
},
|
||||
result = ts_list(
|
||||
num = sample_num
|
||||
)
|
||||
)
|
||||
|
||||
ts_compile(d_normal)
|
||||
|
||||
# compile to:
|
||||
# const out = {
|
||||
# sample_one: R.ocap([R.as_vector(z.number())], R.numeric(1)),
|
||||
# };
|
||||
# const sampler = R.ocap(
|
||||
# [],
|
||||
# R.list({
|
||||
# num: R.ocap([], R.numeric(1))
|
||||
# })
|
||||
# );
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user