genroc

docs / Guides / Process definition

Typescript evaluation

Learn how to run typescript through genroc

If you want to have custom scripts as part of the process, initialize your project with genctl init --eval-node.

The setup

If we look at the project structure, you will see, that there are some extra fields compared to regular one.

├── .genroc                        # registers the `import` resolver for .ts files
├── compose.yaml                   # adds an `eval-node` worker service
├── package.json                   # @genroc/eval-node npm package
├── tsconfig.json
└── definitions
    ├── hello.genroc.yaml          # the example process below
    ├── script-node.genroc.yaml    # the child process that runs a script
    └── greet.ts                   # the script hello runs

The script-node.genroc.yaml is a child process which is an abstraction above the execution engine. Inside it uses external task to expose the script code and the input.

compose.yaml then contains setup for genroc/eval-node docker container. This is our node worker that is able process the script tasks. You can take this as an example implementation of genroc worker.

Example process

The example process will look something like this:

name: hello
input_schema:
  type: object
  properties:
    who: { type: string, default: "world" }
tasks:
  - id: greet
    action:
      type: child
      # `name`, `input_schema` and `raises` come from the child
      <<: "$process: ./script-node.genroc.yaml"
      input:
        # script code
        code: "$import: ./greet.ts"
        # script input
        input:
          who: "$: input.who"
      # defining the script output
      result_schema:
        type: object
        properties:
          greeting: { type: string }
          at: { type: string }
        required: [greeting]
    output: "$: self.result"
    switch:
      - goto: end

output: "$: outputs.greet"

We are using two kinds of resolvers. $process: is build in documented in child process section. Then we have $import: ./greet.ts, this is a special resolver intended for importing typescript files.

The content of the file is bundled with rollup into one string and included directly into the process definition, so it can’t drift.

Generated types

Run genctl types and this setup will also generate Input and Output types for the greet.ts script.

This way the script input and output is tied to the current input and result_schema defined in process. Genroc will fail if those types don’t match.

The script format

Genroc expects default import to be function and it will pass input as a first argument. It will take it’s output as a result.

// `Input` and `Output` are written beside this file by `genctl types`, and by every apply.
import type { Input, Output } from "./greet.genroc";

export default function (input: Input): Output {
  return { greeting: `hello, ${input.who}`, at: new Date().toISOString() };
}

The bundler will also include any imported files and imported libraries.

Custom resolvers

If you open .genroc file, you can see it contains entry for import resolver. It executes genroc-import script which is a part of @genroc/eval-node package (installed in node_modules).

definitions: ["./definitions/**/*.genroc.yaml"]

resolvers:
  - name: import
    phase: code
    ext: [.ts]
    command: [npx, genroc-import]
    # Slot addresses the generated `Input` and `Output` are typed from, relative to the task.
    types:
      Input: task.action.input.input
      Output: task.action.result

The resolver can define what types it needs and genroc will provide json schema types for the specified fields. Here we need task.action.input.input which is the input slot next to the code. And then we also take result as a output.

You can create your custom resolvers in the similar fashion.