Skip to content

Commit

Permalink
Fix union requirements not correctly transpiling to typescript unions (
Browse files Browse the repository at this point in the history
…#13)

* Fix union requirements not correctly transpiling to typescript unions
  • Loading branch information
BolZer authored Dec 16, 2022
1 parent 89e9a1e commit e175f19
Show file tree
Hide file tree
Showing 5 changed files with 25 additions and 40 deletions.
48 changes: 11 additions & 37 deletions Service/GeneratorService.php
Original file line number Diff line number Diff line change
Expand Up @@ -241,29 +241,25 @@ private function guessTypeOfPathVariable(Route $route, string $variable): string
return 'string';
}

if ($this->isDigitRegex($requirement)) {
if ($this->isDigitRequirement($requirement)) {
return 'number';
}

if ($this->isEitherAOrBRegex($requirement)) {
return $this->deriveEitherAOrBRegexExpressionForTypescript($requirement);
if ($this->isUnionRequirement($requirement)) {
return $this->deriveUnionExpressionForTypescript($requirement);
}

return 'string';
}

private function isDigitRegex(string $requirement): bool
private function isDigitRequirement(string $requirement): bool
{
return $requirement === '\d+';
}

private function isEitherAOrBRegex(string $requirement): bool
private function isUnionRequirement(string $requirement): bool
{
$matches = [];

preg_match_all($this->getEitherAOrBRegexGuessRegex(), $requirement, $matches, PREG_SET_ORDER);

return count($matches) > 0;
return str_contains($requirement, '|');
}

private function createRouteParamsMergeExpressionForDefaults(Route $route): string
Expand All @@ -275,37 +271,15 @@ private function createRouteParamsMergeExpressionForDefaults(Route $route): stri
return sprintf('{...%s, ...routeParams}', json_encode($route->getDefaults(), JSON_THROW_ON_ERROR));
}

private function deriveEitherAOrBRegexExpressionForTypescript(string $requirement): string
private function deriveUnionExpressionForTypescript(string $requirement): string
{
$matches = [];

preg_match_all($this->getEitherAOrBRegexGuessRegex(), $requirement, $matches, PREG_SET_ORDER);

if (!$matches) {
throw new \LogicException('At this point the either A Or B regex must have matches');
}
$matches = explode('|', $requirement);

$matchingGroup = $matches[0] ?? [];

if (!$matchingGroup) {
throw new \InvalidArgumentException('At this point the MatchingGroup must exist');
}

$buffer = [];
foreach ($matchingGroup as $key => $match) {
if ($key === 0) {
continue;
}

$buffer[] = $match;
if (count($matches) < 2) {
throw new \LogicException('At this point union parts must be greater than 2!');
}

return implode('|', array_map(static fn (string $matchFromBuffer) => sprintf("'%s'", $matchFromBuffer), $buffer));
}

private function getEitherAOrBRegexGuessRegex(): string
{
return '/([a-zA-Z]+)(?>\|)([a-zA-Z]+)/m';
return implode('|', array_map(static fn (string $matchFromBuffer) => sprintf("'%s'", $matchFromBuffer), $matches));
}

private function retrieveSchemeFromRoute(Route $route): string
Expand Down
8 changes: 8 additions & 0 deletions Tests/GenerateTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,14 @@ public function generationServiceDataProvider(): \Generator
host: 'app.development.org',
schemes: 'https'
));
$routeCollection->add('generate_route_with_long_requirement_as_union', new Route(
path: '/generate/{intent}/{documents}',
requirements: [
'intent' => 'new_email|email|print|printdebug|preview|preview_data|preview_text|gct.legalize'
],
host: 'app.development.org',
schemes: 'https'
));

