@@ -180,6 +180,8 @@ Per-environment constants (take priority over generic):
180180| ` bun.lock ` | Locked dependency graph (committed) |
181181| ` tsconfig.json ` | TypeScript config (strict, ` jsx: react-jsx ` , ` noEmit: true ` ) |
182182| ` webpack.config.js ` | Extends ` @wordpress/scripts ` default config with authkit + admin-profiles entries |
183+ | ` phpstan.neon.dist ` | PHPStan config (level 5, scans ` src/ ` + ` integration-workos.php ` + ` uninstall.php ` , ` phpVersion: 70400 ` , Strauss vendor resolved via ` vendor/autoload.php ` in ` scanFiles ` ) |
184+ | ` phpstan/stubs.php ` | Symbol stubs for ` WORKOS_* ` runtime-defined constants so PHPStan can resolve them statically — never executed |
183185
184186## Build System
185187
@@ -197,6 +199,7 @@ bun run start # Development with watch
197199bun run lint:ts # Type-check TypeScript (tsc --noEmit)
198200bun run lint:php # Lint PHP via PHPCS
199201bun run lint:php:fix # Auto-fix PHP lint issues
202+ composer phpstan # Static analysis (PHPStan level 5, --memory-limit=1G)
200203```
201204
202205` @wordpress/scripts ` v30 transpiles ` .ts ` / ` .tsx ` natively via its default
@@ -297,3 +300,47 @@ Use the global `/slic` skill for comprehensive guidance on test structure, envir
297300
298301- PHP follows WordPress Coding Standards via PHPCS/WPCS
299302- Run ` composer lint ` / ` composer lint:fix ` for PHP linting
303+
304+ ## Static Analysis (PHPStan)
305+
306+ PHPStan analyses the plugin source at ** level 5** and is gated in CI as
307+ a required check on PRs to ` main ` . Config: ` phpstan.neon.dist ` .
308+
309+ ### Stack
310+
311+ - ` phpstan/phpstan ` ^2 — analyzer, in ` composer require-dev `
312+ - ` szepeviktor/phpstan-wordpress ` — WordPress core stubs + WP-aware
313+ inference for ` apply_filters ` , ` wp_remote_request ` , hook signatures
314+ - ` php-stubs/wp-cli-stubs ` — ` WP_CLI ` , ` WP_CLI_Command ` ,
315+ ` WP_CLI\Formatter ` for ` src/WorkOS/CLI/* `
316+ - ` phpstan/extension-installer ` — auto-registers neon files from
317+ installed extensions (no manual ` includes: ` wiring)
318+
319+ ### Scope
320+
321+ - Scanned: ` src/ ` , ` integration-workos.php ` , ` uninstall.php `
322+ - ` phpVersion: 70400 ` so PHP 7.4 syntax mistakes can't slip past on
323+ PHP 8.x runners
324+ - ` treatPhpDocTypesAsCertain: false ` — narrowing is required when a
325+ hook caller may pass something other than the documented type
326+ - Strauss-prefixed ` WorkOS\Vendor\… ` resolved via ` vendor/autoload.php `
327+ in ` scanFiles ` . The PHPStan CI job therefore must run
328+ ` composer install ` WITH scripts (so Strauss runs and prefixed
329+ classes exist on disk) — that's the key difference from the PHPCS
330+ CI job, which uses ` --no-scripts ` + a stub ` vendor/prefixed/autoload.php ` .
331+ - WP-CLI stubs (` vendor/php-stubs/wp-cli-stubs/wp-cli-*.php ` ) and
332+ ` phpstan/stubs.php ` (project-local ` WORKOS_* ` constants) are loaded
333+ via ` scanFiles ` . Not bootstrap files — just symbol discovery.
334+
335+ ### Policy
336+
337+ - ** No baseline.** Findings get fixed in the PR that introduces them.
338+ ` composer phpstan:baseline ` exists as a safety hatch for
339+ exceptional cases but the resulting ` phpstan-baseline.neon ` should
340+ not be committed without discussion.
341+ - ** Tests are not analyzed yet.** Codeception's wp-browser stubs are
342+ partial; revisit once ` phpstan/phpstan-phpunit ` integration is
343+ worth the noise.
344+ - ** Strict-rules extension is intentionally not enabled.** Level 5 is
345+ the floor we're committing to first; reconsider strict-rules as a
346+ follow-up when this is stable.
0 commit comments