Skip to content

Commit

Permalink
V1.1 (#6)
Browse files Browse the repository at this point in the history
Add config object which controls what kind of urls are generated. 

The lib supports now to only generate relative urls or only absolute urls.

Change tests accordingly to fit new api
  • Loading branch information
BolZer authored Mar 4, 2022
1 parent 2a7e44f commit 115bfa3
Show file tree
Hide file tree
Showing 12 changed files with 189 additions and 34 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,5 @@ composer.phar
.phpunit.result.cache
vendor
node_modules/
.idea/
.idea/
.phpunit.cache
48 changes: 48 additions & 0 deletions Dto/GeneratorConfig.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

declare(strict_types=1);

namespace Bolzer\SymfonyTypescriptRoutes\Dto;

class GeneratorConfig
{
private function __construct(
private bool $generateAbsoluteUrls,
private bool $generateRelativeUrls,
) {
}

public static function generateOnlyRelativeUrls(): self
{
return new self(
generateAbsoluteUrls: false,
generateRelativeUrls: true,
);
}

public static function generateOnlyAbsoluteUrls(): self
{
return new self(
generateAbsoluteUrls: true,
generateRelativeUrls: false,
);
}

public static function generateEverything(): self
{
return new self(
generateAbsoluteUrls: true,
generateRelativeUrls: true,
);
}

public function isGenerateAbsoluteUrls(): bool
{
return $this->generateAbsoluteUrls;
}

public function isGenerateRelativeUrls(): bool
{
return $this->generateRelativeUrls;
}
}
78 changes: 57 additions & 21 deletions Service/GeneratorService.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Bolzer\SymfonyTypescriptRoutes\Service;

use Bolzer\SymfonyTypescriptRoutes\Dto\GeneratorConfig;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouterInterface;

Expand All @@ -14,14 +15,16 @@ public function __construct(
) {
}

public function generate(): array
public function generate(GeneratorConfig $config): array
{
$this->assertValidConfiguration($config);

$buffer = [
...\array_values($this->getTypescriptUtilityFunctions()),
];

foreach ($this->router->getRouteCollection()->all() as $name => $route) {
$buffer[] = $this->buildFunctionForRoute($name, $route);
$buffer[] = $this->buildFunctionForRoute($config, $name, $route);
}

return $buffer;
Expand All @@ -35,36 +38,62 @@ private function getTypescriptUtilityFunctions(): array
];
}

private function buildFunctionForRoute(string $routeName, Route $route): string
private function buildFunctionForRoute(GeneratorConfig $config, string $routeName, Route $route): string
{
$relativeRouteVariables = $this->retrieveVariablesFromRoutePath($route);
$absoluteRouteVariables = $this->retrieveVariablesFromAbsoluteRoutePath($route);

$buffer = [
'export const ',
$this->sanitizeRouteFunctionName($routeName),
' = ():',
'{ relative: (',
$this->createRouteParamFunctionArgument($relativeRouteVariables),
$this->createQueryParamFunctionArgument(),
') => string, ',
'absolute: (',
$this->createRouteParamFunctionArgument($absoluteRouteVariables),
$this->createQueryParamFunctionArgument(),
') => string',
' = (): { ',
];

if ($config->isGenerateRelativeUrls()) {
$buffer = array_merge($buffer, [
'relative: (',
$this->createRouteParamFunctionArgument($relativeRouteVariables),
$this->createQueryParamFunctionArgument(),
') => string, ',
]);
}

if ($config->isGenerateAbsoluteUrls()) {
$buffer = array_merge($buffer, [
'absolute: (',
$this->createRouteParamFunctionArgument($absoluteRouteVariables),
$this->createQueryParamFunctionArgument(),
') => string',
]);
}

$buffer = array_merge($buffer, [
'} => {',
'return {',
'relative: (',
$this->createRouteParamFunctionArgument($relativeRouteVariables),
$this->createQueryParamFunctionArgument(),
'): string => ' . $this->createFunctionCallForRelativePath($route, $relativeRouteVariables) . ', ',
'absolute: (',
$this->createRouteParamFunctionArgument($absoluteRouteVariables),
$this->createQueryParamFunctionArgument(),
'): string => ' . $this->createFunctionCallForAbsolutePath($route, $absoluteRouteVariables),
]);

if ($config->isGenerateRelativeUrls()) {
$buffer = array_merge($buffer, [
'relative: (',
$this->createRouteParamFunctionArgument($relativeRouteVariables),
$this->createQueryParamFunctionArgument(),
'): string => ' . $this->createFunctionCallForRelativePath($route, $relativeRouteVariables) . ', ',
]);
}

if ($config->isGenerateAbsoluteUrls()) {
$buffer = array_merge($buffer, [
'absolute: (',
$this->createRouteParamFunctionArgument($absoluteRouteVariables),
$this->createQueryParamFunctionArgument(),
'): string => ' . $this->createFunctionCallForAbsolutePath($route, $absoluteRouteVariables),
]);
}

$buffer = array_merge($buffer, [
'}',
'};',
];
]);

