Skip to content

Commit

Permalink
Adding a Javascript Converter for Enum
Browse files Browse the repository at this point in the history
  • Loading branch information
nyamsprod committed Jan 20, 2024
1 parent fa5d063 commit 991c458
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 55 deletions.
108 changes: 56 additions & 52 deletions src/Enum/JavascriptConverter.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@

final class JavascriptConverter
{
private const EXPORT_NONE = 'none';
private const EXPORT_SIMPLE = 'export';
private const EXPORT_DEFAULT = 'exportDefault';
private const EXPORT_NONE = '';
private const EXPORT_SIMPLE = 'export ';
private const EXPORT_DEFAULT = 'export default ';

private function __construct(
private readonly bool $useSymbol,
Expand All @@ -26,7 +26,13 @@ private function __construct(

public static function new(): self
{
return new self(false, true, null, 2, self::EXPORT_NONE);
return new self(
useSymbol: false,
useImmutability: true,
propertyNameCasing: null,
indentSize: 2,
useExport: self::EXPORT_NONE
);
}

public function propertyNameCase(Closure $casing = null): self
Expand Down Expand Up @@ -156,82 +162,75 @@ public function intendSize(int $indentSize): self
/**
* Converts the Enum into a Javascript object.
*
* If the object name is null the object is not assign to const variable
* If the object name is the empty string the PHP namespaced class name will be used
* If the object name is a non-empty string, it will be used as is as the const variable name
* <ul>
* <li>If the object name is null the object is not assign to const variable</li>
* <li>If the object name is the empty string the PHP namespaced class name will be used</li>
* <li>If the object name is a non-empty string, it will be used as is as the const variable name</li>
* </ul>
*
* @param class-string<BackedEnum> $enumClass
*/
public function convertToObject(string $enumClass, ?string $objectName = null): string
{
$this->filterBackedEnum($enumClass);

$space = $this->indentSize > 0 ? str_repeat(' ', $this->indentSize) : '';
$eol = $this->indentSize > 0 ? "\n" : '';
$space = '';
$eol = '';
if (0 < $this->indentSize) {
$space = str_repeat(' ', $this->indentSize);
$eol = "\n";
}

$objectName = $this->sanitizeName($objectName, $enumClass);
$output = array_reduce(
$enumClass::cases(),
fn (string $output, BackedEnum $enum): string => $output.$space.$this->formatPropertyName($enum).": ".$this->formatPropertyValue($enum)."},$eol",
fn (string $output, BackedEnum $enum): string => $output.$space.$this->formatPropertyName($enum).': '.$this->formatPropertyValue($enum).','.$eol,
''
);

$output = "{".$eol.$output."}";
$output = '{'.$eol.$output.'}';
if ($this->useImmutability) {
$output = "Object.freeze($output)";
}

$output .= $eol;
$objectName = $this->sanitizeName($objectName, $enumClass);
if (null !== $objectName) {
$output = "const $objectName = $output";
}

return $this->formatOutput($output);
return $this->useExport.$output.$eol;
}

/**
* Converts the Enum into a Javascript class.
*
* If the class name is the empty string the PHP namespaced class name will be used
* If the class name is a non-empty string, it will be used as is as the class name
* <ul>
* <li>If the class name is the empty string the PHP namespaced class name will be used</li>
* <li>If the class name is a non-empty string, it will be used as is as the class name</li>
* </ul>
*
* @param class-string<BackedEnum> $enumClass
*/
public function convertToClass(string $enumClass, string $className = ''): string
{
$this->filterBackedEnum($enumClass);

$eol = $this->indentSize > 0 ? "\n" : '';
$space = '';
$eol = '';
if (0 < $this->indentSize) {
$space = str_repeat(' ', $this->indentSize);
$eol = "\n";
}

$className = $this->sanitizeName($className, $enumClass);
$space = str_repeat(' ', $this->indentSize);
$classBody = array_reduce(
$output = array_reduce(
$enumClass::cases(),
fn (string $output, BackedEnum $enum): string => $output
.$space."static {$this->formatPropertyName($enum)} = new $className({$this->formatPropertyValue($enum)})\n",
fn (string $output, BackedEnum $enum): string => $output.$space."static {$this->formatPropertyName($enum)} = new $className({$this->formatPropertyValue($enum)})$eol",
''
);

$output = "class $className {\n$classBody\n$space"."constructor(name) {\n$space$space"."this.name = name\n$space}\n}\n";
$output = 'class '.$className.' {'.$eol.$output.$eol.$space.'constructor(name) {'.$eol.$space.$space.'this.name = name'.$eol.$space.'}'.$eol.'}';

return $this->formatOutput($output);
}

private function formatPropertyName(BackedEnum $enum): string
{
return match ($this->propertyNameCasing) {
null => $enum->name,
default => ($this->propertyNameCasing)($enum->name),
};
}

private function formatPropertyValue(BackedEnum $enum): string|int
{
$value = $enum->value;
$value = is_string($value) ? '"'.$value.'"' : $value;

return match ($this->useSymbol) {
true => 'Symbol('.$value.')',
default => $value,
};
return $this->useExport.$output.$eol;
}

/**
Expand Down Expand Up @@ -262,17 +261,22 @@ private function sanitizeName(?string $className, string $enumClass): ?string
return (string) array_pop($parts);
}

/**
* @param string $output
*
* @return string
*/
public function formatOutput(string $output): string
private function formatPropertyName(BackedEnum $enum): string
{
return match ($this->useExport) {
self::EXPORT_DEFAULT => "export default $output",
self::EXPORT_SIMPLE => "export $output",
default => $output
return match ($this->propertyNameCasing) {
null => $enum->name,
default => ($this->propertyNameCasing)($enum->name),
};
}

private function formatPropertyValue(BackedEnum $enum): string|int
{
$value = $enum->value;
$value = is_string($value) ? '"'.$value.'"' : $value;

return match ($this->useSymbol) {
true => 'Symbol('.$value.')',
default => $value,
};
}
}
5 changes: 2 additions & 3 deletions src/Enum/JavascriptConverterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ public function it_can_convert_to_a_javascript_class(): void
));

$expected = <<<JS
export class Foobar {
export default class Foobar {
static Ok = new Foobar(200)
static Redirection = new Foobar(302)
static NotFound = new Foobar(404)
Expand All @@ -134,10 +134,9 @@ public function it_can_convert_to_a_javascript_class(): void
JS;
$converter = JavascriptConverter::new()
->useImmutability()
->ignoreExport()
->ignoreSymbol()
->intendSize(4)
->useExport()
->useExportDefault()
->propertyNameCase(fn (string $name) => $pascalCase(strtolower(str_replace('HTTP_', '', $name))));

self::assertSame(
Expand Down

0 comments on commit 991c458

Please sign in to comment.