Skip to content

Commit 6394983

Browse files
committed
fix(rules): replace abs() with pure int arithmetic in RelativeDateRule
abs(int) returns float|int — Rector removes the (int) cast (treats it as useless) but Psalm requires it for intdiv(). This creates a circular conflict between kcode format (Rector removes cast) and kcode quality (Psalm fails). Solution: $diff >= 0 ? $diff : -$diff is purely int — no cast, no abs(), no conflict between tools. Also applies Rector refactoring suggestions from kcode format run.
1 parent 62a40ff commit 6394983

19 files changed

Lines changed: 165 additions & 109 deletions

src/Core/TransformationContextImpl.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
final readonly class TransformationContextImpl implements TransformationContext
1717
{
1818
/**
19-
* @param string $fieldName
2019
* @param array<string, mixed> $rootData
2120
* @param array<string, mixed> $parameters
2221
*/

src/Core/TransformerEngine.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@
2020
* @author Walmir Silva <walmir.silva@kariricode.org>
2121
* @since 3.1.0 ARFA 1.3
2222
*/
23-
final class TransformerEngine
23+
final readonly class TransformerEngine
2424
{
2525
public function __construct(
26-
private readonly RuleRegistry $registry,
27-
private readonly ?TransformerConfiguration $configuration = null,
26+
private RuleRegistry $registry,
27+
private ?TransformerConfiguration $configuration = null,
2828
) {
2929
}
3030

src/Provider/TransformerServiceProvider.php

Lines changed: 50 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,38 @@
88
use KaririCode\Transformer\Core\AttributeTransformer;
99
use KaririCode\Transformer\Core\InMemoryRuleRegistry;
1010
use KaririCode\Transformer\Core\TransformerEngine;
11-
use KaririCode\Transformer\Rule\Brazilian;
12-
use KaririCode\Transformer\Rule\Data;
13-
use KaririCode\Transformer\Rule\Date;
14-
use KaririCode\Transformer\Rule\Encoding;
15-
use KaririCode\Transformer\Rule\Numeric;
11+
use KaririCode\Transformer\Rule\Brazilian\CepToDigitsRule;
12+
use KaririCode\Transformer\Rule\Brazilian\CnpjToDigitsRule;
13+
use KaririCode\Transformer\Rule\Brazilian\CpfToDigitsRule;
14+
use KaririCode\Transformer\Rule\Brazilian\PhoneFormatRule;
15+
use KaririCode\Transformer\Rule\Data\ArrayToKeyValueRule;
16+
use KaririCode\Transformer\Rule\Data\CsvToArrayRule;
17+
use KaririCode\Transformer\Rule\Data\ImplodeRule;
18+
use KaririCode\Transformer\Rule\Data\JsonDecodeRule;
19+
use KaririCode\Transformer\Rule\Data\JsonEncodeRule;
20+
use KaririCode\Transformer\Rule\Date\AgeRule;
21+
use KaririCode\Transformer\Rule\Date\DateToIso8601Rule;
22+
use KaririCode\Transformer\Rule\Date\DateToTimestampRule;
23+
use KaririCode\Transformer\Rule\Date\RelativeDateRule;
24+
use KaririCode\Transformer\Rule\Encoding\Base64DecodeRule;
25+
use KaririCode\Transformer\Rule\Encoding\Base64EncodeRule;
26+
use KaririCode\Transformer\Rule\Encoding\HashRule;
27+
use KaririCode\Transformer\Rule\Numeric\CurrencyFormatRule;
28+
use KaririCode\Transformer\Rule\Numeric\NumberToWordsRule;
29+
use KaririCode\Transformer\Rule\Numeric\OrdinalRule;
30+
use KaririCode\Transformer\Rule\Numeric\PercentageRule;
1631
use KaririCode\Transformer\Rule\String\CamelCaseRule;
1732
use KaririCode\Transformer\Rule\String\KebabCaseRule;
1833
use KaririCode\Transformer\Rule\String\MaskRule;
1934
use KaririCode\Transformer\Rule\String\PascalCaseRule;
2035
use KaririCode\Transformer\Rule\String\RepeatRule;
2136
use KaririCode\Transformer\Rule\String\ReverseRule;
2237
use KaririCode\Transformer\Rule\String\SnakeCaseRule;
23-
use KaririCode\Transformer\Rule\Structure;
38+
use KaririCode\Transformer\Rule\Structure\FlattenRule;
39+
use KaririCode\Transformer\Rule\Structure\GroupByRule;
40+
use KaririCode\Transformer\Rule\Structure\PluckRule;
41+
use KaririCode\Transformer\Rule\Structure\RenameKeysRule;
42+
use KaririCode\Transformer\Rule\Structure\UnflattenRule;
2443

2544
/**
2645
* Registers all 32 built-in transformation rules.
@@ -61,40 +80,40 @@ private function registerBuiltinRules(InMemoryRuleRegistry $registry): void
6180
$registry->register('repeat', new RepeatRule());
6281

6382
// ── Data (5) ──────────────────────────────────────────────
64-
$registry->register('json_encode', new Data\JsonEncodeRule());
65-
$registry->register('json_decode', new Data\JsonDecodeRule());
66-
$registry->register('csv_to_array', new Data\CsvToArrayRule());
67-
$registry->register('array_to_key_value', new Data\ArrayToKeyValueRule());
68-
$registry->register('implode', new Data\ImplodeRule());
83+
$registry->register('json_encode', new JsonEncodeRule());
84+
$registry->register('json_decode', new JsonDecodeRule());
85+
$registry->register('csv_to_array', new CsvToArrayRule());
86+
$registry->register('array_to_key_value', new ArrayToKeyValueRule());
87+
$registry->register('implode', new ImplodeRule());
6988

7089
// ── Numeric (4) ───────────────────────────────────────────
71-
$registry->register('currency_format', new Numeric\CurrencyFormatRule());
72-
$registry->register('percentage', new Numeric\PercentageRule());
73-
$registry->register('ordinal', new Numeric\OrdinalRule());
74-
$registry->register('number_to_words', new Numeric\NumberToWordsRule());
90+
$registry->register('currency_format', new CurrencyFormatRule());
91+
$registry->register('percentage', new PercentageRule());
92+
$registry->register('ordinal', new OrdinalRule());
93+
$registry->register('number_to_words', new NumberToWordsRule());
7594

7695
// ── Date (4) ──────────────────────────────────────────────
77-
$registry->register('date_to_timestamp', new Date\DateToTimestampRule());
78-
$registry->register('date_to_iso8601', new Date\DateToIso8601Rule());
79-
$registry->register('relative_date', new Date\RelativeDateRule());
80-
$registry->register('age', new Date\AgeRule());
96+
$registry->register('date_to_timestamp', new DateToTimestampRule());
97+
$registry->register('date_to_iso8601', new DateToIso8601Rule());
98+
$registry->register('relative_date', new RelativeDateRule());
99+
$registry->register('age', new AgeRule());
81100

82101
// ── Structure (5) ─────────────────────────────────────────
83-
$registry->register('flatten', new Structure\FlattenRule());
84-
$registry->register('unflatten', new Structure\UnflattenRule());
85-
$registry->register('pluck', new Structure\PluckRule());
86-
$registry->register('group_by', new Structure\GroupByRule());
87-
$registry->register('rename_keys', new Structure\RenameKeysRule());
102+
$registry->register('flatten', new FlattenRule());
103+
$registry->register('unflatten', new UnflattenRule());
104+
$registry->register('pluck', new PluckRule());
105+
$registry->register('group_by', new GroupByRule());
106+
$registry->register('rename_keys', new RenameKeysRule());
88107

89108
// ── Brazilian (4) ─────────────────────────────────────────
90-
$registry->register('cpf_to_digits', new Brazilian\CpfToDigitsRule());
91-
$registry->register('cnpj_to_digits', new Brazilian\CnpjToDigitsRule());
92-
$registry->register('cep_to_digits', new Brazilian\CepToDigitsRule());
93-
$registry->register('phone_format', new Brazilian\PhoneFormatRule());
109+
$registry->register('cpf_to_digits', new CpfToDigitsRule());
110+
$registry->register('cnpj_to_digits', new CnpjToDigitsRule());
111+
$registry->register('cep_to_digits', new CepToDigitsRule());
112+
$registry->register('phone_format', new PhoneFormatRule());
94113

95114
// ── Encoding (3) ──────────────────────────────────────────
96-
$registry->register('base64_encode', new Encoding\Base64EncodeRule());
97-
$registry->register('base64_decode', new Encoding\Base64DecodeRule());
98-
$registry->register('hash', new Encoding\HashRule());
115+
$registry->register('base64_encode', new Base64EncodeRule());
116+
$registry->register('base64_decode', new Base64DecodeRule());
117+
$registry->register('hash', new HashRule());
99118
}
100119
}

src/Result/TransformationResult.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public function isFieldTransformed(string $field): bool
6161
public function transformedFields(): array
6262
{
6363
$fields = [];
64-
foreach ($this->transformedData as $field => $value) {
64+
foreach (array_keys($this->transformedData) as $field) {
6565
if ($this->isFieldTransformed($field)) {
6666
$fields[] = $field;
6767
}

src/Rule/Data/CsvToArrayRule.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,19 +27,19 @@ public function transform(mixed $value, TransformationContext $context): mixed
2727

2828
$separator = (\is_string($_p = $context->getParameter('separator', ',')) ? $_p : '');
2929
$enclosure = (\is_string($_p = $context->getParameter('enclosure', '"')) ? $_p : '');
30-
$hasHeader = (\is_bool($_p = $context->getParameter('header', true)) ? $_p : false);
30+
$hasHeader = (\is_bool($_p = $context->getParameter('header', true)) && $_p);
3131

3232
$lines = array_filter(
3333
explode("\n", str_replace("\r\n", "\n", $value)),
34-
static fn (string $l) => trim($l) !== '',
34+
static fn (string $l): bool => trim($l) !== '',
3535
);
3636

3737
if ($lines === []) {
3838
return [];
3939
}
4040

4141
$rows = array_map(
42-
static fn (string $line) => str_getcsv($line, $separator, $enclosure, escape: '\\'),
42+
static fn (string $line): array => str_getcsv($line, $separator, $enclosure, escape: '\\'),
4343
$lines,
4444
);
4545

@@ -49,7 +49,7 @@ public function transform(mixed $value, TransformationContext $context): mixed
4949
$headers = array_map(static fn (mixed $h): string => (string) $h, $headers);
5050

5151
return array_map(
52-
static fn (array $row) => array_combine($headers, array_pad($row, \count($headers), '')),
52+
static fn (array $row): array => array_combine($headers, array_pad($row, \count($headers), '')),
5353
$rows,
5454
);
5555
}

src/Rule/Date/RelativeDateRule.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public function transform(mixed $value, TransformationContext $context): mixed
3939
: new \DateTimeImmutable('now', new \DateTimeZone('UTC'));
4040

4141
$diff = $now->getTimestamp() - $date->getTimestamp();
42-
$abs = (int) abs($diff);
42+
$abs = $diff >= 0 ? $diff : -$diff;
4343
$suffix = $diff >= 0 ? 'ago' : 'from now';
4444

4545
return match (true) {

src/Rule/Numeric/NumberToWordsRule.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@
1717
*/
1818
final readonly class NumberToWordsRule implements TransformationRule
1919
{
20-
private const ONES = ['', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine',
20+
private const array ONES = ['', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine',
2121
'ten', 'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen'];
22-
private const TENS = ['', '', 'twenty', 'thirty', 'forty', 'fifty', 'sixty', 'seventy', 'eighty', 'ninety'];
22+
private const array TENS = ['', '', 'twenty', 'thirty', 'forty', 'fifty', 'sixty', 'seventy', 'eighty', 'ninety'];
2323

2424
#[\Override]
2525
public function transform(mixed $value, TransformationContext $context): mixed

tests/Conformance/ArchitecturalContractTest.php

Lines changed: 69 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -4,46 +4,80 @@
44

55
namespace KaririCode\Transformer\Tests\Conformance;
66

7+
use KaririCode\Transformer\Contract\TransformationRule;
8+
use KaririCode\Transformer\Core\TransformerEngine;
9+
use KaririCode\Transformer\Rule\Brazilian\CepToDigitsRule;
10+
use KaririCode\Transformer\Rule\Brazilian\CnpjToDigitsRule;
11+
use KaririCode\Transformer\Rule\Brazilian\CpfToDigitsRule;
12+
use KaririCode\Transformer\Rule\Brazilian\PhoneFormatRule;
13+
use KaririCode\Transformer\Rule\Data\ArrayToKeyValueRule;
14+
use KaririCode\Transformer\Rule\Data\CsvToArrayRule;
15+
use KaririCode\Transformer\Rule\Data\ImplodeRule;
16+
use KaririCode\Transformer\Rule\Data\JsonDecodeRule;
17+
use KaririCode\Transformer\Rule\Data\JsonEncodeRule;
18+
use KaririCode\Transformer\Rule\Date\AgeRule;
19+
use KaririCode\Transformer\Rule\Date\DateToIso8601Rule;
20+
use KaririCode\Transformer\Rule\Date\DateToTimestampRule;
21+
use KaririCode\Transformer\Rule\Date\RelativeDateRule;
22+
use KaririCode\Transformer\Rule\Encoding\Base64DecodeRule;
23+
use KaririCode\Transformer\Rule\Encoding\Base64EncodeRule;
24+
use KaririCode\Transformer\Rule\Encoding\HashRule;
25+
use KaririCode\Transformer\Rule\Numeric\CurrencyFormatRule;
26+
use KaririCode\Transformer\Rule\Numeric\NumberToWordsRule;
27+
use KaririCode\Transformer\Rule\Numeric\OrdinalRule;
28+
use KaririCode\Transformer\Rule\Numeric\PercentageRule;
29+
use KaririCode\Transformer\Rule\String\CamelCaseRule;
30+
use KaririCode\Transformer\Rule\String\KebabCaseRule;
31+
use KaririCode\Transformer\Rule\String\MaskRule;
32+
use KaririCode\Transformer\Rule\String\PascalCaseRule;
33+
use KaririCode\Transformer\Rule\String\RepeatRule;
34+
use KaririCode\Transformer\Rule\String\ReverseRule;
35+
use KaririCode\Transformer\Rule\String\SnakeCaseRule;
36+
use KaririCode\Transformer\Rule\Structure\FlattenRule;
37+
use KaririCode\Transformer\Rule\Structure\GroupByRule;
38+
use KaririCode\Transformer\Rule\Structure\PluckRule;
39+
use KaririCode\Transformer\Rule\Structure\RenameKeysRule;
40+
use KaririCode\Transformer\Rule\Structure\UnflattenRule;
741
use PHPUnit\Framework\Attributes\CoversClass;
842
use PHPUnit\Framework\Attributes\Test;
943
use PHPUnit\Framework\TestCase;
1044

11-
#[CoversClass(\KaririCode\Transformer\Core\TransformerEngine::class)]
45+
#[CoversClass(TransformerEngine::class)]
1246
final class ArchitecturalContractTest extends TestCase
1347
{
14-
private const RULE_CLASSES = [
15-
\KaririCode\Transformer\Rule\String\CamelCaseRule::class,
16-
\KaririCode\Transformer\Rule\String\SnakeCaseRule::class,
17-
\KaririCode\Transformer\Rule\String\KebabCaseRule::class,
18-
\KaririCode\Transformer\Rule\String\PascalCaseRule::class,
19-
\KaririCode\Transformer\Rule\String\MaskRule::class,
20-
\KaririCode\Transformer\Rule\String\ReverseRule::class,
21-
\KaririCode\Transformer\Rule\String\RepeatRule::class,
22-
\KaririCode\Transformer\Rule\Data\JsonEncodeRule::class,
23-
\KaririCode\Transformer\Rule\Data\JsonDecodeRule::class,
24-
\KaririCode\Transformer\Rule\Data\CsvToArrayRule::class,
25-
\KaririCode\Transformer\Rule\Data\ArrayToKeyValueRule::class,
26-
\KaririCode\Transformer\Rule\Data\ImplodeRule::class,
27-
\KaririCode\Transformer\Rule\Numeric\CurrencyFormatRule::class,
28-
\KaririCode\Transformer\Rule\Numeric\PercentageRule::class,
29-
\KaririCode\Transformer\Rule\Numeric\OrdinalRule::class,
30-
\KaririCode\Transformer\Rule\Numeric\NumberToWordsRule::class,
31-
\KaririCode\Transformer\Rule\Date\DateToTimestampRule::class,
32-
\KaririCode\Transformer\Rule\Date\DateToIso8601Rule::class,
33-
\KaririCode\Transformer\Rule\Date\RelativeDateRule::class,
34-
\KaririCode\Transformer\Rule\Date\AgeRule::class,
35-
\KaririCode\Transformer\Rule\Structure\FlattenRule::class,
36-
\KaririCode\Transformer\Rule\Structure\UnflattenRule::class,
37-
\KaririCode\Transformer\Rule\Structure\PluckRule::class,
38-
\KaririCode\Transformer\Rule\Structure\GroupByRule::class,
39-
\KaririCode\Transformer\Rule\Structure\RenameKeysRule::class,
40-
\KaririCode\Transformer\Rule\Brazilian\CpfToDigitsRule::class,
41-
\KaririCode\Transformer\Rule\Brazilian\CnpjToDigitsRule::class,
42-
\KaririCode\Transformer\Rule\Brazilian\CepToDigitsRule::class,
43-
\KaririCode\Transformer\Rule\Brazilian\PhoneFormatRule::class,
44-
\KaririCode\Transformer\Rule\Encoding\Base64EncodeRule::class,
45-
\KaririCode\Transformer\Rule\Encoding\Base64DecodeRule::class,
46-
\KaririCode\Transformer\Rule\Encoding\HashRule::class,
48+
private const array RULE_CLASSES = [
49+
CamelCaseRule::class,
50+
SnakeCaseRule::class,
51+
KebabCaseRule::class,
52+
PascalCaseRule::class,
53+
MaskRule::class,
54+
ReverseRule::class,
55+
RepeatRule::class,
56+
JsonEncodeRule::class,
57+
JsonDecodeRule::class,
58+
CsvToArrayRule::class,
59+
ArrayToKeyValueRule::class,
60+
ImplodeRule::class,
61+
CurrencyFormatRule::class,
62+
PercentageRule::class,
63+
OrdinalRule::class,
64+
NumberToWordsRule::class,
65+
DateToTimestampRule::class,
66+
DateToIso8601Rule::class,
67+
RelativeDateRule::class,
68+
AgeRule::class,
69+
FlattenRule::class,
70+
UnflattenRule::class,
71+
PluckRule::class,
72+
GroupByRule::class,
73+
RenameKeysRule::class,
74+
CpfToDigitsRule::class,
75+
CnpjToDigitsRule::class,
76+
CepToDigitsRule::class,
77+
PhoneFormatRule::class,
78+
Base64EncodeRule::class,
79+
Base64DecodeRule::class,
80+
HashRule::class,
4781
];
4882

4983
#[Test]
@@ -61,7 +95,7 @@ public function testAllRulesImplementContract(): void
6195
{
6296
foreach (self::RULE_CLASSES as $class) {
6397
$this->assertTrue(
64-
is_subclass_of($class, \KaririCode\Transformer\Contract\TransformationRule::class),
98+
is_subclass_of($class, TransformationRule::class),
6599
"{$class} must implement TransformationRule",
66100
);
67101
}

tests/Conformance/ImmutableStateTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
use PHPUnit\Framework\Attributes\Test;
1010
use PHPUnit\Framework\TestCase;
1111

12-
#[CoversClass(\KaririCode\Transformer\Core\TransformationContextImpl::class)]
12+
#[CoversClass(TransformationContextImpl::class)]
1313
final class ImmutableStateTest extends TestCase
1414
{
1515
#[Test]

tests/Integration/FullPipelineTest.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,16 @@
44

55
namespace KaririCode\Transformer\Tests\Integration;
66

7+
use KaririCode\Transformer\Core\InMemoryRuleRegistry;
8+
use KaririCode\Transformer\Core\TransformerEngine;
79
use KaririCode\Transformer\Provider\TransformerServiceProvider;
810
use PHPUnit\Framework\Attributes\CoversClass;
911
use PHPUnit\Framework\Attributes\Test;
1012
use PHPUnit\Framework\TestCase;
1113

12-
#[CoversClass(\KaririCode\Transformer\Core\TransformerEngine::class)]
13-
#[CoversClass(\KaririCode\Transformer\Provider\TransformerServiceProvider::class)]
14-
#[CoversClass(\KaririCode\Transformer\Core\InMemoryRuleRegistry::class)]
14+
#[CoversClass(TransformerEngine::class)]
15+
#[CoversClass(TransformerServiceProvider::class)]
16+
#[CoversClass(InMemoryRuleRegistry::class)]
1517
final class FullPipelineTest extends TestCase
1618
{
1719
#[Test]

0 commit comments

Comments
 (0)