Linter: update to eslint v9

This eslint version brings breaking changes related to the eslint config.
eslint-airbnb-config has yet to release a compatible version with the
new format, and it generally looks unmaintained, hence we drop the dependency
in favor of the built-in recommended configs.
This commit is contained in:
larabr 2025-09-16 18:26:37 +02:00 committed by larabr
parent 7619706e33
commit f12f1bc662
16 changed files with 636 additions and 569 deletions

View file

@ -1,100 +0,0 @@
{
"extends": [
"airbnb-base",
"airbnb-typescript/base"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 2020,
"sourceType": "module",
"project": "tsconfig.eslint.json"
},
"settings": {
"import/resolver": {
"typescript": { "alwaysTryTypes": true }
}
},
"globals": {
"window": "readonly",
"btoa": "readonly",
"atob": "readonly",
"globalThis": "readonly"
},
"env": {
"es6": true,
"mocha": true,
"browser": true
},
"plugins": [
"@typescript-eslint",
"import",
"chai-friendly",
"@protontech/enforce-uint8array-arraybuffer"
],
"rules": {
"prefer-spread": "off",
"no-restricted-syntax": "off",
"arrow-parens": ["error", "always"],
"indent": "off",
"comma-dangle": ["error", "never"],
"consistent-return": "off",
"object-curly-newline": "off",
"prefer-template": "off",
"no-plusplus": "off",
"no-continue": "off",
"no-bitwise": "off",
"no-await-in-loop": "off",
"no-sequences": "warn",
"no-param-reassign": "warn",
"no-return-assign": "warn",
"no-else-return": ["error", { "allowElseIf": true }],
"no-shadow": "off",
"no-unused-expressions": "off",
"no-undef": "error",
"@typescript-eslint/no-unused-expressions": "off",
"chai-friendly/no-unused-expressions": [ "error", { "allowShortCircuit": true } ],
"arrow-body-style": "off",
"space-before-function-paren": "off",
"operator-linebreak": "off",
"implicit-arrow-linebreak": "off",
"no-underscore-dangle": "off",
"import/no-unresolved": ["error", {
"ignore": ["^react$", "ttag", ".data"]
}],
"import/prefer-default-export": "off",
"import/no-extraneous-dependencies": "off",
"import/no-unassigned-import": "error",
"import/named": "error",
"import/extensions": "error",
"max-len": ["error", {
"ignoreComments": true,
"code": 120,
"ignoreStrings": true,
"ignoreTemplateLiterals": true,
"ignoreRegExpLiterals": true
}],
"no-restricted-imports": ["error", {
"name": "openpgp",
"message": "Please import from 'lib/openpgp' instead."
}],
"no-multiple-empty-lines": ["error"],
"no-trailing-spaces": ["error"],
"eol-last": ["error"],
"camelcase": ["error", {"allow": ["openpgp_*"]}],
"padded-blocks": "off",
"@protontech/enforce-uint8array-arraybuffer/enforce-uint8array-arraybuffer": "error",
"@typescript-eslint/naming-convention": ["error", {
"selector": "typeLike",
"format": ["PascalCase", "UPPER_CASE"]
}],
"@typescript-eslint/ban-ts-comment": "off",
"@typescript-eslint/consistent-type-imports": "error",
"@typescript-eslint/consistent-type-exports": "error",
"@typescript-eslint/no-unused-vars": "error",
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/indent": ["error", 4],
"@typescript-eslint/comma-dangle": "off"
}
}

116
eslint.config.mjs Normal file
View file

