Coding standards
lint checks the codebase with every linter you kept in the installer, and lint-fix runs the ones that can fix what they find. Both stop at the first tool that fails. This page lists the tools, where they run and how to fix what they report.
To check and fix the codebase, run the following commands:
- Make
- Ahoy
- No wrapper
make lint # Check coding standards
make lint-fix # Fix what the tools can fix
ahoy lint # Check coding standards
ahoy lint-fix # Fix what the tools can fix
cd build
vendor/bin/phpcs
vendor/bin/phpstan
vendor/bin/rector --clear-cache --dry-run
vendor/bin/twig-cs-fixer
npm run lint
cd ..
npm install
npm run lint-spell
The tools
Locally, lint runs the tools in the order of the following table, while CI runs CSpell first (see In CI). The configuration files live in your project root, and CI reads the same files. So 1 edit changes a rule on your machine and in CI. The PHP and JavaScript tools read copies that assemble makes, as Where they run explains.
| Tool | What it checks | Configuration | Fixes |
|---|---|---|---|
| PHPCS | PHP against the Drupal, DrupalPractice, DrevOps and PHPCompatibility standards for PHP 8.3, and declare(strict_types=1) in every file. | phpcs.xml | Yes |
| PHPStan | PHP with static analysis, with PHPStan Drupal. | phpstan.neon | No |
| Drupal Rector | PHP for deprecated Drupal code. Rector also applies the PHP 8.3 upgrade sets and strict types, plus its dead code, code quality, coding style, type declaration, privatization and naming sets. | rector.php | Yes |
| Twig CS Fixer | Twig templates. | .twig-cs-fixer.php | Yes |
| ESLint | JavaScript, with Prettier formatting. | .eslintrc.json, .eslintignore, .prettierrc.json, .prettierignore | Yes |
| Stylelint | CSS. | .stylelintrc.js | Yes |
| CSpell | Spelling across the codebase. | .cspell.json | No |
Where they run
The PHP and JavaScript tools run from the build directory, where the assembled site holds Drupal core and your dependencies. So run assemble, or build the site, before you lint. ESLint and Stylelint check the extension through its directory in the site. They run only when the build installed the frontend dependencies. Otherwise lint and lint-fix skip them without a warning (see Frontend dependencies).
assemble copies the configuration files of the PHP and JavaScript tools into build, so an edit to one applies after the next assemble. Edit the files in your project root, since the next assemble replaces the copies in build.
CSpell runs from the project root and reads .cspell.json in place. It installs the root package.json dependencies first when node_modules is missing. It checks every text file that git doesn't ignore. It skips hidden files and directories, such as .github. It also skips the paths in the ignorePaths of .cspell.json.
Fix what the linters report
lint-fix runs Rector, PHPCBF, Twig CS Fixer, ESLint and Stylelint with their fix options. PHPCBF is the fixer that comes with PHPCS. To fix what these tools can fix, run the following command:
- Make
- Ahoy
- No wrapper
make lint-fix
ahoy lint-fix
cd build
vendor/bin/rector --clear-cache
vendor/bin/phpcbf
vendor/bin/twig-cs-fixer --no-cache --fix
npm run lint-fix
Review the changes before you commit them. When an automatic fix is wrong, adjust the tool's configuration to suppress the issue or change the fix.
Spelling
CSpell checks prose, code and inline code in Markdown, and skips fenced code blocks. An unknown word fails the check. To make CSpell accept a word:
- Add a word the whole project uses to the
wordsof.cspell.json. - Add a word only 1 file uses to that file, in a comment such as
cspell:ignore laminaswritten in the file's own comment syntax. 1 comment can list several words, separated by spaces.
In CI
CI runs the same tools in its lint jobs, 1 per Drupal major you test. Each tool runs in a step of its own, apart from ESLint and Stylelint, which share 1. CSpell runs first, then the others in the order of the table. A step that fails stops the job, so the steps after it don't run.
To let a step fail without failing the job while you work through its findings, set the step's ignore-failure variable. It's a repository variable, so it covers that step in every lint job. The steps after it then still run.