Universal file structure and project architecture linter.
[!NOTE] The project is in beta and in active development. Some APIs may change.
[!NOTE] Version 0.5.0 introduced a new config file format. We have a codemod to automatically update your config, see the migration guide.
npm i -D steiger
npx steiger ./src
To run in watch mode, add -w
/--watch
to the command:
npx steiger ./src --watch
Steiger is zero-config! If you don't want to disable certain rules, you can safely skip this section.
Steiger is configurable via cosmiconfig
. That means that you can create a steiger.config.ts
or steiger.config.js
file in the root of your project to configure the rules. Import { defineConfig } from "steiger"
to get autocompletion.
The config file shape is highly inspired by ESLint's config file, so if you have configured ESLint before, you'll find it easy to configure Steiger.
// ./steiger.config.js
import { defineConfig } from 'steiger'
import fsd from '@feature-sliced/steiger-plugin'
export default defineConfig([
...fsd.configs.recommended,
{
// disable the `public-api` rule for files in the Shared layer
files: ['./src/shared/**'],
rules: {
'fsd/public-api': 'off',
},
},
])
[!TIP] If you want Steiger to ignore certain files, add an object like this to the config array:
defineConfig([, /* … */ { ignores: ['**/__mocks__/**'] }])
Version 0.5.0 introduced a new config file format. Follow the instructions to migrate your config file.
Currently, Steiger is not extendable with more rules, though that will change in the near future. The built-in rules check for the project's adherence to Feature-Sliced Design.
Rule | Description |
---|---|
ambiguous-slice-names | Forbid slice names that that match some segment’s name in the Shared layer. |
excessive-slicing | Forbid having too many ungrouped slices or too many slices in a group. |
forbidden-imports | Forbid imports from higher layers and cross-imports between slices on the same layer. |
inconsistent-naming | Ensure that all entities are named consistently in terms of pluralization. |
insignificant-slice | Detect slices that have just one reference or no references to them at all. |
no-layer-public-api | Forbid index files on the layer level. |
no-public-api-sidestep | Forbid going around the public API of a slice to import directly from an internal module in a slice. |
no-reserved-folder-names | Forbid subfolders in segments that have the same name as other conventional segments. |
no-segmentless-slices | Forbid slices that don't have any segments. |
no-segments-on-sliced-layers | Forbid segments (like ui, lib, api ...) that appear directly in sliced layer folders (entities, features, ...) |
no-ui-in-app | Forbid having the ui segment on the App layer. |
public-api | Require slices (and segments on sliceless layers like Shared) to have a public API definition. |
repetitive-naming | Ensure that all entities are named consistently in terms of pluralization. |
segments-by-purpose | Discourage the use of segment names that group code by its essence, and instead encourage grouping by purpose |
shared-lib-grouping | Forbid having too many ungrouped modules in shared/lib . |
typo-in-layer-name | Ensure that all layers are named without any typos. |
no-processes | Discourage the use of the deprecated Processes layer. |
import-locality | Require that imports from the same slice be relative and imports from one slice to another be absolute. |
Feel free to report an issue or open a discussion. Ensure you read our Code of Conduct first though :)
To get started with the codebase, see our Contributing guide.
Project licensed under MIT License. Here's what it means