Skip to content

Commit

Permalink
1.5.0
Browse files Browse the repository at this point in the history
- Add partial support for `spatie/laravel-settings` package
  • Loading branch information
ewilan-riviere committed Jun 29, 2023
1 parent 37b9b4f commit b5332be
Show file tree
Hide file tree
Showing 16 changed files with 313 additions and 63 deletions.
34 changes: 30 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,22 @@ return [
*/
'fake_team' => false,
],
/**
* Options for the Spatie settings.
*/
'settings' => [
'filename' => 'types-settings.d.ts',
/**
* The path to the settings directory.
*/
'directory' => app_path('Settings'),
/**
* Settings to skip.
*/
'skip' => [
// 'App\\Settings\\Home',
],
],
/**
* Options for the routes.
*/
Expand Down Expand Up @@ -128,13 +144,23 @@ Generate `resources/js/types-models.d.ts` file with all models types.
php artisan typescriptable:models
```

- Generate TS types for [Eloquent models](https://laravel.com/docs/9.x/eloquent)
- Generate TS types for [Eloquent relations](https://laravel.com/docs/9.x/eloquent-relationships) (except `morphTo`)
- Generate TS types for [Eloquent models](https://laravel.com/docs/10.x/eloquent)
- Generate TS types for [Eloquent relations](https://laravel.com/docs/10.x/eloquent-relationships) (except `morphTo`)
- Generate TS types for `casts` (include native `enum` support)
- Generate TS types for `dates`
- Generate TS types for `appends` (partial for [`Casts\Attribute`](https://laravel.com/docs/9.x/eloquent-mutators#defining-an-accessor), you can use old way to define `get*Attribute` methods)
- Generate TS types for `appends` (partial for [`Casts\Attribute`](https://laravel.com/docs/10.x/eloquent-mutators#defining-an-accessor), you can use old way to define `get*Attribute` methods)
- Generate TS types `counts`
- Generate pagination TS types for [Laravel pagination](https://laravel.com/docs/9.x/pagination) with option `paginate`
- Generate pagination TS types for [Laravel pagination](https://laravel.com/docs/10.x/pagination) with option `paginate`

### Spatie Settings

If you use [`spatie/laravel-settings`](https://github.com/spatie/laravel-settings), you can generate `resources/js/types-settings.d.ts` file with all settings types.

- Generate TS types for Settings from PHP classes

```bash
php artisan typescriptable:settings
```

### Routes

Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "kiwilan/typescriptable-laravel",
"description": "PHP package for Laravel to type Eloquent models and routes with autogenerated TypeScript, ready for Inertia with associated NPM package.",
"version": "1.4.0",
"version": "1.5.0",
"keywords": [
"kiwilan",
"laravel",
Expand Down
16 changes: 16 additions & 0 deletions config/typescriptable.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,22 @@
*/
'fake_team' => false,
],
/**
* Options for the Spatie settings.
*/
'settings' => [
'filename' => 'types-settings.d.ts',
/**
* The path to the settings directory.
*/
'directory' => app_path('Settings'),
/**
* Settings to skip.
*/
'skip' => [
// 'App\\Settings\\Home',
],
],
/**
* Options for the routes.
*/
Expand Down
43 changes: 43 additions & 0 deletions src/Commands/TypescriptableSettingsCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

namespace Kiwilan\Typescriptable\Commands;

use Illuminate\Console\Command;
use Kiwilan\Typescriptable\Typescriptable;

class TypescriptableSettingsCommand extends Command
{
public $signature = 'typescriptable:settings
{--settings-path : Path to settings directory}
{--output-path : Path to output}
{--extends : Extends class to parse}';

public $description = 'Generate Spatie Settings types.';

public function __construct(
public ?string $settingsPath = null,
public ?string $outputPath = null,
public ?string $extends = null,
) {
parent::__construct();
}

public function handle(): int
{
$this->settingsPath = (string) $this->option('settings-path');
$this->outputPath = (string) $this->option('output-path');
$this->extends = (string) $this->option('extends');

$service = Typescriptable::settings($this->settingsPath, $this->outputPath, $this->extends);
// $namespaces = [];

// foreach ($service->items as $item) {
// $namespaces[] = [$item->namespace];
// }
// $this->table(['Models'], $namespaces);

$this->info('Generated settings types.');

return self::SUCCESS;
}
}
1 change: 1 addition & 0 deletions src/Typed/Eloquent/EloquentItem.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Kiwilan\Typescriptable\Typed\Eloquent\Utils\EloquentCast;
use Kiwilan\Typescriptable\Typed\Eloquent\Utils\EloquentProperty;
use Kiwilan\Typescriptable\Typed\Eloquent\Utils\EloquentRelation;
use Kiwilan\Typescriptable\Typed\Utils\ClassItem;

class EloquentItem
{
Expand Down
38 changes: 4 additions & 34 deletions src/Typed/EloquentType.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
namespace Kiwilan\Typescriptable\Typed;

use Illuminate\Support\Str;
use Kiwilan\Typescriptable\Typed\Eloquent\ClassItem;
use Kiwilan\Typescriptable\Typed\Eloquent\ClassTemplate;
use Kiwilan\Typescriptable\Typed\Eloquent\Output\EloquentPhp;
use Kiwilan\Typescriptable\Typed\Eloquent\Output\EloquentTypescript;
use Kiwilan\Typescriptable\Typed\Eloquent\Utils\EloquentProperty;
use Kiwilan\Typescriptable\Typed\Utils\ClassItem;
use Kiwilan\Typescriptable\Typed\Utils\LaravelTeamType;
use Kiwilan\Typescriptable\TypescriptableConfig;

Expand Down Expand Up @@ -40,12 +40,13 @@ public static function make(?string $modelsPath, ?string $outputPath): self
}

$self = new EloquentType($modelsPath, $outputPath);
$self->items = $self->setItems();
// $self->items = $self->setItems();
$self->items = ClassItem::list($self->modelsPath, TypescriptableConfig::modelsSkip());
$self->list = $self->setList();
$self->eloquents = $self->setEloquents();

$typescript = EloquentTypescript::make($self->eloquents, "{$outputPath}/{$tsFilename}");
$php = EloquentPhp::make($self->eloquents, $outputPath);
// $php = EloquentPhp::make($self->eloquents, $outputPath);

$typescript->print();
// $php->print();
Expand Down Expand Up @@ -98,35 +99,4 @@ private function setList(): array

return $list;
}

/**
* @return ClassItem[]
*/
private function setItems(): array
{
/** @var ClassItem[] */
$classes = [];

$iterator = new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($this->modelsPath, \FilesystemIterator::SKIP_DOTS)
);
$skip = TypescriptableConfig::modelsSkip();

/** @var \SplFileInfo $file */
foreach ($iterator as $file) {
if (! $file->isDir()) {
$model = ClassItem::make(
path: $file->getPathname(),
file: $file,
);

if (in_array($model->namespace, $skip)) {
continue;
}
$classes[$model->name] = $model;
}
}

return $classes;
}
}
67 changes: 67 additions & 0 deletions src/Typed/Setting/SettingItem.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php

namespace Kiwilan\Typescriptable\Typed\Setting;

use Kiwilan\Typescriptable\Typed\Eloquent\EloquentItem;
use Kiwilan\Typescriptable\Typed\Utils\ClassItem;
use ReflectionNamedType;
use ReflectionProperty;

class SettingItem
{
/**
* @property SettingItemProperty[] $properties
*/
protected function __construct(
public ClassItem $class,
public string $name,
public array $properties = [],
) {
}

public static function make(ClassItem $class): self
{
$properties = [];
foreach ($class->reflect->getProperties() as $property) {
if ($class->namespace === $property->class) {
$item = SettingItemProperty::make($property);
$properties[$item->name] = $item;
}
}

$self = new self(
class: $class,
name: $class->name,
properties: $properties,
);

return $self;
}
}

class SettingItemProperty
{
protected function __construct(
public string $name,
public string $type = 'mixed',
public bool $isNullable = false,
public bool $isBuiltin = false,
public string $typeTs = 'any',
) {
}

public static function make(ReflectionProperty $property): self
{
$type = $property->getType();
$self = new self(
name: $property->getName(),
type: $type instanceof ReflectionNamedType ? $type->getName() : 'mixed',
isNullable: $type->allowsNull(),
isBuiltin: $type instanceof ReflectionNamedType ? $type->isBuiltin() : false,
);

$self->typeTs = EloquentItem::phpToTs($self->type);

return $self;
}
}
49 changes: 49 additions & 0 deletions src/Typed/Setting/SettingTypescript.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

namespace Kiwilan\Typescriptable\Typed\Setting;

use Illuminate\Support\Facades\File;

class SettingTypescript
{
protected function __construct(
public string $path,
public string $content = '',
) {
}

/**
* @param array<string,SettingItem> $items
*/
public static function make(array $items, string $path): self
{
$self = new self($path);

/** @var string[] */
$content = [];

$content[] = '// This file is auto generated by TypescriptableLaravel.';
$content[] = 'declare namespace App {';
$content[] = ' declare namespace Settings {';

foreach ($items as $model => $item) {
$content[] = " export type {$model} = {";
foreach ($item->properties as $field => $property) {
$field = $property->isNullable ? "{$field}?" : $field;
$content[] = " {$field}: {$property->typeTs}";
}
$content[] = ' }';
}
$content[] = ' }';
$content[] = '}';

$self->content = implode(PHP_EOL, $content);

return $self;
}

public function print(): void
{
File::put($this->path, $this->content);
}
}
40 changes: 23 additions & 17 deletions src/Typed/SettingType.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,40 +2,46 @@

namespace Kiwilan\Typescriptable\Typed;

use Kiwilan\Typescriptable\Typed\Eloquent\ClassItem;
use Kiwilan\Typescriptable\Typed\Eloquent\Utils\EloquentProperty;
use Kiwilan\Typescriptable\Typed\Setting\SettingItem;
use Kiwilan\Typescriptable\Typed\Setting\SettingTypescript;
use Kiwilan\Typescriptable\Typed\Utils\ClassItem;
use Kiwilan\Typescriptable\TypescriptableConfig;

class SettingType
{
/** @var ClassItem[] */
/** @var SettingItem[] */
public array $items = [];

/** @var array<string, EloquentProperty[]> */
public array $eloquents = [];

/** @var array<string, array<string, array<string, string>>> */
public array $list = [];

protected function __construct(
public string $settingsPath,
public string $outputPath,
) {
}

public static function make(?string $settingsPath, ?string $outputPath): self
public static function make(?string $settingsPath, ?string $outputPath, string $extends = 'Spatie\LaravelSettings\Settings'): self
{
// if (! $modelsPath) {
// $modelsPath = TypescriptableConfig::modelsDirectory();
// }
if (! $settingsPath) {
$settingsPath = TypescriptableConfig::settingsDirectory();
}

$tsFilename = TypescriptableConfig::settingsFilename();
if (! $outputPath) {
$outputPath = TypescriptableConfig::setPath();
}

// $tsFilename = TypescriptableConfig::modelsFilename();
// if (! $outputPath) {
// $outputPath = TypescriptableConfig::setPath();
// }
$items = ClassItem::list($settingsPath, TypescriptableConfig::settingsSkip());
$items = array_filter($items, fn (ClassItem $item) => $item->extends === $extends);

$self = new self($settingsPath, $outputPath);

foreach ($items as $item) {
$item = SettingItem::make($item);
$self->items[$item->name] = $item;
}

$typescript = SettingTypescript::make($self->items, "{$outputPath}/{$tsFilename}");
$typescript->print();

return $self;
}
}
Loading

0 comments on commit b5332be

Please sign in to comment.