yield ['output.ts', $routeCollection, GeneratorConfig::generateEverything()];
yield ['output_relative.ts', $routeCollection, GeneratorConfig::generateOnlyRelativeUrls()];
Expand Down
3 changes: 2 additions & 1 deletion Tests/output.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ export const path_user_route_without_scheme = (): { relative: (routeParams: {id:
export const path_users_route_without_requirements_and_defaults = (): { relative: (queryParams?: Record<string, string>) => string, absolute: (queryParams?: Record<string, string>) => string} => {return {relative: (queryParams?: Record<string, string>): string => appendQueryParams('/users', queryParams), absolute: (queryParams?: Record<string, string>): string => appendQueryParams('https://app.development.org/users', queryParams)}};
export const path_users_route_with_requirements = (): { relative: (routeParams: {id:number, locale:'en'|'fr'}, queryParams?: Record<string, string>) => string, absolute: (routeParams: {id:number, locale:'en'|'fr'}, queryParams?: Record<string, string>) => string} => {return {relative: (routeParams: {id:number, locale:'en'|'fr'}, queryParams?: Record<string, string>): string => appendQueryParams(replaceRouteParams('/users/{id}/{locale}', routeParams), queryParams), absolute: (routeParams: {id:number, locale:'en'|'fr'}, queryParams?: Record<string, string>): string => appendQueryParams(replaceRouteParams('https://app.development.org/users/{id}/{locale}', routeParams), queryParams)}};
export const path_users_route_with_requirements_and_defaults = (): { relative: (routeParams: {id:number, locale?:'en'|'fr'}, queryParams?: Record<string, string>) => string, absolute: (routeParams: {id:number, locale?:'en'|'fr'}, queryParams?: Record<string, string>) => string} => {return {relative: (routeParams: {id:number, locale?:'en'|'fr'}, queryParams?: Record<string, string>): string => appendQueryParams(replaceRouteParams('/users/{id}/{locale}', {...{"locale":"en"}, ...routeParams}), queryParams), absolute: (routeParams: {id:number, locale?:'en'|'fr'}, queryParams?: Record<string, string>): string => appendQueryParams(replaceRouteParams('https://app.development.org/users/{id}/{locale}', {...{"locale":"en"}, ...routeParams}), queryParams)}};
export const path_users_route_with_requirements_and_null_defaults = (): { relative: (routeParams: {id:number, locale?:'en'|'fr'}, queryParams?: Record<string, string>) => string, absolute: (routeParams: {id:number, locale?:'en'|'fr'}, queryParams?: Record<string, string>) => string} => {return {relative: (routeParams: {id:number, locale?:'en'|'fr'}, queryParams?: Record<string, string>): string => appendQueryParams(replaceRouteParams('/users/{id}/{locale}', {...{"locale":null}, ...routeParams}), queryParams), absolute: (routeParams: {id:number, locale?:'en'|'fr'}, queryParams?: Record<string, string>): string => appendQueryParams(replaceRouteParams('https://app.development.org/users/{id}/{locale}', {...{"locale":null}, ...routeParams}), queryParams)}};
export const path_users_route_with_requirements_and_null_defaults = (): { relative: (routeParams: {id:number, locale?:'en'|'fr'}, queryParams?: Record<string, string>) => string, absolute: (routeParams: {id:number, locale?:'en'|'fr'}, queryParams?: Record<string, string>) => string} => {return {relative: (routeParams: {id:number, locale?:'en'|'fr'}, queryParams?: Record<string, string>): string => appendQueryParams(replaceRouteParams('/users/{id}/{locale}', {...{"locale":null}, ...routeParams}), queryParams), absolute: (routeParams: {id:number, locale?:'en'|'fr'}, queryParams?: Record<string, string>): string => appendQueryParams(replaceRouteParams('https://app.development.org/users/{id}/{locale}', {...{"locale":null}, ...routeParams}), queryParams)}};
export const path_generate_route_with_long_requirement_as_union = (): { relative: (routeParams: {intent:'new_email'|'email'|'print'|'printdebug'|'preview'|'preview_data'|'preview_text'|'gct.legalize', documents:string}, queryParams?: Record<string, string>) => string, absolute: (routeParams: {intent:'new_email'|'email'|'print'|'printdebug'|'preview'|'preview_data'|'preview_text'|'gct.legalize', documents:string}, queryParams?: Record<string, string>) => string} => {return {relative: (routeParams: {intent:'new_email'|'email'|'print'|'printdebug'|'preview'|'preview_data'|'preview_text'|'gct.legalize', documents:string}, queryParams?: Record<string, string>): string => appendQueryParams(replaceRouteParams('/generate/{intent}/{documents}', routeParams), queryParams), absolute: (routeParams: {intent:'new_email'|'email'|'print'|'printdebug'|'preview'|'preview_data'|'preview_text'|'gct.legalize', documents:string}, queryParams?: Record<string, string>): string => appendQueryParams(replaceRouteParams('https://app.development.org/generate/{intent}/{documents}', routeParams), queryParams)}};
3 changes: 2 additions & 1 deletion Tests/output_absolute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ export const path_user_route_without_scheme = (): { absolute: (routeParams: {sch
export const path_users_route_without_requirements_and_defaults = (): { absolute: (queryParams?: Record<string, string>) => string} => {return {absolute: (queryParams?: Record<string, string>): string => appendQueryParams('https://app.development.org/users', queryParams)}};
export const path_users_route_with_requirements = (): { absolute: (routeParams: {id:number, locale:'en'|'fr'}, queryParams?: Record<string, string>) => string} => {return {absolute: (routeParams: {id:number, locale:'en'|'fr'}, queryParams?: Record<string, string>): string => appendQueryParams(replaceRouteParams('https://app.development.org/users/{id}/{locale}', routeParams), queryParams)}};
export const path_users_route_with_requirements_and_defaults = (): { absolute: (routeParams: {id:number, locale?:'en'|'fr'}, queryParams?: Record<string, string>) => string} => {return {absolute: (routeParams: {id:number, locale?:'en'|'fr'}, queryParams?: Record<string, string>): string => appendQueryParams(replaceRouteParams('https://app.development.org/users/{id}/{locale}', {...{"locale":"en"}, ...routeParams}), queryParams)}};
export const path_users_route_with_requirements_and_null_defaults = (): { absolute: (routeParams: {id:number, locale?:'en'|'fr'}, queryParams?: Record<string, string>) => string} => {return {absolute: (routeParams: {id:number, locale?:'en'|'fr'}, queryParams?: Record<string, string>): string => appendQueryParams(replaceRouteParams('https://app.development.org/users/{id}/{locale}', {...{"locale":null}, ...routeParams}), queryParams)}};
export const path_users_route_with_requirements_and_null_defaults = (): { absolute: (routeParams: {id:number, locale?:'en'|'fr'}, queryParams?: Record<string, string>) => string} => {return {absolute: (routeParams: {id:number, locale?:'en'|'fr'}, queryParams?: Record<string, string>): string => appendQueryParams(replaceRouteParams('https://app.development.org/users/{id}/{locale}', {...{"locale":null}, ...routeParams}), queryParams)}};
export const path_generate_route_with_long_requirement_as_union = (): { absolute: (routeParams: {intent:'new_email'|'email'|'print'|'printdebug'|'preview'|'preview_data'|'preview_text'|'gct.legalize', documents:string}, queryParams?: Record<string, string>) => string} => {return {absolute: (routeParams: {intent:'new_email'|'email'|'print'|'printdebug'|'preview'|'preview_data'|'preview_text'|'gct.legalize', documents:string}, queryParams?: Record<string, string>): string => appendQueryParams(replaceRouteParams('https://app.development.org/generate/{intent}/{documents}', routeParams), queryParams)}};
3 changes: 2 additions & 1 deletion Tests/output_relative.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ export const path_user_route_without_scheme = (): { relative: (routeParams: {id:
export const path_users_route_without_requirements_and_defaults = (): { relative: (queryParams?: Record<string, string>) => string, } => {return {relative: (queryParams?: Record<string, string>): string => appendQueryParams('/users', queryParams), }};
export const path_users_route_with_requirements = (): { relative: (routeParams: {id:number, locale:'en'|'fr'}, queryParams?: Record<string, string>) => string, } => {return {relative: (routeParams: {id:number, locale:'en'|'fr'}, queryParams?: Record<string, string>): string => appendQueryParams(replaceRouteParams('/users/{id}/{locale}', routeParams), queryParams), }};
export const path_users_route_with_requirements_and_defaults = (): { relative: (routeParams: {id:number, locale?:'en'|'fr'}, queryParams?: Record<string, string>) => string, } => {return {relative: (routeParams: {id:number, locale?:'en'|'fr'}, queryParams?: Record<string, string>): string => appendQueryParams(replaceRouteParams('/users/{id}/{locale}', {...{"locale":"en"}, ...routeParams}), queryParams), }};
export const path_users_route_with_requirements_and_null_defaults = (): { relative: (routeParams: {id:number, locale?:'en'|'fr'}, queryParams?: Record<string, string>) => string, } => {return {relative: (routeParams: {id:number, locale?:'en'|'fr'}, queryParams?: Record<string, string>): string => appendQueryParams(replaceRouteParams('/users/{id}/{locale}', {...{"locale":null}, ...routeParams}), queryParams), }};
export const path_users_route_with_requirements_and_null_defaults = (): { relative: (routeParams: {id:number, locale?:'en'|'fr'}, queryParams?: Record<string, string>) => string, } => {return {relative: (routeParams: {id:number, locale?:'en'|'fr'}, queryParams?: Record<string, string>): string => appendQueryParams(replaceRouteParams('/users/{id}/{locale}', {...{"locale":null}, ...routeParams}), queryParams), }};
export const path_generate_route_with_long_requirement_as_union = (): { relative: (routeParams: {intent:'new_email'|'email'|'print'|'printdebug'|'preview'|'preview_data'|'preview_text'|'gct.legalize', documents:string}, queryParams?: Record<string, string>) => string, } => {return {relative: (routeParams: {intent:'new_email'|'email'|'print'|'printdebug'|'preview'|'preview_data'|'preview_text'|'gct.legalize', documents:string}, queryParams?: Record<string, string>): string => appendQueryParams(replaceRouteParams('/generate/{intent}/{documents}', routeParams), queryParams), }};

0 comments on commit e175f19

Please sign in to comment.