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
The minimum Node.js versions are v22.12.0, v24.0.0, as certain plugins depend on require('esm'), while matching the minimum versions supported by ESLint v10.
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 --fixThe default configuration uses CommonJS with ECMAScript 2024.
The javascript and typescript named exports also use ECMAScript 2024.
A TypeScript-specific config using typescript-eslint is available.
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';
import tseslint from 'typescript-eslint';
export default defineConfig([
{
extends: [upholdTypescriptConfig],
files: ['**/*.{ts,tsx}'],
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 { defineConfig } from 'eslint/config';
import { typescript as upholdTypescriptConfig } from 'eslint-config-uphold';
export default defineConfig([
{
extends: [upholdTypescriptConfig],
files: ['**/*.{ts,tsx}']
}
]);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 2024.
import { defineConfig } from 'eslint/config';
import { createTypeScriptConfig } from 'eslint-config-uphold';
export default defineConfig([
{
extends: [await createTypeScriptConfig('commonjs', { ecmaVersion: 2025 })], // 'module' for ESM, 'commonjs' for CJS.
files: ['**/*.{ts,cts,tsx}']
}
]);Likewise, a JavaScript-specific config is exported. The usage is similar to TypeScript's config:
import { defineConfig, globalIgnores } from 'eslint/config';
import { javascript as upholdJavascriptConfig } from 'eslint-config-uphold';
export default defineConfig([
{
extends: [upholdJavascriptConfig],
files: ['**/*.{js,jsx}']
},
globalIgnores(['coverage'])
]);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 2024.
import { defineConfig } from 'eslint/config';
import { createJavaScriptConfig } from 'eslint-config-uphold';
export default defineConfig([
{
extends: [createJavaScriptConfig('module', { ecmaVersion: 2025 })], // 'module' for ESM, 'commonjs' for CJS.
files: ['**/*.{js,mjs,jsx}']
}
]);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 (when sinon is installed) |
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.
This rule is automatically enabled when sinon is detected as an installed dependency. The default export (upholdConfig) always enables this rule, while the individual javascript and typescript configs only enable it conditionally.
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';
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'
}
}
]);All configs can be imported from eslint-config-uphold:
import { javascript, jest, mocha, typescript, vitest } from 'eslint-config-uphold';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.
Note
Missing optional plugin dependencies emit a process.emitWarning() notice (type UpholdEslintWarning) instead of writing to console.warn. These warnings are deduplicated by Node.js and can be suppressed with --no-warnings or NODE_NO_WARNINGS=1.
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