Commit 94ce8b2
authored
ci(js): lint the backend JavaScript, which nothing did (#855)
Closes #825. A file whose methods had landed outside their class passed
the whole CI matrix — **71 green checks** — and the rating buttons it
shipped would not have worked. PHPStan does not read JavaScript, the
functional suite renders the template without executing the module, and
no Playwright spec covers that view. A person reading the diff found it.
## `node --check` lost on evidence, not on taste
It was the cheap candidate: no dependency, no config. Tested against the
actual broken file, it **accepted** it — because it parses a `.js` file
as a CommonJS *script*. ESLint parses it as an ES *module*, which is how
the browser loads it, and reports the parse error on the right line.
That also settles something left open in #842's review. I had written
there that I could not reconcile `node --check` passing with a minimal
reproduction failing, and would not dress it up. The answer is the
parsing mode: the file was a syntax error all along, and `node --check`
read it in the wrong one.
## My reason for not deciding this earlier was wrong
I had said eslint "would bring a JS toolchain into a PHP extension that
has none". One command disproves it: `package.json`,
`package-lock.json`, three devDependencies including Playwright, and CI
already runs `npm install` for the e2e job. ESLint is one more line in a
file that exists.
**No sibling extension lints JavaScript** — `rte_ckeditor_image` has a
`package.json` for commitlint and husky only, `nr-vault` one for
Playwright, `nr-repurpose` none at all. There was no house standard to
copy, which is a reason to set one rather than to wait for it.
## The rule set is small on purpose
`no-undef` is an **error**: it is the rule that catches the defect
above.
`no-unsanitized` is loaded but set to **warn**, and the reason is
measured rather than cautious. As an error it reports 12 assignments,
and **none of them is a hole** — the code escapes through
`escapeHtml()`, visibly, with a comment saying so:
```js
// SECURITY: Escape all external data to prevent XSS
const safeProviderName = escapeHtml(providerInfo.suggestedName);
```
The rule recognises a fixed set of sanitizers and a helper of ours is
not among them. Dropping the plugin was not an option either: two files
already carry `eslint-disable-line no-unsanitized/property` —
suppressions written for a rule that never ran, which become "rule not
found" errors the moment linting is switched on.
Those twelve are triaged in **#854** with the evidence and three
options. A security question belongs where it can be argued and closed,
not in a config comment.
## Verification
| | |
|---|---|
| clean tree | 0 errors, 14 warnings, exit 0 |
| #825's shape reintroduced (method after the class's closing brace) |
parse error, exit 1 |
| `npm ci` from the lockfile, then lint | exit 0 |
Repo rules: no job is defined here — thin caller of the shared
`script-check` reusable, `check-workflow-ownership.php` passes, and
`drift_compare.py` against the org template reports no drift.
`pre-command` installs the devDependencies the runner does not ship.
## One thing worth knowing beyond this repo
This makes nr_llm the first Netresearch TYPO3 extension with a
JavaScript gate. If it holds up, it belongs in the shared template
rather than being rebuilt per repository — otherwise the next extension
gets the same 71-green-checks surprise.
_Assisted by claude-code:claude-opus-5 —
[Session](https://claude.ai/code/session_01MNg1MysJVugv1xo2husknU)_4 files changed
Lines changed: 1212 additions & 3 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
0 commit comments