@proctorio/eslint-config
v4.0.2
Published
Proctorio's opinionated ESLint configuration with strict JSDoc, Allman brace style, and tab indentation. Built for ESLint v10 flat config. Includes TypeScript support.
Maintainers
Readme
@proctorio/eslint-config
Proctorio's opinionated ESLint configuration for JavaScript and TypeScript projects. Built for ESLint v10 flat config with strict code quality standards.
This is a strict config. It enforces Allman brace style, tab indentation, mandatory JSDoc, PascalCase filenames, and many other non-standard rules. Adopting it on an existing codebase will produce significant lint errors. Review the rules below before adopting.
Installation
JavaScript projects:
npm install --save-dev @proctorio/eslint-config eslintTypeScript projects:
npm install --save-dev @proctorio/eslint-config eslint typescript-eslintPlugin dependencies (JSDoc, Unicorn, Belgradian, etc.) are bundled. eslint is a required peer dependency (exact version 10.0.0). typescript-eslint is an optional peer dependency, only needed for TypeScript projects.
Promise rules and the no-eslint-disable rule are inlined from their original packages to eliminate dependency conflicts.
Setup
JavaScript
Create an eslint.config.js file in your project root:
import proctorioConfig from "@proctorio/eslint-config";
export default proctorioConfig;TypeScript
import proctorioConfig from "@proctorio/eslint-config/typescript";
export default proctorioConfig;The TypeScript config extends the base JavaScript config and adds:
- TypeScript parser and
typescript-eslintrecommended rules - Disables 8 JSDoc rules that conflict with TypeScript (type annotations, descriptions, tag names, jsdoc requirement)
- Disables
unicorn/filename-case(TypeScript projects often use lowercase) - Disables
belgradian/member-prefix-rule(TypeScript does not use Hungarian naming) - Disables
complexity,max-depth,no-await-in-loop,require-await,require-unicode-regexp,radix - Disables
no-undefined,no-continue,class-methods-use-this,no-process-env,global-require,no-new - Replaces
no-unused-varswith@typescript-eslint/no-unused-vars(ignores_prefixed args) - Disables
no-undef(TypeScript handles this) - Ignores
*.js,*.mjs,*.cjs,dist/,build/,coverage/,node_modules/by default - Relaxes
@typescript-eslint/no-explicit-anyandno-non-null-assertionin test files
Extending with Custom Rules
import proctorioConfig from "@proctorio/eslint-config";
export default [
...proctorioConfig,
{
rules: {
// Your overrides here
}
}
];Rules
This configuration enforces several rules that differ from common JavaScript conventions. These choices reflect Proctorio's coding standards.
Allman Brace Style
"brace-style": ["error", "allman", { "allowSingleLine": true }]
Opening braces on a new line, contrary to the popular 1TBS used by most JavaScript projects.
// Correct (Allman)
function example()
{
return 42;
}
// Incorrect (1TBS)
function example() {
return 42;
}Tab Indentation
"indent": ["error", "tab", {...}]
Tabs required instead of spaces. Most JavaScript projects use 2 or 4 spaces. Tabs allow developers to configure display width to their own preference.
PascalCase Filenames
"unicorn/filename-case": ["error", { "case": "pascalCase" }]
Files must use PascalCase naming. Overrides exist for test mocks (snake_case), scripts (kebab-case), and JSON files (kebab-case).
Correct: UserService.js, HttpClient.js, DataModel.js
Incorrect: userService.js, http-client.js, data_model.jsMandatory JSDoc
"jsdoc/require-jsdoc": ["error", { require: { FunctionDeclaration, MethodDefinition, ClassDeclaration, ArrowFunctionExpression, FunctionExpression } }]
JSDoc is required on all function types and class declarations. Descriptions must be complete sentences. A hyphen is required before each @param description.
/**
* Calculates the sum of two numbers.
*
* @param {number} a - The first number.
* @param {number} b - The second number.
* @returns {number} The sum.
*/
function add(a, b)
{
return a + b;
}Closure-Mode JSDoc
JSDoc is set to "closure" mode with strict type enforcement:
- Use
Objectnotobjectfor types - Wildcard
*types are banned anytypes are banned- Description style is set to
"tag"(requires@descriptiontag rather than the first line being treated as a description)
No ESLint Disable Comments
"no-eslint-disable/no-eslint-disable": "error"
All eslint-disable comments are banned. Fix the code instead of disabling the rule.
Promise Handling
"promise/catch-or-return": ["error", { terminationMethod: ["catch", "finally"] }]
Promises must be terminated with .catch() or .finally(). Additionally: promise/always-return requires a return in .then(), promise/no-return-wrap prevents unnecessary Promise.resolve()/Promise.reject() wrapping, and promise/param-names enforces consistent resolve/reject naming.
Double Quotes
"quotes": ["error", "double", { "avoidEscape": true, "allowTemplateLiterals": false }]
Double quotes required. Single quotes allowed only to avoid escaping. Template literals are not allowed as simple strings.
Newline Before Return
"newline-before-return": "error"
A blank line is required before every return statement. ESLint deprecated this rule but has not removed it. Proctorio continues to enforce it.
Expiring TODO Comments
"unicorn/expiring-todo-comments": ["error", { "terms": ["todo", "fixme", "xxx"] }]
TODO, FIXME, and XXX comments must include an expiration date or issue reference.
// Correct
// TODO [2026-12-31]: Refactor this function
// TODO [#123]: Fix performance issue
// Incorrect
// TODO: fix this laterMember Prefix Rule (Belgradian)
"belgradian/member-prefix-rule": "error"
Enforces Hungarian-style m_ prefix on member and global variables (pattern: ^m_[a-z]+[A-Z]*\S*). ALL_CAPS constants are exempt. Disabled in the TypeScript config.
Other Notable Rules
These rules are less common and may surprise developers adopting this config:
| Rule | Effect |
|---|---|
| require-unicode-regexp | All regexps must use the u flag |
| no-sync | Bans synchronous methods (fs.readFileSync, etc.) |
| no-continue | Bans continue statements |
| no-eq-null | Bans == null comparisons |
| no-process-env | Bans process.env access |
| no-process-exit | Bans process.exit() |
| linebreak-style | Requires Unix line endings (LF) |
| require-await | Async functions must contain await |
| no-await-in-loop | Bans await inside loops |
Parser Settings
ecmaVersion: 2020— ES2020 syntax supported. ES2021+ features like??=or||=will not parse.sourceType: "module"— All files are treated as ES modules. CommonJSrequire()calls may produce warnings.
File Overrides
Test Mock Files (**/test/mocks/*.mock.js)
- Filename case: snake_case
- JSDoc not required
no-negated-conditionandno-nested-ternarydisabled
Script Files (**/src/scripts/*.js)
- Filename case: kebab-case
- JSDoc not required
no-negated-conditionandno-nested-ternarydisabled
JSON Files (*.json)
- Filename case: kebab-case
Test Files (test/*.Test.js, test/**/*.test.js)
- JSDoc not required
shouldandexpectignored for unused variable checkscomplexityandunicorn/prefer-add-event-listenerdisabledpromise/no-callback-in-promisedisabled
Ignored Directories
**/tools/****/build/****/lib/****/rollup.config.*.js**/src/_data/eleventyComputed.js**/external/**
Globals
This config provides globals for:
- Browser —
window,document, etc. - Node.js —
process,__dirname,require, etc. - Web Extensions —
chrome,browser(also set as explicitreadonly) - Jest —
describe,it,test,expect,beforeEach, etc. (viaglobals.jest) globalThis— set asreadonly
Migration from .eslintrc (ESLint v8/v9)
ESLint v9 introduced flat config as the default, and v10 continues it. If you're migrating from the old .eslintrc JSON format:
Before:
{
"extends": "@proctorio/eslint-config"
}After:
import proctorioConfig from "@proctorio/eslint-config";
export default proctorioConfig;Config file changes from .eslintrc.json to eslint.config.js, format changes from JSON to ES modules, and the config is now an array of configuration objects.
Development
This package uses Vitest for testing:
npm test # Run all tests
npm run test:coverage # Run tests with coverage (80% threshold)
npm run test:watch # Run tests in watch modeRequirements
- Node.js: >= 18.0.0
- ESLint: 10.0.0 (exact — pinned peer dependency)
- Package Type: ESM
