Check allowed external dependencies by element type
It checks import
statements to external modules and allow or disallow them based on the element importing the module and the provided options rules.
"boundaries/external": [<enabled>, { "default": <string>, "rules": <object> }]
enabled
: for enabling the rule. 0=off, 1=warn, 2=error.default
:allow
ordisallow
. If no onerule
matches, the external dependency will be allowed or disallowed based on this value.message
: Custom message for the rule errors. Note that the rule default message provides a lot of information about why the error was produced, so you should define a custom message only if you are sure about what you are doing. Read "error messages" for further information.rules
: Rules to be processed in order to decide if theimport
statement has to be allowed or not.from
:<element matchers>
If the file being analyzed matches with this, then the rule will be executed to know if it allows/disallows theimport
. If not, the rule is skipped.disallow
:<external modules matchers>
If the element being imported matches with this, then the result of the rule will be "disallow", and the import will be notified as aneslint
error (this value can be overwritten by a next rule returning "allow")allow
:<external modules matchers>
If the element being imported matches with this, then the result of the rule will be "allow", and the import will not be notified as aneslint
error (this value can be overwritten by a next rule returning "disallow")importKind
:<string>
Optional. It is useful only when using TypeScript, as it allows to define if the rule applies when the dependency is being imported as a value or as a type. It can be also defined as an array of strings, or a micromatch pattern. Note that possible values to match with are"value"
,"type"
or"typeof"
.message
:<string>
Custom error message only for this rule. Read "error messages" for further info.
allow
and disallow
properties in the options should receive one or multiple patterns to match external libraries. Every single pattern can have next formats:
<string>
. Amicromatch
pattern to match the name of the module.[<string>, <object>]
. An array containing amicromatch
pattern as first element, and an options object, which can have next properties:specifiers
:<array>
Array of used specifiers when importing the library. Each specifier can be expressed also as amicromatch
pattern. Matching specifiers are available as${report.specifiers}
when defining custom error messages.path
:<string>
orArray<string>
. Micromatch patterns to match the path of the imported module. If the path is an array, then the module will match if any of the patterns matches. Note that the path must start with a/
character. The path is available as${report.path}
when defining custom error messages.
When using options, note that:
- If
path
option is provided, then it will only match if the path of the imported module matches with any of the patterns. - If
specifiers
option is provided, then it will only match if any of the specifiers is used in theimport
statement.
Examples
"foo-library"
import "foo-library"
✅import { Link } from "foo-library"
✅import { Link, Foo } from "foo-library"
✅import "another-library"
❌
["foo-library", { specifiers: ["Link"] }]
import { Link } from "foo-library"
✅import { Link, Foo } from "foo-library"
✅import "foo-library"
❌import { Foo } from "foo-library"
❌import "another-library"
❌
["foo-*", { specifiers: ["L*", "F*"] }]
import { Link } from "foo-library"
✅import { Foo } from "foo-another-library"
✅import { Var, Foo } from "foo-library"
✅import "foo-library"
❌import "another-library"
❌
{
"rules": {
"boundaries/external": [2, {
// disallow all external imports by default
"default": "disallow",
"rules": [
{
// from helper elements
"from": ["helpers"],
// allow importing moment
"allow": ["moment"],
// allow only importing types, not values. Useful only in TypeScript
"importKind": "type"
},
{
// from component elements
"from": ["components"],
"allow": [
// allow importing react
"react",
// allow importing any @material-ui module
"@material-ui/*"
]
},
{
// from components of family "molecules"
"from": [[ "components", { "family": "molecules" } ]],
"disallow": [
// disallow importing @material-ui/icons
"@material-ui/icons"
]
},
{
// from modules
"from": ["modules"],
"allow": [
// allow importing react
"react",
// allow importing useHistory, Switch and Route from react-router-dom
["react-router-dom", { "specifiers": ["useHistory", "Switch", "Route"] }],
// allow importing Menu icon and any icon starting with "Log" from @mui/icons-material
["@mui/icons-material", { "path": ["/Menu", "/Log*"] }
]
},
]
}
]
}
}
Examples in the next sections are based on the previous options example and these files and settings.
src/
├── components/
│ ├── atoms/
│ │ ├── atom-a/
│ │ │ ├── index.js
│ │ │ └── AtomA.js
│ │ └── atom-b/
│ │ ├── index.js
│ │ └── AtomB.js
│ └── molecules/
│ ├── molecule-a/
│ │ ├── index.js
│ │ └── MoleculeA.js
│ └── molecule-b/
│ ├── index.js
│ └── MoleculeB.js
├── helpers/
│ ├── data/
│ │ ├── sort.js
│ │ └── parse.js
│ └── permissions/
│ └── roles.js
└── modules/
├── module-a/
│ ├── index.js
│ └── ModuleA.js
└── module-b/
├── index.js
└── ModuleB.js
{
"settings": {
"boundaries/elements": [
{
"type": "helpers",
"pattern": "helpers/*/*.js",
"mode": "file",
"capture": ["category", "elementName"]
},
{
"type": "components",
"pattern": "components/*/*",
"mode": "folder",
"capture": ["family", "elementName"]
},
{
"type": "modules",
"pattern": "modules/*",
"mode": "folder",
"capture": ["elementName"]
}
]
}
}
Helpers can't import value from moment
:
// src/helpers/data/parse.js
import moment from 'moment'
Helpers can't import react
:
// src/helpers/data/parse.js
import React from 'react'
Components can't import moment
:
// src/components/atoms/atom-a/AtomA.js
import moment from 'moment'
Components of family "molecules" can't import @material-ui/icons
:
// src/components/molecules/molecule-a/MoleculeA.js
import { Info } from '@material-ui/icons'
Modules can't import withRouter
from react-router-dom
:
// src/modules/module-a/ModuleA.js
import { withRouter } from 'react-router-dom'
Modules can't import @mui/icons-material
:
// src/modules/module-a/ModuleA.js
import { Login } from '@mui/icons-material'
Helpers can import type from moment
:
// src/helpers/data/parse.js
import type moment from 'moment'
Components can import react
:
// src/components/atoms/atom-a/AtomA.js
import React from 'react'
Components can import @material-ui/core
:
// src/components/atoms/atom-a/AtomA.js
import { Button } from '@material-ui/core'
Modules can import react
:
// src/modules/module-a/ModuleA.js
import React from 'react'
Modules can import useHistory
from react-router-dom
:
// src/modules/module-a/ModuleA.js
import { useHistory } from 'react-router-dom'
Modules can import @mui/icons-material/Menu
:
// src/modules/module-a/ModuleA.js
import Login from '@mui/icons-material/Menu'
Modules can import @mui/icons-material/Login
:
// src/modules/module-a/ModuleA.js
import Login from '@mui/icons-material/Login'
This rule provides a lot of information about the specific option producing an error, so the user can have enough context to solve it.
- If the error is produced because all imports are disallowed by default, and no rule is specificly allowing it, then the message provides information about the file and the external dependency:
No rule allows the usage of external module 'react' in elements of type 'helper'
. - If the error is produced by a specific option, then the message includes information about the option producing it:
Usage of external module 'react' is not allowed in elements of type 'helper' with elementName 'helper-a'. Disallowed in rule 2
- If the error is produced by a specific option including specifiers property, then the message includes information it:
Usage of 'useMemo, useEffect' from external module 'react' is not allowed in elements of type 'helper' with elementName 'helper-a'. Disallowed in rule 2
- If the error is produced by a specific option including path property, then the message includes information it:
Usage of '/Login' from external module '@mui/icons-material' is not allowed in elements of type 'module' with elementName 'module-a'. Disallowed in rule 3
- If the rule contains an
importKind
property, then the message also includes information about the import kind:Usage of type 'useMemo, useEffect' from external module 'react' is not allowed in elements of type 'helper' with elementName 'helper-a'. Disallowed in rule 2
You can also configure a custom error message for changing this default behavior, or even custom error messages only for a specific rule option. Read "error messages" in the main docs for further info about how to configure messages.
Read how to configure the boundaries/elements
setting to assign an element type to each project's file.