Skip to content

fix(lint): let prettier have the last word after eslint --fix - #744

Merged
rubenvdlinde merged 1 commit into
developmentfrom
fix/lint-fix-runs-prettier
Aug 24, 2026
Merged

fix(lint): let prettier have the last word after eslint --fix#744
rubenvdlinde merged 1 commit into
developmentfrom
fix/lint-fix-runs-prettier

Conversation

@rubenvdlinde

Copy link
Copy Markdown
Contributor

Closes #739.

Running the repo's own lint fixer produced a file the repo's own format check
rejected — so fixing lint the documented way landed a red Frontend Check (format).

It is not a rule disagreement

eslint-config-prettier is already applied last in eslint.config.mjs, and it
cannot prevent this. That package only turns rules off, and the culprit is
not a formatting rule.

import-extensions/ban-inline-type-imports rewrites an import, and its
autofixer emits its own text:

import type {Page} from '@playwright/test';    // what eslint --fix writes
import type { Page } from '@playwright/test'   // what prettier demands

Any autofixer that constructs source can do this. Disabling formatting rules
does not stop it, because the rule doing the damage is not one of them.

The fix

lint-fix now re-runs the formatter afterwards:

"lint-fix": "npm run lint -- --fix && npm run format:fix"

That makes the two tools ordered rather than competing: eslint decides what
the code says, prettier decides how it looks, in that order, always. It is
also what the config's own doctrine already says — "exactly one of them is
allowed an opinion and prettier is it"
.

Verified both directions on a clean tree:

after eslint --fix alone:   prettier REJECTS   (the bug)
after chaining format:fix:  prettier OK        (fixed)

Why this went unnoticed — worth knowing

The two tools do not cover the same files:

script scope
lint eslint srcsrc only
format prettier "**/*.{js,ts,vue,css,scss}" — everything, including tests/

tests/e2e/** is format-checked but never linted, so an eslint --fix run
there is outside the workflow CI exercises — which is exactly where I hit this.

Whether to widen eslint's scope to tests/ is a genuine decision with a findings
backlog behind it, so it stays in #739 rather than riding along in a one-line
script fix.

Closes #739.

Running the repo's own lint fixer produced a file the repo's own format check
rejected, so fixing lint the documented way landed a red `Frontend Check
(format)`.

It is not a rule disagreement, and eslint-config-prettier cannot prevent it.
That package only turns rules OFF, and the culprit is not a formatting rule:
`import-extensions/ban-inline-type-imports` rewrites an import, and its AUTOFIXER
emits its own text —

    import type {Page} from '@playwright/test';

— which is not what prettier wants (`{ Page }`, no semicolon). Any autofixer that
constructs source can do this; disabling formatting rules does not stop it.

So `lint-fix` now re-runs the formatter afterwards, which makes the two tools
ordered instead of competing: eslint decides what the code SAYS, prettier decides
how it LOOKS, in that order, always. That matches the config's own stated
doctrine — "exactly one of them is allowed an opinion and prettier is it".

Verified both directions on a clean tree: `eslint --fix` alone leaves
prettier --check REJECTING, and the chained script leaves it passing.

WORTH KNOWING, and the reason this went unnoticed: the two tools do not cover
the same files.

    lint    -> eslint src            (src only)
    format  -> prettier "**/*.{js,ts,vue,css,scss}"   (everything, incl. tests/)

`tests/e2e/**` is format-checked but never linted, so an eslint --fix run there
is outside the workflow CI exercises — which is exactly where I hit this. Whether
to widen eslint's scope to tests/ is a real decision with a findings backlog
behind it, so it stays in #739 rather than riding along here.
@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/stackiq @ 392cee2

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
composer ✅ 130/130
npm ✅ 720/720
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman ⏭️
Playwright
Hydra gates

Quality workflow — 2026-08-24 22:52 UTC

Download the full PDF report from the workflow artifacts.

@rubenvdlinde
rubenvdlinde merged commit 8e5f443 into development Aug 24, 2026
86 checks passed
@rubenvdlinde
rubenvdlinde deleted the fix/lint-fix-runs-prettier branch August 24, 2026 22:53
rubenvdlinde added a commit to ConductionNL/filinq that referenced this pull request Aug 25, 2026
Same fix as ConductionNL/stackiq#744; this repo has the identical shape.

`lint-fix` ran eslint's fixer and stopped, so any autofixer that CONSTRUCTS
source could leave the tree failing `format`. `eslint-config-prettier` cannot
prevent that — it only turns rules off, and the offenders are not formatting
rules: `import-extensions/ban-inline-type-imports` and friends rewrite an import
and emit their own text, which prettier then rejects.

Chaining the formatter afterwards makes the two tools ordered rather than
competing: eslint decides what the code SAYS, prettier decides how it LOOKS, in
that order, always.

THE REASON THIS KEEPS BITING, and it is structural rather than anyone's mistake:

    lint    -> eslint src                              (src ONLY)
    format  -> prettier "**/*.{js,ts,vue,css,scss}"    (everything, incl. tests/)

A new file under `tests/e2e/**` is format-checked in CI but NEVER linted, and
nothing local tells you before you push. Measured today on filinq#796, where a
new Playwright spec went red on `Frontend Check (format)` alone while all 42
other checks passed.

Whether to widen eslint's scope to `tests/` is a separate decision with a
findings backlog behind it, and is not settled here.
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