Primitives::escape()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 8
nc 3
nop 1
dl 0
loc 13
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Squareetlabs\LaravelToon\Toon;
6
7
class Primitives
8
{
9
    public static function encode(mixed $value): string
10
    {
11
        if (null === $value) {
12
            return Constants::NULL_VALUE;
13
        }
14
15
        if (true === $value) {
16
            return Constants::TRUE_VALUE;
17
        }
18
19
        if (false === $value) {
20
            return Constants::FALSE_VALUE;
21
        }
22
23
        if (is_int($value)) {
24
            return (string)$value;
25
        }
26
27
        if (is_float($value)) {
28
            if (!is_finite($value)) {
29
                return Constants::NULL_VALUE;
30
            }
31
32
            $formatted = sprintf('%.17G', $value);
33
34
            return $formatted;
35
        }
36
37
        if (is_string($value)) {
38
            return self::encodeString($value);
39
        }
40
41
        return '';
42
    }
43
44
    private static function encodeString(string $value): string
45
    {
46
        // No quotes needed for simple alphanumeric strings
47
        if (self::needsQuoting($value)) {
48
            return Constants::QUOTE_CHAR.self::escape($value).Constants::QUOTE_CHAR;
49
        }
50
51
        return $value;
52
    }
53
54
    private static function needsQuoting(string $value): bool
55
    {
56
        if ('' === $value) {
57
            return true;
58
        }
59
60
        // Reserved words
61
        if (in_array($value, [Constants::NULL_VALUE, Constants::TRUE_VALUE, Constants::FALSE_VALUE], true)) {
62
            return true;
63
        }
64
65
        // Numeric strings
66
        if (is_numeric($value)) {
67
            return true;
68
        }
69
70
        // Contains special characters
71
        if (preg_match('/[\\s:,\[\]{}\-"\\\n\r\t]/', $value)) {
72
            return true;
73
        }
74
75
        return false;
76
    }
77
78
    private static function escape(string $value): string
79
    {
80
        $result = '';
81
        for ($i = 0; $i < strlen($value); ++$i) {
82
            $char = $value[$i];
83
            if (in_array($char, Constants::ESCAPABLE_CHARS, true)) {
84
                $result .= Constants::ESCAPE_CHAR.Constants::ESCAPE_MAP[$char];
85
            } else {
86
                $result .= $char;
87
            }
88
        }
89
90
        return $result;
91
    }
92
93
    public static function decode(string $value): mixed
94
    {
95
        $value = trim($value);
96
97
        if ('' === $value) {
98
            return '';
99
        }
100
101
        // Handle quoted strings
102
        if (Constants::QUOTE_CHAR === $value[0]) {
103
            return self::unquote($value);
104
        }
105
106
        // Handle null
107
        if (Constants::NULL_VALUE === $value) {
108
            return null;
109
        }
110
111
        // Handle booleans
112
        if (Constants::TRUE_VALUE === $value) {
113
            return true;
114
        }
115
116
        if (Constants::FALSE_VALUE === $value) {
117
            return false;
118
        }
119
120
        // Handle numbers
121
        if (is_numeric($value)) {
122
            if (false !== strpos($value, '.')) {
123
                return (float)$value;
124
            }
125
126
            return (int)$value;
127
        }
128
129
        return $value;
130
    }
131
132
    private static function unquote(string $value): string
133
    {
134
        // Remove surrounding quotes
135
        $value = substr($value, 1, -1);
136
        if (null === $value) {
137
            return '';
138
        }
139
140
        // Unescape characters
141
        $result = '';
142
        $i = 0;
143
        while ($i < strlen($value)) {
144
            if (Constants::ESCAPE_CHAR === $value[$i] && $i + 1 < strlen($value)) {
145
                $nextChar = $value[$i + 1];
146
                if (isset(Constants::UNESCAPE_MAP[$nextChar])) {
147
                    $result .= Constants::UNESCAPE_MAP[$nextChar];
148
                    $i += 2;
149
                } else {
150
                    $result .= $value[$i];
151
                    ++$i;
152
                }
153
            } else {
154
                $result .= $value[$i];
155
                ++$i;
156
            }
157
        }
158
159
        return $result;
160
    }
161
}
162
163