Skip to content

Commit

Permalink
Merge branch 'develop' of github.com:xtend-packages/rest-presenter in…
Browse files Browse the repository at this point in the history
…to develop
  • Loading branch information
adam-code-labx committed Jun 7, 2024
2 parents 631eab3 + bdf4a0f commit 85d2b6b
Show file tree
Hide file tree
Showing 43 changed files with 1,345 additions and 145 deletions.
227 changes: 125 additions & 102 deletions README.md

Large diffs are not rendered by default.

30 changes: 21 additions & 9 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
],
"require": {
"php": "^8.2",
"calebporzio/sushi": "^2.5",
"knuckleswtf/scribe": "^4.35",
"laravel/framework": "^10|^11",
"laravel/prompts": "^0.1.16",
"laravel/sanctum": "^3.0|^4.0",
Expand All @@ -39,6 +41,7 @@
"pestphp/pest-plugin-faker": "^2.0",
"pestphp/pest-plugin-laravel": "^2.3",
"pestphp/pest-plugin-livewire": "^2.1",
"pestphp/pest-plugin-type-coverage": "^2.8",
"phpunit/phpunit": "^10",
"rector/rector": "^1.0.4",
"spatie/invade": "^1.1",
Expand All @@ -61,17 +64,25 @@
},
"scripts": {
"post-autoload-dump": "@php ./vendor/bin/testbench package:discover --ansi",
"pest": "vendor/bin/pest --testsuite=RESTPresenter",
"pest-coverage": "vendor/bin/pest --testsuite=RESTPresenter --coverage",
"test:format": "pint --test",
"test:refactor": "rector --dry-run",
"test:types": "phpstan analyse",
"test:arch": "pest --filter=arch",
"test:type-coverage": "pest --type-coverage --min=100",
"test:unit": "pest --parallel --coverage --min=100",
"test:profile": "pest --profile --parallel",
"check:format": "pint --test",
"check:refactor": "rector --dry-run",
"check:types": "phpstan analyse",
"format": "vendor/bin/pint",
"refactor": "rector",
"check": [
"@check:format",
"@check:refactor",
"@check:types"
],
"test": [
"@test:format",
"@test:refactor",
"@test:types"
"@test:arch",
"@test:type-coverage",
"@test:unit",
"@test:profile"
]
},
"config": {
Expand All @@ -84,7 +95,8 @@
"extra": {
"laravel": {
"providers": [
"XtendPackages\\RESTPresenter\\RESTPresenterServiceProvider"
"XtendPackages\\RESTPresenter\\RESTPresenterServiceProvider",
"XtendPackages\\RESTPresenter\\StarterKits\\Filament\\FilamentPanelProvider"
]
}
},
Expand Down
2 changes: 1 addition & 1 deletion config/rest-presenter.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
'generator' => [
'path' => env('REST_PRESENTER_GENERATOR_PATH', 'app/Api'),
'namespace' => env('REST_PRESENTER_GENERATOR_NAMESPACE', 'App\Api'),
'ts_types_path' => env('REST_PRESENTER_GENERATOR_TS_TYPES_PATH', 'types'),
'ts_types_path' => env('REST_PRESENTER_GENERATOR_TS_TYPES_PATH', 'rest-presenter/types'),
'ts_types_keyword' => env('REST_PRESENTER_GENERATOR_TS_TYPES_KEYWORD', 'interface'),
'ts_types_trailing_semicolon' => env('REST_PRESENTER_GENERATOR_TS_TYPES_TRAILING_SEMICOLON', true),
'test_path' => env('REST_PRESENTER_GENERATOR_TEST_PATH', 'tests/Feature/Api/v1'),
Expand Down
15 changes: 15 additions & 0 deletions src/Commands/GenerateApiCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,16 @@
use Illuminate\Console\Command;
use Illuminate\Filesystem\Filesystem;
use Symfony\Component\Console\Attribute\AsCommand;
use XtendPackages\RESTPresenter\Concerns\InteractsWithGit;
use XtendPackages\RESTPresenter\Support\ApiCollection\Exporters\ExporterContract;

use function Laravel\Prompts\confirm;

#[AsCommand(name: 'rest-presenter:generate-api-collection')]
final class GenerateApiCollection extends Command
{
use InteractsWithGit;

protected $signature = 'rest-presenter:generate-api-collection';

protected $description = 'Exports API collection from your applications API routes';
Expand All @@ -27,6 +32,10 @@ public function handle(): int
{
$this->info('Generating API Collection...');

if (confirm(__('Would you like to auto-commit the generated API collection?'))) {
$this->gitAutoCommit = $this->isCleanWorkingDirectory();
}

$this->exportApiCollection();

return self::SUCCESS;
Expand All @@ -45,6 +54,12 @@ private function exportApiCollection(): void
);

$this->info('API Collection Exported: '.$filePath);

if ($this->gitAutoCommit) {
$this->commitChanges(__('feat: API Collection for :exporter', [
'exporter' => type(config('rest-presenter.exporters.provider'))->asString(),
]));
}
}

private function generateFilePath(): string
Expand Down
1 change: 0 additions & 1 deletion src/Commands/Generator/MakeData.php
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,6 @@ private function transformFieldProperties(array $fields, string $model): string
default => 'string',
};

/** @var Model $model */
$model = type(new $model)->as(Model::class);
if (array_key_exists($field, $model->getCasts()) && $propertyType !== 'array') {
$propertyType = 'string';
Expand Down
6 changes: 5 additions & 1 deletion src/Commands/Generator/MakeResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,11 @@ public function handle(): ?bool

protected function getStub(): string
{
return __DIR__.'/stubs/'.type($this->argument('type'))->asString().'/resource.controller.php.stub';
$stub = $this->argument('name') === 'Auth'
? 'resource.controller.auth.php.stub'
: 'resource.controller.php.stub';

return __DIR__.'/stubs/'.type($this->argument('type'))->asString().'/'.$stub;
}

protected function getDefaultNamespace($rootNamespace): string
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

namespace {{ namespace }};

use {{ resourceNamespace }} as {{ aliasResource }};
use XtendPackages\RESTPresenter\StarterKits\Auth\Sanctum\Actions;

class {{ class }} extends {{ aliasResource }}
{
public static bool $onlyRegisterActionRoutes = true;

/**
* @return array<string, string>
*/
public function routeActions(): array
{
return [
'register' => Actions\Register::class,
'login' => Actions\Login::class,
'logout' => Actions\Logout::class,
'reset-password' => Actions\ResetPassword::class,
];
}
}
99 changes: 99 additions & 0 deletions src/Commands/RESTPresenterFilamentCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<?php

declare(strict_types=1);

namespace XtendPackages\RESTPresenter\Commands;

use Illuminate\Console\Command;
use Illuminate\Filesystem\Filesystem;
use Symfony\Component\Console\Attribute\AsCommand;
use XtendPackages\RESTPresenter\Concerns\InteractsWithGit;

use function Laravel\Prompts\confirm;

#[AsCommand(name: 'rest-presenter:filament')]
final class RESTPresenterFilamentCommand extends Command
{
use InteractsWithGit;

protected $signature = 'rest-presenter:filament
{--install : Install REST Presenter for Filament}
{--uninstall : Uninstall REST Presenter for Filament}';

protected $description = 'REST Presenter for Filament';

public function __construct(protected Filesystem $filesystem)
{
parent::__construct();
}

public function handle(): int
{
if ($this->option('install')) {
return $this->install();
}

if (! $this->filesystem->exists(config('rest-presenter.generator.path').'/StarterKits')) {
$this->components->warn('REST Presenter for Filament is not currently installed.');

return self::FAILURE;
}

if ($this->option('uninstall')) {
return $this->uninstall();
}

$this->components->warn('Please specify an option: --install, --uninstall');

return self::FAILURE;
}

private function install(): int
{
$this->components->info('Installing REST Presenter for Filament');

if (confirm(__('Would you like to auto-commit all changes made by the installer?'))) {
$this->gitAutoCommit = $this->isCleanWorkingDirectory();
}

$this->call('rest-presenter:xtend-starter-kit', ['name' => 'Sanctum']);
if ($this->gitAutoCommit) {
$this->commitChanges('feat: REST Presenter Sanctum Starter Kit');
}

$this->call('rest-presenter:xtend-starter-kit', ['name' => 'Filament']);
if ($this->gitAutoCommit) {
$this->commitChanges('feat: REST Presenter Filament Starter Kit');
}

$this->components->info('REST Presenter Filament installed successfully 🚀');

$this->components->info('Next step when your ready run "php artisan rest-presenter:generate-api-collection" to auto-generate your API collection for Insomnia or Postman.');

return self::SUCCESS;
}

private function uninstall(): int
{
if (! confirm('Are you sure you want to uninstall REST Presenter for Filament?')) {
return self::FAILURE;
}

if (confirm(__('Would you like to auto-commit revert changes made by the installer?'))) {
$this->gitAutoCommit = $this->isCleanWorkingDirectory();
}

$this->filesystem->delete(config_path('rest-presenter.php'));
$this->filesystem->deleteDirectory(config('rest-presenter.generator.path').'/StarterKits');
$this->filesystem->deleteDirectory(app()->basePath('tests/StarterKits'));
$this->filesystem->deleteDirectory(resource_path('rest-presenter'));

if ($this->gitAutoCommit) {
$this->commitChanges('revert: Remove REST Presenter Sanctum & Filament Starter Kits');
}

$this->components->info('REST Presenter Filament uninstalled successfully.');

return self::SUCCESS;
}
}
6 changes: 5 additions & 1 deletion src/Commands/XtendStarterKit.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public function handle(): int
}

$this->generateStarterKit($starterKitsDirectory, $kitPath);
$this->autoDiscoverResources($kitPath);

return self::SUCCESS;
}
Expand Down Expand Up @@ -118,7 +119,8 @@ private function autoDiscoverResources(string $kitPath): void
{
$kitNamespace = Str::of($kitPath)->replace('/', '\\')->value();
$supportedKit = match ($kitNamespace) {
'Filament\Base' => 'FilamentStarterKit',
'Auth\\Sanctum\\Base' => 'SanctumStarterKit',
'Filament\\Base' => 'FilamentStarterKit',
default => false,
};

Expand All @@ -132,6 +134,8 @@ private function autoDiscoverResources(string $kitPath): void
$starterKit = resolve('XtendPackages\\RESTPresenter\\StarterKits\\'.$kitNamespace.'\\'.$supportedKit);
$resources = $starterKit->autoDiscover();

$this->filesystem->deleteDirectory(config('rest-presenter.generator.path').'/StarterKits/'.$kitPath);

if (! $resources) {
$this->components->warn(__('No resources were found for ":supported_kit"', ['supported_kit' => $supportedKit]));

Expand Down
2 changes: 1 addition & 1 deletion src/Concerns/InteractsWithClassDefinitions.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
trait InteractsWithClassDefinitions
{
/**
* @return Collection<string, non-empty-array<string, string>>
* @return Collection<string, non-empty-array<string, class-string>>
*/
protected function scanClassDefinitions(string $filenamePrefix, string $removeFromGroupKey, string $parentClass): Collection
{
Expand Down
33 changes: 33 additions & 0 deletions src/Concerns/InteractsWithGit.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);

namespace XtendPackages\RESTPresenter\Concerns;

use Illuminate\Support\Facades\Process;

trait InteractsWithGit
{
protected bool $gitAutoCommit = false;

protected function commitChanges(string $message): void
{
$this->components->info('Committing changes...');

Process::run('git add .');
Process::run('git commit -m "'.$message.'"');

$this->components->info('Changes committed successfully');
}

protected function isCleanWorkingDirectory(): bool
{
$cleanDir = (Process::run('git diff --quiet'))->exitCode() === 0;

if (! $cleanDir) {
$this->components->warn('Please commit or stash your changes before proceeding with auto-commit');
}

return $cleanDir;
}
}
63 changes: 63 additions & 0 deletions src/Models/Endpoint.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php

declare(strict_types=1);

namespace XtendPackages\RESTPresenter\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Str;
use InvalidArgumentException;
use Sushi\Sushi;

/**
* @property int $id
* @property string $group
* @property string $route
* @property string $type
* @property string $uri
* @property bool $is_authenticated
*/
class Endpoint extends Model
{
use Sushi;

/**
* @return array<mixed>
*/
public function getRows(): array
{
return Http::withOptions(type(['verify' => false])->asArray())
->withHeader('X-REST-PRESENTER-API-KEY', type(config('rest-presenter.auth.key'))->asString())
->get(route('api.v1.resources'))
->collect()->transform(function ($v, $k) {
if (! is_array($v)) {
throw new InvalidArgumentException('v must be an array');
}

$group = Str::of($v['name'])
->beforeLast('.')
->afterLast('.')
->title()
->value();

if ($group === 'V1') {
$group = 'API Resources';
}

$authenticatedRoute = false;
if ($v['middleware'] ?? false) {
$authenticatedRoute = collect(type($v['middleware'])->asArray())->contains('auth:sanctum');
}

return [
'id' => $k + 1,
'group' => $group,
'route' => $v['name'],
'type' => $v['methods'][0],
'uri' => $v['uri'],
'is_authenticated' => $authenticatedRoute,
];
})->toArray();
}
}
Loading

0 comments on commit 85d2b6b

Please sign in to comment.