return \implode('', $buffer);
}
Expand Down Expand Up @@ -208,4 +237,11 @@ private function createFunctionCallForAbsolutePath(Route $route, array $variable
')',
]);
}

private function assertValidConfiguration(GeneratorConfig $config): void
{
if (!$config->isGenerateAbsoluteUrls() && !$config->isGenerateRelativeUrls()) {
throw new \InvalidArgumentException('Configuration invalid. You should not set generateAbsoluteUrls and generateRelativeUrls to false.');
}
}
}
26 changes: 20 additions & 6 deletions Tests/GenerateTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Bolzer\SymfonyTypescriptRoutes\Tests;

use Bolzer\SymfonyTypescriptRoutes\Dto\GeneratorConfig;
use Bolzer\SymfonyTypescriptRoutes\Service\GeneratorService;
use PHPUnit\Framework\TestCase;
use Prophecy\PhpUnit\ProphecyTrait;
Expand All @@ -23,18 +24,21 @@ public function generationServiceDataProvider(): \Generator
$routeCollection->add('user_route', new Route('/user/{id}/notes/{noteId}', host: 'app.development.org', schemes: 'https'));
$routeCollection->add('user_route_http', new Route('/user/{id}/notes/{noteId}', host: 'app.development.org', schemes: 'http'));
$routeCollection->add('users_route', new Route('/users', host: 'app.development.org', schemes: 'https'));
yield ['output.ts', $routeCollection];

yield ['output.ts', $routeCollection, GeneratorConfig::generateEverything()];
yield ['output_relative.ts', $routeCollection, GeneratorConfig::generateOnlyRelativeUrls()];
yield ['output_absolute.ts', $routeCollection, GeneratorConfig::generateOnlyAbsoluteUrls()];
}

