Repository navigation
Conversation
…stead of composer/semver fix(version): read a stability keyword only as a whole word, so `-arm64`, `-build.5` or `-ga` is a feature tail, not alpha or beta, and a lone letter glued to the number, like `1.1.1b`, is a patch letter (#153) fix(version): ignore build metadata when comparing versions, so `1.2.3+5` equals `1.2.3` Constraints are parsed into alternatives of comparisons against bound versions and checked with Version::compare(), so matching and sorting share one order: numbered pre-releases and tails in bounds, a numeric tail like `3.5.0-1` (before, `<3.5.0-preview.3` accepted it while sorting put it above `3.5.0`), any count of number parts (`>=1.2.3.4.5`) and versions Composer could not read (`20250101.1.2.3`). The Composer syntax keeps its meaning: `^`, `~`, wildcards, `||`, AND by space or comma; hyphen ranges, `!=`, a `v` prefix and a space after an operator now work too. composer/semver moves to require-dev, where a test compares the new matcher with it. Closes #154 Closes #153 Assisted-By: Claude Opus 5.5 <noreply@anthropic.com>
fix(version): build metadata after one or two number parts, as in `1.2+5`, makes a stable release of `1.2`, not a preview of `1.2.5` A pre-release bound in a range, like `>=1.0 <2.0-RC1`, `^1.0 || ^2.0-beta.1` or `1.0.0-beta.1 - 2.0.0`, now bounds the range instead of turning into a feature suffix or an error. The lowest stability among the bounds is the minimum stability; an explicit @stability still wins. Feature suffixes, like `^1.0.0-experimental`, read as before. Also: a lone patch letter in a binary's output, like OpenSSL's `1.1.1b`, reads as `1.1.1` again; `1.0.0-1` matches its release again, its numeric tail being a part of the bound; `<>` is not equal; huge number parts, as in `^99999999999999999999`, no longer overflow; `> =1.0` is rejected and an empty term, like `1.2,`, gets its own message. The README files show the range syntax among the constraint examples. Assisted-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
🟡 Changes recommended
Oversized numeric components can compare incorrectly, and standard alphanumeric build metadata remains unsupported.
3 open findings
What changed in this PR
Replaces Composer-based constraint matching with DLoad’s native version ordering while expanding Composer-compatible syntax and stability parsing.
Changes:
- Adds native range parsing and comparison primitives.
- Improves pre-release, suffix, metadata, and binary-version handling.
- Expands tests and documentation; moves
composer/semverto development dependencies.
| File | Description |
|---|---|
src/Module/Version/Range.php |
Adds constraint range parsing. |
src/Module/Version/Comparison.php |
Adds bound comparisons. |
src/Module/Version/Operator.php |
Defines comparison operators. |
src/Module/Version/Constraint.php |
Uses native range matching. |
src/Module/Version/Version.php |
Updates parsing and ordering. |
src/Module/Version/PreRelease.php |
Adds whole-word stability matching. |
src/Module/Binary/BinaryVersion.php |
Refines binary output parsing. |
tests/Unit/Module/Version/RangeTest.php |
Tests native range behavior. |
tests/Unit/Module/Version/RangeComposerTest.php |
Compares behavior with Composer. |
tests/Unit/Module/Version/ConstraintTest.php |
Expands constraint coverage. |
tests/Unit/Module/Version/VersionTest.php |
Tests parsing and ordering. |
tests/Unit/Module/Binary/BinaryVersionTest.php |
Tests binary version extraction. |
composer.json |
Moves Semver to development dependencies. |
composer.lock |
Updates dependency placement. |
README.md |
Documents additional constraint syntax. |
README-zh.md |
Updates Chinese documentation. |
README-ru.md |
Updates Russian documentation. |
README-es.md |
Updates Spanish documentation. |
dload.xsd |
Expands schema examples. |
skills/dload-fetch-tool/SKILL.md |
Documents extended version numbers. |
skills/dload-fetch-tool/references/troubleshooting.md |
Documents suffix stability behavior. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| private static function parseVersion(string $version): ?array | ||
| { | ||
| # Build metadata does not count, so the number goes without it | ||
| $pattern = '/^v?(\d+(?:\.\d+)*)(?:\+\d+)?(?:-(' . self::preReleasePattern() . '))?$/i'; |
|
|
||
| /** A suffix starting with a letter may follow the number right away: `2.0.0rc1`, `1.2.3_beta2`. */ | ||
| protected const VERSION_FALLBACK_PATTERN = 'v?(\d+(?:\.\d+(?:\.\d+(?:\.\d+)*(?:\+\d+)?)?)?)((?:[-+.]|(?=[a-z_]))[\w.-]+)?'; | ||
| protected const VERSION_FALLBACK_PATTERN = 'v?(\d+(?:\.\d+)*(?:\+\d+)?)((?:[-+.]|(?=[a-z_]))[\w.-]+)?'; |
| */ | ||
| public function compareNumber(self $other): int | ||
| { | ||
| return \version_compare($this->comparableNumber(), $other->comparableNumber()); |
`>2.0-beta` now accepts 2.0.0-RC1 and 2.0.0, `<=2.0-beta` rejects 2.0.0 and `!=2.0-beta` excludes only 2.0.0-beta, as in Composer and as the same term already matched within a range. The keyword still sets the minimum stability unless `@` overrides it. A digit inside a feature suffix is no longer taken for a pre-release bound, so `^1.0.0-x64-1`, `^2.0-php8-1` and `1.0.0-beta.1-2` parse again. Assisted-By: Claude Opus 5.5 <noreply@anthropic.com>
2 tasks done
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

What was changed
Rangeof OR-ed groups of AND-edComparisons against boundVersions) instead ofcomposer/semver, so matching and release sorting share one order: numbered pre-releases and tails, numeric tails like1.0.0-1, trailing zeros, build metadata and any count of number parts on both sides (>=1.2.3.4.5).^,~, wildcards,||, AND by space or comma), and more of it now works: hyphen ranges (1.0 - 2.0),!=/<>, avprefix, a space after the operator, pre-release bounds inside multi-term constraints (>=1.0 <2.0-RC1,^1.0 || ^2.0-beta.1), where the lowest bound's stability is the minimum. Malformed constraints fail when parsed, with a message, instead of on every match.-arm64is alpha) #153):-arm64,-build.5,-gaare feature tails, not alpha or beta;-a1,-beta2,2.0.0rc1,1.0.0b2stay pre-releases. A lone letter glued to the number (1.1.1b) is a patch letter, andOpenSSL 1.1.1bin--versionoutput reads as stable1.1.1.composer/semvermoves torequire-dev, whereRangeComposerTestchecks the new matcher against it.Why?
#150 had to bend versions to Composer's parser (at most four number parts, a major part of at most five digits) and decide pre-releases on its own, which left matching and sorting disagreeing, e.g.
<3.5.0-preview.3accepted3.5.0-1while sorting put it above3.5.0. This targets the #150 branch so it lands together with it.Review notes
>=3.5.0-beta.1 <3.5.0is empty; write<3.5.0-RC1.20250101.1.2.3), numeric tails, and constraints that used to throw.Checklist
-arm64is alpha) #153