Uphold-flavored ESLint config.
The rules defined here extend the eslint-recommended preset, as well as the overrides that allow the Prettier pretty-printer to reformat the code without conflicts.
npm install eslint eslint-config-uphold prettier --save-devWarning
Node.js minimum versions are v23.0.0, v22.12.0 and v20.19.0, as @stylistic/eslint-plugin-js depends on the require('esm') module from v4.0.0.
Create an eslint.config.mjs file with the following content:
import upholdConfig from 'eslint-config-uphold';
export default upholdConfig;If you'd like to extend the config, or change rules, you can do so like this:
import { defineConfig } from 'eslint/config';
import upholdConfig from 'eslint-config-uphold';
import yourPlugin from 'your-eslint-plugin';
export default defineConfig([
upholdConfig,
{
name: 'project-name/config',
plugins: {
'your-plugin': yourPlugin
},
rules: {
'your-plugin/rule-name': 'error'
}
}
]);See Using a Shareable Config for more information.
Add a lint command to the scripts section of your package.json, like so:
{
"scripts": {
"lint": "eslint"
}
}and run the linter with:
npm run lintTo automatically fix all lint issues, use the --fix option:
npm run lint --fixA TypeScript-specific config using typescript-eslint is available under eslint-config-uphold/configs/.
It can be used like this, on a eslint.config.mjs file:
import { defineConfig, globalIgnores } from 'eslint/config';
import { typescript as upholdTypescriptConfig } from 'eslint-config-uphold/configs';
import tseslint from 'typescript-eslint';
export default defineConfig([
{
extends: [upholdTypescriptConfig],
name: 'project-name/uphold-typescript',
rules: {
'jsdoc/no-types': 'warn'
}
},
globalIgnores(['coverage', 'dist'])
]);It's also possible to use the config without typescript-eslint. Minimal setup would look like the following:
import { typescript as upholdTypescriptConfig } from 'eslint-config-uphold/configs';
export default upholdTypescriptConfig;The TypeScript config assumes ESM by default.
If your project uses CJS, you can create a custom config using the createTypeScriptConfig factory.
This can also be used to specify a ecmaVersion other than the default 2022.
import { createTypeScriptConfig } from 'eslint-config-uphold/configs';
export default await createTypeScriptConfig('commonjs', { ecmaVersion: 2024 }); // 'module' for ESM, 'commonjs' for CJS.Likewise, a JavaScript-specific config is exported under eslint-config-uphold/configs/. The usage is similar to TypeScript's config:
import { defineConfig, globalIgnores } from 'eslint/config';
import { javascript as upholdJavascriptConfig } from 'eslint-config-uphold/configs';
export default defineConfig([upholdJavascriptConfig, globalIgnores(['coverage'])]);If not wanting to extend the config, it could even be used like the following:
import { javascript as upholdJavascriptConfig } from 'eslint-config-uphold/configs';
export default upholdJavascriptConfig;The JavaScript config assumes CJS by default.
If your project uses ESM, you can create a custom config using the createJavaScriptConfig factory.
This can also be used to specify a ecmaVersion other than the default 2022.
import { createJavaScriptConfig } from 'eslint-config-uphold/configs';
export default createJavaScriptConfig('module', { ecmaVersion: 2024 }); // 'module' for ESM, 'commonjs' for CJS.This config includes custom Uphold-specific rules, under uphold-plugin.
| Rule | Enabled in default config? | Fix? |
|---|---|---|
database-migration-filename-format |
False | False |
explicit-sinon-use-fake-timers |
True | False |
no-trailing-period-in-log-messages |
True | True |
require-comment-punctuation |
True | True |
Validates that migration file names are in the format YYYYMMDDHHMMSS-<name>, where name must match the regex [a-z0-9-]+, the date/time is UTC and is not in the future.
To enable the database-migration-filename-format rule, you can do so as following:
export default defineConfig([
...
{
files: ['**/database/migrations/*.js'] // glob to include/exclude the migration files to lint
name: 'project/migrations',
rules: {
'uphold-plugin/database-migration-filename-format': 'error'
}
},
...
]);Enforces explicit configuration when using Sinon's useFakeTimers() by requiring the toFake option to be specified. This ensures that only the intended timer functions are faked, reducing the risk of unintended side effects in tests.
Valid:
sinon.useFakeTimers({ toFake: ['setTimeout', 'clearTimeout'] });Invalid:
sinon.useFakeTimers(); // ❌ Missing 'toFake' option.Disallows trailing periods in log messages, except for ... (ellipsis). This helps maintain consistency across log messages.
Valid:
console.log('Operation complete');
console.info('Processing...');
logger.error('An error occurred');Invalid:
console.log('Operation complete.'); // ❌ Remove the trailing period.
console.info('Processing..'); // ❌ Use three dots (...) or none.
logger.error('An error occurred.'); // ❌ Remove the trailing period.Options:
-
additionalMethods- You can configure additional methods to check:'uphold-plugin/no-trailing-period-in-log-messages': ['error', { additionalMethods: ['fatal', 'verbose', 'success'] }]
Requires // comment blocks to end with punctuation on the last line. Valid endings are ., :, ;, ?, !, or paired triple backticks (```). This helps maintain consistency in code comments.
Valid:
// This is a comment with a period.
// Is this a question?
// This is important!
// ``` let foo = 1 + 2 ```Invalid:
-
❌ Missing punctuation.
// This is a comment without punctuation // Comment with unmatched backticks ```
Options:
-
exclusionPrefixes- An array of strings. Comments starting with these prefixes (after//) are excluded from the rule:'uphold-plugin/require-comment-punctuation': ['error', { exclusionPrefixes: ['TODO:', 'FIXME:', 'NOTE:'] }]
With this config, comments like
// TODO: implement thiswill not require punctuation. -
additionalAllowedEndings- An array of strings to extend the default allowed endings (.,:,;,?,!,```):'uphold-plugin/require-comment-punctuation': ['error', { additionalAllowedEndings: [')'] }]
With this config, comments ending with
)will also be considered valid.
This package includes individual exported configs for multiple test frameworks:
- Jest, depending on
eslint-plugin-jest. - Mocha, depending on
eslint-plugin-mocha. - Vitest, depending on
@vitest/eslint-pluginandtypescript.
To use them, import the config directly in your eslint.config.mjs file:
import { defineConfig } from 'eslint/config';
import { mocha as upholdMochaConfig } from 'eslint-config-uphold/configs';
import upholdConfig from 'eslint-config-uphold';
export default defineConfig([
upholdConfig,
{
extends: [upholdMochaConfig],
files: ['test/**/*.js'],
name: 'project-name/tests',
rules: {
'mocha/no-identical-title': 'off'
}
}
]);Those can be imported from eslint-config-uphold/configs:
import { jest, mocha, vitest } from 'eslint-config-uphold/configs';Note
Test configs use top-level await for dynamic module detection and are ESM-only. If your project uses CommonJS, your eslint.config.mjs still supports import() and top-level await.
From ESLint's docs > Configure a Parser:
You can use custom parsers to convert JavaScript code into an abstract syntax tree for ESLint to evaluate. You might want to add a custom parser if your code isn’t compatible with ESLint’s default parser, Espree.
(...)
The following third-party parsers are known to be compatible with ESLint:
- Esprima
- @babel/eslint-parser - A wrapper around the Babel parser that makes it compatible with ESLint.
- @typescript-eslint/parser - A parser that converts TypeScript into an ESTree-compatible form so it can be used in ESLint.
See the ESLint repo for ESLint's guidelines on semantic versioning.
A tilde range is set for the ESLint dependency to pick up any patch changes by default.
For any minor/major upgrades to ESLint it is recommended to update both eslint and eslint-config-uphold and keep them in parallel.
This is down to the fact that no guarantee is made that minor upgrades do not cause conflicts or issues with existing or new rules.
The downside here is a package update is required for any security or other bug fixes.
The benefit however is the included rules are always guaranteed to be stable.
See the MIGRATIONS.md file for migration guides between versions v5 and v6, v6 and v7.
The release of a version is automated via the release GitHub workflow. Run it by clicking the "Run workflow" button.
MIT