Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ npm test # Jest acro
## Architectural decisions

- **Package layering**: `node-packages/*` (npm workspaces, `@rtcamp` scope) and `composer-packages/*` (Composer, `rtcamp` vendor) are independent ecosystems sharing one repo for coordinated development only — nothing internal is shared or imported across that boundary.
- **Release via subtree split, not a plain publish**: both ecosystems release with `git subtree split --prefix=<dir>`. Composer packages split to standalone mirror repos (`rtCamp/wp-phpcs`, `rtCamp/wp-phpstan`) on a `v*` tag push; npm packages split to branches of this same repo (`npm/<dirname>`) on every push to `main`.
- **The npm split is a temporary stopgap**: today `@rtcamp/wp-tooling` and friends install only via `git+https://github.com/rtCamp/wp-tooling.git#npm/<dirname>` — there is no public-registry publish yet. A future workflow will `npm publish` directly; nothing here is meant to change in anticipation of that.
- **Composer packages release by subtree split**: a `v*` tag push runs `release-php.yml`, which splits each `composer-packages/*` directory with `git subtree split --prefix=<dir>` to its read-only mirror repo (`rtCamp/wp-phpcs`, `rtCamp/wp-phpstan`) and tags it there for Packagist.
- **npm packages publish to the npm registry**: each `node-packages/*` workspace is published to npmjs.com as `@rtcamp/<dirname>` (public access, set in its `publishConfig`), with its own version. Every push to `main` also splits each workspace to an `npm/<dirname>` branch of this repo, which keeps serving git-URL installs for projects that have not moved to registry versions.
- **Dependency discipline differs by package type**: `wp-tooling` ships zero runtime dependencies (full banned-package list in its own `AGENTS.md`); the three config packages instead rely on `peerDependencies` — consumers bring their own `eslint`/`stylelint`/`tailwindcss`.
- **Prefer official WordPress tooling**: build custom only when no official `@wordpress/*` (or upstream PHPCS/PHPStan) option covers the need, or the official option blocks a hard constraint. `eslint-config` extends `@wordpress/eslint-plugin`, `stylelint-config` extends `@wordpress/stylelint-config`, `wp-phpcs` layers on WPCS/VIPCS/PHPCompatibilityWP/Slevomat, `wp-phpstan` wraps `szepeviktor/phpstan-wordpress`.
- **PHP version skew is intentional**: the packages target PHP `>=8.2` (the rtCamp plugin/theme floor) while the monorepo root requires `>=8.4.1` for `symplify/monorepo-builder`. `monorepo-builder validate` will flag this — expected, not a bug.
Expand All @@ -51,7 +51,7 @@ For full release-mechanism details, see `.github/workflows/release-php.yml` and
- There is no root `composer test` / `composer check` — root `composer.json` has no `scripts` key. Run tests from inside each `composer-packages/*` directory.
- `wp-tooling release:bump` / `release:changelog` are for **consumer** WordPress plugins/themes, not this monorepo. They require a `.php` file with a `Plugin Name:` header at cwd root and throw otherwise.
- Subtree-split artifacts — the `npm/<dirname>` branches and the `wp-phpcs`/`wp-phpstan` mirror repos — are generated. Never hand-edit them; a diverged target fails the next split run instead of being silently rewritten.
- `npm install @rtcamp/wp-tooling` does not resolve from the public npm registry today; the current install path is a git URL (`#npm/wp-tooling`). Don't assume a registry publish exists yet — see Architectural decisions above.
- Never use a `v*` tag for an npm release: `release-php.yml` fires on every `v*` tag and tags share one namespace, so it would cut a Composer release too. Tag npm releases `<name>@<version>` (for example `@rtcamp/eslint-config@1.1.0`).
- Every one of the six packages carries its own `LICENSE` file — `git subtree split` only carries history of files *inside* the split directory, so the root `LICENSE` never reaches a mirror repo or split branch.
- `ci.yml` runs every workspace lint, every Jest suite with its coverage threshold (Node 22.19 and 24), and each `composer-packages/*` suite installed standalone (PHP 8.2, 8.3 and 8.4) on every PR and push to main. A red CI blocks the merge that would otherwise ship straight onto the `npm/*` branches.
- `.vscode/extensions.json` only recommends extensions from verified publishers (Microsoft, GitHub, Red Hat, EditorConfig Foundation) — don't add others, regardless of popularity.
Expand Down
2 changes: 2 additions & 0 deletions composer-packages/phpcs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).