@ -0,0 +1,116 @@
// @ts-check
import eslint from '@eslint/js';
import { defineConfig } from 'eslint/config';
import tseslint from 'typescript-eslint';
import globals from 'globals';
// @ts-expect-error
import pluginChaiFriendly from 'eslint-plugin-chai-friendly';
import pluginImport from 'eslint-plugin-import';
// @ts-expect-error
import pluginEnforceUint8ArrayArrayBuffer from '@protontech/eslint-plugin-enforce-uint8array-arraybuffer';
import pluginStylistic from '@stylistic/eslint-plugin';
export default defineConfig(
eslint.configs.recommended,
tseslint.configs.recommended,
{
languageOptions: {
ecmaVersion: 2022,
sourceType: 'module',
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname
},
globals: {
...globals.browser,
...globals.mocha
}
},
settings: {
'import/resolver': {
typescript: { alwaysTryTypes: true }
}
},
plugins: {
'chai-friendly': pluginChaiFriendly,
'import': pluginImport,
'@protontech/enforce-uint8array-arraybuffer': pluginEnforceUint8ArrayArrayBuffer,
'@stylistic': pluginStylistic
},
rules: {
'prefer-spread': 'off',
'no-restricted-syntax': 'off',
'arrow-parens': ['error', 'always'],
'indent': 'off',
'comma-dangle': ['error', 'never'],
'consistent-return': 'off',
'object-curly-newline': 'off',
'prefer-template': 'off',
'no-plusplus': 'off',
'no-continue': 'off',
'no-bitwise': 'off',
'no-await-in-loop': 'off',
'no-sequences': 'warn',
'no-param-reassign': 'warn',
'no-return-assign': 'warn',
'no-else-return': ['error', { allowElseIf: true }],
'no-shadow': 'off',
'no-unused-expressions': 'off',
'no-undef': 'error',
'no-cond-assign': 'error',
'one-var-declaration-per-line': 'error',
'new-cap': ['error', {
newIsCap: true,
newIsCapExceptions: [],
capIsNew: false
}],
'class-methods-use-this': 'error',
'chai-friendly/no-unused-expressions': [ 'error', { allowShortCircuit: true } ],
'arrow-body-style': 'off',
'space-before-function-paren': 'off',
'operator-linebreak': 'off',
'implicit-arrow-linebreak': 'off',
'no-underscore-dangle': 'off',
'import/no-unresolved': ['error', {
ignore: ['^react$', 'ttag', '.data']
}],
'import/prefer-default-export': 'off',
'import/no-extraneous-dependencies': 'off',
'import/no-unassigned-import': 'error',
'import/named': 'error',
'import/extensions': 'error',
'max-len': ['error', {
ignoreComments: true,
code: 120,
ignoreStrings: true,
ignoreTemplateLiterals: true,
ignoreRegExpLiterals: true
}],
'no-restricted-imports': ['error', {
name: 'openpgp',
message: 'Please import from \'lib/openpgp\' instead.'
}],
'no-multiple-empty-lines': ['error'],
'no-trailing-spaces': ['error'],
'eol-last': ['error'],
'camelcase': ['error', {allow: ['openpgp_*']}],
'padded-blocks': 'off',
'@protontech/enforce-uint8array-arraybuffer/enforce-uint8array-arraybuffer': 'error',
'@typescript-eslint/naming-convention': ['error', {
selector: 'typeLike',
format: ['PascalCase', 'UPPER_CASE']
}],
'@typescript-eslint/ban-ts-comment': 'off',
'@typescript-eslint/consistent-type-imports': 'error',
'@typescript-eslint/consistent-type-exports': 'error',
'@typescript-eslint/no-empty-object-type': ['error', { allowInterfaces: 'with-single-extends' }],
'@typescript-eslint/no-unused-expressions': 'off',
'@typescript-eslint/no-unused-vars': 'error',
'@typescript-eslint/no-empty-function': 'off',
'@stylistic/indent': ['error', 4],
'@stylistic/quotes': ['error', 'single'],
'@stylistic/no-multiple-empty-lines': ['error', { max: 1 }]
}
}
);

View file

