build: add ESLint to script/lint — make check cannot currently catch undefined identifiers #152
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
script/lintrunsprettier --check .(package.json:11), which isbyte-identical to
script/fmt-check(package.json:13). Somake checkrunsthe same formatting check twice and performs no static analysis at all.
This repo is a cryptocurrency wallet and has no linter.
Two hard, shipped, user-facing crashes on
mainare the direct consequence,both of the same class (identifier used but not imported):
addToken.js:24usesshowView, neverimported) — filed separately.
(
transactionDetail.js:136usesaddressDotHtml, never imported) — filedseparately.
make checkis green onmaindespite both. A linter withno-undefwouldhave caught each one at commit time. The CI workflow cannot catch them either,
because nothing exercises the views.
There is also a substantial tail of unused imports that a linter would flag:
src/popup/index.js:15(clearViewStack);confirmTx.js(formatUnits,showFlash,flashCopyFeedback,escapeHtml,currentNetwork);settings.js:13(NETWORKS,SUPPORTED_CHAIN_IDS);addressToken.js(
currentAddress,getAddressValueUsd);addressDetail.js(
currentAddress);approval.js(currentNetwork);home.js(
flashCopyFeedback);send.js(escapeHtml);txStatus.js(saveState);helpers.js:7(getAddressValueUsd).Implementation requirements
yarn(nevernpm). Use the modern flatconfig (
eslint.config.js). Per the global convention, prefer the widelyused, well maintained standard:
@eslint/jsrecommended as the base.no-undef(the rule that catches both live crashes)no-unused-vars(catches the dead-import tail above)the popup and content scripts are browser context,
src/background/is aservice worker, the sources use CommonJS
require/module.exports, andtests/is jest.build.jsis Node. SetecmaVersionappropriately.script/lintin addition to the existing prettier check —do not drop formatting enforcement. Keep
script/fmt-checkas it is.package.json'slintscript should invoke eslint too, soyarn run lintandmake lintagree.imports is in scope for this issue. If a rule produces a large volume of
unrelated churn, narrow the rule rather than mass-editing unrelated code,
and say so in the PR.
files directly.
after this, but after this issue lands, both classes must be
linter-detectable. If they have already landed, confirm the linter stays
green; if not, this issue is expected to surface them.
make checkmust remain non-mutating (REPO_POLICIES) — use--fixonlymanually, never inside
script/lint.Definition of done
eslint.config.jsexists, ESLint is a pinned devDependency inpackage.jsonwith a matchingyarn.lockintegrity entry.make lintruns both ESLint and prettier and fails on either.no-undefandno-unused-varsare active and error-level.foo()with no import into anysrc/filemakes
make lintfail. Demonstrate this in the PR description.src/,tests/, andbuild.js.make checkpasses and modifies no files in the working tree.script/lint.TODO.mdupdated in the same commit.clawbot referenced this issue2026-08-09 07:08:12 +02:00
Scope note, found while landing #206:
script/lintisyarn run lint(prettier --check .) on the host and does not containerize. The only containerized path isscript/cibuild, whose Dockerfile runsmake check.That is tolerable while lint is prettier-only, but it stops being tolerable when this issue puts ESLint behind that target: results would then depend on whichever ESLint the host happens to have, which is the exact class of drift the docker-only lint policy exists to prevent.
So this unit should containerize
script/lintas well as add ESLint to it, andmake checkmust reach the containerized path rather than the host one.Plan, on
issue-152-eslint:yarn add --devpinnedeslint+@eslint/js(exact versions,yarn.lockintegrity entries).eslint.config.js(flat),@eslint/jsrecommended as base,sourceType: "commonjs",ecmaVersioncurrent. Per-tree globals so there are no false positives:src/popup/**+src/content/**browser,src/background/**service worker,src/shared/**the intersection both actually use,tests/**jest + node,build.js+tests/e2e/**node.no-undefandno-unused-varserror-level;dist/,node_modules/,src/shared/phishingBlocklist.jsonignored.no-undeffinds beyond it. If a rule turns out to generate churn unrelated to this issue I will narrow the rule and say so in the PR rather than mass-edit.package.jsonlintbecomes eslint + the existingprettier --check ., soyarn run lintandmake lintagree.script/fmt-checkuntouched, no--fixanywhere in the lint path,make checkstays non-mutating.script/lintgets containerized: alintstage in theDockerfileon the already-pinned node base,script/lintrunningdocker build --target lintfrom the host, and an explicit env guard set in the image so themake checkthat runs inside the CI build takes the native path instead of recursing into docker.make checktherefore reaches the containerized linter, not the host's ESLint.foo()call to asrc/file, capture the failingmake lintoutput into the PR body, revert.script/lintupdated to say what it now runs and that it containerizes;TODO.mdmoved on in the same commit.