Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
b3e393a
flag internal classes
Baptouuuu Nov 2, 2025
44cd3cd
require php 8.4
Baptouuuu Nov 2, 2025
c8271d2
remove named constructor from interface as it is not always implement…
Baptouuuu Nov 2, 2025
73dd863
update dependencies
Baptouuuu Nov 2, 2025
e5ecc0d
CS
Baptouuuu Nov 2, 2025
50edb83
add Template::attempt()
Baptouuuu Nov 2, 2025
2f9afb4
use Attempt when parsing expansion names for more explicit errors
Baptouuuu Nov 2, 2025
fed361d
add fluent api to define expansions
Baptouuuu Nov 2, 2025
cf1b422
better decompose the steps to explode level 4 expansions
Baptouuuu Nov 2, 2025
f627f6e
better decompose the kind of variables to use to expand
Baptouuuu Nov 2, 2025
572e356
remove unnecessary passing variables
Baptouuuu Nov 2, 2025
504c0cb
explicitly define the kind of expressions used in properties
Baptouuuu Nov 2, 2025
3a58eba
no need for NamedValues to implements Expression
Baptouuuu Nov 2, 2025
b3e1058
simplify encoding expanded values
Baptouuuu Nov 2, 2025
3f80cf2
remove dead code
Baptouuuu Nov 2, 2025
de01669
guarantee order of named values
Baptouuuu Nov 2, 2025
cc6fcc1
remove todo
Baptouuuu Nov 2, 2025
9fbb8f9
use more explicit int range
Baptouuuu Nov 2, 2025
355bbf6
use monadic style for level 4 expansion
Baptouuuu Nov 2, 2025
5924e61
wrap keys early on in the expansion mechanism
Baptouuuu Nov 3, 2025
69e887a
dispatch variables at declaration time instead of expand time
Baptouuuu Nov 3, 2025
af5333c
fix the declared exception being thrown
Baptouuuu Nov 3, 2025
2068a84
wrap returns of Template methods that may throw an exception in an At…
Baptouuuu Nov 3, 2025
60ba783
use Attempts instead of throwing to better track errors
Baptouuuu Nov 3, 2025
fba6e08
remove custom exceptions
Baptouuuu Nov 3, 2025
d6c0ce0
use an enum to distinguish the different strategies to encode chars
Baptouuuu Nov 3, 2025
c064bcd
use promoted properties
Baptouuuu Nov 3, 2025
5086adc
avoid storing the name twice
Baptouuuu Nov 3, 2025
ee938a4
tag dependencies
Baptouuuu Jan 25, 2026
a9a0657
fix warnings
Baptouuuu Jan 25, 2026
9d9dfa8
remove todos
Baptouuuu Jan 25, 2026
9d96710
update changelog
Baptouuuu Jan 25, 2026
24a9430
add extensive CI
Baptouuuu Jan 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,3 @@ jobs:
uses: innmind/github-workflows/.github/workflows/psalm-matrix.yml@main
cs:
uses: innmind/github-workflows/.github/workflows/cs.yml@main
with:
php-version: '8.2'
12 changes: 12 additions & 0 deletions .github/workflows/extensive.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
name: Extensive CI

on:
push:
tags:
- '*'
paths:
- '.github/workflows/extensive.yml'

jobs:
blackbox:
uses: innmind/github-workflows/.github/workflows/extensive.yml@main
19 changes: 18 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,26 @@

## [Unreleased]

### Added

- `Innmind\UrlTemplate\Template::attempt()`
- `Innmind\UrlTemplate\Template::expansion()`

### Changed

- Requires `innmind/immutable:~5.18`
- Requires `innmind/immutable:~6.0`
- Requires `innmind/url:~5.0`
- Requires PHP `8.4`
- `Innmind\UrlTemplate\Template::extract()` now returns an `Innmind\Immutable\Attempt`
- `Innmind\UrlTemplate\Template::matches()` now returns an `Innmind\Immutable\Attempt`

### Removed

- `Innmind\UrlTemplate\Template::expand()`, use `::expansion()` instead
- `Innmind\UrlTemplate\Exception\Exception`
- `Innmind\UrlTemplate\Exception\LogicException`
- `Innmind\UrlTemplate\Exception\DomainException`
- `Innmind\UrlTemplate\Exception\ExplodeExpressionCantBeMatched`

## 3.1.0 - 2023-09-16

Expand Down
8 changes: 4 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@
"issues": "http://github.com/Innmind/UrlTemplate/issues"
},
"require": {
"php": "~8.2",
"innmind/url": "~4.1",
"innmind/immutable": "~5.18"
"php": "~8.4",
"innmind/url": "~5.0",
"innmind/immutable": "~6.0"
},
"autoload": {
"psr-4": {
Expand All @@ -30,7 +30,7 @@
}
},
"require-dev": {
"innmind/static-analysis": "^1.2.1",
"innmind/static-analysis": "~1.3",
"innmind/black-box": "~6.5",
"innmind/coding-standard": "~2.0"
}
Expand Down
8 changes: 0 additions & 8 deletions src/Exception/DomainException.php

This file was deleted.

8 changes: 0 additions & 8 deletions src/Exception/Exception.php

This file was deleted.