## [Unreleased]

## [1.0.1] - 2026-10-01

### Added

- `homepage`, `authors` and `support` metadata in `composer.json`, so the Packagist
Expand Down
2 changes: 2 additions & 0 deletions composer-packages/phpstan/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).

## [Unreleased]

## [1.0.1] - 2026-10-01

### Added

- `homepage`, `authors` and `support` metadata in `composer.json`, so the Packagist
Expand Down
2 changes: 2 additions & 0 deletions node-packages/eslint-config/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).

## [Unreleased]

## [1.1.0] - 2026-10-01

### Changed

- `engines.node` raised to `>=22.19` to match the rest of the monorepo (`@rtcamp/wp-tooling` needs it for Lighthouse 13).
Expand Down
18 changes: 16 additions & 2 deletions node-packages/eslint-config/README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,27 @@
# @rtcamp/eslint-config
<h1 align="center">@rtcamp/eslint-config</h1>

rtCamp's shareable **ESLint flat config** for WordPress projects. Extends
<p align="center">
<a href="https://github.com/rtCamp/wp-tooling/blob/main/node-packages/eslint-config/LICENSE"><img src="https://img.shields.io/badge/license-GPL--2.0--or--later-blue.svg" alt="License: GPL-2.0-or-later"></a>
<a href="https://www.npmjs.com/package/@rtcamp/eslint-config"><img src="https://img.shields.io/npm/v/@rtcamp/eslint-config.svg" alt="npm version"></a>
<img src="https://img.shields.io/badge/node-%3E%3D22.19-339933.svg" alt="Node 22.19+">
</p>

<p align="center">
rtCamp's shareable ESLint flat config for WordPress projects.
</p>

---

It extends
`@wordpress/eslint-plugin` (recommended), `@eslint-community/eslint-plugin-eslint-comments`, and
`eslint-plugin-jest` (scoped to `**/*.test.js`).

> Requires ESLint v9+ (flat config). This package is a flat-config array, not a legacy `.eslintrc`.

## Install

Requires Node.js 22.19+.

```bash
npm install --save-dev @rtcamp/eslint-config eslint @wordpress/eslint-plugin
```
Expand Down
2 changes: 1 addition & 1 deletion node-packages/eslint-config/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@rtcamp/eslint-config",
"version": "1.0.0",
"version": "1.1.0",
"description": "rtCamp shareable ESLint flat config for WordPress projects — extends @wordpress/eslint-plugin.",
"license": "GPL-2.0-or-later",
"author": "rtCamp",
Expand Down
2 changes: 2 additions & 0 deletions node-packages/stylelint-config/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).

## [Unreleased]

## [1.1.0] - 2026-10-01

### Changed

- `engines.node` raised to `>=22.19` to match the rest of the monorepo (`@rtcamp/wp-tooling` needs it for Lighthouse 13).
Expand Down
18 changes: 16 additions & 2 deletions node-packages/stylelint-config/README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,24 @@
# @rtcamp/stylelint-config
<h1 align="center">@rtcamp/stylelint-config</h1>

rtCamp's shareable **Stylelint config** for WordPress projects. Extends
<p align="center">
<a href="https://github.com/rtCamp/wp-tooling/blob/main/node-packages/stylelint-config/LICENSE"><img src="https://img.shields.io/badge/license-GPL--2.0--or--later-blue.svg" alt="License: GPL-2.0-or-later"></a>
<a href="https://www.npmjs.com/package/@rtcamp/stylelint-config"><img src="https://img.shields.io/npm/v/@rtcamp/stylelint-config.svg" alt="npm version"></a>
<img src="https://img.shields.io/badge/node-%3E%3D22.19-339933.svg" alt="Node 22.19+">
</p>

<p align="center">
rtCamp's shareable Stylelint config for WordPress projects.
</p>

---

It extends
`@wordpress/stylelint-config` and `@wordpress/stylelint-config/scss`.

## Install

Requires Node.js 22.19+.

