Skip to content

chore(lint): let the linter see tests/ and scripts/ - #920

Merged
rubenvdlinde merged 1 commit into
developmentfrom
chore/lint-covers-tests-and-scripts
Sep 1, 2026
Merged

chore(lint): let the linter see tests/ and scripts/#920
rubenvdlinde merged 1 commit into
developmentfrom
chore/lint-covers-tests-and-scripts

Conversation

@rubenvdlinde

Copy link
Copy Markdown
Contributor

What

npm run lint was eslint src, so tests/ and scripts/ were never linted at all. Across the fleet that hid roughly 3,900 errors, none of which any CI leg had ever shown.

Most of it was the config, not the code, and the same two defects were in every app.

scripts/ had no config block at all

These are CommonJS Node CLI checkers, and flat config defaults every .js to ESM with browser-ish globals, so eslint read the CommonJS wrapper itself as undefined identifiers: require, process, __dirname, __filename, module. A scripts/** block now declares the environment, and a second block covers scripts/**/*.mjs, which is genuinely ESM and needs Node's globals without the CommonJS wrapper.

Declaring beats suppressing: no-undef is the rule that catches a genuinely misspelled identifier, and dozens of fake findings would bury a real one.

The tests block applied a non-TypeScript-aware rule to TypeScript

It named tests/**/*.ts while setting the core no-unused-vars, which v9 deliberately turns off for .ts in favour of the @typescript-eslint version. The core rule reads parameter names inside a function type as bindings, so

t?: (app: string, key: string) => string

reported app and key as unused variables, and every unused catch (e) in a .ts spec reported twice. The block is now split: .js/.mjs on the core rule, .ts/.tsx on the TypeScript one, same patterns on both.

Two more that made eslint report on things it should not have

  • Stale eslint-disable comments naming plugins eslint 10 no longer registers. An inline disable for an unregistered plugin is itself an error (Definition for rule "n/shebang" was not found), so these were findings about the suppression, not the code.
  • no-irregular-whitespace / shell files: eslint was parsing a .sh script that matched a **/*.test.* glob and reporting a syntax error about a file it should never have opened.

The real findings

The useful part: dead locals, unused imports, dead helper functions, unused catch bindings, extensionless relative imports, and == null comparisons spelled out so they still match null and undefined.

Where a rule was genuinely wrong for the code, it got a reasoned exception rather than a silent one, e.g. a suite that compiles as CommonJS and must use require because import.meta is a syntax error there.

Verified

  • npm run lint (now src tests scripts): 0 errors
  • prettier --check: clean
  • unit suite: green
  • app-specific checkers (check:manifest, check:l10n, parity guards) still run and report the same baselines

Part of a fleet-wide pass. The lint script is widened only now that the tree is actually clean, so a half-done app cannot report green.

`npm run lint` was `eslint src`, so two whole trees were never linted. Across
the fleet that hid roughly 3,900 errors, none of which any CI leg had shown.

Most of it was the config, not the code, and the same two defects were in
every app.

**scripts/ had no config block at all.** These are CommonJS Node CLI checkers,
and flat config defaults every `.js` to ESM with browser-ish globals, so eslint
read the CommonJS wrapper itself as undefined identifiers: `require`,
`process`, `__dirname`, `__filename`, `module`. A `scripts/**` block now
declares the environment. Declaring beats suppressing here: `no-undef` is the
rule that catches a genuinely misspelled identifier, and dozens of fake
findings would bury a real one. A second block covers `scripts/**/*.mjs`, which
is ESM and needs Node's globals without the CommonJS wrapper.

**The tests block applied a non-TypeScript-aware rule to TypeScript.** It named
`tests/**/*.ts` while setting the CORE `no-unused-vars`, which v9 deliberately
turns off for `.ts` in favour of the `@typescript-eslint` version. The core
rule reads the parameter names inside a function TYPE as bindings, so

    t?: (app: string, key: string) => string

reports `app` and `key` as unused variables, and every unused `catch (e)` in a
`.ts` spec reports twice. The block is split now: `.js`/`.mjs` on the core
rule, `.ts`/`.tsx` on the TypeScript one, same patterns on both.

Also: stale `eslint-disable` comments naming plugins eslint 10 no longer
registers, which are themselves errors ("Definition for rule ... was not
found"), and a rule that must not parse shell scripts.

The genuinely real findings were the useful part: dead locals, unused imports,
dead helper functions, unused `catch` bindings, extensionless relative imports,
and a handful of `== null` comparisons spelled out so they still match null AND
undefined.

Verified per app: `npm run lint` 0 errors over src + tests + scripts,
`prettier --check` clean, and the unit suite still green.

One finding here was a real defect rather than tidiness. `no-dupe-keys`
flagged this assertion:

    expect(moderationItemTitle({ name: '   ', name: 'Real' })).toBe('Real')

The second `name` silently overwrites the first, so the object actually built
was `{ name: 'Real' }` and the test named "ignores blank/whitespace title
fields" never took the blank branch at all. It could not have failed for the
reason it claimed. It now passes `{ name: '   ', title: 'Real' }`, which does
exercise the fall-through.

`TITLE_FIELDS` carried the same slip, listing `'name'` twice, so the second
entry was dead. Removed. The suite is 5 passed.
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/stackiq @ 5d608e6

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-manifest
check-vue-demi
test-l10n
format
check-schema-l10n
check-l10n-js
composer ✅ 130/130
npm ✅ 711/711
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman ⏭️
Playwright ⏭️ deferred — runs on the promotion into beta/main, not on a pull request into development
Hydra gates

Quality workflow — 2026-09-01 10:05 UTC

Download the full PDF report from the workflow artifacts.

@rubenvdlinde
rubenvdlinde merged commit 8e331e9 into development Sep 1, 2026
50 checks passed
@rubenvdlinde
rubenvdlinde deleted the chore/lint-covers-tests-and-scripts branch September 1, 2026 10:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant