HQL provides a module system based on ES module semantics. Imports are statically analyzed and resolved at compile time. The transpiler emits standard JavaScript ES module import/export statements.
Supported import sources:
.hql files (transpiled to JavaScript).js, .mjs, .cjs files (processed for nested HQL imports).ts, .tsx files (transpiled via esbuild, then processed)npm:, jsr:, http://, https:// specifiers@hlvm/* stdlib packages(import [add] from "./math.hql")
(import [add, subtract, multiply] from "./math.hql")
Compiles to:
import { add } from "./math.hql";
import { add, subtract, multiply } from "./math.hql";
(import [longName as short] from "./module.hql")
(import [add as sum, multiply as times] from "./math.hql")
Compiles to:
import { longName as short } from "./module.hql";
import { add as sum, multiply as times } from "./math.hql";
(import math from "./math.hql")
(math.add 1 2)
Compiles to:
import * as math from "./math.hql";
math.add(1, 2);
(import "./setup.hql")
Compiles to:
import "./setup.hql";
(import [default] from "npm:chalk@4.1.2")
(var chalk default)
Compiles to:
import { default as _default } from "npm:chalk@4.1.2";
The default keyword is preserved in the imported name for default exports.
(import-dynamic "./module.hql")
Compiles to:
import("./module.hql")
Returns a Promise. Use with await in async context:
(let mod (await (import-dynamic "./heavy-module.hql")))
(export (fn add [a b] (+ a b)))
(export (let PI 3.14159))
(export (var counter 0))
(export (class Calculator ...))
(export (enum Color ...))
Compiles to:
export function add(a, b) { return a + b; }
export let PI = 3.14159;
export var counter = 0;
export class Calculator { ... }
Supported declaration keywords (from ALL_DECLARATION_BINDING_KEYWORDS_SET): fn, function, defn, class, enum, let, var, const, def.
(export [add, subtract])
(export [add as sum, subtract as diff])
Compiles to:
export { add, subtract };
export { add as sum, subtract as diff };
Macros in the export vector are automatically filtered out at compile time (macros are compile-time only).
(export myFunction)
Compiles to:
export { myFunction };
(export default myValue)
(export default (fn handler [] "ok"))
Compiles to:
export default myValue;
export default function handler() { return "ok"; }
(import [assertEquals] from "jsr:@std/assert")
Compiles to:
import { assertEquals } from "jsr:@std/assert";
(import [assertEquals] from "https://deno.land/std@0.208.0/assert/mod.ts")
Passed through as-is to the output.
(import [default] from "npm:chalk@4.1.2")
For NPM modules, the runtime tries multiple CDN sources as fallback: direct npm: import, esm.sh, and cdn.skypack.dev.
Macros (macro definitions) are compile-time constructs. The import/export system handles them specially:
import statements)HQL identifiers with hyphens are sanitized for JavaScript compatibility via sanitizeIdentifier():
(import [my-func] from "./util.hql")
The hyphenated name is converted to a valid JavaScript identifier in the output.
HQL handles circular imports by:
inProgressFiles setFor local files, paths are resolved via path().resolve(baseDir, modulePath):
baseDir is the importing file's directorybaseDir is the project root (or explicitly provided base directory)Resolved paths are cached in an import map. Content-based caching (SHA-256 hashing) avoids redundant processing; cached files are stored in .hql_cache.
Security: relative import paths are validated to prevent path traversal outside the project directory. Null bytes in paths are rejected.
Tested in tests/unit/organized/syntax/import-export/import-export.test.ts:
as)