ergebnis/composer-normalize

repository·main·Indexed 22 days ago

https://github.com/ergebnis/composer-normalize

A tool and Composer plugin that automatically normalizes and formats the composer.json file. It ensures consistent structure, indentation, and property ordering, including alphabetizing packages within requirement blocks and standardizing whitespace. It can be installed as a Composer plugin, via Phar, or Phive, and supports a --dry-run flag for use in Continuous Integration (CI) pipelines.

Tokens
6.1K
Snippets
11
Records
11
Agent score
28%

What's inside ergebnis/composer-normalize

  1. Install ergebnis/composer-normalize via Composer

    main

    To install ergebnis/composer-normalize as a Composer plugin in your development environment, follow these two steps:

    1. Require the package as a dev dependency:

      composer require --dev ergebnis/composer-normalize
    2. Explicitly allow the plugin to run (required by modern Composer security settings):

      composer config allow-plugins.ergebnis/composer-normalize true
    composer require --dev ergebnis/composer-normalize
    composer config allow-plugins.ergebnis/composer-normalize true
  2. Use composer-normalize in Continuous Integration (CI)

    main

    To use composer-normalize in a CI pipeline to ensure composer.json is correctly formatted and composer.lock is up-to-date without modifying files, use the --dry-run flag.

    If the file is not normalized or the lock file is out-of-date, the command will exit with code 1 and output a diff.

    composer normalize --dry-run
  3. Configure indentation in composer.json

    main

    You can define preferred indentation settings directly in your composer.json under the extra.composer-normalize key. These settings will override any command-line options provided during execution.

    Supported keys:

    • indent-size: An integer greater than 0.
    • indent-style: Either "space" or "tab".
    {
      "extra": {
        "composer-normalize": {
          "indent-size": 2,
          "indent-style": "space"
        }
      }
    }
  4. Examples of composer-normalize in action (phpspec)

    main

    Running composer normalize against phpspec/phpspec demonstrates how the tool standardizes property ordering (e.g., moving type and description up) and cleans up whitespace and indentation within the composer.json file.

    ### `phpspec/phpspec`
    
    Running
    
    ```sh
    composer normalize

    against https://github.com/phpspec/phpspec/blob/7.0.1/composer.json yields the following diff:

    diff --git a/composer.json b/composer.json
    index 90150a37..276a2ecd 100644
    --- a/composer.json
    +++ b/composer.json
    @@ -1,72 +1,73 @@
     {
    -    "name":         "phpspec/phpspec",
    -    "description":  "Specification-oriented BDD framework for PHP 7.1+",
    -    "keywords":     ["BDD", "SpecBDD", "TDD", "spec", "specification", "tests", "testing"],
    -    "homepage":     "http://phpspec.net/",
    -    "type":         "library",
    -    "license":      "MIT",
    -    "authors":      [
    +
    +    "name": "phpspec/phpspec",
    +    "type": "library",
    +    "description": "Specification-oriented BDD framework for PHP 7.1+",
    +    "keywords": [
    +        "BDD",
    +        "SpecBDD",
    +        "TDD",
    +        "spec",
    +        "specification",
    +        "tests",
    +        "testing"
    +    ],
    +    "homepage": "http://phpspec.net/",
    +    "license": "MIT",
    +    "authors": [
             {
    -            "name":      "Konstantin Kudryashov",
    -            "email":     "ever.zet@gmail.com",
    -            "homepage":  "http://everzet.com"
    +            "name": "Konstantin Kudryashov",
    +            "email": "ever.zet@gmail.com",
    +            "homepage": "http://everzet.com"
             },
             {
    -            "name":      "Marcello Duarte",
    -            "homepage":  "http://marcelloduarte.net/"
    +            "name": "Marcello Duarte",
    +            "homepage": "http://marcelloduarte.net/"
             },
             {
    -            "name":      "Ciaran McNulty",
    -            "homepage":  "https://ciaranmcnulty.com/"
    +            "name": "Ciaran McNulty",
    +            "homepage": "https://ciaranmcnulty.com/"
             }
         ],
    - 
         "require": {
    -        "php":                      "^7.3 || 8.0.*",
    -        "phpspec/prophecy":         "^1.9",
    -        "phpspec/php-diff":         "^1.0.0",
    -        "sebastian/exporter":       "^3.0 || ^4.0",
    -        "symfony/console":          "^3.4 || ^4.4 || ^5.0",
    +        "php": "^7.3 || 8.0.*",
    +        "ext-tokenizer": "*",
    +        "doctrine/instantiator": "^1.0.5",
    +        "phpspec/php-diff": "^1.0.0",
    +        "phpspec/prophecy": "^1.9",
    +        "sebastian/exporter": "^3.0 || ^4.0",
    +        "symfony/console": "^3.4 || ^4.4 || ^5.0",
             "symfony/event-dispatcher": "^3.4 || ^4.4 || ^5.0",
    -        "symfony/process":          "^3.4 || ^4.4 || ^5.0",
    -        "symfony/finder":           "^3.4 || ^4.4 || ^5.0",
    -        "symfony/yaml":             "^3.4 || ^4.4 || ^5.0",
    -        "doctrine/instantiator":    "^1.0.5",
    -        "ext-tokenizer":            "*"
    +        "symfony/finder": "^3.4 || ^4.4 || ^5.0",
    +        "symfony/process": "^3.4 || ^4.4 || ^5.0",
    +        "symfony/yaml": "^3.4 || ^4.4 || ^5.0"
         },
    +    "conflict": {
    +        "sebastian/comparator": "<1.2.4"
    +    },
         "require-dev": {
    -        "behat/behat":           "^3.3",
    -        "symfony/filesystem":    "^3.4 || ^4.0 || ^5.0",
    -        "phpunit/phpunit":       "^8.0 || ^9.0"
    +        "behat/behat": "^3.3",
    +        "phpunit/phpunit": "^8.0 || ^9.0",
    +        "symfony/filesystem": "^3.4 || ^4.0 || ^5.0"
         },
    - 
         "suggest": {
             "phpspec/nyan-formatters": "Adds Nyan formatters"
         },
    - 
    -    "conflict": {
    -        "sebastian/comparator" : "<1.2.4"
    -    }
    -
    -    "extra": {
    -        "branch-alias": {
    -            "dev-main": "7.0.x-dev"
    -        }
    -    }
    -
         "autoload": {
             "psr-0": {
                 "PhpSpec": "src/"
             }
         },
    - 
         "autoload-dev": {
             "psr-0": {
                 "spec\\PhpSpec": "."
             }
         },
    - 
    -    "bin": ["bin/phpspec"],
    -
    -    "extra": {
    -        "branch-alias": {
    -            "dev-main": "7.0.x-dev"
    -        }
    -    }
    -
    +    "bin": [
    +        "bin/phpspec"
    +    ],
    +    "extra": {
    +        "branch-alias": {
    +            "dev-main": "7.0.x-dev"
    +        }
    +    }
     }
  5. Examples of composer-normalize in action

    main

    The following examples demonstrate how composer normalize transforms composer.json files to ensure consistent formatting, property ordering, and structure.

    Key transformations observed in these examples include:

    • Property Reordering: Moving sections like require-dev, config, and extra to standardized positions.
    • Package Sorting: Alphabetizing packages within requirement blocks (e.g., require, require-dev).
    • Whitespace Normalization: Standardizing indentation and removing unnecessary whitespace.
    • Structural Cleanup: Consolidating or reordering keys like bin, autoload, and scripts to follow a predictable pattern.
    ### `pestphp/pest`
    
    Running
    
    ```sh
    composer normalize

    against https://github.com/pestphp/pest/blob/v0.3.19/composer.json yields the following diff:

    diff --git a/composer.json b/composer.json
    index 1cfbf1e..204f20f 100644
    --- a/composer.json
    +++ b/composer.json
    @@ -25,6 +25,32 @@
             "pestphp/pest-plugin-init": "^0.3",
             "phpunit/phpunit": ">= 9.3.7 <= 9.5.0"
         },
    +    "require-dev": {
    +        "illuminate/console": "^7.16.1",
    +        "illuminate/support": "^7.16.1",
    +        "laravel/dusk": "^6.9.1",
    +        "mockery/mockery": "^1.4.1",
    +        "pestphp/pest-dev-tools": "dev-master"
    +    },
    +    "config": {
    +        "preferred-install": "dist",
    +        "sort-packages": true
    +    },
    +    "extra": {
    +        "branch-alias": {
    +            "dev-master": "0.3.x-dev"
    +        },
    +        "laravel": {
    +            "providers": [
    +                "Pest\\Laravel\\PestServiceProvider"
    +            ]
    +        },
    +        "pest": {
    +            "plugins": [
    +                "Pest\\Plugins\\Version"
    +            ]
    +        }
    +    },
         "autoload": {
             "psr-4": {
                 "Pest\": "src/"
    @@ -42,49 +68,23 @@
                 "tests/Autoload.php"
             }
         },
    -    "require-dev": {
    -        "illuminate/console": "^7.16.1",
    -        "illuminate/support": "^7.16.1",
    -        "laravel/dusk": "^6.9.1",
    -        "mockery/mockery": "^1.4.1",
    -        "pestphp/pest-dev-tools": "dev-master"
    -    },
         "minimum-stability": "dev",
         "prefer-stable": true,
    -    "config": {
    -        "sort-packages": true,
    -        "preferred-install": "dist"
    -    },
         "bin": [
             "bin/pest"
         ],
         "scripts": {
             "lint": "php-cs-fixer fix -v",
    -        "test:lint": "php-cs-fixer fix -v --dry-run",
    -        "test:types": "phpstan analyse --ansi --memory-limit=0",
    -        "test:unit": "php bin/pest --colors=always --exclude-group=integration",
    -        "test:integration": "php bin/pest --colors=always --group=integration",
    -        "update:snapshots": "REBUILD_SNAPSHOTS=true php bin/pest --colors=always",
             "test": [
                 "@test:lint",
                 "@test:types",
                 "@test:unit",
                 "@test:integration"
    -        ]
    -    },
    -    "extra": {
    -        "branch-alias": {
    -            "dev-master": "0.3.x-dev"
    -        },
    -        "pest": {
    -            "plugins": [
    -                "Pest\\Plugins\\Version"
    -            ]
    -        },
    -        "laravel": {
    -            "providers": [
    -                "Pest\\Laravel\\PestServiceProvider"
    -            ]
    -        }
    +        ],
    +        "test:integration": "php bin/pest --colors=always --group=integration",
    +        "test:lint": "php-cs-fixer fix -v --dry-run",
    +        "test:types": "phpstan analyse --ansi --memory-limit=0",
    +        "test:unit": "php bin/pest --colors=always --exclude-group=integration",
    +        "update:snapshots": "REBUILD_SNAPSHOTS=true php bin/pest --colors=always"
         }
     }
  6. Examples of composer-normalize in action (phpunit)

    main

    Running composer normalize against phpunit/phpunit demonstrates how the tool handles the suggest, config, and extra blocks, ensuring they are placed correctly and that internal properties like optimize-autoloader are consistently formatted.

    ### `phpunit/phpunit`
    
    Running
    
    ```sh
    composer normalize

    against https://github.com/sebastianbergmann/phpunit/blob/9.5.0/composer.json yields the following diff:

    diff --git a/composer.json b/composer.json
    index fd6461fc3..23c3a3596 100644
    --- a/composer.json
    +++ b/composer.json
    @@ -1,7 +1,7 @@
     {
         "name": "phpunit/phpunit",
    -    "description": "The PHP Unit Testing framework.",
         "type": "library",
    +    "description": "The PHP Unit Testing framework.",
         "keywords": [
             "phpunit",
             "xunit",
    @@ -16,10 +16,6 @@
                 "role": "lead"
             }
         ],
    -    "support": {
    -        "issues": "https://github.com/sebastianbergmann/phpunit/issues"
    -    },
    -    "prefer-stable": true,
         "require": {
             "php": ">=7.3",
             "ext-dom": "*",
    @@ -54,20 +50,22 @@
             "ext-PDO": "*",
             "phpspec/prophecy-phpunit": "^2.0.1"
         },
    +    "suggest": {
    +        "ext-soap": "*",
    +        "ext-xdebug": "*"
    +    },
         "config": {
    +        "optimize-autoloader": true,
             "platform": {
                 "php": "7.3.0"
             },
    -        "optimize-autoloader": true,
             "sort-packages": true
         },
    -    "suggest": {
    -        "ext-soap": "*",
    -        "ext-xdebug": "*"
    +    "extra": {
    +        "branch-alias": {
    +            "dev-master": "9.5-dev"
    +        }
         },
    -    "bin": [
    -        "phpunit"
    -    ],
         "autoload": {
             "classmap": [
                 "src/"
    @@ -86,9 +84,11 @@
                 "tests/_files/NamespaceCoveredFunction.php"
             ]
         },
    -    "extra": {
    -        "branch-alias": {
    -            "dev-master": "9.5-dev"
    -        }
    -    }
    +
    +    "prefer-stable": true,
    +    "bin": [
    +        "phpunit"
    +    ],
    +    "support": {
    +        "issues": "https://github.com/sebastianbergmann/phpunit/issues"
    +    }
     }
  7. Configure indentation in composer.json extra

    main

    You can persist indentation settings directly in your composer.json file under the extra key. This ensures that anyone running the normalize command on your project uses the same formatting rules.

    The configuration must be under the composer-normalize key and requires both indent-size and indent-style.

    Required Keys:

    • indent-size: An integer greater than 0.
    • indent-style: A string representing the indentation character (e.g., the character used for spaces or tabs).

    Note: If both CLI options and composer extra configuration are provided, the configuration in composer extra takes precedence.

    {
        "extra": {
            "composer-normalize": {
                "indent-size": 4,
                "indent-style": ""
            }
        }
    }
  8. Reference: NormalizeCommand arguments and options

    main

    The NormalizeCommand allows you to control how composer.json is processed and how the output is displayed.

    ### Arguments
    - `file`: Path to `composer.json` file (optional, defaults to `composer.json` in working directory)
    
    ### Options
    - `--diff`: Show the results of normalizing
    - `--dry-run`: Show the results of normalizing, but do not modify any files
    - `--indent-size`: Indent size (an integer greater than 0); should be used with the `--indent-style` option
    - `--indent-style`: Indent style (one of "space", "tab"); should be used with the `--indent-size` option
    - `--no-check-lock`: Do not check if lock file is up to date
    - `--no-update-lock`: Do not update lock file if it exists
  9. Normalize composer.json

    main

    Use the following commands to normalize the composer.json file in your current working directory based on your installation method:

    • Composer plugin: composer normalize
    • Phar: ./composer-normalize.phar
    • Phive: ./tools/composer-normalize
    composer normalize
  10. Use the `normalize` command to format composer.json

    main

    The normalize command formats your composer.json file according to its official JSON schema. It ensures consistent ordering and structure. By default, it will attempt to update the composer.lock file if it exists after normalizing the JSON file.

    Arguments:

    • file (optional): The path to the composer.json file you want to normalize. If omitted, it defaults to the standard composer.json in the current directory.

    Options:

    • --diff: Shows a diff of the changes that would be applied without necessarily modifying the file (though if used without --dry-run, it will still modify the file).
    • --dry-run: Shows the diff of the changes but does not modify the composer.json file.
    • --indent-size <integer>: Sets the number of spaces/characters for indentation (must be an integer > 0).
    • --indent-style <style>: Sets the character used for indentation. Valid styles are determined by the available characters in the normalizer (typically spaces or tabs).
    • --no-check-lock: Skips the check that ensures the composer.lock file is up to date with composer.json before running.
    • --no-update-lock: Prevents the command from automatically running composer update --lock to synchronize the lock file after normalization.
    composer normalize
    composer normalize composer.test.json --dry-run
    composer normalize --diff --indent-size 4 --indent-style space