Skip to content

Export Tiers

Transit discovers functions in your source code using a three-tier system. Higher tiers provide more control; Tier 1 requires zero source changes.

The scanner automatically discovers functions that are public by their language’s own rules:

Language Detection Method Example
Rust Text scan for pub fn / pub async fn pub fn process_job(job: FileJob) -> Result
Java Text scan for lines starting with public + ( public String processJob(String argsJson)
JavaScript Tree-sitter query for export_statement + function_declaration export function processJob(data) {}
Python Tree-sitter query for function_definition (non-underscore prefix) and class methods def process_job(data): or class Service: def process(self):

No annotations, no markers, no source changes. Just write normal code with normal visibility modifiers.

// This is automatically discovered — it's a pub fn
pub fn process_general(job: FileJob) -> ProcessResult { ... }
// This is automatically discovered — it's a public method
public String processSpecialized(String argsJson) { ... }
# This is automatically discovered — it's a top-level def
def process_job(data):
return transform(data)
# Class methods are also discovered (qualified as ClassName.method_name)
class DataProcessor:
def process(self, data):
return transform(data)

Python class detection: Methods inside classes are automatically discovered and qualified with the class name (e.g., DataProcessor.process). Private methods (starting with _) are filtered out.

A comment marker at the top of a file exports all eligible functions in that file into the flat namespace:

// transit:file
// All public functions in this file are exported
pub fn helper_a() -> String { ... }
pub fn helper_b() -> String { ... }
# transit:file
def process(data):
return transform(data)
// transit:file
public class Utils {
public static String format(String input) { ... }
public static String parse(String input) { ... }
}

Effect: Functions in the file are available via the flat namespace (rs.helperA()) in addition to the qualified form.

A comment marker placed directly above a function exports that specific function, even if it would otherwise be private:

// transit:function
fn internal_helper(data: &[u8]) -> String {
format!("Internal: {} bytes", data.len())
}
# transit:function
def _private_transform(data):
return optimized_path(data)
// transit:function
function computeHash(buffer) { ... }

Key point: Tier 3 overrides the language’s visibility rules. A _private-prefixed Python function or a non-pub Rust function becomes callable from other languages when marked with // transit:function.

This is intentional: the whole point is to export fast internal helpers that would be inconvenient to reimplement in another language.

When multiple files export functions with the same name, the flat namespace uses the last one seen. To call a specific file’s version, use the qualified form:

// If lib.rs and utils.rs both export "process":
await rs["lib"]["process"](data) // calls lib.rs's process
await rs["utils"]["process"](data) // calls utils.rs's process
// Dot notation also works:
await rs.lib.process(data)
Language Tier 2 (file) Tier 3 (function)
Rust // transit:file // transit:function
JavaScript // transit:file // transit:function
TypeScript // transit:file // transit:function
Python # transit:file # transit:function
Java // transit:file // transit:function

Transit considered and rejected several alternatives:

  • Decorator/annotation style (#[transit::export], @Transit.Export): Requires a library import in every file. Changes the language’s syntax.
  • Keyword substitution (tdef, transitfunc): Requires a preprocessor to rewrite the file before compilation. Risk of the transformed version diverging from what the compiler sees.
  • Comment markers: Valid syntax in every language. No preprocessing needed. The scanner detects them during its normal tree-sitter parse pass. The developer’s code runs unchanged.
  1. Tier 1 baseline: All natively public functions are always in the manifest
  2. Tier 2/3 markers: Add functions to the flat namespace (can include private functions)
  3. Config overrides: transit.config.json can add additional exports for generated/vendored code:
{
"exports": [
{ "file": "legacy/parser.rs", "function": "parse_legacy_format" }
]
}

Resolution order: Tier 1 + Tier 2/3 are discovered first, then config entries are added on top (union, not replacement).

The scanner produces a manifest entry for each discovered function:

{
"language": "rust",
"sourceFile": "/path/to/lib.rs",
"functionName": "process_general",
"signature": "pub fn process_general(job: FileJob) -> ProcessResult",
"exportTier": 1
}

The transit-js layer normalizes names to support both snake_case and camelCase lookups. A Rust function process_general is callable as both rs.process_general() and rs.processGeneral().