npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

eslint-plugin-lookin-tavrus-fsd

v0.1.22

Published

An ESLint plugin to enforce FSD architectural rules

Readme

eslint-plugin-lookin-tavrus-fsd

An ESLint plugin to enforce strict architectural boundaries in Feature-Sliced Design (FSD).


This plugin ensures clean, modular, and consistent import practices in scalable frontend projects adhering to Feature-Sliced Design principles. It promotes architectural discipline by enforcing rules for import paths, layer dependencies, and segment hierarchies, with support for auto-fixing violations where possible.


⭐ Found this plugin helpful? Give it a star on GitHub! Your support and feedback are highly appreciated.


✨ Key Features

  • Relative Imports Within Slices: Enforces relative imports within the same FSD slice for modularity, with auto-fix support.
  • Public API Enforcement: Restricts absolute imports to public API files (e.g., index.ts, testing.ts) for layers and shared segments, with auto-fix support.
  • Layer Import Directionality: Ensures imports follow FSD layer hierarchy to prevent invalid dependencies and detects slice-level circular dependencies within the same file's context, with options to ignore specific patterns. For broader, project-wide cycle detection, consider tools like dependency-cruiser.
  • Segment Import Hierarchy: Controls imports between segments (e.g., ui, model, lib) within a slice based on a custom hierarchy, allowing flexible configurations like api segments importing model types.
  • Test-Specific Imports: Allows test-only imports (e.g., testing.ts) in designated test files and provides options to ignore layer/circularity checks for test utility files.
  • Custom Alias Support: Supports project path aliases (e.g., @) for flexible path resolution.
  • Next.js App Router Compatibility: Recognizes app/**/page.tsx and app/**/layout.tsx as part of the pages layer.
  • Configurable Rules: Offers robust options for ignoring patterns, customizing layers, and defining public API files.

📦 Installation

Install the plugin via npm:

npm install eslint-plugin-lookin-tavrus-fsd --save-dev

Ensure ESLint is installed in your project:

npm install eslint --save-dev

⚙️ Quick Start Configuration

To get started with minimal setup, configure the plugin in your ESLint configuration file (e.g., .eslintrc.js) with the most essential rules: public-api-imports and path-checker. These rules enforce public API usage and relative imports within slices, respectively, and are suitable for most FSD projects.

Minimal Configuration (Recommended for Beginners)

// .eslintrc.js
export default {
  plugins: ['lookin-tavrus-fsd'],
  rules: {
    'lookin-tavrus-fsd/public-api-imports': ['error', {
      alias: '@', // Replace with your project's alias, if any
      testFilesPatterns: ['**/*.test.ts', '**/*.spec.ts'], // Adjust to match your test file patterns
    }],
    'lookin-tavrus-fsd/path-checker': ['error', {
      alias: '@', // Replace with your project's alias, if any
    }],
  },
};

Extended Minimal Configuration (With Layer Imports)

For projects requiring stricter layer dependency control, add the layer-imports rule to enforce FSD layer directionality and detect circular dependencies. This is particularly useful for larger projects or those using Next.js App Router.

// .eslintrc.js
export default {
  plugins: ['lookin-tavrus-fsd'],
  rules: {
    'lookin-tavrus-fsd/public-api-imports': ['error', {
      alias: '@',
      testFilesPatterns: ['**/*.test.ts', '**/*.spec.ts'],
    }],
    'lookin-tavrus-fsd/path-checker': ['error', {
      alias: '@',
    }],
    'lookin-tavrus-fsd/layer-imports': ['error', {
      alias: '@',
      pagesLayerPatterns: ['pages', 'app/**/page.tsx', 'app/**/layout.tsx'], // Support for Next.js App Router
    }],
  },
};

Full Configuration (With All Rules)

For advanced users who want to enforce segment hierarchies and barrel file imports, include all rules. This configuration is ideal for mature projects with complex slice structures, providing the highest level of architectural discipline.