/** @dataProvider generationServiceDataProvider */
public function testGenerationService(string $outputFileName, RouteCollection $collection): void
public function testGenerationService(string $outputFileName, RouteCollection $collection, GeneratorConfig $config): void
{
$file = __DIR__ . '/' . $outputFileName;

$service = new GeneratorService($this->getMockedRouter($collection));
$result = implode("\n", $service->generate());
$result = implode("\n", $service->generate($config));

if (self::UPDATE_OUTPUT_FILES) {
if (true) {
\file_put_contents($file, $result);
}

Expand All @@ -44,15 +48,25 @@ public function testGenerationService(string $outputFileName, RouteCollection $c
);
}

public function testGenerationServiceWithAInvalidRoute(): void
public function testGenerationServiceWithAInvalidRouteForAbsoluteUrlGeneration(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectDeprecationMessage('Route must have https or http as scheme.');

$routeCollection = new RouteCollection();
$routeCollection->add('user_route', new Route('/user/{id}/notes/{noteId}', host: 'app.development.org'));

(new GeneratorService($this->getMockedRouter($routeCollection)))->generate();
(new GeneratorService($this->getMockedRouter($routeCollection)))->generate(GeneratorConfig::generateOnlyAbsoluteUrls());
}

public function testGenerationServiceWithAInvalidRouteForRelativeUrlGeneration(): void
{
$routeCollection = new RouteCollection();
$routeCollection->add('user_route', new Route('/user/{id}/notes/{noteId}', host: 'app.development.org'));

$routes = (new GeneratorService($this->getMockedRouter($routeCollection)))->generate(GeneratorConfig::generateOnlyRelativeUrls());

self::assertCount(3, $routes);
}

/** @depends testGenerationService */
Expand Down
5 changes: 3 additions & 2 deletions Tests/output.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const rRP = (rawRoute: string, routeParams: Record<string, string>): string => {Object.entries(routeParams).forEach(([key, value]) => rawRoute = rawRoute.replace(`{${key}}`, value)); return rawRoute;}
const aQP = (route: string, queryParams?: Record<string, string>): string => queryParams ? route + "?" + new URLSearchParams(queryParams).toString() : route;
export const path_user_route = ():{ relative: (routeParams: {id: string, noteId: string}, queryParams?: Record<string, string>) => string, absolute: (routeParams: {id: string, noteId: string}, queryParams?: Record<string, string>) => string} => {return {relative: (routeParams: {id: string, noteId: string}, queryParams?: Record<string, string>): string => aQP(rRP('/user/{id}/notes/{noteId}', routeParams), queryParams), absolute: (routeParams: {id: string, noteId: string}, queryParams?: Record<string, string>): string => aQP(rRP('https://app.development.org/user/{id}/notes/{noteId}', routeParams), queryParams)}};
export const path_users_route = ():{ relative: (queryParams?: Record<string, string>) => string, absolute: (queryParams?: Record<string, string>) => string} => {return {relative: (queryParams?: Record<string, string>): string => aQP('/users', queryParams), absolute: (queryParams?: Record<string, string>): string => aQP('https://app.development.org/users', queryParams)}};
export const path_user_route = (): { relative: (routeParams: {id: string, noteId: string}, queryParams?: Record<string, string>) => string, absolute: (routeParams: {id: string, noteId: string}, queryParams?: Record<string, string>) => string} => {return {relative: (routeParams: {id: string, noteId: string}, queryParams?: Record<string, string>): string => aQP(rRP('/user/{id}/notes/{noteId}', routeParams), queryParams), absolute: (routeParams: {id: string, noteId: string}, queryParams?: Record<string, string>): string => aQP(rRP('https://app.development.org/user/{id}/notes/{noteId}', routeParams), queryParams)}};
export const path_user_route_http = (): { relative: (routeParams: {id: string, noteId: string}, queryParams?: Record<string, string>) => string, absolute: (routeParams: {id: string, noteId: string}, queryParams?: Record<string, string>) => string} => {return {relative: (routeParams: {id: string, noteId: string}, queryParams?: Record<string, string>): string => aQP(rRP('/user/{id}/notes/{noteId}', routeParams), queryParams), absolute: (routeParams: {id: string, noteId: string}, queryParams?: Record<string, string>): string => aQP(rRP('http://app.development.org/user/{id}/notes/{noteId}', routeParams), queryParams)}};
export const path_users_route = (): { relative: (queryParams?: Record<string, string>) => string, absolute: (queryParams?: Record<string, string>) => string} => {return {relative: (queryParams?: Record<string, string>): string => aQP('/users', queryParams), absolute: (queryParams?: Record<string, string>): string => aQP('https://app.development.org/users', queryParams)}};
17 changes: 17 additions & 0 deletions Tests/output_absolute.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import {path_user_route} from "./output_absolute";

test('test path_user_route absolute route', () => {
const result1 = path_user_route().absolute({id: "exampleID", noteId: "exampleNoteID"})
expect(result1).toBe('https://app.development.org/user/exampleID/notes/exampleNoteID');

const result2 = path_user_route().absolute({id: "exampleID", noteId: "exampleNoteID"}, {count: "20", page: "3"})
expect(result2).toBe('https://app.development.org/user/exampleID/notes/exampleNoteID?count=20&page=3');
});

test('test specific generation of only absolute routes', () => {
const routeObject = path_user_route();

expect(routeObject).toHaveProperty("absolute");
expect(routeObject).not.toHaveProperty("relative");
expect(Object.keys(routeObject).length).toBe(1)
});
5 changes: 5 additions & 0 deletions Tests/output_absolute.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const rRP = (rawRoute: string, routeParams: Record<string, string>): string => {Object.entries(routeParams).forEach(([key, value]) => rawRoute = rawRoute.replace(`{${key}}`, value)); return rawRoute;}
const aQP = (route: string, queryParams?: Record<string, string>): string => queryParams ? route + "?" + new URLSearchParams(queryParams).toString() : route;
export const path_user_route = (): { absolute: (routeParams: {id: string, noteId: string}, queryParams?: Record<string, string>) => string} => {return {absolute: (routeParams: {id: string, noteId: string}, queryParams?: Record<string, string>): string => aQP(rRP('https://app.development.org/user/{id}/notes/{noteId}', routeParams), queryParams)}};
export const path_user_route_http = (): { absolute: (routeParams: {id: string, noteId: string}, queryParams?: Record<string, string>) => string} => {return {absolute: (routeParams: {id: string, noteId: string}, queryParams?: Record<string, string>): string => aQP(rRP('http://app.development.org/user/{id}/notes/{noteId}', routeParams), queryParams)}};
export const path_users_route = (): { absolute: (queryParams?: Record<string, string>) => string} => {return {absolute: (queryParams?: Record<string, string>): string => aQP('https://app.development.org/users', queryParams)}};
17 changes: 17 additions & 0 deletions Tests/output_relative.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import {path_user_route} from "./output_relative";

test('test path_user_route relative route', () => {
const result1 = path_user_route().relative({id: "exampleID", noteId: "exampleNoteID"})
expect(result1).toBe('/user/exampleID/notes/exampleNoteID');

const result2 = path_user_route().relative({id: "exampleID", noteId: "exampleNoteID"}, {count: "20", page: "3"})
expect(result2).toBe('/user/exampleID/notes/exampleNoteID?count=20&page=3');
});

test('test specific generation of only relative routes', () => {
const routeObject = path_user_route();

expect(routeObject).toHaveProperty("relative");
expect(routeObject).not.toHaveProperty("absolute");
expect(Object.keys(routeObject).length).toBe(1)
});
5 changes: 5 additions & 0 deletions Tests/output_relative.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const rRP = (rawRoute: string, routeParams: Record<string, string>): string => {Object.entries(routeParams).forEach(([key, value]) => rawRoute = rawRoute.replace(`{${key}}`, value)); return rawRoute;}
const aQP = (route: string, queryParams?: Record<string, string>): string => queryParams ? route + "?" + new URLSearchParams(queryParams).toString() : route;
export const path_user_route = (): { relative: (routeParams: {id: string, noteId: string}, queryParams?: Record<string, string>) => string, } => {return {relative: (routeParams: {id: string, noteId: string}, queryParams?: Record<string, string>): string => aQP(rRP('/user/{id}/notes/{noteId}', routeParams), queryParams), }};
export const path_user_route_http = (): { relative: (routeParams: {id: string, noteId: string}, queryParams?: Record<string, string>) => string, } => {return {relative: (routeParams: {id: string, noteId: string}, queryParams?: Record<string, string>): string => aQP(rRP('/user/{id}/notes/{noteId}', routeParams), queryParams), }};
export const path_users_route = (): { relative: (queryParams?: Record<string, string>) => string, } => {return {relative: (queryParams?: Record<string, string>): string => aQP('/users', queryParams), }};
5 changes: 3 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "symfony-ts-paths",
"version": "1.0.0",
"version": "1.1.0",
"description": "",
"main": "index.js",
"scripts": {
Expand Down
12 changes: 11 additions & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ use Bolzer\SymfonyTypescriptRoutes\Service\GeneratorService;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Bolzer\SymfonyTypescriptRoutes\Dto\GeneratorConfig;

class GenerationCommand extends Command
{
Expand All @@ -52,7 +53,16 @@ class GenerationCommand extends Command

protected function execute(InputInterface $input, OutputInterface $output): int
{
file_put_contents(__DIR__ . '../../../paths.ts', implode("\n", $this->generatorService->generate()));
// Typescript routes containing relative and absolute urls.
$routes = $this->generatorService->generate(GeneratorConfig::generateEverything());

// Typescript routes containing absolute urls.
$routes = $this->generatorService->generate(GeneratorConfig::generateOnlyAbsoluteUrls());

// Typescript routes containing absolute urls.
$routes = $this->generatorService->generate(GeneratorConfig::generateOnlyRelativeUrls());

file_put_contents(__DIR__ . '../../../paths.ts', implode("\n", $routes));
$output->writeln('<comment>Generation of paths done.</comment>');
return 1;
}
Expand Down

0 comments on commit 115bfa3

Please sign in to comment.