Skip to content

Commit f28b3c5

Browse files
Deprecate codecs in favour of decoders and other things (#33)
1 parent 499847b commit f28b3c5

File tree

88 files changed

+1953
-1642
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

88 files changed

+1953
-1642
lines changed

CHANGELOG.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77
## [Unreleased]
88
### Added
99
- `trasformValidationSuccess` function for decoders. Structurally equivalent to a map. (#24)
10+
- Decoders to replace codecs (#33).
11+
### Changed
12+
- `Validation::sequence` moved to `ListOfValidation::sequence` (#33)
13+
### Deprecated
14+
- The usage of codecs is deprecated in favour of decoders. (#24)
1015
### Fixed
1116
- Used Psalm specific annotations to avoid confusing IDEs without Psalm support. (#26)
12-
### Deprecated
13-
- Usage of codecs is deprecated in favour of decoders. (#24)
17+
- Evety class in the namespace `Facile\PhpCodec\Internal` is marked as internal, and it should not be used outside. (#33)
1418

1519
## [0.0.1] - 2021-04-30
1620
### Added

Makefile

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,14 @@ sh:
1010
docker-compose up -d
1111
docker-compose exec php bash
1212

13-
psalm:
13+
psalm-src:
1414
./vendor/bin/psalm src --no-cache
1515

16+
psalm-tests:
17+
./vendor/bin/psalm tests --no-cache
18+
19+
psalm: psalm-src psalm-tests
20+
1621
type-assertions:
1722
./vendor/bin/psalm tests/type-assertions --no-cache
1823

@@ -29,4 +34,6 @@ cs-fix:
2934
cs-check:
3035
./vendor/bin/php-cs-fixer fix --ansi --verbose --dry-run
3136

32-
ci: test cs-check psalm type-assertions architecture
37+
ci: test cs-fix psalm type-assertions architecture
38+
39+
ci-check: test cs-check psalm type-assertions architecture

README.md

Lines changed: 7 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -30,57 +30,13 @@ Its documentation starts with:
3030
I strongly recomend the reading of [The Idea](https://github.com/gcanti/io-ts/blob/master/index.md#the-idea) section
3131
from the io-ts documentation.
3232

33-
## Types and combinators
34-
35-
All the implemented codecs and combinators are exposed through methods of the class `Facile\PhpCodec\Codecs`.
36-
37-
| Typescript Type | Psalm Type | Codec |
38-
| --- | --- | --- |
39-
| `unknown` | `mixed` | `Codecs::mixed()` |
40-
| `null` | `null` | `Codecs::null()` |
41-
| `bool` | `bool` | `Codecs::bool()` |
42-
| `number` | `int` | `Codecs::int()` |
43-
| `number` | `float` | `Codecs::float()` |
44-
| `string` | `string` | `Codecs::string()` |
45-
| `'s'` | `'s'` | `Codecs::literal('s')` |
46-
| `Array<T>` | `list<T>` | `Codecs::listt(Type $item)` |
47-
| - | `A::class` | `Codecs::classFromArray(Type[] $props, callable $factory, A::class)` |
33+
## Decoders
4834

49-
## Examples
35+
Decoders are objects with decoding capabilities.
36+
A decoder of type `Decoder<I, A>` takes an input of type `I` and builds a result of type `Validation<A>`.
37+
38+
The class `Facile\PhpCodec\Decoders` provides a list of built-in decoders.
5039

51-
For further examples take a look to the [examples](https://github.com/facile-it/php-codec/tree/master/tests/examples):
52-
53-
```php
54-
use Facile\PhpCodec\Codecs;
55-
56-
$codec = Codecs::classFromArray(
57-
[
58-
'a' => Codecs::string(),
59-
'b' => Codecs::int(),
60-
'c' => Codecs::bool(),
61-
'd' => Codecs::float()
62-
],
63-
function (string $a, int $b, bool $c, float $d): Foo {
64-
return new Foo($a, $b, $c, $d);
65-
},
66-
Foo::class
67-
);
68-
69-
// Gives an instance of ValidationSuccess<Foo>
70-
$validation = $codec->decode(['a' => 'hey', 'b' => 123, 'c' => false, 'd' => 1.23]);
71-
72-
// Gives an instance of ValidationFailures
73-
$failures = $codec->decode(['a' => 'hey', 'b' => 123, 'c' => 'a random string', 'd' => 1.23]);
74-
75-
class Foo {
76-
public function __construct(
77-
string $a,
78-
int $b,
79-
bool $c,
80-
float $d
81-
) {
82-
// [...]
83-
}
84-
}
85-
```
40+
## Examples
8641

42+
Take a look to the [examples](https://github.com/facile-it/php-codec/tree/master/tests/examples) folder.

composer.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33
"description": "A partial porting of io-ts in PHP",
44
"type": "library",
55
"require-dev": {
6-
"vimeo/psalm": "^4.4.0",
76
"phpunit/phpunit": "^8.5",
87
"giorgiosironi/eris": "^0.12.0",
98
"phpunit/php-code-coverage": "^7.0",
109
"phpat/phpat": "^0.7.5",
11-
"facile-it/facile-coding-standard": "^0.4.1"
10+
"facile-it/facile-coding-standard": "^0.4.1",
11+
"icomefromthenet/reverse-regex": "^0.1.0"
1212
},
1313
"license": "MIT",
1414
"authors": [
@@ -35,7 +35,8 @@
3535
}
3636
},
3737
"require": {
38-
"php": "^7.2 | ^8.0"
38+
"php": "^7.2 | ^8.0",
39+
"vimeo/psalm": "^4.8"
3940
},
4041
"prefer-stable": true,
4142
"archive": {

psalm.xml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@
1010
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
1111
>
1212
<projectFiles>
13-
<directory name="src" />
14-
<directory name="tests/type-assertions" />
13+
<directory name="src"/>
14+
<directory name="tests"/>
1515
<ignoreFiles>
16-
<directory name="vendor" />
16+
<directory name="vendor"/>
1717
</ignoreFiles>
1818
</projectFiles>
1919
</psalm>

src/Codecs.php

Lines changed: 70 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -4,70 +4,66 @@
44

55
namespace Facile\PhpCodec;
66

7-
use Facile\PhpCodec\Internal\Arrays\ListCodec;
8-
use Facile\PhpCodec\Internal\Arrays\MapType;
9-
use Facile\PhpCodec\Internal\Combinators\ClassFromArray;
10-
use Facile\PhpCodec\Internal\Combinators\ComposeCodec;
11-
use Facile\PhpCodec\Internal\Combinators\LiteralType;
12-
use Facile\PhpCodec\Internal\Combinators\UnionCodec;
7+
use Facile\PhpCodec\Internal\Combinators\PipeCodec;
138
use Facile\PhpCodec\Internal\IdentityEncoder;
14-
use Facile\PhpCodec\Internal\Primitives\BoolType;
15-
use Facile\PhpCodec\Internal\Primitives\CallableDecoder;
16-
use Facile\PhpCodec\Internal\Primitives\FloatType;
17-
use Facile\PhpCodec\Internal\Primitives\IntDecoder;
18-
use Facile\PhpCodec\Internal\Primitives\MixedDecoder;
19-
use Facile\PhpCodec\Internal\Primitives\NullType;
20-
use Facile\PhpCodec\Internal\Primitives\StringType;
219
use Facile\PhpCodec\Internal\Primitives\UndefinedDecoder;
22-
use Facile\PhpCodec\Internal\Useful\DateTimeFromIsoStringType;
23-
use Facile\PhpCodec\Internal\Useful\IntFromStringDecoder;
24-
use Facile\PhpCodec\Internal\Useful\RegexType;
2510
use Facile\PhpCodec\Utils\ConcreteCodec;
2611

2712
final class Codecs
2813
{
2914
/**
3015
* @psalm-return Codec<null, mixed, null>
16+
*
17+
* @deprecated use decoder instead
18+
* @see Decoders::null()
3119
*/
3220
public static function null(): Codec
3321
{
34-
return new NullType();
22+
return self::fromDecoder(Decoders::null());
3523
}
3624

3725
/**
3826
* @psalm-return Codec<string, mixed, string>
27+
*
28+
* @deprecated use decoder instead
29+
* @see Decoders::string()
3930
*/
4031
public static function string(): Codec
4132
{
42-
return new StringType();
33+
return self::fromDecoder(Decoders::string());
4334
}
4435

4536
/**
46-
* @template I of mixed
47-
* @psalm-return Codec<int, I, int>
37+
* @psalm-return Codec<int, mixed, int>
4838
*
4939
* @deprecated use decoder instead
5040
* @see Decoders::int()
5141
*/
5242
public static function int(): Codec
5343
{
54-
return self::fromDecoder(new IntDecoder());
44+
return self::fromDecoder(Decoders::int());
5545
}
5646

5747
/**
5848
* @psalm-return Codec<float, mixed, float>
49+
*
50+
* @deprecated use decoder instead
51+
* @see Decoders::float()
5952
*/
6053
public static function float(): Codec
6154
{
62-
return new FloatType();
55+
return self::fromDecoder(Decoders::float());
6356
}
6457

6558
/**
6659
* @psalm-return Codec<bool, mixed, bool>
60+
*
61+
* @deprecated use decoder instead
62+
* @see Decoders::bool()
6763
*/
6864
public static function bool(): Codec
6965
{
70-
return new BoolType();
66+
return self::fromDecoder(Decoders::bool());
7167
}
7268

7369
/**
@@ -76,10 +72,13 @@ public static function bool(): Codec
7672
* @psalm-return Codec<T, mixed, T>
7773
*
7874
* @param mixed $x
75+
*
76+
* @deprecated use decoder instead
77+
* @see Decoders::literal()
7978
*/
8079
public static function literal($x): Codec
8180
{
82-
return new LiteralType($x);
81+
return self::fromDecoder(Decoders::literal($x));
8382
}
8483

8584
/**
@@ -90,42 +89,60 @@ public static function literal($x): Codec
9089
*/
9190
public static function intFromString(): Codec
9291
{
93-
return self::fromDecoder(new IntFromStringDecoder());
92+
return self::fromDecoder(Decoders::intFromString());
9493
}
9594

9695
/**
97-
* @psalm-return Codec<\DateTime, string, \DateTime>
96+
* @psalm-return Codec<\DateTimeInterface, string, \DateTimeInterface>
97+
*
98+
* @deprecated use decoder instead
99+
* @see Decoders::dateTimeFromString()
98100
*/
99101
public static function dateTimeFromIsoString(): Codec
100102
{
101-
return new DateTimeFromIsoStringType();
103+
return self::fromDecoder(Decoders::dateTimeFromString());
102104
}
103105

104106
/**
105107
* @psalm-template T
106108
* @psalm-param Codec<T, mixed, T> $itemCodec
107109
* @psalm-return Codec<list<T>, mixed, list<T>>
110+
*
111+
* @deprecated use decoder instead
112+
* @see Decoders::listOf()
108113
*/
109114
public static function listt(Codec $itemCodec): Codec
110115
{
111-
return new ListCodec($itemCodec);
116+
return self::fromDecoder(Decoders::listOf($itemCodec));
112117
}
113118

114119
/**
115-
* @psalm-template T
116-
* @psalm-param non-empty-array<string, Codec> $props
120+
* @psalm-template T of object
121+
* @psalm-template K of array-key
122+
* @psalm-template Vs
123+
* @psalm-template PD of non-empty-array<K, Decoder<mixed, Vs>>
124+
* @psalm-param PD $props
117125
* @psalm-param callable(...mixed):T $factory
118126
* @psalm-param class-string<T> $fqcn
119127
* @psalm-return Codec<T, mixed, T>
128+
*
129+
* @deprecated use decoder instead
130+
* @see Decoders::classFromArrayPropsDecoder()
120131
*/
121132
public static function classFromArray(
122133
array $props,
123134
callable $factory,
124135
string $fqcn
125136
): Codec {
126-
return self::pipe(
127-
new MapType(),
128-
new ClassFromArray($props, $factory, $fqcn)
137+
/** @var Decoder<mixed, non-empty-array<array-key, Vs>> $propsDecoder */
138+
$propsDecoder = Decoders::arrayProps($props);
139+
140+
return self::fromDecoder(
141+
Decoders::classFromArrayPropsDecoder(
142+
$propsDecoder,
143+
$factory,
144+
$fqcn
145+
)
129146
);
130147
}
131148

@@ -150,7 +167,7 @@ public static function classFromArray(
150167
* @psalm-return (func_num_args() is 2 ? Codec<B, IA, OB>
151168
* : (func_num_args() is 3 ? Codec<C, IA, OC>
152169
* : (func_num_args() is 4 ? Codec<D, IA, OD>
153-
* : (func_num_args() is 5 ? Codec<E, IA, OC> : Codec)
170+
* : (func_num_args() is 5 ? Codec<E, IA, OE> : Codec)
154171
* )))
155172
*/
156173
public static function pipe(
@@ -161,32 +178,45 @@ public static function pipe(
161178
?Codec $e = null
162179
): Codec {
163180
// Order is important: composition is not commutative
164-
return new ComposeCodec(
181+
return new PipeCodec(
165182
$a,
166183
$c instanceof Codec
167184
? self::pipe($b, $c, $d, $e)
168185
: $b
169186
);
170187
}
171188

189+
/**
190+
* @param Codec $a
191+
* @param Codec $b
192+
* @param Codec ...$others
193+
*
194+
* @return Codec
195+
*
196+
* @deprecated use decoder instead
197+
* @see Decoders::union()
198+
*/
172199
public static function union(Codec $a, Codec $b, Codec ...$others): Codec
173200
{
174201
// Order is important, this is not commutative
175202
return \array_reduce(
176203
$others,
177204
static function (Codec $carry, Codec $current): Codec {
178-
return new UnionCodec($current, $carry);
205+
return self::fromDecoder(Decoders::union($current, $carry));
179206
},
180-
new UnionCodec($a, $b)
207+
self::fromDecoder(Decoders::union($a, $b))
181208
);
182209
}
183210

184211
/**
185212
* @psalm-return Codec<string[], string, string[]>
213+
*
214+
* @deprecated use decoder instead
215+
* @see Decoders::regex()
186216
*/
187217
public static function regex(string $regex): Codec
188218
{
189-
return new RegexType($regex);
219+
return self::fromDecoder(Decoders::regex($regex));
190220
}
191221

192222
/**
@@ -226,7 +256,7 @@ public static function undefined($default = null): Codec
226256
*/
227257
public static function mixed(): Codec
228258
{
229-
return self::fromDecoder(new MixedDecoder());
259+
return self::fromDecoder(Decoders::mixed());
230260
}
231261

232262
/**
@@ -237,6 +267,6 @@ public static function mixed(): Codec
237267
*/
238268
public static function callable(): Codec
239269
{
240-
return self::fromDecoder(new CallableDecoder());
270+
return self::fromDecoder(Decoders::callable());
241271
}
242272
}

0 commit comments

Comments
 (0)