// .eslintrc.js
export default {
  plugins: ['lookin-tavrus-fsd'],
  rules: {
    'lookin-tavrus-fsd/public-api-imports': [
      'error',
      {
        alias: '@',
        testFilesPatterns: ['**/*.test.*', '**/*.stories.*', '**/StoreDecorator.tsx'],
        sharedSegmentsToEnforce: ['ui', 'lib', 'api', 'config', 'consts'],
      },
    ],
    'lookin-tavrus-fsd/path-checker': [
      'error', { alias: '@' },
    ],
    'lookin-tavrus-fsd/layer-imports': [
      'error',
      {
        alias: '@',
        ignoreImportPatterns: ['**/StoreProvider', '**/ThemeProvider', '**/testing', '**/shared/lib/tests/**',],
        ignoreCircularDependencyPatterns: ['**/*.stories.*', '**/shared/lib/tests/**',],
        pagesLayerPatterns: ['pages', 'app/**/page.tsx', 'app/**/layout.tsx'],
      },
    ],
    'lookin-tavrus-fsd/slice-segment-imports': ['error', {
      alias: '@',
      segmentHierarchy: {
        ui: ['model', 'lib', 'api'],
        model: ['lib', 'api'],
        lib: ['api'],
        api: ['model'], // Adjusted to allow API segments to import from 'model' (e.g., for types)
      },
      allowSameSegmentImports: true,
    }],
    'lookin-tavrus-fsd/force-public-api-barrel-imports': ['error', {
      alias: '@',
      layersToEnforce: ['entities', 'features', 'widgets', 'pages'],
      publicApiFileNames: ['index.ts', 'index.js', 'testing.ts', 'testing.js'],
      ignorePatterns: ['**/api/*'],
    }],
  },
};

🔍 Rules Overview

Below is a detailed description of each rule, including its purpose, options, examples, and limitations.

🔹 path-checker

Purpose: Enforces relative imports within the same FSD slice to maintain modularity. Automatically converts absolute imports to relative paths when applicable.

Options:

| Option | Type | Description | Default | |--------|------|-------------|---------| | alias | string | Project path alias (e.g., @). | '' |

Examples:

// ❌ Incorrect (absolute import within same slice)
import { helper } from '@/features/user/model/slice/helper';

// ✅ Correct (auto-fixed by rule)
import { helper } from '../../model/slice/helper';

Limitations:

  • Only applies to imports within the same slice.
  • Requires accurate alias configuration for projects using path aliases.

Error Message:

Imports within the same Feature-Sliced Design slice must be relative.


🔹 public-api-imports

Purpose: Restricts absolute imports to public API files (index.ts) for FSD layers (entities, features, pages, widgets, shared) and test-only imports (testing.ts) in test files. Enforces public API imports for specified shared segments (e.g., ui, lib). Provides auto-fix to correct import paths.

Options:

| Option | Type | Description | Default | |--------|------|-------------|---------| | alias | string | Project path alias (e.g., @). | '' | | testFilesPatterns | string[] | Glob patterns for test-related files (e.g., ['**/*.test.ts', '**/*.stories.*', '**/StoreDecorator.tsx']). | [] | | enforceSharedSegmentPublicApi | boolean | Enforce public API for shared segments. | true | | sharedSegmentsToEnforce | string[] | Shared segments to enforce public API (e.g., ['ui', 'lib', 'api', 'config', 'consts']). | ['ui', 'lib', 'api', 'config', 'consts', 'utils'] |

Examples:

// ✅ Correct
import { UserCard } from '@/features/user'; // Public API
import { mockUser } => '@/entities/user/testing'; // In test file
import { Button } from '@/shared/ui'; // Shared public API

// ❌ Incorrect
import { something } from '@/features/user/model/slice'; // Deep import
import { mockUser } from '@/entities/user/testing'; // In non-test file
import { styles } from '@/shared/ui/Button/Button.module.css'; // Deep shared import

Limitations:

  • Assumes public API files are named index.ts or testing.ts.
  • Shared segment enforcement requires careful configuration of sharedSegmentsToEnforce.

Error Messages:

Import '{{importPath}}' must be from the public API (e.g., '{{publicApiPath}}'). Testing import '{{importPath}}' is only allowed in test files. Import '{{importPath}}' from shared layer must be from its public API (e.g., '{{publicApiPath}}').


🔹 layer-imports

Purpose: Enforces FSD layer import directionality to prevent higher layers from importing lower layers. Supports Next.js App Router patterns for the pages layer. Includes slice-level circular dependency detection within the current file's context, with configurable ignore patterns. This helps catch immediate self-referential cycles and short-chain cycles within a single linting pass, serving as a useful preliminary check.

Options:

| Option | Type | Description | Default | |--------|------|-------------|---------| | alias | string | Project path alias (e.g., @). | '' | | ignoreImportPatterns | string[] | Glob patterns for imports to completely ignore from all layer-related checks (e.g., ['**/StoreProvider', '**/ThemeProvider', '**/testing', '**/shared/lib/tests/**']). | [] | | ignoreCircularDependencyPatterns | string[] | Glob patterns for files or paths for which circular dependency checks should be skipped (e.g., ['**/*.stories.*', '**/shared/lib/tests/**']). | [] | | pagesLayerPatterns | string[] | Glob patterns for pages layer files (e.g., ['app/**/page.tsx', 'app/**/layout.tsx']). | ['pages', 'app/**/page.tsx', 'app/**/layout.tsx'] |

