Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
91.67% covered (success)
91.67%
11 / 12
80.00% covered (warning)
80.00%
4 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
JavascriptIdentifier
91.67% covered (success)
91.67%
11 / 12
80.00% covered (warning)
80.00%
4 / 5
9.05
0.00% covered (danger)
0.00%
0 / 1
 getRegularExpression
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 validate
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
3
 createFromText
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 createRandom
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 humanize
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2namespace Apie\TypescriptCodeBuilder\ValueObjects;
3
4use Apie\Core\Attributes\Description;
5use Apie\Core\Attributes\FakeMethod;
6use Apie\Core\Identifiers\KebabCaseSlug;
7use Apie\Core\Utils\IdentifierConstants;
8use Apie\Core\ValueObjects\Exceptions\InvalidStringForValueObjectException;
9use Apie\Core\ValueObjects\Interfaces\HasRegexValueObjectInterface;
10use Apie\Core\ValueObjects\IsStringWithRegexValueObject;
11use Faker\Generator;
12use ReflectionClass;
13
14#[FakeMethod('createRandom')]
15#[Description('A valid JavaScript identifier that is not a reserved keyword')]
16class JavascriptIdentifier implements HasRegexValueObjectInterface
17{
18    use IsStringWithRegexValueObject;
19
20    private const RESERVED_WORDS = [
21        'as', 'assert', 'async', 'await', 'break', 'case', 'catch', 'class', 'const',
22        'continue', 'debugger', 'default', 'delete', 'do', 'else', 'export', 'extends',
23        'false', 'finally', 'for', 'from', 'function', 'get', 'if', 'implements', 'import',
24        'in', 'instanceof', 'interface', 'let', 'new', 'null', 'of', 'package', 'private',
25        'protected', 'public', 'return', 'set', 'static', 'super', 'switch', 'this', 'throw',
26        'true', 'try', 'typeof', 'var', 'void', 'while', 'with', 'yield',
27        'enum', 'eval', 'arguments', 'abstract', 'boolean', 'byte', 'char', 'double', 'final',
28        'float', 'goto', 'int', 'long', 'native', 'short', 'synchronized', 'throws',
29        'transient', 'volatile',
30        // typescript only reserved words
31        'any', 'bigint', 'never', 'number', 'object', 'string', 'symbol', 'unknown', 'void',
32        'abstract', 'asserts', 'declare', 'infer', 'is', 'keyof', 'namespace', 'module', 'readonly', 'satisifies',
33        'type', 'unique', 'undefined'
34    ];
35
36    public static function getRegularExpression(): string
37    {
38        return '/^[A-Za-z_][A-Za-z0-9_]*$/D';
39    }
40
41    public static function validate(string $input): void
42    {
43        if (!preg_match(static::getRegularExpression(), $input) || in_array($input, self::RESERVED_WORDS, true)) {
44            throw new InvalidStringForValueObjectException($input, new ReflectionClass(self::class));
45        }
46    }
47
48    public static function createFromText(string $input): static
49    {
50        if (!preg_match(static::getRegularExpression(), $input)) {
51            $input = KebabCaseSlug::fromText($input)->toCamelCaseSlug()->toNative();
52        }
53        if (in_array($input, self::RESERVED_WORDS, true)) {
54            $input = '__' . $input;
55        }
56
57        return new self($input);
58    }
59
60    public static function createRandom(Generator $faker): static
61    {
62        do {
63            $input = $faker->randomElement(IdentifierConstants::RANDOM_IDENTIFIERS);
64        } while (in_array($input, self::RESERVED_WORDS, true));
65
66        return new static($input);
67    }
68
69    public function humanize(): string
70    {
71        return $this->toNative();
72    }
73}