2.3 KiB
2.3 KiB
ADDED Requirements
Requirement: Barrel export form
Per-feature module barrels (src/<category>/<feature>/index.ts) SHALL re-export their module surface using explicit named re-exports, not export * from. Package-root barrels (src/index.ts) MAY use export * from or export * as <name> from namespace exports until they are migrated under a separate change. Generated selector indexes (paths matching *.select/index.ts, plus per-impl-variant forwarders such as *.native/index.ts and *.noble/index.ts that contain only a single export * forwarder line) are exempt because transparent forwarding of the impl surface is the entire purpose of those files.
The reasons match openspec/AGENTS.md §6a:
- The barrel is the public contract;
export *makes the contract whatever the source file happens to declare today. - Adding a new private helper to
<feature>.tsmust not auto-leak through the barrel. - Type-only re-exports remain clean (
export { type X }per symbol). - Tree-shaking is equivalent under
"sideEffects": falsewith rollup or esbuild — there is no bundle-size argument forexport *.
Scenario: Feature-module barrel uses explicit named exports
- WHEN
src/<category>/<feature>/index.tsre-exports the contents of<feature>.ts - THEN the barrel uses
export { Symbol1, type Type1, ... } from "./<feature>.js" - AND the barrel does NOT contain a line starting with
export * from "./<feature>(with or without the.jssuffix)
Scenario: Generated selector index exemption
- WHEN
src/<path>/<primitive>.select/index.tsexists for a per-primitive selector - THEN that file is permitted to contain
export * from "./<primitive>.select.js" - AND its parent directory ends in
.select
Scenario: Namespace re-export at package root is permitted
- WHEN
src/index.tsre-exports a sub-namespace - THEN it MAY use
export * as <name> from "./<path>.js"(namespace export)
Scenario: Repository scan finds no banned barrel forms
- WHEN
grep -rn '^export \* from' packages/ --include='*.ts' | grep -v '/dist/' | grep -v '/src/index.ts:' | grep -v '/.select/' | grep -v 'export \* as'is run - THEN no line returned matches a
<feature>/index.tspath AND every remaining line is in a*.select/,*.native/, or*.noble/forwarder index OR a non-index.tsimpl file