Git Product home page Git Product logo

eslint-plugin-boundaries's Introduction

Build status Coverage Status Quality Gate

NPM dependencies Renovate Last commit Last release

NPM downloads License

eslint-plugin-boundaries

In words of Robert C. Martin, "Software architecture is the art of drawing lines that I call boundaries. Those boundaries separate software elements from one another, and restrict those on one side from knowing about those on the other." (*acknowledgements)

This plugin ensures that your architecture boundaries are respected by the elements in your project checking the folders and files structure and the import statements (Read the main rules overview chapter for better comprehension.). It is not a replacement for eslint-plugin-import, on the contrary, the combination of both plugins is recommended.

Installation

This module is distributed via npm which is bundled with node and should be installed as one of your project's devDependencies:

npm install --save-dev eslint eslint-plugin-boundaries

eslint-plugin-boundaries does not install ESLint for you. You must install it yourself.

Then, in your .eslintrc.json file:

{
  "plugins": ["boundaries"],
  "extends": ["plugin:boundaries/recommended"],
  "settings": {
    "boundaries/types": ["helpers", "models", "views", "controllers"],
  }
}

Each architecture should define its own element types to make the plugin work properly. Otherwise, you will receive a warning and rules won't be applied. Read the configuration chapter for further info.

Main rules overview

Private elements

This rule ensures that elements can't require other element's children. So, when an element B is children of A, B becomes a "private" element of A, and only A can use it. (Also other descendants of A could use B if "allowUncles" option is enabled in the rule).

Read the docs of the boundaries/no-private rule for further info.

Entry point

This rule ensures that elements can't import another file from other element than the defined entry point for that type (index.js by default)

Read the docs of the boundaries/entry-point rule for further info.

Allowed element types

This rule ensures that dependencies between your project element types are allowed.

Examples of usage:

  • Define types in your project as "models", "views" and "controllers". Then ensure that "views" and "models" can be required only by "controllers", and "controllers" will never be used by "views" or "models".
  • Define types in your project as "components", "views", "layouts", "pages", "helpers". Then ensure that "components" can only require "helpers", that "views" can only require "components" or "helpers", that "layouts" can only require "views", "components" or "helpers", and that "pages" can require any other element type.

Read the docs of the boundaries/allowed-types rule for further info.

Forbidden external modules

External dependencies used by each type of element in your project can be checked using this rule. For example, you can define that "helpers" can't import react, or "components" can't import react-router-dom.

Read the docs of the boundaries/no-external rule for further info.

Requisites

The plugin needs your files and folders to be named and organized in a way that it can recognize the type of an element, and its position in an elements hierarchy (And this is not necessarily bad, because if the plugin can recognize them, an human developer will do it easily too, and your project will become more organized before even running eslint ๐Ÿ˜‰).

So there are basic rules that have to be followed to make it work:

  • Folder names: Elements of a certain type must be always allocated under a folder which name should be the type itself (models/[x], controllers/[y], helpers/[z], etc.).
  • Folders hierarchy: Type folders can also be created inside elements folders. Then these children elements will become "private" ones of the element containing them, and the "private elements" rule will be applied (controllers/[x]/models/[y], controllers/[x]/views/[z], etc.).
  • Unique entry point for each element: Ideally, each element should expose an unique file as "entry point". By default, the plugin considers this file being the index.js one, and will not allow to import any other element file (using only element folder names in imports statements is the recommended way to work when using this plugin), but this behavior can be configured. You can define a different main file pattern or even a different file pattern for each element type. You could also change the configuration to allow importing any element file, but this is strongly not recommended, as it breaks the motivation of the plugin itself.

The plugin won't apply rules to an element when it does not recognize its type, but you can force all elements in your project to follow these patterns enabling the boundaries/prefer-recognized-types rule.

Rules

Configuration

Global settings

Each architecture should define its own element types to make the plugin work properly. Otherwise, you will receive a warning and rules won't be applied.

In your .eslintrc.json file:

{
  "settings": {
    "boundaries/types": ["helpers", "components", "views", "layouts", "pages", "app"],
    "boundaries/ignore": ["src/**/*.spec.js", "src/**/*.test.js"],
    "boundaries/alias": {
      "components": "src/components",
      "helpers": "src/helpers"
    }
  }
}
  • boundaries/types: Folder names containing an specific type of elements. _In the example above, the plugin will recognize all children folders of a folder named helpers" as elements of type "helpers" (helpers/[x], components/foo/helpers/[y], etc.).
  • boundaries/ignore: Files matching these glob expressions will be ignored by the plugin.
  • boundaries/alias: If you are using alias in the project (e.g. webpack resolve alias or babel-plugin-module-resolver), you'll have to provide those alias also to the plugin configuration.

NOTE: The plugin uses globule under the hood to do file names and folders matching.

Rules configuration

Some rules require extra configuration, and it has to be defined in each specific "rule" property of the .eslintrc.json file. For example, allowed types relationships has to be provided for the boundaries/allowed-types rule. Rules requiring extra configuration will print a warning in case they are enabled without the needed extra config. Please refer to the docs of each rule for further info.

Predefined configurations

This plugin is distributed with two different predefined configurations: "recommended" and "strict".

Recommended

We recommend to use this setting until you are familiarized with the folders structure required by this plugin and its configuration, or if you are applying the plugin to an already existing project. Rules boundaries/prefer-recognized-types, boundaries/no-import-not-recognized-types and boundaries/no-import-ignored are disabled, so it allows to have parts of the project non-compliant with your element types, allowing refactor the code progressively.

{
  "extends": ["plugin:boundaries/recommended"]
}

Strict

All rules are enabled, so all elements in the project will be compliant with your architecture boundaries. ๐Ÿ˜ƒ

{
  "extends": ["plugin:boundaries/strict"]
}

Custom configuration

Settings and specific rules can be configured separately following the eslint configuration docs.

Acknowledgements

* Quote from Robert C. Martin's book "Clean Architecture: A Craftsman's Guide to Software Structure and Design".

Contributing

Contributors are welcome. Please read the contributing guidelines and code of conduct.

License

MIT, see LICENSE for details.

eslint-plugin-boundaries's People

Contributors

javierbrea avatar renovate-bot avatar renovate[bot] avatar

Stargazers

 avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.