Split code across modules
Every .km file is a module with its own scope. Import only the declarations the caller needs.
Project tree
text
modules/
├── format.km
└── main.kmformat.km
ts
function normalize(name: string): string {
if (name === "") { return "guest"; }
return name;
}
export class Greeting {
constructor(public message: string) {}
}
export function greeting(name: string): Greeting {
return new Greeting("Welcome, " + normalize(name));
}main.km
ts
import { Greeting, greeting } from "./format";
import go fmt from "fmt";
function render(value: Greeting): string { return value.message; }
function main(): void {
fmt.Println(render(greeting("Aki")));
fmt.Println(render(greeting("")));
}Run
sh
keika check main.km
keika run main.kmExpected output:
text
Welcome, Aki
Welcome, guestmain.km imports the explicitly exported Greeting and greeting declarations. normalize is private: trying to import it would also be rejected, not just trying to call it without an import. Imports used by format.km do not become visible transitively. Files without any source export retain legacy importability of all top-level declarations; selective imports alone do not make helpers private.
Relative paths may include or omit .km. Resolution is relative to the importing file. Cycles, missing modules, missing declarations, duplicate bindings, and import/declaration conflicts are diagnosed before Go generation.
See Modules and projects.