```bash
npm install --save-dev @rtcamp/stylelint-config stylelint @wordpress/stylelint-config stylelint-scss
```
Expand Down
2 changes: 1 addition & 1 deletion node-packages/stylelint-config/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@rtcamp/stylelint-config",
"version": "1.0.0",
"version": "1.1.0",
"description": "rtCamp shareable Stylelint config for WordPress projects — extends @wordpress/stylelint-config (+ scss).",
"license": "GPL-2.0-or-later",
"author": "rtCamp",
Expand Down
2 changes: 2 additions & 0 deletions node-packages/tailwind-config/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).

## [Unreleased]

## [1.1.0] - 2026-10-01

### Changed

- `engines.node` raised to `>=22.19` to match the rest of the monorepo (`@rtcamp/wp-tooling` needs it for Lighthouse 13).
Expand Down
20 changes: 17 additions & 3 deletions node-packages/tailwind-config/README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,24 @@
# @rtcamp/tailwind-config
<h1 align="center">@rtcamp/tailwind-config</h1>

rtCamp's Tailwind CSS v4 integration for WordPress themes: a shareable PostCSS config plus a
webpack plugin that keeps Tailwind theme tokens in sync with `theme.json`.
<p align="center">
<a href="https://github.com/rtCamp/wp-tooling/blob/main/node-packages/tailwind-config/LICENSE"><img src="https://img.shields.io/badge/license-GPL--2.0--or--later-blue.svg" alt="License: GPL-2.0-or-later"></a>
<a href="https://www.npmjs.com/package/@rtcamp/tailwind-config"><img src="https://img.shields.io/npm/v/@rtcamp/tailwind-config.svg" alt="npm version"></a>
<img src="https://img.shields.io/badge/node-%3E%3D22.19-339933.svg" alt="Node 22.19+">
</p>

<p align="center">
rtCamp's Tailwind CSS v4 PostCSS config and theme.json sync for WordPress themes.
</p>

---

It ships a shareable PostCSS config plus a webpack plugin that keeps Tailwind theme tokens in
sync with `theme.json`.

## Install

Requires Node.js 22.19+.

```bash
npm install --save-dev @rtcamp/tailwind-config tailwindcss @tailwindcss/postcss
```
Expand Down
2 changes: 1 addition & 1 deletion node-packages/tailwind-config/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@rtcamp/tailwind-config",
"version": "1.0.0",
"version": "1.1.0",
"description": "rtCamp shareable Tailwind CSS v4 PostCSS config + theme.json→Tailwind webpack plugin for WordPress projects.",
"license": "GPL-2.0-or-later",
"author": "rtCamp",
Expand Down
6 changes: 4 additions & 2 deletions node-packages/wp-tooling/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).

## [Unreleased]

## [2.0.0] - 2026-10-01
Comment thread
aryanjasala marked this conversation as resolved.
Resolved

### Added

- `detect-changes --strict` (library: `detectChanges({ strict: true })`): a failed `git diff` exits 1 (throws the new `DetectChangesError`, code `EDIFFFAIL`, exported from `@rtcamp/wp-tooling/ci`) instead of reporting zero changes, which skipped every job gated on the counts and left the run green. Off by default, so existing callers see no change; CI callers should turn it on. The stderr wording keeps the "git diff failed" phrase that rtCamp/wp-shared-workflows matches today.
Expand All @@ -26,7 +28,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
- fill `testVersion` from the `Requires PHP` header (PHPCompatibility aborts on the first line of every file without it), `minimum_wp_version` from `Requires at least`, the text domain from `Text Domain`, and the prefixes from the text domain and the PSR-4 namespace;
- accept PSR-4 class file names, and exempt block `render.php` files from the global-variable prefix and text-domain-mismatch checks, since core includes them inside a function and they translate with `block.json`'s text domain;
- lint `tests/`, exempting it from the prefix, VIP file-operation and remote-data, `ini_set` and global-override rules by sniff name. An exclude-pattern on a re-referenced standard such as `WordPress-Docs` has no effect, because its sniffs are already loaded;
- declare `rtcamp/wp-phpcs` as the only dev dependency, with two `composer.json` wiring entries without which `composer require` fails: the `rtCamp/wp-phpcs` VCS repository, since the package is not on Packagist, and `allow-plugins` for the Composer installer that registers the standards.
- declare `rtcamp/wp-phpcs` as the only dev dependency, with two `composer.json` wiring entries without which `composer require` fails: the `rtCamp/wp-phpcs` VCS repository, so the install works whether or not Packagist serves the package, and `allow-plugins` for the Composer installer that registers the standards.

