// ESLint flat config. Static analysis for make check; formatting stays with // prettier (script/fmt-check), so nothing here touches style. // // The sources are CommonJS and are bundled per entrypoint by build.js, so the // globals differ by tree and are declared per tree below. Getting that wrong in // either direction defeats the point: too few globals buries a real no-undef in // false positives, too many hides the next unimported identifier. const js = require("@eslint/js"); const globals = require("globals"); // The extension APIs. MV3 Chrome exposes `chrome`; Firefox exposes both, and // the code feature-detects between them. const extensionGlobals = { chrome: "readonly", browser: "readonly", }; const commonjs = { ecmaVersion: 2024, sourceType: "commonjs", }; module.exports = [ { ignores: ["dist/", "node_modules/"], }, js.configs.recommended, { rules: { // The two rules this config exists for. Both are already // error-level in the recommended set; restated so a future // recommended-set change cannot silently downgrade them. "no-undef": "error", // `_`-prefixed arguments are the deliberate "present for the // interface, unused here" marker: the popup views share one // init(ctx) signature and three of the eight do not read ctx. // An unused catch binding is written `catch {`, which the repo // already does, so caught errors stay checked. "no-unused-vars": ["error", { argsIgnorePattern: "^_" }], // Off tree-wide: it requires every rethrow to carry `{ cause }`, // at 3 sites today (src/shared/balances.js 207 and 215, // tests/e2e/firefox/run.js 131). That is a change to what the // wallet's error paths actually throw, and it is a decision of its // own rather than a side effect of turning a linter on — so it is // off everywhere, including for new code, until that decision is // made. Unlike no-useless-assignment below, this is not an // accommodation of particular sites and must not be scoped to // them. "preserve-caught-error": "off", }, }, // no-useless-assignment stays on everywhere except the two files that // wipe decrypted key material: the `password = null` and // `decryptedSecret = null` assignments after use are dead by construction // — that is what a best-effort wipe is — and the rule's fix is to delete // the wipe. 9 sites: approval.js 582, 593, 618, 648, 692, 703, 728, 764 // and confirmTx.js 459. Everything else in the tree is still checked, so // an ordinary dead store elsewhere is still an error. { files: ["src/popup/views/approval.js", "src/popup/views/confirmTx.js"], rules: { "no-useless-assignment": "off", }, }, // Popup and content scripts: page/window context. { files: ["src/popup/**/*.js", "src/content/**/*.js"], languageOptions: { ...commonjs, globals: { ...globals.browser, ...extensionGlobals }, }, }, // MV3 background: a service worker, with no window and no document. { files: ["src/background/**/*.js"], languageOptions: { ...commonjs, globals: { ...globals.serviceworker, ...extensionGlobals }, }, }, // src/shared is bundled into both, so it may only use what both provide: // the service worker globals are the intersection, plus the extension APIs. { files: ["src/shared/**/*.js"], languageOptions: { ...commonjs, globals: { ...globals.serviceworker, ...extensionGlobals }, }, }, // src/shared/ens.js is the documented exception to the line above: its own // header says POPUP ONLY, it caches in localStorage, and only popup views // require it. Linting it as a service worker would be wrong about the file. { files: ["src/shared/ens.js"], languageOptions: { ...commonjs, globals: { ...globals.browser, ...extensionGlobals }, }, }, // Unit tests: jest on node. { files: ["tests/**/*.test.js"], languageOptions: { ...commonjs, globals: { ...globals.node, ...globals.jest }, }, }, // The build script is a plain node program. { files: ["build.js"], languageOptions: { ...commonjs, globals: { ...globals.node }, }, }, // The e2e harnesses are node programs that also carry, inline, the // callbacks they ship into the browser via page.evaluate — so both // contexts really are present in the same file and both sets of globals // are in scope somewhere in it. { files: ["tests/e2e/**/*.js"], languageOptions: { ...commonjs, globals: { ...globals.node, ...globals.browser, ...extensionGlobals, }, }, }, // This config file itself. { files: ["eslint.config.js"], languageOptions: { ...commonjs, globals: { ...globals.node }, }, }, ];