Giter Club home page Giter Club logo

composerparser's Introduction

Composer Parser

A dependency-free parser library for composer.json and composer.lock files.

Installation

composer require mcstreetguy/composer-parser

Usage

Parsing

I recommend using the provided magic Factory method for parsing:

use MCStreetguy\ComposerParser\Factory as ComposerParser;

$composerJson = ComposerParser::parse('/path/to/composer.json');
$lockfile = ComposerParser::parse('/path/to/composer.lock');

Even if this is the easiest way to retrieve an instance, it may be that you for some reason cannot rely on these automations (e.g. if you got a differing filename). In this case you can also call the parse methods directly:

$composerJson = ComposerParser::parseComposerJson('/some/file');
$lockfile = ComposerParser::parseLockfile('/another/file');

Please note that ComposerParser will not complain about any missing fields, instead it fills all missing values with default ones to ensure integrity.

Exception Handling

During instatiation through the Factory, two exceptions may occur:

try {
    $composerJson = ComposerParser::parse('/path/to/composer.json');
} catch (InvalidArgumentException $e) {
    // The given file could not be found or is not readable
} catch (RuntimeException $e) {
    // The given file contained an invalid JSON string
}

Doing it the manual way

If you can not rely on the Factory for any reason, you can also instantiate the class directly.
This is however not recommended and may lead to unexpected behaviour.

use \MCStreetguy\ComposerParse\ComposerJson;

$rawData = file_get_contents('/path/to/composer.json');
$parsedData = json_decode($rawData, true);

$composerJson = new ComposerJson($parsedData);

As you can see the constructor needs an array with the parsed json data. This applies to all constructor methods throughout the library.

Sub-components

You can also create sub-components directly. In this case you have to keep in mind, that their constructors only accept the isolated data from the composer manifest (e.g. the Author class expects you to pass only the contents of one of the objects in the author-field).

use \MCStreetguy\ComposerParse\Json\Author;

$rawData = file_get_contents('/path/to/composer.json');
$parsedData = json_decode($rawData, true);

$author = new Author($parsedData['authors'][0]);

Data Retrieval

All class instances provide getters for their properties. The structure is directly adapted from the composer.json schema. The corresponding property names of wrapper classes have been converted to camelCase (see the PSR-1 standard for further information).

For any property you can use the provided getter methods.

$license = $composerJson->getLicense();
$version = $composerJson->getVersion();

It's also possible to directly access properties. Please note that this is read-only!

$description = $composerJson->description;
$require = $composerJson->require;

You may also call empty() or isset() on the class properties.
To check if the whole wrapper is empty (useful for nested classes) there is an isEmpty() method inherited:

if ($composerJson->config->isEmpty()) {
    // Do something
}

Special Classes

ComposerParser uses some special classes for parts of the json schema.

PackageMap

The PackageMap class is used for the fields require, require-dev, conflict, replace, provide and suggest. It converts a json structure like this:

{
    "require": {
        "vendor/package": "^2.3",
        "foo/bar": "dev-master"
    }
}

into an array structure like this:

$require = [
    [
        "package" => "vendor/package",
        "version" => "^2.3"
    ],
    [
        "package" => "foo/bar",
        "version" => "dev-master"
    ]
]

Additionally it implements the Iterator and ArrayAccess interfaces, thus you may directly access it's contents or put it in a foreach loop:

$require = $composerJson->getRequire();

$fooBar = $require[1];

foreach ($require as $requirement) {
    $package = $requirement['package'];
    $version = $requirement['version'];

    echo "I need $package at version $version!";
}

If you for some reason need the original mapped data you can retrieve it as following:

$map = $require->getData();
NamespaceMap

The NamespaceMap is used for the fields autoload.psr-0 and autoload.psr-4. In fact this class is identical to the PackageMap. The only difference are the map keys:

{
    "psr-4": {
        "MCStreetguy\\ComposerParser\\": "src/"
    }
}
$psr4 = [
    [
        "namespace" => "MCStreetguy\\ComposerParser\\",
        "source" => "src/"
    ]
]

Global Configuration

By default, the library tries to load your global configuration file, if there is any. It follows the location rules for the composer home directory as defined in the documentation. If there is no readable global configuration file present, this step is silently skipped.

Just as composer itself, the following precedence rule applies to global configuration files:

In case global configuration matches local configuration, the local configuration in the project's composer.json always wins. (source: https://getcomposer.org/doc/03-cli.md#composer-home-config-json)

You may suppress this behaviour by passing true as second parameter to the parse, parseComposerJson and parseLockfile methods.

Versioning

We use SemVer for versioning. For the versions available, see the tags on this repository.

Testing

If you contribute to this project, you have to ensure that your changes don't mess up the existing functionality. Therefore this repository comes with a PhpUnit testing configuration, that you can execute by running make test. See their documentation on more information on how to install the tool.

Authors

See also the list of contributors who participated in this project.

Acknowledgement

Special thanks go to antonkomarev who helped discovering and fixing several deeply nested bugs in the libraries architecture.

License

This project is licensed under the MIT License - see the LICENSE file for details

composerparser's People

Contributors

antonkomarev avatar mcstreetguy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

Forkers

cybercog janedbal

composerparser's Issues

[BUG] Fatal error: Uncaught TypeError: array_key_exists(): Argument #2 ($array) must be of type array, bool given in /vendor/mcstreetguy/composer-parser/src/ComposerJson.php:259

