Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New config structure docs #96

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
5 changes: 5 additions & 0 deletions .changeset/little-zebras-pay.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'steiger': minor
---

Add documentation about the new config structure
160 changes: 160 additions & 0 deletions EXAMPLES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
# Examples

## Structure and concepts

There are 3 types of config objects that you can put in your config file. They follow 2 purposes: registration and configuration.

- Plugin - allows you to register a plugin that provides rules to run. (We will consider this one in more detail in a later section)
- Config Object - allows you to configure the behaviour of rules provided by the plugins. It has the following shape:
```text
{
"files"?: <GlobArray>,
"ignores"?: <GlobArray>,
"rules": {
<RuleName>: <Severity> | [<Severity>, <RuleOptions>]
}
}
```
```javascript
export default defineConfig({
files: ['./src/shared/**'],
ignores: ['./src/shared/__mocks__/**'],
rules: {
'fsd/no-public-api': 'off',
'fsd/forbidden-imports': ['warn', { someOption: false }],
},
})
```
- Global ignore - allows you to disable all rules for a specific part of the file system.
```text
{
ignores: <GlobArray>
}
```
```javascript
export default defineConfig([
...fsd.configs.recommended,
{
ignores: ['./src/shared/__mocks__/**'],
},
])
```

Parts of the config object:

- Severity - can be one of the following: "off", "warn", "error"
- GlobArray - string array with glob patterns to match files and folders in your project.
- RuleOptions - an object that contains specific rule options and can be passed to the rule to configure its behavior.

## Examples

Here are some rules on how configuration is processed:

- Config objects are processed from top to bottom, so if there are multiple config object that match the same file for the same rule, the last one will be applied.
- You can set options for a rule once. When set, options are applied for the entire file system that is covered by Steiger.

Note that this line `...fsd.configs.recommended,` just takes the plugin and the recommended rules configuration (all enabled with "error" severity by default) and puts it into the config array.

### Example 1. Default case

```javascript
// ./steiger.config.ts
import fsd from '@feature-sliced/steiger-plugin'
import defineConfig from 'steiger'

export default defineConfig([...fsd.configs.recommended])
```

### Example 2. FSD with all rules enabled by default, but excluding a couple of folders

```javascript
import fsd from '@feature-sliced/steiger-plugin'
import defineConfig from 'steiger'

export default defineConfig([
...fsd.configs.recommended,
{
ignores: ['**/__mocks__/**'],
},
])
```

### Example 3. FSD without certain rules.

```javascript
import fsd from '@feature-sliced/steiger-plugin'
import defineConfig from 'steiger'

export default defineConfig([
...fsd.configs.recommended,
{
rules: {
'fsd/no-processes': 'off',
'fsd/no-public-api-sidestep': 'warn',
},
},
{
files: ['./src/shared/**'],
rules: {
'fsd/public-api': 'off',
},
},
])
```

### Example 4. Disabling a rule for files in a specific folder and the folder itself.

```javascript
import fsd from '@feature-sliced/steiger-plugin'
import defineConfig from 'steiger'

export default defineConfig([
...fsd.configs.recommended,
{
files: ['./src/shared', './src/shared/**'],
rules: {
'fsd/no-public-api': 'off',
},
},
])
```

### Example 5. Using ignores along with files.

```javascript
import fsd from '@feature-sliced/steiger-plugin'
import defineConfig from 'steiger'

export default defineConfig([
...fsd.configs.recommended,
{
files: ['./src/shared', './src/shared/**'],
ignores: ['./src/shared/lib/**', './src/shared/ui/**'],
rules: {
'fsd/no-public-api': 'off', // Disable the rule for the shared folder, but not for the lib and ui folders
},
},
])
```

### Example 6. Setting rule options.

```javascript
import fsd from '@feature-sliced/steiger-plugin'
import defineConfig from 'steiger'

export default defineConfig([
...fsd.configs.recommended,
{
rules: {
'fsd/no-public-api': ['warn', { someOptions: true }],
},
},
{
files: ['./src/shared/**'],
rules: {
'fsd/no-public-api': ['error', { someOptions: false }], // Would throw an error as you can't override the options
},
},
])
```
88 changes: 88 additions & 0 deletions MIGRATION_GUIDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# Migration guide

## From 0.4.0 to 0.5.0

**Step 1**: First of all you need to make sure you upgraded Steiger package to version 0.5.0 or higher.

**Step 2**: You need to install `@feature-sliced/steiger-plugin` package (that contains all FSD rules to run checks in your project). Run one of the following commands based on the package manager you use.

**pnpm**:

```shell
pnpm add -D @feature-sliced/steiger-plugin
```

**yarn**:

```shell
yarn add -D @feature-sliced/steiger-plugin
```

**npm**:

```shell
npm i -D @feature-sliced/steiger-plugin
```

**Step 3**: The final step. You need to bring your `steiger.config.js` file to the new configuration format. You can do that automatically by running one of the following commands. (Alter the command before running if your config file has an extension different from `.js`)

Here is an example of the transformation that will be applied to your config:

<table><thead><tr>
<th>Before</th>
<th>After</th>
</tr></thead><tbody><tr><td>