@ -1,3 +1,5 @@
/* eslint-disable @typescript-eslint/no-require-imports */
/* global require, process, module */
const { firefox, chromium, webkit } = require('playwright');
process.env.CHROME_BIN = chromium.executablePath();
@ -36,7 +38,7 @@ module.exports = function(config) {
webpack: {
optimization: {
nodeEnv: 'production', // silence OpenPGP.js debug errors, triggered by some tests
nodeEnv: 'production' // silence OpenPGP.js debug errors, triggered by some tests
},
resolve: {
fallback: {

View file

@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/lines-between-class-members */
// Copied from https://github.com/paulmillr/noble-hashes/blob/main/test/misc/md5.ts
import { HashMD } from '@noble/hashes/_md';
@ -36,6 +35,7 @@ class MD5 extends HashMD<MD5> {
}
protected process(view: DataView, offset: number): void {
// eslint-disable-next-line no-param-reassign
for (let i = 0; i < 16; i++, offset += 4) MD5_W[i] = view.getUint32(offset, true);
// Compression function main loop, 64 rounds
let { A, B, C, D } = this;

View file

@ -30,7 +30,7 @@ const TimeoutHandler = {
setTimeout(
() => Argon2S2K.reloadWasmModule(),
10 * SECOND
) as any as number
)
: undefined;
}
};

View file

@ -30,7 +30,6 @@ export async function unsafeSHA1(data: MaybeWebStream<Uint8Array<ArrayBuffer>>)
const { sha1 } = await import('@noble/hashes/sha1');
const hashInstance = sha1.create();
const inputReader = data.getReader(); // AsyncInterator is still not widely supported
// eslint-disable-next-line no-constant-condition
while (true) {
const { done, value } = await inputReader.read();
if (done) {

View file

@ -85,7 +85,7 @@ export const canKeyEncrypt = async (publicKey, date = serverTime()) => {
try {
await encryptMessage({ textData: 'test message', encryptionKeys: publicKey, date });
return true;
} catch (e) {
} catch {
return false;
}
};

View file

@ -1,5 +1,3 @@
/// <reference path="./verify.d.ts" />
import { removeTrailingSpaces } from './utils';
import { verifyMessage } from './verify';
import { VERIFICATION_STATUS, MAX_ENC_HEADER_LENGTH } from '../constants';

View file

@ -1,4 +1,4 @@
/* eslint-disable @typescript-eslint/indent */
/* eslint-disable @stylistic/indent */
import type {
VerifyOptions,
VerifyMessageResult as openpgp_VerifyMessageResult,

2
lib/pmcrypto.d.ts vendored
View file

@ -1,4 +1,4 @@
/* eslint-disable @typescript-eslint/indent */
/* eslint-disable @stylistic/indent */
import {
type DecryptOptions,
type DecryptMessageResult as openpgp_DecryptMessageResult,

View file

@ -30,7 +30,7 @@ export function concatArrays(arrays: Uint8Array<ArrayBuffer>[]): Uint8Array<Arra
return result;
}
const isString = (data: any): data is string | String => {
const isString = (data: unknown): data is string => {
return typeof data === 'string' || data instanceof String;
};

928
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -14,7 +14,7 @@
],
"scripts": {
"test": "karma start karma.conf.js",
"lint": "eslint lib test --quiet",
"lint": "eslint eslint.config.mjs lib test",
"postversion": "git push && git push --tags",
"test-type-definitions": "tsc"
},
@ -29,13 +29,15 @@
},
"homepage": "https://github.com/ProtonMail/pmcrypto#readme",
"dependencies": {
"@openpgp/web-stream-tools": "~0.1.3",
"@noble/hashes": "^1.8.0",
"@openpgp/web-stream-tools": "~0.1.3",
"jsmimeparser": "npm:@protontech/jsmimeparser@^3.0.2",
"openpgp": "npm:@protontech/openpgp@~6.2.2"
},
"devDependencies": {
"@protontech/eslint-plugin-enforce-uint8array-arraybuffer": "^1.0.0",
"@eslint/js": "^9.35.0",
"@protontech/eslint-plugin-enforce-uint8array-arraybuffer": "^2.0.0",
"@stylistic/eslint-plugin": "^5.3.1",
"@types/bn.js": "^5.2.0",
"@types/chai": "^5.2.2",
"@types/chai-as-promised": "^7.1.8",
@ -43,16 +45,12 @@
"@types/mocha": "^9.1.1",
"@types/sinon": "^17.0.4",
"@types/webpack-env": "^1.18.8",
"@typescript-eslint/eslint-plugin": "^7.18.0",
"@typescript-eslint/parser": "^7.18.0",
"bn.js": "^5.2.2",
"chai": "^5.2.1",
"chai-as-promised": "^7.1.2",
"elliptic": "^6.6.1",
"eslint": "^8.57.1",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-config-airbnb-typescript": "^18.0.0",
"eslint-import-resolver-typescript": "^3.10.1",
"eslint": "^9.35.0",
"eslint-import-resolver-typescript": "^4.4.4",
"eslint-plugin-chai-friendly": "^1.1.0",
"eslint-plugin-import": "^2.32.0",
"karma": "^6.4.4",
@ -67,6 +65,7 @@
"sinon": "^19.0.5",
"ts-loader": "^9.5.4",
"typescript": "^5.9.2",
"typescript-eslint": "^8.43.0",
"web-streams-polyfill": "^3.3.3",
"webpack": "^5.101.3",
"webpack-cli": "^4.10.0"

View file

@ -2,7 +2,7 @@ import { expect } from 'chai';
import { ec as EllipticCurve } from 'elliptic';
import BN from 'bn.js';
import { decryptKey, enums, type KeyID, type PacketList } from '../../lib/openpgp';
import { decryptKey, enums, type PublicKeyEncryptedSessionKeyPacket, type KeyID, type PacketList } from '../../lib/openpgp';
import { generateKey, generateForwardingMaterial, doesKeySupportForwarding, encryptMessage, decryptMessage, readMessage, readKey, readPrivateKey, serverTime } from '../../lib';
import { computeProxyParameter, isForwardingKey } from '../../lib/key/forwarding';
import { hexStringToArray, concatArrays, arrayToHexString } from '../../lib/utils';
@ -19,9 +19,13 @@ async function testProxyTransform(
const ciphertext = await readMessage({ armoredMessage: armoredCiphertext });
for (
// missing PublicKeyEncryptedSessionKeyPacket field declarations
const packet of ciphertext.packets.filterByTag(enums.packet.publicKeyEncryptedSessionKey) as PacketList<any>
const packet of ciphertext.packets.filterByTag(
enums.packet.publicKeyEncryptedSessionKey
) as PacketList<PublicKeyEncryptedSessionKeyPacket>
) {
// @ts-expect-error missing `publicKeyID` field declaration
if (packet.publicKeyID.equals(originalSubkeyID)) {
// @ts-expect-error missing `encrypted` field
const bG = packet.encrypted.V;
const point = curve.curve.decodePoint(bG.subarray(1).reverse());
const bkG = new Uint8Array(
@ -31,7 +35,9 @@ async function testProxyTransform(
.toArray('le', 32)
);
const encoded = concatArrays([new Uint8Array([0x40]), bkG]);
// @ts-expect-error missing `encrypted` field
packet.encrypted.V = encoded;
// @ts-expect-error missing `publicKeyID` field
packet.publicKeyID = finalRecipientSubkeyID;
}
}

View file

@ -1,11 +0,0 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"noEmitOnError": false
},
"include": [
"./test/**/*",
"./lib/**/*",
"*.js"
]
}

View file

@ -12,8 +12,4 @@
"types": ["webpack-env", "mocha"], // avoid pulling in node types
"lib": ["dom", "esnext"]
},
"include": [
"./test/**/*"
],
"files": ["./lib/index.ts"]
}