Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

eslint-plugin-canonical

Package Overview
Dependencies
Maintainers
1
Versions
68
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

eslint-plugin-canonical

Canonical linting rules for ESLint.

  • 4.13.0
  • Source
  • npm
  • Socket score

Version published
Weekly downloads
71K
increased by16.97%
Maintainers
1
Weekly downloads
 
Created
Source

eslint-plugin-canonical

NPM version Travis build status js-canonical-style

ESLint rules for Canonical ruleset.

Installation

npm install eslint --save-dev
npm install @typescript-eslint/parser --save-dev
npm install eslint-plugin-canonical --save-dev

Configuration

  1. Set parser property to @typescript-eslint/parser.
  2. Add plugins section and specify eslint-plugin-canonical as a plugin.
  3. Enable rules.
{
  "parser": "@typescript-eslint/parser",
  "plugins": [
    "canonical"
  ],
  "rules": {
    "canonical/filename-match-exported": 0,
    "canonical/filename-match-regex": 0,
    "canonical/filename-no-index": 0,
    "canonical/id-match": [
      2,
      "(^[A-Za-z]+(?:[A-Z][a-z]*)*\\d*$)|(^[A-Z]+(_[A-Z]+)*(_\\d$)*$)|(^(_|\\$)$)",
      {
        "ignoreDestructuring": true,
        "ignoreNamedImports": true,
        "onlyDeclarations": true,
        "properties": true
      }
    ],
    "canonical/no-restricted-strings": 0,
    "canonical/no-use-extend-native": 2,
    "canonical/prefer-inline-type-import": 2,
    "canonical/sort-keys": [
      2,
      "asc",
      {
        "caseSensitive": false,
        "natural": true
      }
    ]
  }
}

Shareable configurations

This plugin exports a recommended configuration that enforces Canonical type good practices.

To enable this configuration use the extends property in your .eslintrc config file:

{
  "extends": [
    "plugin:canonical/recommended"
  ],
  "plugins": [
    "canonical"
  ]
}

See ESLint documentation for more information about extending configuration files.

Rules

destructuring-property-newline

Like object-property-newline, but for destructuring.

export-specifier-newline

Forces every export specifier to be on a new line.

Tip: Combine this rule with object-curly-newline to have every specifier on its own line.

"object-curly-newline": [
  2,
  {
    "ExportDeclaration": "always"
  }
],

Working together, both rules will produces exports such as:

export { 
  a,
  b,
  c
};

filename-match-exported

Match the file name against the default exported value in the module. Files that don't have a default export will be ignored. The exports of index.js are matched against their parent directory.

// Considered problem only if the file isn't named foo.js or foo/index.js
export default function foo() {}

// Considered problem only if the file isn't named Foo.js or Foo/index.js
module.exports = class Foo() {}

// Considered problem only if the file isn't named someVariable.js or someVariable/index.js
module.exports = someVariable;

// Never considered a problem
export default { foo: "bar" };

If your filename policy doesn't quite match with your variable naming policy, you can add one or multiple transforms:

"canonical/filename-match-exported": [ 2, { "transforms": "kebab" } ]

Now, in your code:

// Considered problem only if file isn't named variable-name.js or variable-name/index.js
export default function variableName;

Available transforms:

  • snake
  • kebab
  • camel
  • pascal

For multiple transforms simply specify an array like this (null in this case stands for no transform):

"canonical/filename-match-exported": [2, { "transforms": [ null, "kebab", "snake" ] } ]

If you prefer to use suffixes for your files (e.g. Foo.react.js for a React component file), you can use a second configuration parameter. It allows you to remove parts of a filename matching a regex pattern before transforming and matching against the export.

"canonical/filename-match-exported": [ 2, { "suffix": "\\.react$" } ]

Now, in your code:

// Considered problem only if file isn't named variableName.react.js, variableName.js or variableName/index.js
export default function variableName;

If you also want to match exported function calls you can use the third option (a boolean flag).

"canonical/filename-match-exported": [ 2, { "matchCallExpression": true } ]

Now, in your code:

// Considered problem only if file isn't named functionName.js or functionName/index.js
export default functionName();

filename-match-regex

Enforce a certain file naming convention using a regular expression.

The convention can be configured using a regular expression (the default is camelCase.js). Additionally exporting files can be ignored with a second configuration parameter.

"canonical/filename-match-regex": [2, { "regex": "^[a-z_]+$", "ignoreExporting": true }]

With these configuration options, camelCase.js will be reported as an error while snake_case.js will pass. Additionally the files that have a named default export (according to the logic in the match-exported rule) will be ignored. They could be linted with the match-exported rule. Please note that exported function calls are not respected in this case.

filename-no-index

