ADR-0012 — One index.ts per folder, canonical import paths
Status: Accepted
Context
The Product Owner asked for an index.ts in every folder, imports targeting the folder and never a file of another folder, and automatic rewriting on save to the shortest path (folder/index.ts → folder, folder/file → folder).
Caveat
"Barrel files" have known costs in large codebases: worse tree-shaking, slower tools, import cycles (REF-TKDODO-BARRELS, REF-ATLASSIAN-BARRELS). They are acceptable here because:
- the library has no dependency and will stay small (a few hundred modules at most);
package.jsondeclares"sideEffects": false: the bundler can prune;- cycles are forbidden and detected (
import-x/no-cycle); - importing an ancestor barrel (the classic cause of cycles) is forbidden by the custom rule.
Decision
- Every code folder has an
index.ts(local/folder-has-index) containing onlyexport * from "./x";, one per module or sub-folder, sorted (local/barrel-exports, autofixed). - Canonical path (
local/canonical-import-path, autofixed): import the child of the common ancestor that contains the target.- same folder → the file:
./dot; - other folder → the folder:
../geometry(never../geometry/index, nor../geometry/arc/filletSetback); - file of an ancestor folder → the file:
../dot(going through the ancestor's barrel would create a cycle); - never a
.tsextension.
- same folder → the file:
- Importing the barrel of one's own folder or of an ancestor is an error (guaranteed cycle).
import-x/no-useless-path-segments,import-x/extensionsandimport-x/no-internal-modulesare off: the custom rule is the only source of path fixes (no competing fixes).
Consequences
- Creating a file →
npm run fix(or saving theindex.ts) updates the barrel. - Tests (
*.test.ts) are never exported by a barrel. playground/index.tsis the application entry point, not a barrel.
References
REF-TKDODO-BARRELS, REF-ATLASSIAN-BARRELS, imports.md