---
output: github_document
---

<!-- README.md is generated from README.Rmd. Please edit that file -->

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  fig.path = "man/figures/README-",
  out.width = "100%"
)
```

# ts

<!-- badges: start -->
<!-- badges: end -->

The **ts** package makes it easy for users to write functions that can be used in [**rserve-ts**](https://www.npmjs.com/package/rserve-ts) applications.

## Installation

You can install the development version of ts from [GitHub](https://github.com/) with:

``` r
# install.packages("devtools")
devtools::install_github("tmelliott/ts")
```

## Example

Writing functions is easy, just use the `ts_*()` functions to define formals and return types.


```r
library(ts)
addFn <- ts_function(
  function(a = ts_numeric(1), b = ts_numeric(1)) a + b,
  result = ts_numeric(1)
)
sampleFn <- ts_function(
  function(x = ts_character(), n = ts_integer(1)) sample(x, n),
  result = ts_character()
)
app <- ts_function(
  function() {
    list(
      add = addFn,
      sample = sampleFn
    )
  },
  result = ts_list(
    add = appFn,
    sample = sampleFn
  )
)

ts_compile(app)
```

This will generate the following rserve-ts function definitions:
```typescript
import { types as R } from "rserve-ts";

export const app = {
  add: z.function(
    z.tuple([z.number(), z.number()]),
    z.promise(R.numeric(1))
  ),
  sample: z.function(
    z.tuple([z.array(z.string()), z.integer()]),
    z.promise(R.character())
  )
};
```

which will generate the following types:
```typescript
type App = {
  add: (x: number, y: number) => Promise<Robj.Numeric<1>>;
  sample: (x: string[], n: number) => Promise<Robj.Character>;
};
```

Besides generating the schema as shown above, the app object can also  be 'deployed' using Rserve:

```r
ts_deploy(app, port = 6311, daemon = FALSE)
# listening on port 6311
```

## State of the project

Here's what's currently working:

```{r, error = TRUE}
library(ts)

myfun <- ts_function(mean, x = ts_numeric(), result = ts_numeric(1))
myfun(1:5)

myfun("hello world")

cat(readLines("tests/testthat/app.R"), sep = "\n")

ts_compile("tests/testthat/app.R", file = "")
```

## TODO

- [ ] Add support for more types
- [ ] Allow generic types (e.g., `<T>(x: T) => T`)
- [ ] Add support for conditional return types

  e.g., `const sample = <T, N extends number>(x: T[], n: N) => N extends 1 ? T : T[]`

- [ ] Function overloads? Perhaps just a wrapper around several function definitions...
