Specifying Ranges
Ranges can be specified as ">" (greater than), ">=" (greater than or equal to), "<" (less than), or "<=" (less than or equal to).
So, if version 1.15 is the last version that works with our custom code, we could use the following to restrict our installation to using the 1.15 release.
composer require "drupal/admin_toolbar:<= 1.15"
In this case, we could actually just specify the exact version. The less than operator is more useful on the right side of an OR or AND operator. For example, if we knew an upcoming release was going to introduce a breaking change, we could specify ^1.12 <= 1.15
and we'd get at least 1.12, but never go above 1.15.
In the example we're working with, let's add an OR operator to specify multiple possible ranges.
Multiple Ranges
Let's pretend that version 1.17 of Admin Toolbar has a breaking change, but 1.18 will fix it. We can specify multiple ranges to automatically skip version 1.17, and then continue updating to later releases. We've already used the " " (space) to specify the AND operator (you could also use a "," (comma) to indicate AND), now let's use the "||" (double pipe) operator to specify the OR operator.
composer require "drupal/admin_toolbar:<= 1.16 || ^1.18"
You'll see that when I enter the above command, version 1.16 is installed because it is the latest release that is less than or equal to 1.16, OR at least 1.18 (I'm using the "^" (caret) to respect semantic versioning). So with this setup, once 1.18 is released, it will be installed along with future releases.
Let me change the ranges to demonstrate how that works. Let's pretend now, that version 1.16 had the issue and 1.17 fixed it. While we were still using 1.15, we could have typed:
composer require "drupal/admin_toolbar:<= 1.15 || ^1.17"
This time you'll see that version 1.17 is installed because it's the latest that matches our restraints. uFture releases will also be installed because we're using the "^" (caret).