Skip to content
This repository was archived by the owner on Sep 22, 2025. It is now read-only.

Commit c8ea243

Browse files
authored
V1.4.2 - Fix Union Generation (#15)
Fix union generation not evaluating possible regex statements
1 parent e175f19 commit c8ea243

File tree

7 files changed

+47
-7
lines changed

7 files changed

+47
-7
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
cs_fix:
2-
vendor/bin/php-cs-fixer fix ./
2+
PHP_CS_FIXER_IGNORE_ENV=true vendor/bin/php-cs-fixer fix ./
33

44
lint:
55
./vendor/bin/psalm

Service/GeneratorService.php

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
class GeneratorService
1212
{
1313
public function __construct(
14-
private RouterInterface $router,
14+
private readonly RouterInterface $router,
1515
) {
1616
}
1717

@@ -262,6 +262,11 @@ private function isUnionRequirement(string $requirement): bool
262262
return str_contains($requirement, '|');
263263
}
264264

265+
private function isPhpRegexExpression(string $requirement): bool
266+
{
267+
return str_starts_with($requirement, '\\');
268+
}
269+
265270
private function createRouteParamsMergeExpressionForDefaults(Route $route): string
266271
{
267272
if (!$route->getDefaults()) {
@@ -279,7 +284,25 @@ private function deriveUnionExpressionForTypescript(string $requirement): string
279284
throw new \LogicException('At this point union parts must be greater than 2!');
280285
}
281286

282-
return implode('|', array_map(static fn (string $matchFromBuffer) => sprintf("'%s'", $matchFromBuffer), $matches));
287+
$transformedMatches = array_map(function ($match) {
288+
if ($this->isDigitRequirement($match)) {
289+
return 'number';
290+
}
291+
292+
if ($this->isPhpRegexExpression($match)) {
293+
return 'string';
294+
}
295+
296+
return $match;
297+
}, $matches);
298+
299+
return implode('|', array_map(function (string $matchFromBuffer) {
300+
if ($matchFromBuffer === 'string' || $matchFromBuffer === 'number') {
301+
return sprintf('%s', $matchFromBuffer);
302+
}
303+
304+
return sprintf("'%s'", $matchFromBuffer);
305+
}, $transformedMatches));
283306
}
284307

285308
private function retrieveSchemeFromRoute(Route $route): string

Tests/GenerateTest.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,15 @@ public function generationServiceDataProvider(): \Generator
6161
$routeCollection->add('generate_route_with_long_requirement_as_union', new Route(
6262
path: '/generate/{intent}/{documents}',
6363
requirements: [
64-
'intent' => 'new_email|email|print|printdebug|preview|preview_data|preview_text|gct.legalize'
64+
'intent' => 'new_email|email|print|printdebug|preview|preview_data|preview_text|gct.legalize',
65+
],
66+
host: 'app.development.org',
67+
schemes: 'https'
68+
));
69+
$routeCollection->add('generate_route_requirement_union_with_regex', new Route(
70+
path: '/generate/{id}',
71+
requirements: [
72+
'id' => 'new|\d+',
6573
],
6674
host: 'app.development.org',
6775
schemes: 'https'

Tests/output.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@ export const path_users_route_without_requirements_and_defaults = (): { relative
77
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)}};
88
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)}};
99
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)}};
10-
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)}};
10+
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)}};
11+
export const path_generate_route_requirement_union_with_regex = (): { relative: (routeParams: {id:'new'|number}, queryParams?: Record<string, string>) => string, absolute: (routeParams: {id:'new'|number}, queryParams?: Record<string, string>) => string} => {return {relative: (routeParams: {id:'new'|number}, queryParams?: Record<string, string>): string => appendQueryParams(replaceRouteParams('/generate/{id}', routeParams), queryParams), absolute: (routeParams: {id:'new'|number}, queryParams?: Record<string, string>): string => appendQueryParams(replaceRouteParams('https://app.development.org/generate/{id}', routeParams), queryParams)}};

Tests/output_absolute.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@ export const path_users_route_without_requirements_and_defaults = (): { absolute
77
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)}};
88
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)}};
99
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)}};
10-
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)}};
10+
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)}};
11+
export const path_generate_route_requirement_union_with_regex = (): { absolute: (routeParams: {id:'new'|number}, queryParams?: Record<string, string>) => string} => {return {absolute: (routeParams: {id:'new'|number}, queryParams?: Record<string, string>): string => appendQueryParams(replaceRouteParams('https://app.development.org/generate/{id}', routeParams), queryParams)}};

Tests/output_relative.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@ export const path_users_route_without_requirements_and_defaults = (): { relative
77
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), }};
88
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), }};
99
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), }};
10-
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), }};
10+
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), }};
11+
export const path_generate_route_requirement_union_with_regex = (): { relative: (routeParams: {id:'new'|number}, queryParams?: Record<string, string>) => string, } => {return {relative: (routeParams: {id:'new'|number}, queryParams?: Record<string, string>): string => appendQueryParams(replaceRouteParams('/generate/{id}', routeParams), queryParams), }};

codecov.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
coverage:
2+
status:
3+
project:
4+
default:
5+
target: 90%
6+
threshold: 1%

0 commit comments

Comments
 (0)