| Source | Format | Processing |
|---|---|---|
| HQL files | .hql | Parsed, macro-expanded, transpiled to JS |
| JavaScript files | .js, .mjs, .cjs | Checked for nested HQL imports, cached |
| TypeScript files | .ts, .tsx | Transpiled to JS via esbuild, then processed |
| NPM modules | npm:package | Imported via Deno's npm: specifier, fallback to esm.sh/skypack CDNs |
| JSR modules | jsr:@scope/pkg | Imported directly from JSR registry |
| HTTP(S) modules | https://..., http://... | Imported directly from URL |
| Embedded stdlib | @hlvm/* | Loaded from embedded package content |
(import [symbol1, symbol2] from "module-path")
The from keyword is required. Symbols are listed in a vector [...]. Commas between symbols are optional (treated as whitespace by the parser).
(import [symbol1, symbol2 as alias2] from "module-path")
The as keyword renames the import in local scope.
(import name from "module-path")
When the second element is a bare symbol (not a vector), this produces import * as name from "...".
(import "module-path")
No specifiers. Produces import "module-path";. Used for modules imported for side effects only.
(import-dynamic "module-path")
(import-dynamic some-variable)
Produces import("module-path") or import(some_variable). This is a separate form from import -- it uses the keyword import-dynamic. The argument can be a string literal or any expression. Returns a Promise.
(export (fn name [params] body))
(export (let name value))
(export (var name value))
(export (const name value))
(export (class Name ...))
(export (enum Name ...))
The inner form must be a declaration (function, variable, class, or enum). Validated against ALL_DECLARATION_BINDING_KEYWORDS_SET which includes: fn, function, defn, class, enum, let, var, const, def.
(export [name1, name2])
(export [name1 as alias1, name2])
Exports previously defined symbols by name. Supports as aliases. Macros in the vector are silently filtered out.
(export name)
Exports a single previously defined symbol. Produces export { name };.
(export default expression)
Produces export default <expression>;. The expression is transformed recursively.
Both import and export processing check whether symbols are macros:
import statement. If all symbols in an import are macros, the entire import declaration is omitted.export statement. If all symbols are macros, the entire export declaration is omitted.Macro detection uses the compiler symbol table plus environment/import state as the single source of truth for compile-time-only macro visibility.
The processImports() function in imports.ts handles runtime import resolution during the interpreter/macro-expansion phase:
Promise.allimport()import() with CDN fallback for npmFor 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)npm:, jsr:, @hlvm/) bypass path validationinProgressFiles set.hql_cache directory__module_{basename}_{hash}) to prevent collisionsAll imported and exported identifiers pass through sanitizeIdentifier() to produce valid JavaScript names. The default keyword is preserved as-is for default imports.