Describe the bug
Fatal error: Uncaught TypeError: array_key_exists(): Argument #2 ($array) must be of type array, bool given in vendor/mcstreetguy/composer-parser/src/ComposerJson.php:259

To Reproduce
in your composer.json if you have some repositories set to false:
"repositories": { "my-repo": { "type": "composer", "url": "http://my-repo.com" }, "packagist.org": false, "packagist": false },

Add packagist.org to Repositories

Accordingly to the specification - there is a way to disable packagist.org.

But if you add it to composer.json - parser will return this value:

{"type":"","url":"","options":[],"package":null}

Maybe it will be better to have by default packagist repository in list:

"packagist.org": {
  "type": "composer",
  "url": "https?://repo.packagist.org",
  "allow_ssl_downgrade": true
},

And remove it if "packagist.org": false is in place?

Or just not to add this object to the parsed repositories list, but then we need to denote that packagist is disabled somehow.

[Feature] Add compabillity composer 2.2

Is your feature request related to a problem? Please describe.
Add feature of composer 2.2 :
inside the config object we got new sction "allow-plugins"

Describe the solution you'd like
Add new properties to the class vendor/mcstreetguy/composer-parser/src/Json/Config.php also Get method

[warning] Depreciated php 8.1

Describe the bug
Deprecated: Return type of MCStreetguy\ComposerParser\Service\AbstractMap::current() should either be compatible with Iterator::current(): mixed, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /vendor/mcstreetguy/composer-parser/src/Service/AbstractMap.php on line 67

Deprecated: Return type of MCStreetguy\ComposerParser\Service\AbstractMap::next() should either be compatible with Iterator::next(): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in
/vendor/mcstreetguy/composer-parser/src/Service/AbstractMap.php on line 89

Deprecated: Return type of MCStreetguy\ComposerParser\Service\AbstractMap::key() should either be compatible with Iterator::key(): mixed, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in vendor/mcstreetguy/composer-parser/src/Service/AbstractMap.php on line 78

Deprecated: Return type of MCStreetguy\ComposerParser\Service\AbstractMap::valid() should either be compatible with Iterator::valid(): bool, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in vendor/mcstreetguy/composer-parser/src/Service/AbstractMap.php on line 100

Deprecated: Return type of MCStreetguy\ComposerParser\Service\AbstractMap::rewind() should either be compatible with Iterator::rewind(): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in vendor/mcstreetguy/composer-parser/src/Service/AbstractMap.php on line 56

Deprecated: Return type of MCStreetguy\ComposerParser\Service\AbstractMap::offsetExists($offset) should either be compatible with ArrayAccess::offsetExists(mixed $offset): bool, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in endor/mcstreetguy/composer-parser/src/Service/AbstractMap.php on line 129

Deprecated: Return type of MCStreetguy\ComposerParser\Service\AbstractMap::offsetGet($offset) should either be compatible with ArrayAccess::offsetGet(mixed $offset): mixed, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /vendor/mcstreetguy/composer-parser/src/Service/AbstractMap.php on line 153

Deprecated: Return type of MCStreetguy\ComposerParser\Service\AbstractMap::offsetSet($offset, $value) should either be compatible with ArrayAccess::offsetSet(mixed $offset, mixed $value): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /vendor/mcstreetguy/composer-parser/src/Service/AbstractMap.php on line 113

Deprecated: Return type of MCStreetguy\ComposerParser\Service\AbstractMap::offsetUnset($offset) should either be compatible with ArrayAccess::offsetUnset(mixed $offset): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /vendor/mcstreetguy/composer-parser/src/Service/AbstractMap.php on line 141

To Reproduce
Use the library with php 8.1

Expected behavior
No warning, can be fix by set the return type of each method.

Allow multiple package versions inside of the package repository

The "package" key in a package repository may be set to an array to define multiple versions of a package: https://getcomposer.org/doc/05-repositories.md#package-2

Here is a payload for the test:

"repositories": [
    {
        "type": "package",
        "package": [
            {
                "name": "smarty/smarty",
                "version": "2.0.0",
                "dist": {
                    "url": "https://www.smarty.net/files/Smarty-2.0.0.zip",
                    "type": "zip"
                },
                "source": {
                    "url": "http://smarty-php.googlecode.com/svn/",
                    "type": "svn",
                    "reference": "tags/Smarty_2_0_0/distribution/"
                },
                "autoload": {
                    "classmap": ["libs/"]
                }
            },
            {
                "name": "smarty/smarty",
                "version": "3.0.0",
                "dist": {
                    "url": "https://www.smarty.net/files/Smarty-3.0.0.zip",
                    "type": "zip"
                },
                "source": {
                    "url": "http://smarty-php.googlecode.com/svn/",
                    "type": "svn",
                    "reference": "tags/Smarty_3_0_0/distribution/"
                },
                "autoload": {
                    "classmap": ["libs/"]
                }
            }
        ]
    }
],

As output I assumed to see repository with array of packages.

Personally I have never seen any project which defines repository packages in this way. Just keep in mind that these changes are breaking because getPackage returns ?ComposerJson right now, but may start to return an array of ComposerJson instances too. I don't really like it because return type becomes mixed ComposerJson|ComposerJson[]|null and will require additional checks in user application to determine what we have inside: is it array or one instance only.

As possible solutions to prevent mixed return type I think it could return array even when there is only one package instance defined. To prevent introduction of breaking changes in v1 this feature could be delayed for the v2 version.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.