@borela-tech/eslint-config
v3.1.0
Published
ESLint config used in Borela Tech projects.
Maintainers
Readme
@borela-tech/eslint-config
Shared ESLint configuration for Borela Tech projects.
Features
- Preconfigured ESLint rules
- Includes some rules from:
- 27 custom rules for consistent code organization:
array-items-line-breakbrace-style-control-statementsbrace-style-object-literalcompact-array-itemsexport-filename-matchfunction-call-argument-line-breakfunction-cognitive-complexityfunction-parameter-line-breakimports-and-re-exports-at-topindividual-importsindividual-re-exportsinterface-property-line-breakmax-declarations-per-filemultiline-union-type-aliasesnaming-conventionno-inline-object-typesno-unnecessary-bracesobject-property-line-breakone-export-per-fileprefer-inline-exportsingle-line-arrow-function-parameterssingle-line-function-parameterssingle-line-importssingle-line-re-exportssingle-line-test-descriptionsorted-importssorted-re-exports
Installation
npm install --save-dev @borela-tech/eslint-configUsage
Create a file named eslint.config.ts in the root of your project and add the
following code:
import {config} from '@borela-tech/eslint-config'
export {config as default}Custom Rules
This package includes 27 custom ESLint rules to enforce consistent code organization. Most custom rules are auto-fixable.
array-items-line-break
Enforces each array item to be on its own line when the array expression exceeds 80 characters.
Bad:
const a = [veryLongItemNameOne, veryLongItemNameTwo, veryLongItemNameThree]Good:
const a = [
veryLongItemNameOne,
veryLongItemNameTwo,
veryLongItemNameThree,
]brace-style-control-statements
Enforces control statement bodies to be on a separate line from the condition.
Bad:
if (foo) return
if (foo) {return}Good:
if (foo)
return
if (foo) {
return
}brace-style-object-literal
Enforces braces of multiline object literals to be on their own lines.
Bad:
const x = {foo: 1,
bar: 2}Good:
const x = {
foo: 1,
bar: 2,
}compact-array-items
Enforces arrays with multiline items (objects or arrays) to use a compact, inline bracket style, as long as the line does not exceed 80 characters.
Bad:
const foo = [
{
id: 1,
},
{
id: 2,
},
]Good:
const foo = [{
id: 1,
}, {
id: 2,
}]export-filename-match
Enforces exported filenames match the default export name. Allows exceptions for index.ts, .test.ts, and .spec.ts files.
Bad:
// file: utils.ts
export default function helper() {}Good:
// file: helper.ts
export default function helper() {}function-call-argument-line-break
Enforces line breaks in function call arguments when the line exceeds 80 characters.
Bad:
const result = someFunctionWithAVeryLongName(arg1, arg2, arg3)Good:
const result = someFunctionWithAVeryLongName(
arg1,
arg2,
arg3,
)function-cognitive-complexity
Enforces a cognitive complexity threshold (default 15) for functions.
Bad:
function handleSubmit() {
if (a) {
if (b) {
if (c) {
if (d) {
doSomething()
}
}
}
}
}Good:
function handleSubmit() {
if (a && b && c && d) {
doSomething()
}
}function-parameter-line-break
Enforces line breaks in function parameters when the line exceeds 80 characters.
Bad:
function myFunctionWithAVeryLongName(param1, param2, param3) {}Good:
function myFunctionWithAVeryLongName(
param1,
param2,
param3,
) {}imports-and-re-exports-at-top
Ensures all imports and re-exports appear at the top of the file before any other statements.
Bad:
const foo = 'bar'
import {baz} from 'module'Good:
import {baz} from 'module'
const foo = 'bar'individual-imports
Enforces one import per statement instead of grouped imports:
Bad:
import {foo, bar, baz} from 'module'Good:
import {foo} from 'module'
import {bar} from 'module'
import {baz} from 'module'individual-re-exports
Enforces one re-export per statement instead of grouped re-exports:
Bad:
export {foo, bar, baz} from 'module'Good:
export {foo} from 'module'
export {bar} from 'module'
export {baz} from 'module'interface-property-line-break
Enforces line breaks in interface properties when the line exceeds 80 characters.
Bad:
interface Config {foo: string; bar: number; baz: boolean}Good:
interface Config {
foo: string
bar: number
baz: boolean
}max-declarations-per-file
Enforces a single top-level declaration (function or type) per file. Allows exceptions for .config, .model, .spec, .stories, and .test files.
Bad:
export function foo() {}
export function bar() {}Good:
// file: foo.ts
export function foo() {}
// file: bar.ts
export function bar() {}multiline-union-type-aliases
Enforces multiline union type aliases.
Bad:
type Status = 'pending' | 'active' | 'completed'Good:
type Status =
| 'pending'
| 'active'
| 'completed'naming-convention
Enforces consistent naming conventions:
- React components (functions returning
JSX.Element,ReactElement, orReactNode) usePascalCase - Wrapped components (e.g.,
memo(...),forwardRef(...)) usePascalCase - React contexts (e.g.,
createContext(...),React.createContext(...)) usePascalCase - Functions use
camelCase - Classes, enums, interfaces, and type aliases use
PascalCase - Variables (
let/var) usecamelCase - Constants (
const) useUPPER_CASEwhen assigned a literal value, otherwisecamelCaseorUPPER_CASE - Names prefixed with
_(e.g.,_unused) are exempt
Bad:
const myButton = (): JSX.Element => null
const myButtons = memo(function MyButtons(): JSX.Element { return null; })
const appContext = createContext(null)
function my_function() {}
const MY_VALUE = 42
class myClass {}Good:
const MyButton = (): JSX.Element => null
const MyButtons = memo(function MyButtons(): JSX.Element { return null; })
const AppContext = createContext(null)
function myFunction() {}
const myValue = 42
class MyClass {}no-inline-object-types
Disallows inline object types in function parameters and return types. Converts them to named interfaces.
Bad:
function foo(x: {a: string}) {}
let x: {a: string} = {a: ''}Good:
interface X {a: string}
function foo(x: X) {}
interface InlineType {a: string}
let x: InlineType = {a: ''}no-unnecessary-braces
Removes braces from single-line statements and adds braces to multi-line statements without braces.
Bad:
if (condition) {
doSomething()
}
if (condition)
return {
a: 1,
b: 2,
c: 3,
}Good:
if (condition)
doSomething()
if (condition) {
return {
a: 1,
b: 2,
c: 3,
}
}object-property-line-break
Enforces object literal formatting based on complexity and line length. Mixed shorthand and non-shorthand properties must be multiline, while multiline objects that fit on one line are collapsed.
Bad:
const a = {foo, bar: bar}
const b = {
foo,
bar,
}Good:
const a = {
foo,
bar: bar,
}
const b = {foo, bar}one-export-per-file
Enforces one export per file. Allows exceptions for index.ts,
.test.ts, and .spec.ts files.
Bad:
export const foo = 'bar'
export const baz = 'qux'Good:
// file: foo.ts
export const foo = 'bar'
// file: index.ts
export const foo = 'bar'
export const baz = 'qux'prefer-inline-export
Prefers inline exports.
Bad:
class Foo {}
export {foo}Good:
export class Foo {}single-line-arrow-function-parameters
Ensures arrow function parameters are on a single line when they fit within 80 characters.
Bad:
const fn = (
x,
y,
) => x + yGood:
const fn = (x, y) => x + ysingle-line-function-parameters
Ensures function parameters are on a single line when they fit within 80 characters.
Bad:
function foo(
bar,
baz,
) {}Good:
function foo(bar, baz) {}single-line-imports
Ensures imports are on a single line (converts multiline imports to single line).
Bad:
import {
foo,
bar,
} from 'module'Good:
import {foo, bar} from 'module'single-line-re-exports
Ensures re-exports are on a single line (converts multiline re-exports to single line).
Bad:
export {
foo,
bar,
} from 'module'Good:
export {foo, bar} from 'module'single-line-test-description
Enforces Jest test descriptions to fit on a single line and within 80 characters (configurable via maxLength). Instead of breaking the call across lines, shorten the description. Applies to it, test, describe and variants such as it.only, test.skip, describe.each, etc.
Bad:
it('throws when a different field is registered under an existing key', () => {})
it(
'short desc',
() => {},
)
describe('a very long description that definitely exceeds the eighty character limit for sure', () => {})Good:
it('short desc', () => {})
it('short', () => {
expect(1).toBe(1)
})
describe('short', () => {})sorted-imports
Enforces imports are sorted alphabetically within their respective groups:
- Side-effect imports (e.g.,
import 'module') - Default imports (e.g.,
import React from 'react') - Named imports (e.g.,
import {useState} from 'react') - Type imports (e.g.,
import type {Config} from 'module')
Within each group, imports are sorted alphabetically by module source. Named import specifiers within each import are also sorted alphabetically.
Bad:
import {z, a} from 'module'
import type {Config} from 'config'
import React from 'react'Good:
import React from 'react'
import {a, z} from 'module'
import type {Config} from 'config' sorted-re-exports
Enforces re-exports are sorted alphabetically within their respective groups:
- Re-export all (e.g.,
export * from 'module') - Re-export named (e.g.,
export {foo, bar} from 'module') - Re-export type (e.g.,
export type {Type1, Type2} from 'module')
Within each group, re-exports are sorted alphabetically by module source. Named export specifiers are also sorted alphabetically.
Bad:
export {bar} from 'module'
export * from 'another'
export type {TypeB} from 'types'Good:
export * from 'another'
export {bar} from 'module'
export type {TypeB} from 'types'