| title | Linting Strategy & Implementation Guide | |||||||
|---|---|---|---|---|---|---|---|---|
| description | Comprehensive guide to linting setup, configuration, and automation across LightSpeed WordPress projects | |||||||
| file_type | documentation | |||||||
| version | 1.0 | |||||||
| last_updated | 2025-10-26 | |||||||
| owners |
|
|||||||
| tags |
|
This document provides a comprehensive overview of the linting strategy, tools, and automation used across LightSpeed WordPress projects to maintain code quality, consistency, and standards compliance.
- Overview
- Linting Tools
- Configuration Files
- NPM Scripts Integration
- VS Code Integration
- Automation & Git Hooks
- File Type Specific Linting
- Quality Assurance Workflow
- Troubleshooting
- Related Documentation
Our linting strategy follows these core principles:
- Consistency: Unified coding standards across all projects
- Automation: Lint checks run automatically during development and CI/CD
- Progressive Enhancement: Start with basics, add complexity as needed
- Developer Experience: Fast feedback with helpful error messages
- WordPress Standards: Align with official WordPress coding standards
- 🚀 Faster Development: Catch issues early in the development cycle
- 🔒 Quality Assurance: Enforce coding standards automatically
- 🤝 Team Consistency: Same standards for all team members
- 📚 Documentation: Self-documenting code through consistent patterns
- 🔄 CI/CD Integration: Prevent bad code from reaching production
| Tool | Purpose | Configuration | Auto-fix |
|---|---|---|---|
| ESLint | JavaScript/TypeScript linting | eslint.config.js |
✅ |
| Stylelint | CSS/SCSS linting | stylelint.config.js |
✅ |
| Prettier | Code formatting | prettier.config.js |
✅ |
| markdownlint | Markdown linting | .markdownlint.json |
✅ |
| Spectral | YAML/JSON linting | .spectral.yaml |
❌ |
| npmPkgJsonLint | package.json validation | npmpackagejsonlint.config.cjs |
❌ |
- Modern flat config (
eslint.config.js) for ESLint 9+ - TypeScript support with
typescript-eslint - Prettier integration to avoid formatting conflicts
- Environment-based configuration via
.envvariables
- WordPress CSS standards alignment
- SCSS syntax support for modern CSS workflows
- Auto-fixing for spacing, formatting, and ordering
- Consistent formatting across all supported file types
- Integration with ESLint and Stylelint to avoid conflicts
- Configurable via environment variables
// eslint.config.js
import "dotenv/config";
import js from "@eslint/js";
import ts from "typescript-eslint";
import prettier from "eslint-plugin-prettier";
const ignoreFolders = process.env.ESLINT_IGNORE
? process.env.ESLINT_IGNORE.split(",")
: [
"node_modules/**",
"build/**",
"dist/**",
"coverage/**",
"playwright-report/**",
"test-results/**",
"vendor/**",
".next/**",
"logs/**",
];
export default [
js.configs.recommended,
...ts.configs.recommended,
{
files: ["**/*.{js,jsx,ts,tsx,cjs,mjs}"],
ignores: ignoreFolders,
plugins: { prettier },
rules: {
"prettier/prettier": "warn",
},
},
];The package JSON lint configuration now lives in npmpackagejsonlint.config.cjs (CJS for environment variable access and comments). You can influence rule enforcement via the following environment variables in .env (see .env.example):
| Variable | Purpose | Default |
|---|---|---|
NPMPKGJSONLINT_STRICT_MODE |
Treat version-format failures as errors (otherwise warning) |
false |
NPMPKGJSONLINT_NAME_FORMAT |
Severity for name-format rule (error/warning/off) |
error |
NPMPKGJSONLINT_REQUIRE_FIELDS |
Master toggle for all required metadata rules | true |
NPMPKGJSONLINT_REQUIRE_DESCRIPTION |
Require description field |
true |
NPMPKGJSONLINT_REQUIRE_REPOSITORY |
Require repository field |
true |
NPMPKGJSONLINT_REQUIRE_LICENSE |
Require license field |
true |
NPMPKGJSONLINT_REQUIRE_AUTHOR |
Require author field |
true |
NPMPKGJSONLINT_REQUIRE_DESCRIPTION |
Require description field (granular override) |
true |
NPMPKGJSONLINT_REQUIRE_REPOSITORY |
Require repository field (granular override) |
true |
NPMPKGJSONLINT_DISABLE_ORDER |
Disable prefer-property-order enforcement |
false |
NPMPKGJSONLINT_IGNORE_PATHS |
Additional comma‑separated paths to ignore | (empty) |
Example script (already defined):
To temporarily relax ordering while keeping other rules:
NPMPKGJSONLINT_DISABLE_ORDER=true npm run lint:pkg-jsonTo enforce strict version formatting in CI:
NPMPKGJSONLINT_STRICT_MODE=true npm run lint:pkg-jsonIncremental adoption strategy (updated 2025-10-26):
- Enable required metadata (default) and address any missing fields.
- Turn on strict version formatting (
NPMPKGJSONLINT_STRICT_MODE=true). - Keep scope validation off until an allowed scope list is defined.
- License enforcement currently set to a permissive warning for
GPL-3.0-or-later; raise toerrorafter normalization. - Use granular overrides (
NPMPKGJSONLINT_REQUIRE_*) to relax a single field without disabling all requirements.
The scaffold-related ignores were removed; configuration now assumes real package metadata present.
# .env - Customize linting behaviour
ESLINT_IGNORE=node_modules/**,build/**,custom-folder/**
PRETTIER_TAB_WIDTH=4
PRETTIER_USE_TABS=false
PRETTIER_PRINT_WIDTH=80| File | Purpose | Environment Support |
|---|---|---|
eslint.config.js |
ESLint flat configuration | ✅ ESLINT_IGNORE |
prettier.config.js |
Prettier formatting rules | ✅ Multiple env vars |
.markdownlint.json |
Markdown linting rules | ❌ |
.spectral.yaml |
YAML/JSON schema validation | ❌ |
.spectral-workflows.yaml |
GitHub Actions workflow validation | ❌ |
{
"scripts": {
"lint": "npm run lint:js && npm run lint:css && npm run lint:yaml && npm run lint:pkg-json",
"lint:all": "npm run lint && npm run lint:workflows && npm run lint:md",
"lint:js": "eslint '**/*.{js,jsx,ts,tsx}' --fix",
"lint:css": "stylelint '**/*.{css,scss}' --fix",
"lint:md": "markdownlint '**/*.md' --fix",
"lint:yaml": "spectral lint '**/*.{yml,yaml}' --ruleset .spectral.yaml",
"lint:workflows": "spectral lint '.github/workflows/*.{yml,yaml}' --ruleset .spectral-workflows.yaml",
"lint:pkg-json": "npmPkgJsonLint --configFile npmpackagejsonlint.config.cjs ."
}
}{
"scripts": {
"format": "npm run format:js && npm run format:css",
"format:js": "prettier '**/*.{js,jsx,ts,tsx}' --write && prettier '**/*.json' --write && eslint '**/*.{js,jsx,ts,tsx}' --fix --format",
"format:css": "prettier '**/*.{css,scss}' --write && stylelint '**/*.{css,scss}' --fix",
"format:md": "prettier '**/*.md' --write"
}
}# Run all linting (core tools)
npm run lint
# Run comprehensive linting (includes workflows and markdown)
npm run lint:all
# Fix specific file types
npm run lint:js
npm run lint:css
# Format code
npm run format{
"recommendations": [
"esbenp.prettier-vscode",
"dbaeumer.vscode-eslint",
"stylelint.vscode-stylelint",
"DavidAnson.vscode-markdownlint",
"stoplight.spectral"
]
}The .vscode/settings.json file provides:
- Format on save for all supported file types
- ESLint integration with auto-fix on save
- Stylelint validation for CSS/SCSS files
- File associations for custom file types
- Problem matchers for terminal integration
{
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true,
"source.fixAll.stylelint": true,
},
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact",
],
"stylelint.validate": ["css", "scss", "sass"],
}Linting is automated through Git hooks managed by Husky and lint-staged:
{
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"*.{js,jsx,ts,tsx}": ["eslint --fix", "prettier --write"],
"*.{css,scss}": ["stylelint --fix", "prettier --write"],
"*.md": ["markdownlint --fix", "prettier --write"]
}
}# .github/workflows/lint.yml
name: Lint
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
- run: npm ci
- run: npm run lint:all- ESLint with TypeScript support
- Prettier integration for formatting
- WordPress coding standards alignment
- Auto-fix for most issues
Key Rules:
- 2-space indentation
- Single quotes for strings
- Semicolons required
- No unused variables
- Consistent naming conventions
- Stylelint with WordPress CSS standards
- Auto-fix for property ordering and formatting
- SCSS syntax support for modern workflows
Key Rules:
- Alphabetical property ordering
- Consistent indentation
- No duplicate selectors
- Valid CSS properties
- markdownlint for consistent documentation
- Auto-fix for formatting issues
- Custom rules for project-specific needs
Key Rules:
- Consistent heading styles
- Proper list formatting
- No trailing whitespace
- Consistent link formatting
- Spectral for schema validation
- Separate configs for workflows vs general YAML
- GitHub Actions specific validation
- Prettier for formatting
- npmPkgJsonLint for package.json validation
- Schema validation where applicable
In addition to linting, we validate WordPress JSON schemas to catch config errors:
- Theme JSON: We validate the repository’s
theme.jsonagainst WordPress’s official schema (pinned to the version our projects use). Runnpm run test:schema:themeto check the theme configuration. - Block JSON: Similarly,
block.jsonfiles are validated with the official Block API schema (npm run test:schema:block).
These schema tests use AJV under the hood. The schemas are stored in our repo under .github/schemas/wp/ and are pinned to a specific WP version (e.g. 6.6) for consistency. By pinning, our tests won’t suddenly break on a new WP release – we’ll update the schema files quarterly or as new WP versions come out.
These schema validations run as part of npm run check (and thus in CI). Locally, you can run the specific scripts above to debug schema errors. A failure means the theme.json or block.json doesn’t conform to expected structure, which could lead to runtime errors in WordPress.
Note: Currently, only the LightSpeed CodeRabbit agent uses a JSON schema (for frontmatter) – now extended to WP theme and block configs. This proactive testing reduces the chance of invalid config shipping.
- Write Code - Focus on functionality
- Save File - Auto-format and lint on save (VS Code)
- Pre-commit - Automated linting of staged files
- Push - Optional pre-push hooks for comprehensive checks
- CI/CD - Automated linting in GitHub Actions
| Stage | Tools | Action on Failure |
|---|---|---|
| Editor | ESLint, Stylelint, Prettier | Visual indicators, auto-fix |
| Pre-commit | lint-staged + all linters | Block commit |
| CI/CD | All linting tools | Block merge |
# Quick quality check
npm run lint
# Comprehensive check (includes all file types)
npm run lint:all
# Check specific issues
eslint src/components/Button.js
stylelint src/styles/main.scss
markdownlint README.md# Check ESLint configuration
npx eslint --print-config src/index.js
# Test specific files
npx eslint src/components/Button.js --debug# Check for conflicting rules
npx eslint-config-prettier src/index.js- Restart ESLint Server: Command Palette → "ESLint: Restart ESLint Server"
- Check Output Panel: View → Output → ESLint
- Verify Extensions: Ensure recommended extensions are installed
# Check ignored patterns
echo $ESLINT_IGNORE
# Verify .gitignore patterns are working
npx eslint --debug- Check configuration files exist and are valid
- Verify npm scripts match current tooling setup
- Test individual tools before combined scripts
- Check environment variables if using custom configs
- Review VS Code settings for editor integration
- ESLint Configuration - Detailed ESLint setup
- Stylelint Configuration - CSS linting configuration
- Prettier Configuration - Code formatting setup
- Markdownlint Configuration - Markdown linting rules
- Husky Configuration - Git hooks setup
- Lint-staged Configuration - Pre-commit automation
- NPM Scripts Configuration - Scripts and automation
- VS Code Settings - Editor configuration
- VS Code MCP - MCP server integration
- Coding Standards - Organization-wide standards
- WordPress Standards - WordPress-specific guidelines
💡 Next Steps: Configure pre-commit hooks → HUSKY-PRECOMMITS.md
For details on how linting is enforced before commits, see HUSKY-PRECOMMITS.md. This document explains how Husky is configured to run linting and other checks automatically, and how to manage or bypass hooks if needed.
Have questions? Ping us on GitHub! 🐙 Made with 💚 by LightSpeedWP Contact