Skip to content

Bring the Node and file baselines in line with WordPress's tools - #63

Merged
ahegyes merged 18 commits into
trunkfrom
fix/node-and-file-baselines
Nov 6, 2026
Merged

ahegyes merged 18 commits into
trunkfrom
fix/node-and-file-baselines

Conversation

@ahegyes

@ahegyes ahegyes commented Nov 6, 2026 •

Copy link
Copy Markdown
Owner

Summary

The Node lint baselines missed .jsx files, common unit-test names, the scoped vendor-prefixed/ tree and WordPress's SCSS formatting rules; the .editorconfig, .distignore, ignore rules and script lanes drifted from WordPress core, the release check and CI. This aligns each one, moves the end-to-end tier to tests/EndToEnd, removes the unused PostCSS base, and indents JSON and NEON with tabs.

Type of change

  • PHP source (Composer scripts, php-scoper config)
  • Reusable workflow (.github/workflows/reusable-*.yml)
  • PHPCS / PHPStan ruleset (php/quality-assurance/)
  • Node config (eslint, stylelint, playwright, tsconfig)
  • Documentation
  • Other

Checklist

  • Tests added or updated (PHPUnit suites under tests/Unit/)
  • composer test passes locally
  • If this changes a reusable workflow's inputs/outputs, docs/workflows.md is updated to reflect the new contract
  • If this changes a ruleset, downstream consumer behavior is considered (this repo ships to dev-trunk consumers immediately)

Breaking changes for downstream consumers

  • End-to-end tier: the Playwright factory's testDir and the ESLint base's Playwright scope are tests/EndToEnd; rename tests/e2e when moving the npm pin.
  • ESLint: .jsx files are linted, and *.spec.* files and __tests__/ folders outside tests/EndToEnd get the unit-test rules.
  • Stylelint: the base extends @wordpress/stylelint-config/scss-stylistic, so existing SCSS may report formatting errors to fix.
  • PostCSS: node/postcss.config.base.js and the @wordpress/postcss-plugins-preset peer are gone; wp-scripts' fallback serves a project without a PostCSS config.
  • TypeScript: the typescript peer is ^6.0.0.
  • Release archive: CONTRIBUTING.md, SECURITY.md and postcss.config.* must not ship; the baseline .distignore excludes them, so copy it again.
  • Editor config: .editorconfig is WordPress core's with indent_size = 4, every YAML extension at two spaces and no CRLF rule, so JSON and NEON indent with tabs; copy it and re-indent.

Additive: both lint baselines ignore vendor-prefixed/.

The locks trailed the latest releases within range. Both Composer
locks and the block.json tools' npm lock need nothing; the root npm
lock moves electron-to-chromium to 1.5.469, and no version moves down.

zizmor 1.32.0 is out, but the pinned zizmor-action v0.8.0 carries no
lock for it; v0.8.1 does, and Dependabot's cooldown holds that bump
until it is seven days old, so Workflow Checks stays on 1.31.1.

Assisted-by: Claude Code:claude-opus-5-5
The tracked JSON files used two or four spaces, and the NEON files and
phpunit.dist.xml four, while WordPress core's .editorconfig gives every
file but YAML a tab and WordPress's Prettier config writes JSON with
tabs, so an editor following either mixed the indentation of the file
it touched. Every such file now indents with one tab per level; the
PHPUnit root's attributes keep their column with two tabs and a space,
as the framework's do.

npm writes a lock with its manifest's indentation, so both npm locks
follow their package.json files here rather than in the next update.
Composer writes its locks with four spaces whatever the manifest uses,
so they stay as they are. The change is whitespace only: git diff -w is
empty, and every file parses to the same value as before.

Assisted-by: Claude Code:claude-opus-5-5
The smoke never checked a plain .jsx file, which the ESLint base leaves
unconfigured, or the .spec and __tests__ names wp-scripts treats as unit
tests; it checked the end-to-end folder as tests/e2e beside the
PascalCase test tiers, and no Node baseline was checked against the
vendor-prefixed/ tree the scoping pipeline writes. The SCSS baseline's
formatting rules, which wp-scripts' own default enforces, had no row,
and the release's forbidden-entry rows lacked CONTRIBUTING.md,
SECURITY.md and a PostCSS config.

The smoke now asserts that a .jsx file is linted, that .spec, __tests__
and test/ paths get the unit-test rules while a spec under
tests/EndToEnd gets only the Playwright rules, that both lint baselines
ignore vendor-prefixed/, that the Stylelint base carries the stylistic
preset and that Playwright's testDir is tests/EndToEnd. The release
rows add the three files. All of these fail until the next commits.

