Skip to content

Tartak is a functional programming language that compiles to TypeScript types.

Notifications You must be signed in to change notification settings

mieszkosabo/tartak

Repository files navigation

tartak logo

Tartak

Tartak is a functional programming language that compiles to TypeScript types.

My goal was to create a language that's not just a syntax sugar over TypeScript types, but a language that's as close to any general purpose programming language as possible.

Tartak uses hotscript, ts-arithmetic and many other tricks to make it happen.

🔔 Keep in mind that this project is a work in progress, may contain bugs and missing features. Also, see the ROADMAP section for planned features. Feel free to request features or report bugs with GitHub issues.

Feature highlights:

  • first-class functions (closures, functions returning functions, partial application, etc.)
  • support for arithmetic, relational and logical operators
  • built-in test sections a la Rust
  • pattern matching

Quick demo

// file: parseRoute.tartak

// exported types will be available for you to import from compiled files
// to distinguish between objects ({}) and blocks, blocks have a colon before the opening brace (:{})
export type parseRoute = (route: string) => :{
  // assign computations to variables like this
  let parts = route.split("/"); // -> ["users", "<id:string>", "posts", "<index:number>"]

  // last expression is the return value, like in Rust
  parts
    // method chaining!
    .filter((part) => part.startsWith("<")) // -> ["<id:string>", "<index:number>"]
    .map((part) => match part {
      // infer subparts of the expression during pattern matching
      `<${infer name}:${infer ty}>` -> [name, ty]
    }) // -> [["id", "string"], ["index", "number"]]
    .toUnion() // -> ["id", "string"] | ["index", "number"]
    .fromEntries() // -> { id: "string"; index: "number" }
    .mapValues((ty) => match ty {
      "string" -> string,
      "number" -> number
    }) // -> { id: string; index: number }
}

type params = parseRoute("/users/<id:string>/posts/<index:number>")
//   ^?
//    { id: string; index: number; }


// Add tests alongside your code
#[test] :{
  AssertEqual(
    parseRoute("/users/<id:string>/posts/<index:number>"),
    { id: string, index: number }
  )
  AssertEqual(
    parseRoute("/users/noParams"),
    {}
  )
}

Then, compile the file with:

npx tartak parseRoute.tartak

This will generate a parseRoute.tartak.ts file that exports parseRoute type, which can be imported and used like this:

import { parseRoute } from "./routeParser.tartak";

declare function redirect<Route extends string>(
  route: Route,
  params: parseRoute<Route>
): void;

redirect("/api/v1/user/<id:string>", {
  id: "123", // OK
});

redirect("/api/v1/user/<id:string>", {
  id: 123, // Error: Type 'number' is not assignable to type 'string'
});

redirect("/api/v1/user/<id:string>", {
  hello: "123", // Error: Object literal may only specify known properties, and hello does not exist in type:
});

Getting started

First, install Tartak with your favorite package manager:

npm i -D tartak
yarn add -D tartak
pnpm add -D tartak
bun add -D tartak

Then, create a file with the .tartak extension and start writing your code. You can place .tartak files anywhere in your project. For example:

// hello.tartak

export type greet = (name: string) => `hello ${name}`;

To compile your code into a TypeScript file, run:

# This will recursively look for all .tartak files starting from the current directory and compile them to corresponding *.tartak.ts files.
npx tartak

# Or, you can specify the path to the file you want to compile
npx tartak hello.tartak

# Or, you can watch for changes
npx tartak --watch

ROADMAP

  • readonly
  • optional parameters
  • language server?
  • optional object properties
  • cli: --watch flag
  • imports/exports
  • closures
  • partial application
  • arithmetic operators
    • - (subtraction)
    • - (negation)
    • +
    • /
    • ** (power)
    • % (mod)
  • relational and logical operators
    • ==
    • !=
    • <
    • <=
    • >
    • >=
    • && (logical and)
    • || (logical or)
    • ! (logical not)
  • string methods
    • .length
    • .trimLeft
    • .trimRight
    • .trim
    • .replace
    • .slice
    • .split
    • .repeat
    • .startsWith
    • .endsWith
    • .toTuple
    • .toNumber
    • .toString
    • .stringsPrepend
    • .stringsAppend
    • .uppercase
    • .lowercase
    • .capitalize
    • .uncapitalize
    • .snakeCase
    • .camelCase
    • .kebabCase
    • .compare
    • .lessThan
    • .lessThanOrEqual
    • .greaterThan
    • .greaterThanOrEqual
  • number methods
    • .abs
  • object methods
    • .readonly
    • .mutable
    • .required
    • .partial
    • .readonlyDeep
    • .mutableDeep
    • .requiredDeep
    • .partialDeep
    • .update
    • .keys
    • .values
    • .allPath
    • .get
    • .fromEntries
    • .entries
    • .mapValues
    • .mapKeys
    • .assign
    • .pick
    • .pickBy
    • .omit
    • .omitBy
    • .objectCamelCase
    • .objectCamelCaseDeep
    • .objectSnakeCase
    • .objectSnakeCaseDeep
    • .objectKebabCase
    • .objectKebabCaseDeep
  • union methods
    • .mapUnion
    • .extract
    • .extractBy
    • .exclude
    • .excludeBy
    • .unionNonNullable
    • .unionToTuple
    • .unionToIntersection
  • tuple methods
    • .partition
    • .isEmpty
    • .zip
    • .zipWith
    • .sort
    • .head
    • .tail
    • .at
    • .last
    • .flatMap
    • .find
    • .drop
    • .take
    • .takeWhile
    • .groupBy
    • .join
    • .map
    • .filter
    • .reduce
    • .reduceRight
    • .reverse
    • .every
    • .splitAt
    • .toUnion
    • .toIntersection
    • .prepend
    • .append
    • .concat
    • .min
    • .max
    • .sum
  • objects
    • accessing properties
  • mapped types
  • records
  • unions
  • intersections
  • string literals
  • match
  • first-class testing framework? (kinda)
  • syntax highlighting (barely works)

Syntax highlighting

Currently one can symlink the tartak-syntax-highlighter to the ~/.vscode/extensions directory to get syntax highlighting in Visual Studio Code. TODO: publish the extension to the marketplace.

  • later TODO: create a language server.

internal notes

this["arg0"] is the captured environment of the function, parameters are stored in this["arg1"], this["arg2"], .... Because hotscript supports up to 4 arguments, then tartak functions support up to 3 arguments.

This should be fine, because one of the argument can always be a tuple or an object.

About

Tartak is a functional programming language that compiles to TypeScript types.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published