Skip to content

Instantly share code, notes, and snippets.

@ArrayIterator
Created October 19, 2024 01:29
Show Gist options
  • Save ArrayIterator/dd25215a2fcbbbd7daff2ccb13faa6e9 to your computer and use it in GitHub Desktop.
Save ArrayIterator/dd25215a2fcbbbd7daff2ccb13faa6e9 to your computer and use it in GitHub Desktop.

Revisions

  1. ArrayIterator created this gist Oct 19, 2024.
    161 changes: 161 additions & 0 deletions SemanticVersion.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,161 @@
    <?php
    declare(strict_types=1);

    class SemanticVersion implements JsonSerializable
    {
    /**
    * Regex pattern for semantic versioning
    * eg:
    * 1.2.3
    * v1.2.3
    * 1.2.3-beta
    * 1.2.3-beta.1
    * 1.2.3-beta.1+build.1
    * 1.2.3+build.1
    * 1.2.3+build.1.2
    *
    * contains array matched keys:
    * {
    * "prefix"?: "[a-zA-Z]+",
    * "major": "[0-9]+",
    * "minor": "[0-9]+",
    * "patch": "[0-9]+",
    * "release_separator"?: "[+\-]", // optional
    * "release"?: "[a-zA-Z0-9]+([a-zA-Z0-9.+\-]*[a-zA-Z0-9])?", // optional the release version
    * }
    */
    public const SEMANTIC_VERSION_REGEX = '^
    (?x)
    (?<prefix>[a-zA-Z]+)? # optional prefix: eg : "v" in "v1.2.3"
    (?P<major>[0-9]+) # major version
    \.(?P<minor>[0-9]+) # minor version
    \.(?P<patch>[0-9]+) # patch version
    (?:
    (?P<release_separator>[+\-])
    (?P<release>
    [a-zA-Z0-9]+ # should start with a number or a letter
    (?:
    [a-zA-Z0-9.+\-]* # allow any number of letters, numbers, dots, plus and minus
    [a-zA-Z0-9] # should end with a number or a letter
    )?
    ) # release version
    )?
    $';

    /**
    * The version string
    *
    * @var string
    */
    public readonly string $version;

    /**
    * Is the version string valid
    *
    * @var bool
    */
    public readonly bool $valid;

    /**
    * The major version
    *
    * @var int|null
    */
    public readonly ?int $major;

    /**
    * The minor version
    *
    * @var int|null
    */
    public readonly ?int $minor;

    /**
    * The patch version
    *
    * @var int|null
    */
    public readonly ?int $patch;

    /**
    * The release separator
    *
    * @var string|null
    */
    public readonly ?string $releaseSeparator;

    /**
    * The release version
    *
    * @var string|null
    */
    public readonly ?string $release;

    /**
    * SemanticVersion constructor.
    *
    * @param string $version
    */
    public function __construct(string $version)
    {
    $this->version = trim($version);

    preg_match('/' . self::SEMANTIC_VERSION_REGEX . '/', $this->version, $matches);

    $this->valid = !empty($matches);
    $this->major = is_array($matches) && isset($matches['major']) ? (int) $matches['major'] : null;
    $this->minor = is_array($matches) && isset($matches['minor']) ? (int) $matches['minor'] : null;
    $this->patch = is_array($matches) && isset($matches['patch']) ? (int) $matches['patch'] : null;
    $this->releaseSeparator = is_array($matches)
    && isset($matches['release_separator'])
    ? $matches['release_separator']
    : null;
    $this->release = is_array($matches) && isset($matches['release']) ? $matches['release'] : null;
    }

    public function __toString(): string
    {
    return $this->version;
    }

    /**
    * @return array{
    * version: string,
    * valid: bool,
    * major: int|null,
    * minor: int|null,
    * patch: int|null,
    * release_separator: string|null,
    * release: string|null
    * }
    */
    public function toArray(): array
    {
    return [
    'version' => $this->version,
    'valid' => $this->valid,
    'major' => $this->major,
    'minor' => $this->minor,
    'patch' => $this->patch,
    'release_separator' => $this->releaseSeparator,
    'release' => $this->release,
    ];
    }

    /**
    * @return array{
    * version: string,
    * valid: bool,
    * major: int|null,
    * minor: int|null,
    * patch: int|null,
    * release_separator: string|null,
    * release: string|null
    * }
    */
    public function jsonSerialize(): array
    {
    return $this->toArray();
    }
    }