Assisted-by: Claude Code:claude-opus-5-5
ESLint discovers only .js, .mjs and .cjs files unless a config names
another extension, and the recommended config names only the
TypeScript ones, so `wp-scripts lint-js` passed a project's .jsx files
without linting them, accessibility rules included. The unit-test
rules matched test/ folders and *.test.* names only, so a *.spec.* file
or a __tests__/ folder lost its vitest checks.

The base names **/*.jsx before the recommended config, as wp-scripts'
own default does, and scopes the unit-test rules to wp-scripts' globs,
which also keep a snapshot or JSON file in a test/ folder unlinted. The
end-to-end folder stays outside them, since its Playwright specs share
the .spec suffix.

Assisted-by: Claude Code:claude-opus-5-5
The Playwright factory's testDir and the ESLint base's Playwright scope
named tests/e2e, the one lowercase folder beside the PascalCase Unit,
Integration, Fixtures and Support tiers, and a name the sibling a8csp
baselines spell tests/EndToEnd. Both now read tests/EndToEnd, and the
README says so. Consumers rename their folder when they move their pin.

Assisted-by: Claude Code:claude-opus-5-5
The ESLint and Stylelint baselines ignored vendor/ and node_modules/
but not vendor-prefixed/, where the scoping pipeline copies each scoped
package whole, its scripts and styles included, while both PHPCS
profiles already skip it. A project-wide lint run, such as an editor's,
then reported findings in third-party code. Both lists now skip it.

Assisted-by: Claude Code:claude-opus-5-5
The base extended @wordpress/stylelint-config/scss, which leaves out
the formatting rules, such as tab indentation and trailing semicolons,
that the scss-stylistic preset adds and that wp-scripts' own default
config extends. wp-scripts format does not touch SCSS, so nothing
checked how a consumer's styles were formatted. The base now extends
scss-stylistic, keeping its ignores, disable-comment reports and the
selector-class-pattern override, and the README names the preset.

Assisted-by: Claude Code:claude-opus-5-5
The PostCSS base rebuilt the chain @wordpress/scripts already uses when
a project has no PostCSS config, while overriding a project's own
cssnano config, and no consumer imported it; it cost an export, a peer
dependency, README rows and a smoke probe. The base, its export, the
@wordpress/postcss-plugins-preset peer, its README rows and its probe
go, and wp-scripts' fallback serves.

@wordpress/e2e-test-utils-playwright was a direct devDependency that
nothing in the package imports and @wordpress/scripts already brings
at the same range, so it goes, and the lock keeps every version.

format:scripts formatted only node/ while lint:scripts also linted the
smoke harness, and neither reached eslint.config.mjs, so a Prettier
finding in the harness had no fixer and the root config was never
linted. Both scripts now take one path list.

Assisted-by: Claude Code:claude-opus-5-5
The baseline .distignore left CONTRIBUTING.md and SECURITY.md in a
plugin's archive, which every consumer then excluded by hand, and it
named a config for every Node tool but PostCSS, whose project config
wp-scripts reads. The release's forbidden-entry check missed the same
three, so a consumer that copied the baseline shipped them unnoticed.

The baseline excludes CONTRIBUTING.md, SECURITY.md and postcss.config.*,
the release's forbidden arms mirror them, and the README lists the
documents. A wp dist-archive build of a probe plugin from the baseline,
holding every forbidden entry, passes the check, which fails the same
build from the previous baseline on these files.

Assisted-by: Claude Code:claude-opus-5-5
The file differed from WordPress core's in two places: it indented JSON
with two spaces, which WordPress's Prettier config rewrites with tabs,
and it applied CRLF to *.txt without core's wp-config-sample.php. It
also inherited what core's file leaves out: no tab width, so editors
drew tabs at their own width rather than the four columns PHPCS and
Prettier align to, and a two-space rule for .yml alone, which handed a
.yaml file the tab default YAML forbids.

The file is now core's with indent_size = 4, [*.{yml,yaml}] in place of
[*.yml], and no CRLF section, as Gutenberg, WooCommerce, PHPStan and
Playground also drop it: core keeps it for the Windows users of its
download zip, and an editor following it rewrote an LF readme.txt as
CRLF. JSON, NEON and XML take the tab default, which the files already
use. The README describes the file.

Assisted-by: Claude Code:claude-opus-5-5
.github/actionlint.yaml was the one YAML file in the repository with
the .yaml extension, beside dependabot.yml, zizmor.yml and every
workflow. actionlint finds .github/actionlint.yml the same way, and
under that name its ignore for the job context's workflow_repository
and workflow_sha holds, while a run without the config reports both.

Assisted-by: Claude Code:claude-opus-5-5
The framework's, the template's and the monorepo's quality-check open
with composer validate --strict, which CI's PHP lint workflow runs as
its own job, but configs' quality-check and quality-check:all did not,
so an invalid or out-of-date manifest passed locally and failed in CI.
Both now open with it, and the command lists in AGENTS.md,
CONTRIBUTING.md, the README and tests/README.md say so; CONTRIBUTING's
separate validate step goes.

Assisted-by: Claude Code:claude-opus-5-5
Composer stops a script after 300 seconds, and Infection over the
unit suite runs longer, so composer test:unit:mutation, test:all and
quality-check:all failed locally with a timeout once Infection had
processed about a sixth of its mutants. The mutation script now opens
with Composer\Config::disableProcessTimeout, as the framework's long
scripts do.

Assisted-by: Claude Code:claude-opus-5-5
npm's quality-check:all passed straight to composer quality-check:all,
which runs only the Composer side, so the cross-tool maximum skipped
the Node baselines' lint and smoke that lint:all runs. audit ran plain
composer audit and npm audit, which fail on development advisories and
abandoned packages the CI gate only reports, so it failed where CI
passed. format:all stopped whenever PHPCBF fixed a file, since PHPCBF
exits 1 then, and never reached the script formatter.

quality-check:all now runs composer quality-check:all, which keeps the
manifest validation, the PHP lint and the tests in Composer's quality
group, and then lint:scripts and lint:config. audit runs the gate's
composer audit --locked --abandoned=report and npm audit --omit=dev
--audit-level=high, and format:all continues on PHPCBF's exit 1 while
still stopping on its exit 2, a fix that failed.

Assisted-by: Claude Code:claude-opus-5-5
The typescript peer admitted any version from 6.0.0, TypeScript 7
included, which typescript-eslint, loaded by the ESLint base whenever
TypeScript is installed, refuses; Dependabot offered that major and its
pull request failed. The peer now reads ^6.0.0, the README says why, and
both npm entries in dependabot.yml ignore TypeScript's major updates.

Assisted-by: Claude Code:claude-opus-5-5
configs was the one repository whose PHPStan run covered its tests,
while the framework, the template and the plugins analyse none of
theirs; its PHPUnit config ran in a fixed order and let a deprecation
pass, where the framework and the template randomize and fail on one;
and Infection wrote its reports to build/infection/, outside the
tests/.cache/ directory every other test tool writes to.

PHPStan's self-lint now analyses php/ alone, PHPUnit runs in random
order and fails on a deprecation, and Infection reports to
tests/.cache/infection/. Three runs of the unit suite under different
seeds pass.

Assisted-by: Claude Code:claude-opus-5-5
The .gitignore carried only the toptal block's exact dotenv names, so
.env.production, auth.json, .npmrc, a private key or an id_rsa file
could be staged by an accidental git add, while the sibling a8csp
repositories ignore all of them. The rules a8csp uses now sit above the
toptal block; no tracked file matches them, so no fixture needs an
exception, and git check-ignore confirms each pattern at the root and
in a nested folder.

Assisted-by: Claude Code:claude-opus-5-5
The fixtures folder was lowercase beside configs' own tests/Unit and
tests/Support, and against the tests/Fixtures folder of the framework
and the template, which name the same tier. It is now tests/Fixtures,
renamed in two steps because macOS's filesystem folds case, and every
reference follows: Quality's paths, the classmap exclusion, the smoke
and lint scripts, the tests ruleset's case-sensitive exclusion, the
tests' fixture paths, the smoke's probes and the layout in AGENTS.md
and tests/README.md. Its subfolders keep their kebab-case names, as
fixture projects. The change is a rename only.

Assisted-by: Claude Code:claude-opus-5-5
@ahegyes ahegyes changed the title Fix/node and file baselines Bring the Node and file baselines in line with WordPress's tools Nov 6, 2026
@ahegyes
ahegyes merged commit 31c8801 into trunk Nov 6, 2026
37 checks passed
@ahegyes
ahegyes deleted the fix/node-and-file-baselines branch November 6, 2026 22:21
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