Having a bunch of index.js files can have negative influence on developer experience, e.g. when opening files by name. When enabling this rule. index.js files will always be considered a problem.

id-match

The --fix option on the command line automatically fixes problems reported by this rule.

Note: This rule is equivalent to id-match, except for addition of ignoreNamedImports.

This rule requires identifiers in assignments and function definitions to match a specified regular expression.

Options
  • "properties": false (default) does not check object properties
  • "properties": true requires object literal properties and member expression assignment properties to match the specified regular expression
  • "classFields": false (default) does not class field names
  • "classFields": true requires class field names to match the specified regular expression
  • "onlyDeclarations": false (default) requires all variable names to match the specified regular expression
  • "onlyDeclarations": true requires only var, function, and class declarations to match the specified regular expression
  • "ignoreDestructuring": false (default) enforces id-match for destructured identifiers
  • "ignoreDestructuring": true does not check destructured identifiers
  • "ignoreNamedImports": false (default) enforces id-match for named imports
  • "ignoreNamedImports": true does not check named imports

import-specifier-newline

Forces every import specifier to be on a new line.

Tip: Combine this rule with object-curly-newline to have every specifier on its own line.

"object-curly-newline": [
  2,
  {
    "ImportDeclaration": "always"
  }
],

Working together, both rules will produces imports such as:

import { 
  a,
  b,
  c
} from 'foo';

no-barrel-import

The --fix option on the command line automatically fixes problems reported by this rule.

Requires that resources are imported from the same files in which they are defined.

This rule converts the following:

// foo.ts
import { bar } from './bar';
// bar.ts
export { baz as bar } from './baz';
// baz.ts
export const baz = 'BAZ';

to:

// foo.ts
import { baz as bar } from './baz';
// baz.ts
export const baz = 'BAZ';

This rule handles

  • named imports
  • default imports
  • aliased imports

You must configure import/parsers and import/resolver for this rule to work, e.g.

settings: {
  'import/parsers': {
    '@typescript-eslint/parser': ['.ts', '.tsx'],
  },
  'import/resolver': {
    typescript: {
      project: path.resolve(
        __dirname,
        'tsconfig.json',
      ),
    },
  },
},

no-export-all

The --fix option on the command line automatically fixes problems reported by this rule.

Requite that re-exports are named.

no-reassign-imports

Restricts re-assigning imports to variables that are exported.

no-restricted-imports

Disallow specified modules when loaded by import

