Files
suaveplan/openspec/archive/2026-05-03-barrel-explicit-exports/specs/monorepo-structure/spec.md
2026-05-27 23:29:53 +01:00

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>.ts must not auto-leak through the barrel.
  • Type-only re-exports remain clean (export { type X } per symbol).
  • Tree-shaking is equivalent under "sideEffects": false with rollup or esbuild — there is no bundle-size argument for export *.

Scenario: Feature-module barrel uses explicit named exports

  • WHEN src/<category>/<feature>/index.ts re-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 .js suffix)

Scenario: Generated selector index exemption

  • WHEN src/<path>/<primitive>.select/index.ts exists 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.ts re-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.ts path AND every remaining line is in a *.select/, *.native/, or *.noble/ forwarder index OR a non-index.ts impl file