Migrate from Steiger
Markdown for agentsSteiger is the linter of Feature-Sliced Design. Archangel’s fsd preset has a rule for each of
Steiger’s 21 rules, with the same name and a link to Steiger’s page for it. A test in the archangel
repository runs Steiger and the preset on the same repositories, and compares the files that each
one reports.
Feature-Sliced Design tells you how to use the preset. This page tells you how to move from Steiger.
The config before
Section titled “The config before”import { defineConfig } from 'steiger';import fsd from '@feature-sliced/steiger-plugin';
export default defineConfig([ ...fsd.configs.recommended, { rules: { 'fsd/insignificant-slice': 'off', }, },]);The config after
Section titled “The config after”import { defineConfig, fsd } from '@enhance-eng/archangel';
export default defineConfig({ extends: [fsd({ root: 'src' })], off: ['fsd/insignificant-slice'],});| Steiger | archangel |
|---|---|
...fsd.configs.recommended |
extends: [fsd({ root: 'src' })] |
| All rules on | fsd({ root: 'src', strict: true }) |
'fsd/<rule>': 'off' |
off: ['fsd/<rule>'] |
'fsd/<rule>': 'warn' |
No equivalent. A rule is on or off. |
ignores: [...] |
ignore: [...] in the config, in .gitignore syntax. It removes the files from the whole check. |
files: [...] with a rule off |
Write a rule with the same name as the preset rule. Your rule replaces it. |
| A second FSD root | A second fsd({ root, name }) with its own name, for example fsd-admin. |
Run it
Section titled “Run it”-
Check the repository:
Terminal $ npx archangel checkerror[may-not-import]: src/features/login/ui/login-form.ts may not import "../../signup", because files in "features" may not import "all of (fsd/features, not src/features/*/@x/**)" in a different instance--> src/features/login/ui/login-form.ts:1:28|1 | import { signupLink } from '../../signup';| ^^^^^^^^^^^^^^ remove the import, or move the code to files that may import it|= note: rule: fsd/forbidden-imports= note: reason: A module may import only from layers below its own, and a slice not from another slice of its layer, except through @x.= note: see: https://feature-sliced.github.io/steiger/rules/forbidden-importschecked 8 files and 8 imports: 1 problemfsd/shared matches nothing in this repositoryfsd/entities matches nothing in this repositoryfsd/widgets matches nothing in this repositoryfsd/processes matches nothing in this repositoryFor what a code means, run `archangel docs may-not-import`.The feature
loginimports the featuresignup, sofsd/forbidden-importsrefuses it. The lines that say “matches nothing” are parts of the preset with no files. A repository usually has only some layers, so these lines are not errors. -
Run
npx archangel test. It checks the examples of each preset rule in your repository, under the preset’sroot, with your tsconfig. -
Remove Steiger when the results are the same.
The rules
Section titled “The rules”Each rule name has the prefix of the preset, fsd/ by default. The rules that Steiger recommends
are on by default. strict: true adds the four rules that Steiger has as options.
| Steiger rule | archangel rule | On |
|---|---|---|
fsd/forbidden-imports |
fsd/forbidden-imports |
Default |
fsd/no-public-api-sidestep |
fsd/no-public-api-sidestep |
Default |
fsd/public-api |
fsd/public-api |
Default |
fsd/no-layer-public-api |
fsd/no-layer-public-api |
Default |
fsd/no-reserved-folder-names |
fsd/no-reserved-folder-names |
Default |
fsd/no-segmentless-slices |
fsd/no-segmentless-slices |
Default |
fsd/no-segments-on-sliced-layers |
fsd/no-segments-on-sliced-layers |
Default |
fsd/no-ui-in-app |
fsd/no-ui-in-app |
Default |
fsd/segments-by-purpose |
fsd/segments-by-purpose |
Default |
fsd/no-processes |
fsd/no-processes |
Default |
fsd/typo-in-layer-name |
fsd/typo-in-layer-name |
Default |
fsd/ambiguous-slice-names |
fsd/ambiguous-slice-names |
Default |
fsd/inconsistent-naming |
fsd/inconsistent-naming |
Default |
fsd/insignificant-slice |
fsd/insignificant-slice |
Default |
fsd/repetitive-naming |
fsd/repetitive-naming |
Default |
fsd/excessive-slicing |
fsd/excessive-slicing |
Default |
fsd/shared-lib-grouping |
fsd/shared-lib-grouping |
Default |
fsd/no-higher-level-imports |
fsd/no-higher-level-imports |
strict: true |
fsd/no-cross-imports |
fsd/no-cross-imports |
strict: true |
fsd/import-locality |
fsd/import-locality |
strict: true |
fsd/no-wildcard-exports |
fsd/no-wildcard-exports |
strict: true |
The rules about imports and folders are built-in conditions of archangel. The seven rules about
names and counts, from typo-in-layer-name to shared-lib-grouping, are conditions of the preset’s
plugin, and they read the whole tree as Steiger does.
Results that change
Section titled “Results that change”These differences are on purpose. The test that compares the two tools names each one.
- A slice is any folder in a sliced layer. The built-in rules take each folder directly in Entities, Features, Widgets or Pages as a slice, with or without segments. They do not know slice groups. Steiger finds a slice by the segments inside it. The plugin rules find slices and slice groups as Steiger does.
- Each folder in
shared/uiandshared/libneeds an index file.fsd/public-apiasks for it even when the segment has an index file of its own. Steiger checks those folders only when the segment has none. - A misspelt layer is reported beside the real one.
fsd/typo-in-layer-namereportssrc/featurezeven whensrc/featuresexists. Steiger then reports nothing. - A layer has its exact name. The built-in rules take only a folder named exactly as a layer.
Steiger also reads
1_sharedor_appas a layer. - Code outside the layers is checked too.
fsd/no-public-api-sidestepchecks imports from files outside the layers, such as tests. A deep import from a test is still a sidestep. Steiger reads only the files in the layers. - A re-export is an import. Each rule counts
export ... fromas an import, because a re-export loads the module.