Default Layer Hierarchy:

| Layer | Can Import From | |-------|-----------------| | app | entities, features, pages, widgets, shared | | pages | entities, features, widgets, shared | | widgets | entities, features, shared | | features | entities, shared | | entities | entities, shared | | shared | shared |

Examples:

// ✅ Correct
import { Article } from '@/entities/article'; // features → entities
import { SharedHeader } from '@/shared/ui/SharedHeader'; // app/dashboard/page.tsx → shared
import { StarRating } from '@/shared/ui/StarRating'; // In a story file, circularity ignored

// ❌ Incorrect
import { Layout } from '@/pages/layout'; // features → pages
import { AppConfig } from '@/app/config'; // app/profile/page.tsx → app
// Assuming entities/user and entities/profile have a mutual dependency not ignored,
// and this specific import completes a cycle within the current file's context or established graph.
import { User } from '@/entities/user'; // Circular dependency if this import closes a User <-> Profile cycle

Limitations:

  • Circular dependency detection within this rule is effective for cycles that are completable within the scope of a single file's imports, or direct back-and-forth dependencies between two slices that are both processed and detected by the rule's internal graph during the linting run.
  • For complex, multi-file, or deep circular dependencies across your entire project, a dedicated tool like dependency-cruiser is recommended for a holistic analysis.
  • Static analysis only; does not handle dynamic imports.

Error Messages:

Import violates Feature-Sliced Design: '{{currentLayer}}' layer cannot import from '{{importLayer}}'. Circular dependency detected: '{{currentSlice}}' slice imports '{{importSlice}}', which creates a cycle.


🔹 slice-segment-imports

Purpose: Enforces a strict import hierarchy between segments (e.g., ui, model, lib, api) within the same FSD slice, based on a user-defined segmentHierarchy. This allows fine-grained control over internal slice dependencies, including scenarios where api segments might import model for types.

Options:

| Option | Type | Description | Default | |--------|------|-------------|---------| | alias | string | Project path alias (e.g., @). | '' | | segmentHierarchy | { [segment: string]: string[] } | Defines allowed import directions (e.g., { ui: ['model', 'lib'] }). | Required | | allowSameSegmentImports | boolean | Allow imports within the same segment. | true |

Example Configuration:

segmentHierarchy: {
  ui: ['model', 'lib', 'api'],
  model: ['lib', 'api'],
  lib: ['api'],
  api: ['model'], // Example: Allows 'api' to import from 'model' (e.g., for types)
}

Examples:

// ✅ Correct
import { getUserData } from '../lib/utils'; // model → lib
import { getUserName } from '../model/selectors'; // ui → model
import { Notification } from '../model/types/notifications'; // api → model (with `api: ['model']` config)

// ❌ Incorrect
import { UserAvatar } from '../ui/UserAvatar'; // model → ui
import { selectUserData } from '../model/selectors'; // api → model (if `api: []` config)

Limitations:

  • Only applies to relative imports within the same slice.
  • No enforcement for segments not defined in segmentHierarchy.

Error Messages:

Segment '{{currentSegment}}' in slice '{{currentLayer}}/{{currentSlice}}' cannot import from segment '{{importedSegment}}'. Allowed: {{allowedImports}}. Imports from the same segment '{{currentSegment}}' are not allowed within slice '{{currentLayer}}/{{currentSlice}}'.


🔹 force-public-api-barrel-imports

Purpose: Enforces absolute imports to FSD layers through public API barrel files (e.g., index.ts, testing.ts), with auto-fix support. This prevents deep absolute imports into layers and segments.

Options:

| Option | Type | Description | Default | |--------|------|-------------|---------| | alias | string | Project path alias (e.g., @). | '' | | layersToEnforce | string[] | Layers to enforce barrel imports (e.g., ['entities', 'features']). | ['entities', 'features', 'widgets', 'pages'] | | publicApiFileNames | string[] | Public API file names (e.g., ['index.ts', 'testing.ts']). | ['index.ts', 'index.tsx', 'index.js', 'index.jsx'] | | ignorePatterns | string[] | Glob patterns for imports to ignore (e.g., ['**/api/*']). | [] |

Examples:

// ✅ Correct
import { UserCard } from '@/entities/User'; // Public API
import { Button } from '@/shared/ui'; // Shared segment (if enforced)