Every PHP file the bundled `wp/*`, `wp-api/*` and `setup/phpunit` scaffolds render (classes, tests and the PHPUnit bootstrap), and the five `utility/*` accessor snippets, passes both.
- `automattic/vipwpcs` as `lint/phpcs/vip`'s dev dependency, with `allow-plugins` wiring for `dealerdirect/phpcodesniffer-composer-installer`, which WPCS and VIPCS depend on: without it a non-interactive `composer require` exits 1 and no standard is registered. The `setup` skill's install command and `docs/examples.md` use the same package.
Expand All @@ -46,7 +48,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
- PHPCS scaffolds exclude intentionally broken AI evaluation fixtures. The standalone server profiler uses short arrays and documents the specific PHPCS exceptions required by WP-CLI evaluation, privileged CLI query data and STDERR diagnostics.
- Feature hooks: `readEnv`/`setEnv` and `readDefine`/`setDefine` treat the key or define name as a literal. They were interpolated into a regular expression, so a name containing `.` or another metacharacter could read or flip a different line.
- `wp-tooling features`: when `npm install` fails after enabling a feature, the retry commands it prints no longer put runtime dependencies under `--save-dev`, and a failed interactive change reads "Failed to enable <id>" rather than "Failed to enabling <id>".
- `lint/eslint`, `lint/stylelint` and `setup/tailwind` asked for `@rtcamp/eslint-config`, `@rtcamp/stylelint-config` and `@rtcamp/tailwind-config` at `^0.1.0` from the npm registry. None of them is published there (all three 404, and the packages are at 1.0.0), so `npm install` failed, and `features --enable tailwind --record-deps` wrote a spec into package.json that broke the project's next `npm install`. They now use the git specs the skeletons already use (`github:rtCamp/wp-tooling#npm/<package>`).
- `lint/eslint`, `lint/stylelint` and `setup/tailwind` asked for `@rtcamp/eslint-config`, `@rtcamp/stylelint-config` and `@rtcamp/tailwind-config` at `^0.1.0` from the npm registry. None of them was on the registry at that version (all three returned 404 when this was fixed), so `npm install` failed, and `features --enable tailwind --record-deps` wrote a spec into package.json that broke the project's next `npm install`. They now use the git specs the skeletons already use (`github:rtCamp/wp-tooling#npm/<package>`).
- `lint/phpcs/full` now extends `rtCampWP-Basic` from `rtcamp/wp-phpcs` (and reports it plus `dealerdirect/phpcodesniffer-composer-installer` as dev dependencies) instead of `vendor/rtcamp/wp-framework/phpcs.xml.dist`. The framework export-ignores that file, so every dist install, the Composer default, ended up with a ruleset pointing at a file that was not there. The generated ruleset also sets `testVersion` to `8.2-`, which PHPCompatibilityWP needs.
- `detect-changes --output github` and `coverage-gate --output github` write multi-line outputs under a random per-output heredoc delimiter instead of the fixed `EOF_WP_TOOLING`. The file lists come from the pull request, so a PR adding a file named `EOF_WP_TOOLING` followed by one named `php-count=0` could close the heredoc early and override the real count, skipping the PHP jobs.
- `discover_from: composer.json:autoload.psr-4` now resolves **path** inputs (`base_path`, `*_path`, `*_dir`) from the map entry's directory instead of skipping them, grafted the same way namespaces already were — with a root of `Acme\Blog\` → `inc/`, a `base_path` default of `includes/Services` resolves to `inc/Services`. Previously the namespace was grafted but the directory kept the manifest default, so any project not laid out under `includes/` got a correctly-namespaced class written outside its autoload root, where it never loaded. Affects the 12 bundled scaffolds that declare PSR-4 discovery on `base_path`. Projects already using `includes/`, projects without a `composer.json`, and callers that pass `--base_path` explicitly are unaffected.
Expand Down
Loading
Loading