8 changes: 0 additions & 8 deletions src/Exception/ExplodeExpressionCantBeMatched.php

This file was deleted.

8 changes: 0 additions & 8 deletions src/Exception/LogicException.php

This file was deleted.

113 changes: 113 additions & 0 deletions src/Expansion.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
<?php
declare(strict_types = 1);

namespace Innmind\UrlTemplate;

use Innmind\UrlTemplate\Expression\Name;
use Innmind\Url\Url;
use Innmind\Immutable\{
Sequence,
Str,
Map,
};

/**
* @psalm-immutable
*/
final class Expansion
{
/**
* @param Sequence<Expression> $expressions
* @param Map<non-empty-string, string> $values
* @param Map<non-empty-string, list<string>> $lists
* @param Map<non-empty-string, list<array{Name, string}>> $keys
*/
private function __construct(
private Str $template,
private Sequence $expressions,
private Map $values,
private Map $lists,
private Map $keys,
) {
}

/**
* @psalm-pure
* @internal
*
* @param Sequence<Expression> $expressions
*/
public static function of(Str $template, Sequence $expressions): self
{
return new self(
$template,
$expressions,
Map::of(),
Map::of(),
Map::of(),
);
}

/**
* @no-named-arguments
*
* @param non-empty-string $name
*/
public function with(string $name, string ...$values): self
{
if (\count($values) === 1) {
return new self(
$this->template,
$this->expressions,
($this->values)($name, $values[0]),
$this->lists->remove($name),
$this->keys->remove($name),
);
}

return new self(
$this->template,
$this->expressions,
$this->values->remove($name),
($this->lists)($name, $values),
$this->keys->remove($name),
);
}

/**
* @no-named-arguments
*
* @param non-empty-string $name
* @param array{string, string} ...$keys
*/
public function withKeys(string $name, array ...$keys): self
{
return new self(
$this->template,
$this->expressions,
$this->values->remove($name),
$this->lists->remove($name),
($this->keys)($name, \array_map(
static fn($pair) => [Name::of($pair[0]), $pair[1]],
$keys,
)),
);
}

public function expand(): Url
{
$url = $this->expressions->reduce(
$this->template,
fn(Str $template, $expression) => $template->replace(
$expression->toString(),
$expression->expand(
$this->values,
$this->lists,
$this->keys,
),
),
);

return Url::of($url->toString());
}
}
21 changes: 10 additions & 11 deletions src/Expression.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@

namespace Innmind\UrlTemplate;

use Innmind\UrlTemplate\Expression\Name;
use Innmind\Immutable\{
Map,
Str,
Maybe,
Attempt,
};

/**
Expand All @@ -15,19 +15,18 @@
*/
interface Expression
{
public function expansion(): Expression\Expansion;

/**
* @psalm-pure
*
* @return Maybe<self>
* @param Map<non-empty-string, string> $values
* @param Map<non-empty-string, list<string>> $lists
* @param Map<non-empty-string, list<array{Name, string}>> $keys
*/
public static function of(Str $string): Maybe;

public function expansion(): Expression\Expansion;
public function expand(Map $values, Map $lists, Map $keys): string;

/**
* @param Map<non-empty-string, string|list<string>|list<array{string, string}>> $variables
* @return Attempt<string>
*/
public function expand(Map $variables): string;
public function regex(): string;
public function regex(): Attempt;
public function toString(): string;
}
49 changes: 27 additions & 22 deletions src/Expression/Level1.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,41 +10,43 @@
use Innmind\Immutable\{
Map,
Str,
Maybe,
Attempt,
};

/**
* @psalm-immutable
* @internal
*/
final class Level1 implements Expression
{
private Name $name;
private UrlEncode $encode;

private function __construct(Name $name)
{
$this->name = $name;
$this->encode = new UrlEncode;
private function __construct(
private Name $name,
private UrlEncode $encode,
) {
}

/**
* @psalm-pure
*
* @return Attempt<self>
*/
#[\Override]
public static function of(Str $string): Maybe
public static function of(Str $string): Attempt
{
/** @var Maybe<Expression> */
return Name::one($string, Expansion::simple)->map(
static fn($name) => new self($name),
);
return Name::one($string, Expansion::simple)
->map(self::named(...));
}

/**
* @psalm-pure
*/
public static function named(Name $name): self
{
return new self($name);
return new self($name, UrlEncode::everything);
}

public function name(): Name
{
return $this->name;
}

#[\Override]
Expand All @@ -54,22 +56,25 @@ public function expansion(): Expansion
}

#[\Override]
public function expand(Map $variables): string
public function expand(Map $values, Map $lists, Map $keys): string
{
/** @psalm-suppress InvalidArgument Because of the filter */
return $variables
return $values
->get($this->name->toString())
->filter(\is_string(...))
->match(
fn(string $variable) => ($this->encode)($variable),
$this->encode->encode(...),
static fn() => '',
);
}

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

#[\Override]
public function regex(): string
public function regex(): Attempt
{
return "(?<{$this->name->toString()}>[a-zA-Z0-9\%\-\.\_\~]*)";
return Attempt::result("(?<{$this->name->toString()}>[a-zA-Z0-9\%\-\.\_\~]*)");
}

#[\Override]
Expand Down
Loading