Modules

Import and export syntax for splitting code across files.

Tish supports ES-module style import and export for organizing code across multiple files, similar to Node.js and modern JavaScript.

Import

Named imports

import { foo, bar } from "./utils.tish"

Import specific exports with optional renaming:

import { foo as f, bar } from "./utils.tish"

Namespace import

import * as utils from "./utils.tish"
utils.foo()
utils.bar()

Default import

import main from "./app.tish"

Export

Named exports

export const PI = 3.14
export fn add(a, b) { return a + b }
export let counter = 0

Default export

export default fn main() { return "Hello" }

Each module may have at most one default export.

Native module imports

tish: (npm / packaged native modules)

Native modules (e.g. egui, Polars) are usually imported via the tish: specifier:

import { Egui } from 'tish:egui'
import { Polars } from 'tish:polars'
 
Egui.run((ctx) => {
  ctx.panel("Form", (ui) => {
    ui.heading("Hello")
    if (ui.button("Click")) console.log("clicked")
  })
})
 
let df = Polars.read_csv("./data.csv")
  • Use named imports: import { Egui } from 'tish:egui'
  • The module must be listed in your project's package.json dependencies (e.g. tish-egui)
  • Resolution walks node_modules and parent directories to find the package
  • No --features needed: native imports drive compilation and Cargo dependencies automatically

cargo: (Rust crates with the Value ABI)

Use cargo: for crates listed under package.jsontish.rustDependencies (same key as in the import). The crate must expose pub fn {snake}(args: &[Value]) -> Value. In practice, generate that glue with tishlang-cargo-bindgen (like bindgen) and commit the output, or use a published crate that already matches the contract.

import { to_string, from_str } from 'cargo:tish_serde_json'
{
  "tish": {
    "rustDependencies": {
      "tish_serde_json": { "path": "./crates/tish_serde_json" }
    }
  }
}

This path is only for tish build --target native with the Rust native backend. It does not run in the interpreter, VM, or JS output. Full rules and CLI usage: Native Modules (Author Guide).

Creating or publishing a tish: npm module? See the same Native Modules (Author Guide).

Path resolution

  • Relative paths: ./foo.tish, ../lib/utils.tish — resolved relative to the importing file's directory
  • Native modules: tish:egui, tish:polars — resolved via package.json and project layout; cargo:my_crate — resolved via tish.rustDependencies (Rust native build only)
  • The .tish extension is optional for file imports; it is added if the path has no extension

Limits (Phase 1)

  • No bare specifier resolution (e.g. import x from "lodash") for file modules
  • For tish: modules, add the package to package.json dependencies; use tish:name in imports. For cargo:, add keys under tish.rustDependencies instead (no npm package required for that key).

Example

greet.tish:

export fn greet(name) {
  return "Hello, " + name
}

main.tish:

import { greet } from "./greet.tish"
console.log(greet("World"))

Run with zectre run src/main.tish or compile with zectre compile src/main.tish -o app.

Improve this documentation