Structure & cardinality
Beyond where a single file lives, an architecture often constrains the shape of a folder: how many files of a kind it holds, and whether its barrel re-exports every sibling. These two rule options close those gaps.
barrel
Re-export barrels (index.ts) are conventional but usually unchecked, so a new sibling is silently omitted from the barrel and never surfaces to importers. barrel asserts that an index re-exports every sibling matching a glob.
{
name: 'schema-barrel',
files: 'models/**/index.ts',
barrel: { mustReexport: '../*.model.ts' }, // every sibling model must be re-exported
}The glob is resolved relative to the index file's own directory. Shapelint reads each matched index, collects its export … from '…' specifiers (extension- agnostic), and flags any sibling that isn't re-exported with ARCH_BARREL_INCOMPLETE, naming the missing module.
contains (cardinality)
requires asserts a companion file exists; it can't say a kind is unique. contains constrains how many files of a kind a folder may hold.
{
name: 'one-controller-per-feature',
files: 'features/*',
contains: {
'*.controller.ts': 'exactly-one',
'*.module.ts': 'exactly-one',
},
}Here files matches folders (features/*), not files. For each matched folder, every { glob: cardinality } entry counts the matching files:
| Cardinality | Passes when the count is |
|---|---|
'exactly-one' | exactly 1 |
'at-most-one' | 0 or 1 |
'at-least-one' | 1 or more |
A feature folder with two *.controller.ts files fails ARCH_CARDINALITY; one with exactly one passes.