// ❌ Incorrect
import { LoginForm } from '@/features/Auth/ui/LoginForm'; // Deep import
import { Config } from '@/shared/config/index.ts'; // Deep shared import (if enforced)

Limitations:

  • Only applies to absolute imports.
  • Requires careful configuration of ignorePatterns for edge cases (e.g., direct API client imports).

Error Message:

Import '{{originalImportPath}}' should go through the public API barrel file: '{{suggestedImportPath}}'.


📁 Supported FSD Layers

  • app
  • entities
  • features
  • widgets
  • shared
  • pages

Other directories are ignored by default.


🏗️ Example Project Structure

/src/
├── app/
│   └── config/
├── entities/
│   └── comment/
│       ├── model/
│       ├── ui/
│       ├── index.ts
│       └── testing.ts
├── features/
│   └── user/
│       ├── model/
│       └── index.ts
├── pages/
│   └── dashboard/
│       ├── page.tsx
│       └── index.ts
├── shared/
│   ├── api/
│   ├── config/
│   ├── lib/
│   │   └── tests/ # Your test utilities folder
│   └── ui/
│       └── index.tsx
├── widgets/

✅ Valid vs ❌ Invalid Examples

✅ Valid

// Relative within slice
import { reducer } from '../model/slice.js';

// Public API
import { UserCard } from '@/entities/user';

// Test import in test file
import { mockUser } from '@entities/user/testing';

// Allowed layer direction
import { Article } from '@entities/article';

// Allowed segment import (ui → model)
import { getUserData } from '../model/selectors';

// Allowed segment import (api → model, with custom hierarchy)
import { Notification } from '../model/types/notifications';

// Barrel import
import { UserData } from '@entities/User';

// Ignored import for layer/circularity (e.g., StoreProvider, a story file, or shared/lib/tests utility)
import { StoreProvider } from '@/app/providers/StoreProvider';
import { StarRating } from '@/shared/ui/StarRating'; // If this is a .stories.tsx file
import { componentRender } from '@/shared/lib/tests/componentRender/componentRender';

❌ Invalid

// Deep import bypassing public API
import { helper } from '@features/user/model/helper';

// Absolute import within same slice
import { helper } from '@features/user/model/helper';

// Test import in non-test file
import { mockUser } from '@entities/user/testing';

// Disallowed layer direction
import { Layout } from '@pages/layout';

// Disallowed segment import (model → ui)
import { UserAvatar } from '../ui/UserAvatar';

// Non-barrel import
import { LoginForm } from '@features/Auth/ui/LoginForm';

// Circular dependency (if not ignored by config, and completes a cycle within the current file's processing context)
import { User } from '@/entities/User'; // E.g., if this specific import forms a User <-> Profile cycle

📄 Rule Summary

| Rule | Description | |------|-------------| | path-checker | Enforces relative imports within the same FSD slice, with auto-fix. | | public-api-imports | Restricts absolute imports to public/test APIs, with auto-fix for layers and shared segments. | | layer-imports | Enforces FSD layer import directionality and detects slice-level circular dependencies within a file's context. | | slice-segment-imports | Enforces segment import hierarchy within a slice, allowing flexible configurations like api importing model types. | | force-public-api-barrel-imports | Enforces absolute imports through public API barrel files, with auto-fix. |


🧠 Example Error Messages

  • path-checker: "Imports within the same Feature-Sliced Design slice must be relative."
  • public-api-imports:
    • "Import 'entities/comment/model/slice' must be from the public API (e.g., 'entities/comment')."
    • "Testing import 'entities/user/testing' is only allowed in test files."
    • "Shared segment import 'shared/ui/Button/Button.module.tsx' must be from the public API (e.g., 'shared/ui/Button')."
  • layer-imports:
    • "Import violates Feature-Sliced Design: 'features' layer cannot import from 'pages'."
    • "Circular dependency detected: 'user' slice imports 'profile', which creates a cycle."
  • slice-segment-imports:
    • "Segment 'model' in slice 'features/user' cannot import from 'ui'. Allowed: lib, api."
    • "Imports from the same segment 'model' are not allowed within slice 'features/user'."
  • force-public-api-barrel-imports:
    • "Import '@/features/Auth/ui/LoginForm' should go through the public API barrel file: '@/features/Auth'."

👨‍💻 Author

Developed by Lookin-Tavrus, inspired by the Ulbi TV frontend course. This plugin aims to empower frontend developers to build scalable, maintainable applications using Feature-Sliced Design.