```ts
// steiger.config.ts
import { defineConfig } from 'steiger'

export default defineConfig({
rules: {
'public-api': 'off',
'ambiguous-slice-names': 'off',
'no-processes': 'off',
},
})
```

</td><td>

```ts
// steiger.config.ts
import { defineConfig } from 'steiger'
import fsd from '@feature-sliced/steiger-plugin'

export default defineConfig([
...fsd.configs.recommended,
{
rules: {
'fsd/public-api': 'off',
'fsd/ambiguous-slice-names': 'off',
'fsd/no-processes': 'off',
},
},
])
```

</td></tr></tbody></table>

**! Don't forget to check the changes after the migration and bring them to the code style adopted in your project**

**pnpm**:

```shell
pnpx jscodeshift -t https://raw.githubusercontent.com/feature-sliced/steiger/master/packages/steiger/migrations/convert-config-to-flat.js steiger.config.js
```

**yarn**:

```shell
yarn dlx jscodeshift -t https://raw.githubusercontent.com/feature-sliced/steiger/master/packages/steiger/migrations/convert-config-to-flat.js steiger.config.js
```

**npm**:

```shell
npx jscodeshift -t https://raw.githubusercontent.com/feature-sliced/steiger/master/packages/steiger/migrations/convert-config-to-flat.js steiger.config.js
```
76 changes: 63 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,22 @@ Universal file structure and project architecture linter.
> [!NOTE]
> The project is in beta and in active development. Some APIs may change.

# Features
> [!NOTE]
> Version 0.5.0 introduces a new config file format. Please refer to the [Configuration](#configuration) section for more information and migration guide.

## Features

- Built-in set of rules to validate adherence to [Feature-Sliced Design](https://feature-sliced.design/)
- Watch mode
- Rule configurability

# Installation
## Installation

```bash
npm i -D steiger
```

# Usage
## Usage

```bash
npx steiger ./src
Expand All @@ -31,23 +34,70 @@ To run in watch mode, add `-w`/`--watch` to the command:
npx steiger ./src --watch
```

# Configuration
## Configuration

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.
daniilsapa marked this conversation as resolved.
Show resolved Hide resolved

```ts
import { defineConfig } from 'steiger'
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.

### Example

Here are some rules on how configuration is processed:

export default defineConfig({
rules: {
'public-api': 'off',
- Config objects are processed from top to bottom, so if there are multiple config object that match the same file for the same rule, the last one will be applied.
daniilsapa marked this conversation as resolved.
Show resolved Hide resolved
- GlobalIgnore objects `{ ignores: ['**/__mocks__/**'] }` are applied to all rules, they are processed first and permanently remove files from the linter's field of view, so you can't reassign severity to them in other later objects.
- You can set options for a rule once. When set, options are applied for the entire file system that is covered by Steiger.
daniilsapa marked this conversation as resolved.
Show resolved Hide resolved

Note that this line `...fsd.configs.recommended,` just takes the plugin and the recommended rules configuration (all enabled with "error" severity by default) and puts it into the config array.

```javascript
// ./steiger.config.ts
import fsd from '@feature-sliced/steiger-plugin'
import defineConfig from 'steiger'

export default defineConfig([
...fsd.configs.recommended,
{
// ignore all mock files for all rules
ignores: ['**/__mocks__/**'],
},
{
files: ['./src/shared/**'],
rules: {
// disable public-api rule for files in /shared folder
'fsd/public-api': 'off',
},
},
})
{
files: ['./src/widgets/**'],
ignores: ['**/discount-offers/**'],
rules: {
// disable no-segmentless-slices rule for all widgets except /discount-offers
'fsd/no-segmentless-slices': 'off',
},
},
])
```

# Rules
### Glob matching

All globs are matched only against files, folder severities are computed based on the files inside them. The formula is simple: the folder severity is the highest severity of files inside it (from highest to lowest: error, warn, off).

**Glob examples**:

- `./src/shared/**` - matches all files in the `shared` folder and its subfolders
- `./src/shared/*` - matches all files that are direct children of the `shared` folder
- `./src/shared` - based on the fact that globs are matched against files, this one matches only `shared` file (without an extension) inside the `src` folder
- `**/__mocks__/**` - matches all files in all `__mocks__` folders throughout the project
- `**/*.{test,spec}.{ts,tsx}` - matches all test files in the project

### Migration from 0.4.0

Version 0.5.0 introduced a new config file format. Follow the [instructions](MIGRATION_GUIDE.md) to migrate your config file.

## Rules

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](https://feature-sliced.design/).

Expand Down Expand Up @@ -80,12 +130,12 @@ Currently, Steiger is not extendable with more rules, though that will change in
</tbody>
</table>

# Contribution
## Contribution

Feel free to report an issue or open a discussion. Ensure you read our [Code of Conduct](CODE_OF_CONDUCT.md) first though :)

To get started with the codebase, see our [Contributing guide](CONTRIBUTING.md).

# Legal info
## Legal info

Project licensed under [MIT License](LICENSE.md). [Here's what it means](https://choosealicense.com/licenses/mit/)
Loading