This rule is similar to no-restricted-imports except that it allows you to specify unique messages for each restricted import (a workaround for issue issues#15261).

no-restricted-strings

Disallow specified strings.

Options

The 1st option is an array of strings that cannot be contained in the codebase.

no-unused-exports

Identifies unused TypeScript exports.

Note This rule is implemented using ts-unused-exports.

Options
ConfigTypeRequiredDefaultDescription
tsConfigPathstringRequiredPath to tsconfig.json
allowUnusedEnumsbooleanfalseAllow unused enums.
allowUnusedTypesbooleanfalseAllow unused type and interface.

no-use-extend-native

prefer-import-alias

The --fix option on the command line automatically fixes problems reported by this rule.

Restrict imports to path aliases or relative imports limited by depth.

The same alias can be applied using multiple rules, e.g.

'canonical/prefer-import-alias': [
  2,
  {
    aliases: [
      {
        alias: '@/',
        matchParent: path.resolve(__dirname, 'src'),
        matchPath: '^src\\/',
      },
      {
        alias: '@/',
        matchPath: '^src\\/',
        maxRelativeDepth: 2,
      },
    ],
  },
],

In this example, we are saying:

  • rewrite import path to use alias when
    • import path matches ^src\/
    • the grandfather directory is path.resolve(__dirname, 'src')
  • rewrite import path to use alias when
    • import path matches ^src\/
    • relative import is greater than 2

The grandfather directory is essentially whichever directory that is accessed by the doubledot (../) by the import path.

prefer-inline-type-import

The --fix option on the command line automatically fixes problems reported by this rule.

TypeScript 4.5 introduced type modifiers that allow to inline type imports as opposed to having dedicated import type. This allows to remove duplicate type imports. This rule enforces use of import type modifiers.

prefer-react-lazy

Requires that components that can be loaded lazily be imported using the React.lazy() function.

import { lazy } from 'react';
import { Foo } from './Foo';

export default () => {
  return Math.random() > 0.5 ? <Foo /> : null;
};

This rule converts the above code to:

import { lazy } from 'react';

const Foo = lazy(() => import('./Foo.js').then(({ Foo }) => ({ default: Foo })));

export default () => {
  return Math.random() > 0.5 ? <Foo /> : null;
};

prefer-use-mount

In React, it is common to use useEffect without dependencies when the intent is to run the effect only once (on mount and unmount). However, just doing that may lead to undesired side-effects, such as the effect being called twice in Strict Mode. For this reason, it is better to use an abstraction such as useMount that handles this use case.

require-extension

The --fix option on the command line automatically fixes problems reported by this rule.

Adds .js extension to all imports and exports.

It resolves the following cases:

Relative imports

Relative imports that resolve to a file of the same name:

import './foo'; // => import './foo.js';

Relative imports that resolve to an index file:

import './foo'; // => import './foo/index.js';

The above examples would also work if the file extension was .ts or .tsx, i.e.

import './foo'; // => import './foo.ts';
import './foo'; // => import './foo/index.tsx';

TypeScript paths

For this to work, you have to configure import/resolver:

settings: {
  'import/resolver': {
    typescript: {
      project: path.resolve(__dirname, 'tsconfig.json'),
    },
  },
},

Imports that resolve to a file of the same name:

import { foo } from '@/foo'; // => import { foo } from '@/foo.js';

Imports that resolve to an index file:

import { foo } from '@/foo'; // => import { foo } from '@/foo/index.js';

sort-keys

The --fix option on the command line automatically fixes problems reported by this rule.

Note: This rule is equivalent to sort-keys, except that it is fixable.

This rule requires identifiers in assignments and function definitions to match a specified regular expression.

Options

The 1st option is "asc" or "desc".

  • "asc" (default) - enforce properties to be in ascending order.
  • "desc" - enforce properties to be in descending order.

The 2nd option is an object which has 3 properties.

  • caseSensitive - if true, enforce properties to be in case-sensitive order. Default is true.
  • minKeys - Specifies the minimum number of keys that an object should have in order for the object's unsorted keys to produce an error. Default is 2, which means by default all objects with unsorted keys will result in lint errors.
  • natural - if true, enforce properties to be in natural order. Default is false. Natural Order compares strings containing combination of letters and numbers in the way a human being would sort. It basically sorts numerically, instead of sorting alphabetically. So the number 10 comes after the number 3 in Natural Sorting.

virtual-module

The --fix option on the command line automatically fixes problems reported by this rule.

Enforces "virtual modules" architecture.

Virtual modules is a convention-driven code architecture enforced using ESLint rules. In the most simple of terms, a virtual module is any directory that has a barrel file (index.ts). index.ts is the only way that a virtual module can be imported; any files contained inside of the same directory cannot be imported from outside of the virtual module, unless they are explicitly re-exported through index.ts.

Using the virtual module pattern:

  • You separate the module public interface from their implementation details.
  • You ensure that there is only 1 way to import every module across the project.
  • You ensure that there are no cycling dependencies within the project.

Virtual Modules Architecture

The basic idea behind a virtual module is that every directory in your project that has index.ts becomes a "virtual module". That virtual module (and sub-folders) can only be imported through index.ts, i.e. index.ts needs to explicitly export everything that is part of the public interface. This pattern ensures that there is only one way to import all modules across the entire project, and that virtual module implementation details are not public unless they are explicitly re-exported through index.ts.

It is easiest to illustrate this using an example:

components/
├── Foo/
│   ├── Baz/
│   │   └── index.ts
│   └── Qux/
│       └── index.ts/
│           └── Quux/
│               └── index.ts
└── Bar/
    └── index.ts

In this example, Bar, Baz, Qux and Quux are all virtual modules.

  • Bar can import from Baz and vice-versa.
  • Bar can import from Qux and vice-versa.
  • Baz can import from Qux and vice-versa.
  • Bar cannot import directly from Quux because it is a sub-module of Qux. Only Qux can import from Quux.
  • Foo does not have index.ts, therefore it is not a virtual module.
components/
├── Foo/
│   ├── index.ts
│   └── utilities.ts
└── Bar/
    └── index.ts

In this example, Foo and Bar are virtual modules.

  • Foo can import from Bar and vice-versa.

However, unless /components/Foo/index.ts explicitly exports from ./utilities.ts, then Bar cannot access Foo utilities, i.e. ./utilities.ts is an implementation detail of Foo not meant for consumption by the rest of the application.

Other notes:

  • Within a virtual module, only absolute imports can be used to import outside modules.
  • Within a virtual module, only relative imports can be used to import module files (allows to relocate virtual module without impacting internal imports).
  • A virtual module cannot import index.ts of itself (prevents circular references).
  • A virtual module cannot access parent module (prevents circular references).

FAQ

Why is the @typescript-eslint/parser?

This ESLint plugin is written using @typescript-eslint/utils, which assume that @typescript-eslint/parser is used.

Some rules may work without @typescript-eslint/parser. However, rules are implemented and tested assuming that @typescript-eslint/parser is used.

Keywords

FAQs

Package last updated on 12 Oct 2023

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc