11. Importing existing projects
ucm import <dir> --into ns [--exclude a,b] [--update] [--verbose]
Each file becomes a namespace: core/src/analyze.ts → ns.core.analyze (src path segments and index file
names are dropped). Imports between files, barrels and workspace packages resolve to hashes.
- Test files are skipped:
*.test.ts,*.spec.ts,*.test-d.ts, andtest,tests,__tests__,dist,buildandnode_modulesdirectories. --excludetakes paths relative to<dir>, comma-separated, e.g. test helpers that need a dev dependency.- All problems at once. Import reports every problem in the project in one pass and imports nothing until there are none.
--updatere-imports a project whose files changed, asucm updatewould.
Compiler options for imports are described in compiler options.
11.1 Verified projects
These have been imported, verified (ucm verify: every definition renders and re-hashes to itself) and run from
a scratch file:
| project | definitions | notes |
|---|---|---|
| neverthrow | 51 | strict: false, kept as its check profile |
| ts-pattern | 247 | namespace imports (P.infer<…>), declare const |
valibot (library/src, --exclude vitest) | 941 | 573 files in 4s; module state, @ts-expect-error above overloads |
| ucm-ts itself | packages/ | see self-hosting |
11.2 What import mode accepts beyond scratch files
- Enums, namespaces and parameter properties. Node can't strip these, so their cache modules start with
// ucm: transformand are compiled by a module hook when loaded. They hash like any other syntax. - Namespace imports of project modules.
import * as ns from "./mod"withns.memberis a reference tomember, hashed exactly as if it had been imported by name. Usingnsitself as a value is still refused. declare const x: unique symbol, the usual brand pattern, is a type-only definition. It's salted like a term, so two identical declarations are still two distinct symbols.- Top-level
letis module state (a lazy cache, a config cell). It's salted, so each declaration is its own cell. Every definition that assigns to it shares its component (one module), because an imported binding is read-only. Readers import it and see live updates. // @ts-expect-errorand// @ts-ignoredirectly above a declaration (including above an overload) stay with it. Like other comments they aren't hashed, but they decide whether it typechecks.
Still refused: declare module/declare global, import x = require(), decorators, and top-level statements.
A top-level statement can't be skipped quietly, because that could leave a definition half-initialized; wrap
it in an immediately-invoked function.
built from 5890e54f