adachsoft / composer-json-fixer
Validate and automatically fix composer.json files for PHP libraries.
Installs: 1
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Forks: 0
pkg:composer/adachsoft/composer-json-fixer
Requires
- php: >=8.2
- adachsoft/collection: 3.0.2
- adachsoft/console-io: ^0.1
Requires (Dev)
- adachsoft/php-code-style: dev-main
- friendsofphp/php-cs-fixer: ^3.89
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^12.4
- rector/rector: ^2.3
This package is not auto-updated.
Last update: 2026-02-27 17:00:17 UTC
README
A small PHP library and CLI tool for validating and automatically fixing composer.json files, with a focus on library packages.
The tool runs a set of opinionated rules against your composer.json, reports issues, and can generate patches or write fixes back to disk while preserving indentation style.
Requirements
- PHP >= 8.2
composer.jsonsize up to 5 MB (hard limit enforced by file reader)
Runtime dependencies are installed automatically via Composer (notably adachsoft/console-io and adachsoft/collection).
Installation
Install via Composer:
composer require --dev adachsoft/composer-json-fixer
The package is intended primarily as a dev-tool, hence
--devin the example. You can also install it as a regular dependency if you need to ship it with your application.
After installation, Composer exposes the binary as:
./vendor/bin/composer-json-fixer
CLI Usage
Basic commands
Validate a composer.json file:
./vendor/bin/composer-json-fixer validate --path=path/to/composer.json
Fix a composer.json file and show a patch (dry-run):
./vendor/bin/composer-json-fixer fix --path=path/to/composer.json --dry-run
Fix a composer.json file in place:
./vendor/bin/composer-json-fixer fix --path=path/to/composer.json
You can optionally provide a JSON configuration file with rule settings:
./vendor/bin/composer-json-fixer validate --path=path/to/composer.json --config=path/to/config.json
./vendor/bin/composer-json-fixer fix --path=path/to/composer.json --config=path/to/config.json
Exit codes
0– success, no issues (or all issues fixed and file is valid)1– validation failed, at least one issue (error or warning) remains before/after fix, or invalid/broken file
Note: the CLI does not distinguish severity for exit codes – any reported issue (even a warning) results in a non‑zero exit code.
CLI output
The CLI uses adachsoft/console-io for colored and icon-enhanced output. Example flows:
validatewith no issues:- prints a success message and exits with code
0
- prints a success message and exits with code
validatewith issues:- prints all issues (severity, message, JSON pointer) and exits with code
1
- prints all issues (severity, message, JSON pointer) and exits with code
fix --dry-run:- prints a unified diff with proposed changes but does not modify the file
fix(write mode):- prints a diff if there are changes
- writes the updated
composer.json - validates the result and prints final status
Indentation is preserved (2 spaces, 4 spaces or tabs) based on the original file.
Library Usage (Public API)
The main entry point is AdachSoft\ComposerJsonFixer\PublicApi\ComposerJsonFixerInterface.
In most cases you should use the ComposerJsonFixerBuilder from the Public API, which wires Core dependencies and rules for you.
Construction via builder
<?php
use AdachSoft\ComposerJsonFixer\PublicApi\ComposerJsonFixerBuilder;
use AdachSoft\ComposerJsonFixer\PublicApi\ComposerJsonFixerInterface;
$builder = new ComposerJsonFixerBuilder();
// Without explicit configuration – uses default rule set
$fixer = $builder->build();
// Or, using a configuration file (see section below)
$fixerFromConfig = $builder->buildFromConfigFile(__DIR__ . '/composer-json-fixer.config.json');
assert($fixer instanceof ComposerJsonFixerInterface);
You normally do not need to instantiate Core classes (ComposerJsonFileReader, ComposerJsonFileWriter, DefaultRuleProvider, UnifiedDiffGenerator) by hand – this is handled inside the builder.
Configuration file (rules)
The builder supports a JSON configuration file passed on the CLI (--config) or directly to buildFromConfigFile().
The configuration controls:
- which rules are enabled/disabled,
- rule-specific parameters (e.g. packages for
RequireVersionNormalizationRule).
Example configuration file (snake_case JSON):
{
"rules": [
{
"rule_id": "require_version_normalization",
"enabled": true,
"params": {
"packages": [
"phpunit/phpunit",
"phpstan/phpstan"
]
}
},
{
"rule_id": "config_must_be_object",
"enabled": true,
"params": {}
}
]
}
Validation API
use AdachSoft\ComposerJsonFixer\PublicApi\Dto\ValidateComposerJsonRequestDto;
$request = new ValidateComposerJsonRequestDto('/path/to/composer.json');
$response = $fixer->validate($request);
if ($response->isValid) {
// no issues
} else {
foreach ($response->issues as $issue) {
// $issue is AdachSoft\ComposerJsonFixer\Core\ComposerJsonIssue
// $issue->severity (IssueSeverityEnum::Error|Warning)
// $issue->message (string)
// $issue->jsonPointer (?string)
}
}
Fix API
use AdachSoft\ComposerJsonFixer\PublicApi\Dto\FixComposerJsonRequestDto;
use AdachSoft\ComposerJsonFixer\PublicApi\Enum\FixModeEnum;
$request = new FixComposerJsonRequestDto(
'/path/to/composer.json',
FixModeEnum::DryRun, // or FixModeEnum::Write
);
$response = $fixer->fix($request);
// $response is AdachSoft\ComposerJsonFixer\PublicApi\Dto\FixComposerJsonResponseDto
if ($response->unifiedDiff !== null) {
echo $response->unifiedDiff; // unified diff between original and fixed JSON
}
if ($response->wasWritten) {
// file was updated on disk
}
if (!$response->isValidAfterFix) {
// some issues remain after automatic fix
}
Exceptions
The following public exceptions can be thrown by the reader/fixer facade:
AdachSoft\ComposerJsonFixer\PublicApi\Exception\ComposerJsonNotFoundException– file does not existAdachSoft\ComposerJsonFixer\PublicApi\Exception\ComposerJsonInvalidException– file is too large, not readable, or contains invalid JSON
Rules
The library ships with a set of built-in rules, all implementing:
AdachSoft\ComposerJsonFixer\Core\Rule\ComposerJsonRuleInterface
Each rule provides:
getRuleId(): stringvalidate(ComposerJsonDocument $document): ComposerJsonIssueCollectionfix(array $data): ?array– returns modified decoded JSON ornullwhen no change is applied
MissingRequiredFieldsRule
Checks that the following fields are present at the root level:
namedescriptiontypelicenseauthorskeywords
Severity: error for each missing field.
This rule does not auto-fill missing values during
fix()(no guessing of metadata).
Psr4NamespaceConsistencyRule
For packages with:
type: "library"- valid non-empty
name(vendor/package-name)
The rule computes an expected PSR-4 namespace from the package name using ExpectedPsr4Namespace, e.g.:
vendor/package-name→Vendor\PackageName\\
Behavior:
validate()compares the firstautoload.psr-4key with the expected namespace and reports a warning if they differ.- Internally, the rule compares the normalized namespace (multiple backslashes collapsed) so that
DoubleBackslashInNamespaceRuleand this rule work together.
- Internally, the rule compares the normalized namespace (multiple backslashes collapsed) so that
fix()rewrites only the firstautoload.psr-4key to the expected namespace, preserving:- the original path for that entry
- all other
psr-4entries - all other
autoloadsections (classmap,files, etc.).
DoubleBackslashInNamespaceRule
Normalizes namespace keys in autoload.psr-4 by collapsing multiple backslashes:
AdachSoft\\\\Foo\\→AdachSoft\Foo\\
Reports warnings for affected entries and updates keys during fix().
ConfigMustBeObjectRule
Ensures that the root config section is a JSON object, not a JSON array.
Examples:
"config": [](JSON array) → issue + fix to"config": {}(empty object, represented asstdClassin PHP)"config": {}(already an object) → no issue
The rule uses both the decoded data and the raw JSON to distinguish between [] and {} at the root level.
Severity: warning.
RequireVersionNormalizationRule
Normalizes overly specific versions for selected packages in require, e.g.:
"phpunit/phpunit": "9.6.5"→"9.6""adachsoft/command-executor-lib": "2.0.1"→"2.0"
Behavior:
validate()emits warnings for versions matchingx.y.z(fullmajor.minor.patch) for a configured list of packages.fix()rewrites them tox.y(i.e. drops the patch segment) for configured packages, such as:phpunit/phpunitphpstan/phpstanrector/rectoradachsoft/command-executor-lib
After a successful fix, a subsequent validate should no longer report normalization warnings for these packages.
Indentation & Formatting
The tool tries hard not to destroy your formatting:
- The reader inspects the original file and detects the indentation style (2 spaces, 4 spaces, or tab).
- The fixer uses
json_encode(..., JSON_PRETTY_PRINT)and then rewrites the leading spaces on each line to match the detected indent. - If the file is fully minified (single line), the fixer will pretty-print it using a default indent (4 spaces).
Note: key ordering may still change according to json_encode behavior; the primary focus is on logical structure and indent style, not on preserving exact byte-for-byte formatting.
Development
Running tests
composer install
# Unit and functional tests
./vendor/bin/phpunit tests
Static analysis
./vendor/bin/phpstan analyse src tests
Code style
This project follows coding standards provided by adachsoft/php-code-style.
./vendor/bin/php-cs-fixer fix
Limitations
- Only JSON files up to 5 MB are supported.
- Automatic fixes are intentionally conservative – some rules only validate and do not attempt to guess missing metadata.
- The ruleset is opinionated and biased towards typical library packages; custom requirements may need additional rules.
Contributions in the form of new rules or improvements to existing ones are welcome, as long as they keep the behavior predictable and safe for CI usage.