diff --git a/.docs/README.md b/.docs/README.md
index a2f5d4b..902eb41 100644
--- a/.docs/README.md
+++ b/.docs/README.md
@@ -5,14 +5,14 @@
## Installation
```bash
-composer require contributte/mate --dev
+composer require contributte/crafter --dev
```
## Quickstart
-1. Create `.mate.neon` in your project root.
+1. Create `crafter.neon` in your project root.
-You can initialize it by running `vendor/bin/mate init`. Or you can create it manually.
+You can initialize it by running `vendor/bin/crafter init`. Or you can create it manually.
```neon
data:
@@ -21,14 +21,14 @@ data:
username: {type: string}
email: {type: string}
password: {type: string}
- createdAt: {type: Nette\Utils\DateTime}
- updatedAt: {type: Nette\Utils\DateTime}
+ createdAt: {type: datetime}
+ updatedAt: {type: datetime}
```
-2. Run `vendor/bin/mate` or `php mate.phar` in your project root.
+2. Run `vendor/bin/crafter` or `php crafter.phar` in your project root.
```
-vendor/bin/mate craft
+vendor/bin/crafter craft
```
## Configuration
@@ -37,39 +37,33 @@ Under construction.
## Usage
-### `mate init`
+### `crafter init`
-Create `.mate.neon` in your project.
+Create `crafter.neon` in your project.
-### `mate craft`
+### `crafter craft`
-Generate files based on `.mate.neon`.
+Generate files based on `crafter.neon`.
-```bash
-vendor/bin/mate craft --struct user
-```
+You can define:
+
+- `--data|-k` - data structure key
+- `--scope|-s` - scope of generation
```bash
-vendor/bin/mate craft --struct user --crafter=entity
-vendor/bin/mate craft --struct user --crafter=repository
-
-vendor/bin/mate craft --struct user --crafter=bus --mode=create
-vendor/bin/mate craft --struct user --crafter=bus --mode=update
-vendor/bin/mate craft --struct user --crafter=bus --mode=delete
-vendor/bin/mate craft --struct user --crafter=bus --mode=list
-vendor/bin/mate craft --struct user --crafter=bus --mode=get
-
-vendor/bin/mate craft --struct user --crafter=api --mode=create
-vendor/bin/mate craft --struct user --crafter=api --mode=update
-vendor/bin/mate craft --struct user --crafter=api --mode=delete
-vendor/bin/mate craft --struct user --crafter=api --mode=list
-vendor/bin/mate craft --struct user --crafter=api --mode=get
+vendor/bin/crafter craft -k user
+vendor/bin/crafter craft -k user -s database
```
-### `mate generate`
+### `crafter generate`
+
+Generate whole project based on template.
+
+You can define:
-Generate whole project based on `.mate.neon`.
+- `--template|-t` - project template
+- `--directory|-d` - output folder
```bash
-vendor/bin/mate generate --template api
+vendor/bin/crafter generate -t nella -d demo
```
diff --git a/README.md b/README.md
index 91f6a0a..5b5b1c1 100644
--- a/README.md
+++ b/README.md
@@ -1,14 +1,14 @@
-![](https://heatbadger.now.sh/github/readme/contributte/mate/)
+![](https://heatbadger.now.sh/github/readme/contributte/crafter/)
-
-
-
-
+
+
+
+
-
-
+
+
@@ -20,10 +20,10 @@ Website 🚀 contributte.org | Contact
## Usage
-To install the latest version of `contributte/mate` use [Composer](https://getcomposer.org).
+To install the latest version of `contributte/crafter` use [Composer](https://getcomposer.org).
```
-composer require contributte/mate
+composer require contributte/crafter
```
## Documentation
diff --git a/bin/crafter b/bin/crafter
new file mode 100755
index 0000000..be0df1d
--- /dev/null
+++ b/bin/crafter
@@ -0,0 +1,4 @@
+#!/usr/bin/env php
+ Expect::string()->required(),
- 'email' => Expect::string()->required(),
- 'password' => Expect::string()->required(),
- 'createdAt' => Expect::string()->required(),
- 'updatedAt' => Expect::string()->required(),
- 'roles' => Expect::string()->required(),
- ])->castTo(self::class);
- }
-
-}
diff --git a/examples/d01/app/Api/User/Create/CreateUserResponse.php b/examples/d01/app/Api/User/Create/CreateUserResponse.php
deleted file mode 100644
index 9866399..0000000
--- a/examples/d01/app/Api/User/Create/CreateUserResponse.php
+++ /dev/null
@@ -1,20 +0,0 @@
-payload = $dto;
-
- return $self;
- }
-
-}
diff --git a/examples/d01/app/Api/User/Delete/DeleteUserController.php b/examples/d01/app/Api/User/Delete/DeleteUserController.php
deleted file mode 100644
index 8560754..0000000
--- a/examples/d01/app/Api/User/Delete/DeleteUserController.php
+++ /dev/null
@@ -1,28 +0,0 @@
-payload = $dto;
-
- return $self;
- }
-
-}
diff --git a/examples/d01/app/Api/User/List/ListUserController.php b/examples/d01/app/Api/User/List/ListUserController.php
deleted file mode 100644
index a57daf3..0000000
--- a/examples/d01/app/Api/User/List/ListUserController.php
+++ /dev/null
@@ -1,28 +0,0 @@
- Expect::structure([
- 'username' => Expect::anyOf('asc', 'desc'),
- ])->required(false)->castTo('array'),
- 'q' => Expect::structure([
- 'username' => Expect::string(),
- ])->required(false)->castTo('array'),
- ])->castTo(self::class);
- }
-
-}
diff --git a/examples/d01/app/Api/User/List/ListUserResponse.php b/examples/d01/app/Api/User/List/ListUserResponse.php
deleted file mode 100644
index 2996302..0000000
--- a/examples/d01/app/Api/User/List/ListUserResponse.php
+++ /dev/null
@@ -1,30 +0,0 @@
-entities as $entity) {
- $payload[] = $entity->toArray();
- }
-
- $self->entities = $payload;
- $self->count = $result->count;
- $self->limit = $result->limit;
- $self->page = $result->page;
-
- return $self;
- }
-
-}
diff --git a/examples/d01/app/Api/User/Update/UpdateUserController.php b/examples/d01/app/Api/User/Update/UpdateUserController.php
deleted file mode 100644
index 9e06008..0000000
--- a/examples/d01/app/Api/User/Update/UpdateUserController.php
+++ /dev/null
@@ -1,28 +0,0 @@
- Expect::string(),
- 'email' => Expect::string(),
- 'password' => Expect::string(),
- 'createdAt' => Expect::string(),
- 'updatedAt' => Expect::string(),
- 'roles' => Expect::string(),
- ])->castTo(self::class);
- }
-
-}
diff --git a/examples/d01/app/Api/User/Update/UpdateUserResponse.php b/examples/d01/app/Api/User/Update/UpdateUserResponse.php
deleted file mode 100644
index 1db51e0..0000000
--- a/examples/d01/app/Api/User/Update/UpdateUserResponse.php
+++ /dev/null
@@ -1,20 +0,0 @@
-payload = $dto;
-
- return $self;
- }
-
-}
diff --git a/examples/d01/app/Domain/User/CreateUserCommand.php b/examples/d01/app/Domain/User/CreateUserCommand.php
deleted file mode 100644
index e904859..0000000
--- a/examples/d01/app/Domain/User/CreateUserCommand.php
+++ /dev/null
@@ -1,20 +0,0 @@
-username = $command->username;
- $user->email = $command->email;
- $user->password = $command->password;
- $user->createdAt = $command->createdAt;
- $user->updatedAt = $command->updatedAt;
- $user->roles = $command->roles;
-
- try {
- $this->em->persist($user);
- $this->em->flush();
- } catch (UniqueConstraintViolationException $e) {
- throw EntityExistsException::alreadyExists(User::class, $e);
- }
-
- // $this->ed->dispatch(new UserCreatedEvent($user));
-
- return Result::from($user);
- }
-
-}
diff --git a/examples/d01/app/Domain/User/Database/User.php b/examples/d01/app/Domain/User/Database/User.php
deleted file mode 100644
index 816f04d..0000000
--- a/examples/d01/app/Domain/User/Database/User.php
+++ /dev/null
@@ -1,42 +0,0 @@
-
- */
-class UserRepository extends AbstractRepository
-{
-
- public function __construct(
- EntityManagerInterface $em
- )
- {
- parent::__construct($em->getRepository(User::class));
- }
-
-}
diff --git a/examples/d01/app/Domain/User/DeleteUserCommand.php b/examples/d01/app/Domain/User/DeleteUserCommand.php
deleted file mode 100644
index de3fca9..0000000
--- a/examples/d01/app/Domain/User/DeleteUserCommand.php
+++ /dev/null
@@ -1,15 +0,0 @@
-em->getRepository(User::class)->findOneBy(['id' => $command->id]);
-
- if ($user === null) {
- throw EntityNotFoundException::notFoundByUiid(User::class, $command->id);
- }
-
- if ($command->username !== null) {
- $user->username = $command->username;
- }
- if ($command->email !== null) {
- $user->email = $command->email;
- }
- if ($command->password !== null) {
- $user->password = $command->password;
- }
- if ($command->createdAt !== null) {
- $user->createdAt = $command->createdAt;
- }
- if ($command->updatedAt !== null) {
- $user->updatedAt = $command->updatedAt;
- }
- if ($command->roles !== null) {
- $user->roles = $command->roles;
- }
-
- $this->em->persist($user);
- $this->em->flush();
-
- // $this->ed->dispatch(new UserUpdatedEvent($user));
-
- return Result::from($user);
- }
-
-}
diff --git a/examples/d02/.mate.neon b/examples/d02/.mate.neon
deleted file mode 100644
index 04bec7a..0000000
--- a/examples/d02/.mate.neon
+++ /dev/null
@@ -1,51 +0,0 @@
-app:
- namespace: App
-
- craft:
- # Database
- - { category: database, type: entity, class: "App\Domain\${name|ucfirst}\Database\${name|ucfirst}", baseClass: App\Model\Database\Entity\AbstractEntity }
- - { category: database, type: repository, class: "App\Domain\${name|ucfirst}\Database\${name|ucfirst}Repository", baseClass: App\Model\Database\Repository\AbstractRepository }
- # Domain
- - { category: domain, type: command, flavor: create, class: "App\Domain\${name|ucfirst}\Create${name|ucfirst}Command" }
- - { category: domain, type: handler, flavor: create, class: "App\Domain\${name|ucfirst}\Create${name|ucfirst}Handler", dependencies: { em: Doctrine\ORM\EntityManagerInterface } }
- - { category: domain, type: command, flavor: update, class: "App\Domain\${name|ucfirst}\Update${name|ucfirst}Command" }
- - { category: domain, type: handler, flavor: update, class: "App\Domain\${name|ucfirst}\Update${name|ucfirst}Handler", dependencies: { em: Doctrine\ORM\EntityManagerInterface } }
- - { category: domain, type: command, flavor: get, class: "App\Domain\${name|ucfirst}\Get${name|ucfirst}Command" }
- - { category: domain, type: handler, flavor: get, class: "App\Domain\${name|ucfirst}\Get${name|ucfirst}Handler", dependencies: { em: Doctrine\ORM\EntityManagerInterface } }
- - { category: domain, type: command, flavor: list, class: "App\Domain\${name|ucfirst}\List${name|ucfirst}Command" }
- - { category: domain, type: handler, flavor: list, class: "App\Domain\${name|ucfirst}\List${name|ucfirst}Handler", dependencies: { em: Doctrine\ORM\EntityManagerInterface } }
- - { category: domain, type: command, flavor: delete, class: "App\Domain\${name|ucfirst}\Delete${name|ucfirst}Command" }
- - { category: domain, type: handler, flavor: delete, class: "App\Domain\${name|ucfirst}\Delete${name|ucfirst}Handler", dependencies: { em: Doctrine\ORM\EntityManagerInterface } }
- # API (create)
- - { category: api, type: controller, flavor: create, class: "App\Api\${name|ucfirst}\Create\Create${name|ucfirst}Controller" }
- - { category: api, type: request, flavor: create, class: "App\Api\${name|ucfirst}\Create\Create${name|ucfirst}Request" }
- - { category: api, type: request_body, flavor: create, class: "App\Api\${name|ucfirst}\Create\Create${name|ucfirst}Body" }
- - { category: api, type: response, flavor: create, class: "App\Api\${name|ucfirst}\Create\Create${name|ucfirst}Response" }
- # API (update)
- - { category: api, type: controller, flavor: update, class: "App\Api\${name|ucfirst}\Update\Update${name|ucfirst}Controller" }
- - { category: api, type: request, flavor: update, class: "App\Api\${name|ucfirst}\Update\Update${name|ucfirst}Request" }
- - { category: api, type: request_body, flavor: update, class: "App\Api\${name|ucfirst}\Update\Update${name|ucfirst}Body" }
- - { category: api, type: response, flavor: update, class: "App\Api\${name|ucfirst}\Update\Update${name|ucfirst}Response" }
- # API (get)
- - { category: api, type: controller, flavor: get, class: "App\Api\${name|ucfirst}\Get\Get${name|ucfirst}Controller" }
- - { category: api, type: request, flavor: get, class: "App\Api\${name|ucfirst}\Get\Get${name|ucfirst}Request" }
- - { category: api, type: response, flavor: get, class: "App\Api\${name|ucfirst}\Get\Get${name|ucfirst}Response" }
- # API (list)
- - { category: api, type: controller, flavor: list, class: "App\Api\${name|ucfirst}\List\List${name|ucfirst}Controller" }
- - { category: api, type: request, flavor: list,class: "App\Api\${name|ucfirst}\List\List${name|ucfirst}Request" }
- - { category: api, type: request_filter, flavor: list,class: "App\Api\${name|ucfirst}\List\List${name|ucfirst}Filter" }
- - { category: api, type: response, flavor: list,class: "App\Api\${name|ucfirst}\List\List${name|ucfirst}Response" }
- # API (delete)
- - { category: api, type: controller, flavor: delete, class: "App\Api\${name|ucfirst}\Delete\Delete${name|ucfirst}Controller" }
- - { category: api, type: response, flavor: delete,class: "App\Api\${name|ucfirst}\Delete\Delete${name|ucfirst}Response" }
-
-data:
- user:
- name: user
- craft: [api, domain, database]
- fields:
- username: {type: string}
- email: {type: string}
- password: {type: string}
- createdAt: {type: Nette\Utils\DateTime }
- updatedAt: {type: Nette\Utils\DateTime}
diff --git a/examples/d02/app/Domain/User/CreateUserCommand.php b/examples/d02/app/Domain/User/CreateUserCommand.php
deleted file mode 100644
index c933f3f..0000000
--- a/examples/d02/app/Domain/User/CreateUserCommand.php
+++ /dev/null
@@ -1,17 +0,0 @@
-username,
- email: $command->email,
- password: $command->password,
- createdAt: $command->createdAt,
- updatedAt: $command->updatedAt,
- );
-
-
- $this->em->persist($entity);
- $this->em->flush();
-
-
- return $entity;
- }
-}
diff --git a/examples/presets/custom-crafters/.gitignore b/examples/presets/custom-crafters/.gitignore
new file mode 100644
index 0000000..0be5ce5
--- /dev/null
+++ b/examples/presets/custom-crafters/.gitignore
@@ -0,0 +1,3 @@
+*
+!.gitignore
+crafter.neon
diff --git a/examples/d01/.mate.neon b/examples/presets/custom-crafters/crafter.neon
similarity index 74%
rename from examples/d01/.mate.neon
rename to examples/presets/custom-crafters/crafter.neon
index fc88379..aa49dc6 100644
--- a/examples/d01/.mate.neon
+++ b/examples/presets/custom-crafters/crafter.neon
@@ -1,10 +1,9 @@
-mate:
- presets: [moderntv]
+dir: app
+presets: [fx]
-app:
- scopes: [database, bus, api]
+crafters: [] # TODO
-structs:
+data:
user:
fields:
username: {type: string}
diff --git a/examples/presets/preset-default/.gitignore b/examples/presets/preset-default/.gitignore
new file mode 100644
index 0000000..0be5ce5
--- /dev/null
+++ b/examples/presets/preset-default/.gitignore
@@ -0,0 +1,3 @@
+*
+!.gitignore
+crafter.neon
diff --git a/examples/presets/preset-default/crafter.neon b/examples/presets/preset-default/crafter.neon
new file mode 100644
index 0000000..bd2f6c2
--- /dev/null
+++ b/examples/presets/preset-default/crafter.neon
@@ -0,0 +1,8 @@
+dir: src
+namespace: MyApp
+
+data:
+ user:
+ fields:
+ username: {type: string}
+ email: {type: string}
diff --git a/examples/presets/preset-nette/.gitignore b/examples/presets/preset-nette/.gitignore
new file mode 100644
index 0000000..0be5ce5
--- /dev/null
+++ b/examples/presets/preset-nette/.gitignore
@@ -0,0 +1,3 @@
+*
+!.gitignore
+crafter.neon
diff --git a/examples/projects/nella/.gitignore b/examples/projects/nella/.gitignore
new file mode 100644
index 0000000..0be5ce5
--- /dev/null
+++ b/examples/projects/nella/.gitignore
@@ -0,0 +1,3 @@
+*
+!.gitignore
+crafter.neon
diff --git a/phpstan.neon b/phpstan.neon
index 2c30fdf..a23661e 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -23,27 +23,26 @@ parameters:
typeAliases:
ConfigShape: """
array{
- app: array{
- appDir: string,
- namespace: string,
- scopes: array|null,
- crafters: array|null,
- baseClass: string|null
- }>|null
- },
- mate: array{
- presets: array|null
- },
- structs: array|null,
+ preset: string|null,
+ template: string|null,
+ crafters: CraftersShape,
+ data: array|null
- }>|null
+ nullable: bool|null,
+ }>,
+ vars: array|null,
+ }>
}
"""
+ CraftersShape: """
+ array|null,
+ }>
+ """
diff --git a/resources/example/example1.neon b/resources/example/example1.neon
new file mode 100644
index 0000000..7342cfe
--- /dev/null
+++ b/resources/example/example1.neon
@@ -0,0 +1,28 @@
+# Schema version
+version: 1
+
+# Type of crafter
+type: preset
+
+# Application directory
+dir: src
+
+# Application namespace
+namespace: MyApp
+
+# Global variables
+vars: []
+
+# List of crafters
+crafters: []
+
+# Data structures
+data:
+ user:
+ fields:
+ username: {type: string}
+ email: {type: string}
+ password: {type: string}
+ createdAt: {type: Nette\Utils\DateTime}
+ updatedAt: {type: Nette\Utils\DateTime}
+ roles: {type: array}
diff --git a/resources/presets/default/config.neon b/resources/presets/default/config.neon
deleted file mode 100644
index d9342c3..0000000
--- a/resources/presets/default/config.neon
+++ /dev/null
@@ -1,5 +0,0 @@
-app:
- namespace: App
- appDir: app
-
- crafters: []
diff --git a/resources/presets/default/crafter.neon b/resources/presets/default/crafter.neon
new file mode 100644
index 0000000..e554ec1
--- /dev/null
+++ b/resources/presets/default/crafter.neon
@@ -0,0 +1,5 @@
+# Schema version
+version: 1
+
+# List of crafters
+crafters: []
diff --git a/resources/presets/fx/crafter.neon b/resources/presets/fx/crafter.neon
new file mode 100644
index 0000000..02f44c0
--- /dev/null
+++ b/resources/presets/fx/crafter.neon
@@ -0,0 +1,220 @@
+# Schema version
+version: 1
+
+# List of crafters
+crafters:
+ # Database ================================
+ database_entity:
+ name: entity
+ scopes: [database]
+ crafter:
+ type: latte # explicit
+ template: %cwd%/templates/database/entity.latte
+ class: 'App\Domain\{$name|firstUpper}\Database\{$name|firstUpper}'
+
+ database_repository:
+ name: repository
+ scopes: [database]
+ crafter:
+ # type: latte # autodetect by extension
+ template: %cwd%/templates/database/repository.latte
+ class: 'App\Domain\{$name|firstUpper}\Database\{$name|firstUpper}Repository'
+
+ # Bus ====================================
+ # Bus (create)
+ bus_command_create:
+ name: command@create
+ scopes: [bus]
+ crafter:
+ template: %cwd%/templates/bus/command_create.latte
+ class: 'App\Domain\{$name|firstUpper}\Create{$name|firstUpper}Command'
+ bus_handler_create:
+ name: handler@create
+ scopes: [bus]
+ crafter:
+ template: %cwd%/templates/bus/handler_create.latte
+ class: 'App\Domain\{$name|firstUpper}\Create{$name|firstUpper}Handler'
+ # Bus (update)
+ bus_command_update:
+ name: command@update
+ scopes: [bus]
+ crafter:
+ template: %cwd%/templates/bus/command_update.latte
+ class: 'App\Domain\{$name|firstUpper}\Update{$name|firstUpper}Command'
+ bus_handler_update:
+ name: handler@update
+ scopes: [bus]
+ crafter:
+ template: %cwd%/templates/bus/handler_update.latte
+ class: 'App\Domain\{$name|firstUpper}\Update{$name|firstUpper}Handler'
+ # Bus (get)
+ bus_command_get:
+ name: command@get
+ scopes: [bus]
+ crafter:
+ template: %cwd%/templates/bus/command_get.latte
+ class: 'App\Domain\{$name|firstUpper}\Get{$name|firstUpper}Command'
+ bus_handler_get:
+ name: handler@get
+ scopes: [bus]
+ crafter:
+ template: %cwd%/templates/bus/handler_get.latte
+ class: 'App\Domain\{$name|firstUpper}\Get{$name|firstUpper}Handler'
+ # Bus (list)
+ bus_command_list:
+ name: command@update
+ scopes: [bus]
+ crafter:
+ template: %cwd%/templates/bus/command_list.latte
+ class: 'App\Domain\{$name|firstUpper}\List{$name|firstUpper}Command'
+ bus_handler_list:
+ name: handler@create
+ scopes: [bus]
+ crafter:
+ template: %cwd%/templates/bus/handler_list.latte
+ class: 'App\Domain\{$name|firstUpper}\List{$name|firstUpper}Handler'
+ # Bus (delete)
+ bus_command_delete:
+ name: command@delete
+ scopes: [bus]
+ crafter:
+ template: %cwd%/templates/bus/command_delete.latte
+ class: 'App\Domain\{$name|firstUpper}\Delete{$name|firstUpper}Command'
+ bus_handler_delete:
+ name: handler@delete
+ scopes: [bus]
+ crafter:
+ template: %cwd%/templates/bus/handler_delete.latte
+ class: 'App\Domain\{$name|firstUpper}\Delete{$name|firstUpper}Handler'
+
+ # API ====================================
+ # API (create)
+ api_controller_create:
+ name: controller@create
+ scopes: [api]
+ crafter:
+ template: %cwd%/templates/api/controller_create.latte
+ class: 'App\Api\{$name|firstUpper}\Create\Create{$name|firstUpper}Controller'
+
+ api_request_create:
+ name: request@create
+ scopes: [api]
+ crafter:
+ template: %cwd%/templates/api/request_create.latte
+ class: 'App\Api\{$name|firstUpper}\Create\Create{$name|firstUpper}Request'
+
+ api_request_body_create:
+ name: request_body@create
+ scopes: [api]
+ crafter:
+ template: %cwd%/templates/api/request_body_create.latte
+ class: 'App\Api\{$name|firstUpper}\Create\Create{$name|firstUpper}RequestBody'
+
+ api_response_create:
+ name: response@create
+ scopes: [api]
+ crafter:
+ template: %cwd%/templates/api/response_create.latte
+ class: 'App\Api\{$name|firstUpper}\Create\Create{$name|firstUpper}Response'
+
+ # API (update)
+ api_controller_update:
+ name: controller@update
+ scopes: [api]
+ crafter:
+ template: %cwd%/templates/api/controller_update.latte
+ class: 'App\Api\{$name|firstUpper}\Update\Update{$name|firstUpper}Controller'
+
+ api_request_update:
+ name: request@update
+ scopes: [api]
+ crafter:
+ template: %cwd%/templates/api/request_update.latte
+ class: 'App\Api\{$name|firstUpper}\Update\Update{$name|firstUpper}Request'
+
+ api_request_body_update:
+ name: request_body@update
+ scopes: [api]
+ crafter:
+ template: %cwd%/templates/api/request_body_update.latte
+ class: 'App\Api\{$name|firstUpper}\Update\Update{$name|firstUpper}RequestBody'
+
+ api_response_update:
+ name: response@update
+ scopes: [api]
+ crafter:
+ template: %cwd%/templates/api/response_update.latte
+ class: 'App\Api\{$name|firstUpper}\Update\Update{$name|firstUpper}Response'
+
+ # API (get)
+ api_controller_get:
+ name: controller@get
+ scopes: [api]
+ crafter:
+ template: %cwd%/templates/api/controller_get.latte
+ class: 'App\Api\{$name|firstUpper}\Get\Get{$name|firstUpper}Controller'
+
+ api_request_get:
+ name: request@get
+ scopes: [api]
+ crafter:
+ template: %cwd%/templates/api/request_get.latte
+ class: 'App\Api\{$name|firstUpper}\Get\Get{$name|firstUpper}Request'
+
+ api_response_get:
+ name: response@get
+ scopes: [api]
+ crafter:
+ template: %cwd%/templates/api/response_get.latte
+ class: 'App\Api\{$name|firstUpper}\Get\Get{$name|firstUpper}Response'
+
+ # API (list)
+ api_controller_list:
+ name: controller@list
+ scopes: [api]
+ crafter:
+ template: %cwd%/templates/api/controller_list.latte
+ class: 'App\Api\{$name|firstUpper}\List\List{$name|firstUpper}Controller'
+
+ api_request_list:
+ name: request@list
+ scopes: [api]
+ crafter:
+ template: %cwd%/templates/api/request_list.latte
+ class: 'App\Api\{$name|firstUpper}\List\List{$name|firstUpper}Request'
+
+ api_request_filter_list:
+ name: request_filter@list
+ scopes: [api]
+ crafter:
+ template: %cwd%/templates/api/request_filter_list.latte
+ class: 'App\Api\{$name|firstUpper}\List\List{$name|firstUpper}RequestFilter'
+
+ api_response_list:
+ name: response@list
+ scopes: [api]
+ crafter:
+ template: %cwd%/templates/api/response_list.latte
+ class: 'App\Api\{$name|firstUpper}\List\List{$name|firstUpper}Response'
+
+ # API (delete)
+ api_controller_delete:
+ name: controller@delete
+ scopes: [api]
+ crafter:
+ template: %cwd%/templates/api/controller_delete.latte
+ class: 'App\Api\{$name|firstUpper}\Delete\Delete{$name|firstUpper}Controller'
+
+ api_request_delete:
+ name: request@delete
+ scopes: [api]
+ crafter:
+ template: %cwd%/templates/api/request_delete.latte
+ class: 'App\Api\{$name|firstUpper}\Delete\Delete{$name|firstUpper}Response'
+
+ api_response_delete:
+ name: response@delete
+ scopes: [api]
+ crafter:
+ template: %cwd%/templates/api/response_delete.latte
+ class: 'App\Api\{$name|firstUpper}\Delete\Delete{$name|firstUpper}Response'
diff --git a/resources/presets/moderntv/templates/api/controller_create.latte b/resources/presets/fx/templates/api/controller_create.latte
similarity index 100%
rename from resources/presets/moderntv/templates/api/controller_create.latte
rename to resources/presets/fx/templates/api/controller_create.latte
diff --git a/resources/presets/moderntv/templates/api/controller_delete.latte b/resources/presets/fx/templates/api/controller_delete.latte
similarity index 100%
rename from resources/presets/moderntv/templates/api/controller_delete.latte
rename to resources/presets/fx/templates/api/controller_delete.latte
diff --git a/resources/presets/moderntv/templates/api/controller_get.latte b/resources/presets/fx/templates/api/controller_get.latte
similarity index 100%
rename from resources/presets/moderntv/templates/api/controller_get.latte
rename to resources/presets/fx/templates/api/controller_get.latte
diff --git a/resources/presets/moderntv/templates/api/controller_list.latte b/resources/presets/fx/templates/api/controller_list.latte
similarity index 100%
rename from resources/presets/moderntv/templates/api/controller_list.latte
rename to resources/presets/fx/templates/api/controller_list.latte
diff --git a/resources/presets/moderntv/templates/api/controller_update.latte b/resources/presets/fx/templates/api/controller_update.latte
similarity index 100%
rename from resources/presets/moderntv/templates/api/controller_update.latte
rename to resources/presets/fx/templates/api/controller_update.latte
diff --git a/resources/presets/moderntv/templates/api/request_body_create.latte b/resources/presets/fx/templates/api/request_body_create.latte
similarity index 100%
rename from resources/presets/moderntv/templates/api/request_body_create.latte
rename to resources/presets/fx/templates/api/request_body_create.latte
diff --git a/resources/presets/moderntv/templates/api/request_body_update.latte b/resources/presets/fx/templates/api/request_body_update.latte
similarity index 100%
rename from resources/presets/moderntv/templates/api/request_body_update.latte
rename to resources/presets/fx/templates/api/request_body_update.latte
diff --git a/resources/presets/moderntv/templates/api/request_create.latte b/resources/presets/fx/templates/api/request_create.latte
similarity index 100%
rename from resources/presets/moderntv/templates/api/request_create.latte
rename to resources/presets/fx/templates/api/request_create.latte
diff --git a/resources/presets/moderntv/templates/api/request_delete.latte b/resources/presets/fx/templates/api/request_delete.latte
similarity index 100%
rename from resources/presets/moderntv/templates/api/request_delete.latte
rename to resources/presets/fx/templates/api/request_delete.latte
diff --git a/resources/presets/moderntv/templates/api/request_filter_list.latte b/resources/presets/fx/templates/api/request_filter_list.latte
similarity index 100%
rename from resources/presets/moderntv/templates/api/request_filter_list.latte
rename to resources/presets/fx/templates/api/request_filter_list.latte
diff --git a/resources/presets/moderntv/templates/api/request_get.latte b/resources/presets/fx/templates/api/request_get.latte
similarity index 100%
rename from resources/presets/moderntv/templates/api/request_get.latte
rename to resources/presets/fx/templates/api/request_get.latte
diff --git a/resources/presets/moderntv/templates/api/request_list.latte b/resources/presets/fx/templates/api/request_list.latte
similarity index 100%
rename from resources/presets/moderntv/templates/api/request_list.latte
rename to resources/presets/fx/templates/api/request_list.latte
diff --git a/resources/presets/moderntv/templates/api/request_update.latte b/resources/presets/fx/templates/api/request_update.latte
similarity index 100%
rename from resources/presets/moderntv/templates/api/request_update.latte
rename to resources/presets/fx/templates/api/request_update.latte
diff --git a/resources/presets/moderntv/templates/api/response_create.latte b/resources/presets/fx/templates/api/response_create.latte
similarity index 100%
rename from resources/presets/moderntv/templates/api/response_create.latte
rename to resources/presets/fx/templates/api/response_create.latte
diff --git a/resources/presets/moderntv/templates/api/response_delete.latte b/resources/presets/fx/templates/api/response_delete.latte
similarity index 100%
rename from resources/presets/moderntv/templates/api/response_delete.latte
rename to resources/presets/fx/templates/api/response_delete.latte
diff --git a/resources/presets/moderntv/templates/api/response_get.latte b/resources/presets/fx/templates/api/response_get.latte
similarity index 100%
rename from resources/presets/moderntv/templates/api/response_get.latte
rename to resources/presets/fx/templates/api/response_get.latte
diff --git a/resources/presets/moderntv/templates/api/response_list.latte b/resources/presets/fx/templates/api/response_list.latte
similarity index 100%
rename from resources/presets/moderntv/templates/api/response_list.latte
rename to resources/presets/fx/templates/api/response_list.latte
diff --git a/resources/presets/moderntv/templates/api/response_update.latte b/resources/presets/fx/templates/api/response_update.latte
similarity index 100%
rename from resources/presets/moderntv/templates/api/response_update.latte
rename to resources/presets/fx/templates/api/response_update.latte
diff --git a/resources/presets/moderntv/templates/bus/command_create.latte b/resources/presets/fx/templates/bus/command_create.latte
similarity index 100%
rename from resources/presets/moderntv/templates/bus/command_create.latte
rename to resources/presets/fx/templates/bus/command_create.latte
diff --git a/resources/presets/moderntv/templates/bus/command_delete.latte b/resources/presets/fx/templates/bus/command_delete.latte
similarity index 100%
rename from resources/presets/moderntv/templates/bus/command_delete.latte
rename to resources/presets/fx/templates/bus/command_delete.latte
diff --git a/resources/presets/moderntv/templates/bus/command_get.latte b/resources/presets/fx/templates/bus/command_get.latte
similarity index 100%
rename from resources/presets/moderntv/templates/bus/command_get.latte
rename to resources/presets/fx/templates/bus/command_get.latte
diff --git a/resources/presets/moderntv/templates/bus/command_list.latte b/resources/presets/fx/templates/bus/command_list.latte
similarity index 100%
rename from resources/presets/moderntv/templates/bus/command_list.latte
rename to resources/presets/fx/templates/bus/command_list.latte
diff --git a/resources/presets/moderntv/templates/bus/command_update.latte b/resources/presets/fx/templates/bus/command_update.latte
similarity index 100%
rename from resources/presets/moderntv/templates/bus/command_update.latte
rename to resources/presets/fx/templates/bus/command_update.latte
diff --git a/resources/presets/moderntv/templates/bus/handler_create.latte b/resources/presets/fx/templates/bus/handler_create.latte
similarity index 100%
rename from resources/presets/moderntv/templates/bus/handler_create.latte
rename to resources/presets/fx/templates/bus/handler_create.latte
diff --git a/resources/presets/moderntv/templates/bus/handler_delete.latte b/resources/presets/fx/templates/bus/handler_delete.latte
similarity index 100%
rename from resources/presets/moderntv/templates/bus/handler_delete.latte
rename to resources/presets/fx/templates/bus/handler_delete.latte
diff --git a/resources/presets/moderntv/templates/bus/handler_get.latte b/resources/presets/fx/templates/bus/handler_get.latte
similarity index 100%
rename from resources/presets/moderntv/templates/bus/handler_get.latte
rename to resources/presets/fx/templates/bus/handler_get.latte
diff --git a/resources/presets/moderntv/templates/bus/handler_list.latte b/resources/presets/fx/templates/bus/handler_list.latte
similarity index 100%
rename from resources/presets/moderntv/templates/bus/handler_list.latte
rename to resources/presets/fx/templates/bus/handler_list.latte
diff --git a/resources/presets/moderntv/templates/bus/handler_update.latte b/resources/presets/fx/templates/bus/handler_update.latte
similarity index 100%
rename from resources/presets/moderntv/templates/bus/handler_update.latte
rename to resources/presets/fx/templates/bus/handler_update.latte
diff --git a/resources/presets/moderntv/templates/database/entity.latte b/resources/presets/fx/templates/database/entity.latte
similarity index 100%
rename from resources/presets/moderntv/templates/database/entity.latte
rename to resources/presets/fx/templates/database/entity.latte
diff --git a/resources/presets/moderntv/templates/database/repository.latte b/resources/presets/fx/templates/database/repository.latte
similarity index 100%
rename from resources/presets/moderntv/templates/database/repository.latte
rename to resources/presets/fx/templates/database/repository.latte
diff --git a/resources/presets/moderntv/config.neon b/resources/presets/moderntv/config.neon
deleted file mode 100644
index 3a10827..0000000
--- a/resources/presets/moderntv/config.neon
+++ /dev/null
@@ -1,228 +0,0 @@
-app:
- namespace: App
- appDir: app
-
- crafters:
- # Database ================================
- database_entity:
- crafter: entity
- scopes: [database]
- template: %presetDir%/templates/database/entity.latte
- class: 'App\Domain\{$name|firstUpper}\Database\{$name|firstUpper}'
- baseClass: App\Model\Database\Entity\AbstractEntity
-
- database_repository:
- crafter: repository
- scopes: [database]
- template: %presetDir%/templates/database/repository.latte
- class: 'App\Domain\{$name|firstUpper}\Database\{$name|firstUpper}Repository'
- baseClass: App\Model\Database\Repository\AbstractRepository
-
- # Bus ====================================
- # Bus (create)
- bus_command_create:
- crafter: command
- mode: create
- scopes: [bus]
- template: %presetDir%/templates/bus/command_create.latte
- class: 'App\Domain\{$name|firstUpper}\Create{$name|firstUpper}Command'
- bus_handler_create:
- crafter: handler
- mode: create
- scopes: [bus]
- template: %presetDir%/templates/bus/handler_create.latte
- class: 'App\Domain\{$name|firstUpper}\Create{$name|firstUpper}Handler'
- dependencies:
- em: Doctrine\ORM\EntityManagerInterface
- # Bus (update)
- bus_command_update:
- crafter: command
- mode: update
- scopes: [bus]
- template: %presetDir%/templates/bus/command_update.latte
- class: 'App\Domain\{$name|firstUpper}\Update{$name|firstUpper}Command'
- bus_handler_update:
- crafter: handler
- mode: update
- scopes: [bus]
- template: %presetDir%/templates/bus/handler_update.latte
- class: 'App\Domain\{$name|firstUpper}\Update{$name|firstUpper}Handler'
- dependencies:
- em: Doctrine\ORM\EntityManagerInterface
- # Bus (get)
- bus_command_get:
- crafter: command
- mode: get
- scopes: [bus]
- template: %presetDir%/templates/bus/command_get.latte
- class: 'App\Domain\{$name|firstUpper}\Get{$name|firstUpper}Command'
- bus_handler_get:
- crafter: handler
- mode: get
- scopes: [bus]
- template: %presetDir%/templates/bus/handler_get.latte
- class: 'App\Domain\{$name|firstUpper}\Get{$name|firstUpper}Handler'
- dependencies:
- em: Doctrine\ORM\EntityManagerInterface
- # Bus (list)
- bus_command_list:
- crafter: command
- mode: update
- scopes: [bus]
- template: %presetDir%/templates/bus/command_list.latte
- class: 'App\Domain\{$name|firstUpper}\List{$name|firstUpper}Command'
- bus_handler_list:
- crafter: handler
- mode: create
- scopes: [bus]
- template: %presetDir%/templates/bus/handler_list.latte
- class: 'App\Domain\{$name|firstUpper}\List{$name|firstUpper}Handler'
- dependencies:
- em: Doctrine\ORM\EntityManagerInterface
- # Bus (delete)
- bus_command_delete:
- crafter: command
- mode: delete
- scopes: [bus]
- template: %presetDir%/templates/bus/command_delete.latte
- class: 'App\Domain\{$name|firstUpper}\Delete{$name|firstUpper}Command'
- bus_handler_delete:
- crafter: handler
- mode: delete
- scopes: [bus]
- template: %presetDir%/templates/bus/handler_delete.latte
- class: 'App\Domain\{$name|firstUpper}\Delete{$name|firstUpper}Handler'
- dependencies:
- em: Doctrine\ORM\EntityManagerInterface
-
- # API ====================================
- # API (create)
- api_controller_create:
- crafter: controller
- mode: create
- scopes: [api]
- template: %presetDir%/templates/api/controller_create.latte
- class: 'App\Api\{$name|firstUpper}\Create\Create{$name|firstUpper}Controller'
-
- api_request_create:
- crafter: request
- mode: create
- scopes: [api]
- template: %presetDir%/templates/api/request_create.latte
- class: 'App\Api\{$name|firstUpper}\Create\Create{$name|firstUpper}Request'
-
- api_request_body_create:
- crafter: request_body
- mode: create
- scopes: [api]
- template: %presetDir%/templates/api/request_body_create.latte
- class: 'App\Api\{$name|firstUpper}\Create\Create{$name|firstUpper}RequestBody'
-
- api_response_create:
- crafter: response
- mode: create
- scopes: [api]
- template: %presetDir%/templates/api/response_create.latte
- class: 'App\Api\{$name|firstUpper}\Create\Create{$name|firstUpper}Response'
-
- # API (update)
- api_controller_update:
- crafter: controller
- mode: update
- scopes: [api]
- template: %presetDir%/templates/api/controller_update.latte
- class: 'App\Api\{$name|firstUpper}\Update\Update{$name|firstUpper}Controller'
-
- api_request_update:
- crafter: request
- mode: update
- scopes: [api]
- template: %presetDir%/templates/api/request_update.latte
- class: 'App\Api\{$name|firstUpper}\Update\Update{$name|firstUpper}Request'
-
- api_request_body_update:
- crafter: request_body
- mode: update
- scopes: [api]
- template: %presetDir%/templates/api/request_body_update.latte
- class: 'App\Api\{$name|firstUpper}\Update\Update{$name|firstUpper}RequestBody'
-
- api_response_update:
- crafter: response
- mode: update
- scopes: [api]
- template: %presetDir%/templates/api/response_update.latte
- class: 'App\Api\{$name|firstUpper}\Update\Update{$name|firstUpper}Response'
-
- # API (get)
- api_controller_get:
- crafter: controller
- mode: get
- scopes: [api]
- template: %presetDir%/templates/api/controller_get.latte
- class: 'App\Api\{$name|firstUpper}\Get\Get{$name|firstUpper}Controller'
-
- api_request_get:
- crafter: request
- mode: get
- scopes: [api]
- template: %presetDir%/templates/api/request_get.latte
- class: 'App\Api\{$name|firstUpper}\Get\Get{$name|firstUpper}Request'
-
- api_response_get:
- crafter: response
- mode: get
- scopes: [api]
- template: %presetDir%/templates/api/response_get.latte
- class: 'App\Api\{$name|firstUpper}\Get\Get{$name|firstUpper}Response'
-
- # API (list)
- api_controller_list:
- crafter: controller
- mode: list
- scopes: [api]
- template: %presetDir%/templates/api/controller_list.latte
- class: 'App\Api\{$name|firstUpper}\List\List{$name|firstUpper}Controller'
-
- api_request_list:
- crafter: request
- mode: list
- scopes: [api]
- template: %presetDir%/templates/api/request_list.latte
- class: 'App\Api\{$name|firstUpper}\List\List{$name|firstUpper}Request'
-
- api_request_filter_list:
- crafter: request_filter
- mode: list
- scopes: [api]
- template: %presetDir%/templates/api/request_filter_list.latte
- class: 'App\Api\{$name|firstUpper}\List\List{$name|firstUpper}RequestFilter'
-
- api_response_list:
- crafter: response
- mode: list
- scopes: [api]
- template: %presetDir%/templates/api/response_list.latte
- class: 'App\Api\{$name|firstUpper}\List\List{$name|firstUpper}Response'
-
- # API (delete)
- api_controller_delete:
- crafter: controller
- mode: delete
- scopes: [api]
- template: %presetDir%/templates/api/controller_delete.latte
- class: 'App\Api\{$name|firstUpper}\Delete\Delete{$name|firstUpper}Controller'
-
- api_request_delete:
- crafter: request
- mode: delete
- scopes: [api]
- template: %presetDir%/templates/api/request_delete.latte
- class: 'App\Api\{$name|firstUpper}\Delete\Delete{$name|firstUpper}Response'
-
- api_response_delete:
- crafter: response
- mode: delete
- scopes: [api]
- template: %presetDir%/templates/api/response_delete.latte
- class: 'App\Api\{$name|firstUpper}\Delete\Delete{$name|firstUpper}Response'
diff --git a/resources/presets/nette/crafter.neon b/resources/presets/nette/crafter.neon
new file mode 100644
index 0000000..3e0ae5f
--- /dev/null
+++ b/resources/presets/nette/crafter.neon
@@ -0,0 +1,11 @@
+# Schema version
+version: 1
+
+# List of crafters
+crafters:
+ presenter:
+ input: '%cwd%/templates/presenter/presenter.latte'
+ output: '/{$namespace}\UI\{$name|firstUpper}\{$name|firstUpper}Presenter.php'
+ presenter_template:
+ input: '%cwd%/templates/presenter/template.latte'
+ output: '/UI/{$name|firstUpper}/Templates/default.latte'
diff --git a/resources/presets/nette/templates/presenter/presenter.latte b/resources/presets/nette/templates/presenter/presenter.latte
new file mode 100644
index 0000000..b9631c5
--- /dev/null
+++ b/resources/presets/nette/templates/presenter/presenter.latte
@@ -0,0 +1,10 @@
+class->namespace};
+
+use {$ctx->class->rootNamespace}\UI\BasePresenter;
+
+class {$ctx->class->className} extends BasePresenter
+{
+
+}
diff --git a/resources/presets/nette/templates/presenter/template.latte b/resources/presets/nette/templates/presenter/template.latte
new file mode 100644
index 0000000..4f46a35
--- /dev/null
+++ b/resources/presets/nette/templates/presenter/template.latte
@@ -0,0 +1,5 @@
+{block #content}
+
+
+ Hello!
+
diff --git a/resources/presets/preset.dsl.neon b/resources/presets/preset.dsl.neon
new file mode 100644
index 0000000..ebe8f8e
--- /dev/null
+++ b/resources/presets/preset.dsl.neon
@@ -0,0 +1,21 @@
+# Schema version
+version: 1
+
+# List of crafters
+crafters:
+ # Full syntax
+ acme:
+ id: acme@acme
+ crafter:
+ type: latte
+ template: %cwd%/templates/acme.latte
+ file: "{$namespace}\Acme\{$name|firstUpper}\Foo\{$name|firstUpper}.php"
+ vars:
+ some: variable
+
+ # Compact syntax
+ acme2:
+ id: acme2@acme
+ crafter:
+ template: %cwd%/templates/acme.latte
+ file: "App\Acme\{$name|firstUpper}\Foo\{$name|firstUpper}.php"
diff --git a/resources/projects/_defaults/LICENSE.latte b/resources/projects/_defaults/LICENSE.latte
deleted file mode 100644
index 4337da9..0000000
--- a/resources/projects/_defaults/LICENSE.latte
+++ /dev/null
@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) {{=date('Y')} Contributte
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/resources/projects/_defaults/Makefile.latte b/resources/projects/_defaults/Makefile.latte
deleted file mode 100644
index fbf63e6..0000000
--- a/resources/projects/_defaults/Makefile.latte
+++ /dev/null
@@ -1,56 +0,0 @@
-############################################################
-# PROJECT ##################################################
-############################################################
-.PHONY: project install setup clean
-
-project: install setup
-
-install:
-composer install
-
-setup:
-mkdir -p var/tmp var/log
-chmod +0777 var/tmp var/log
-
-clean:
-find var/tmp -mindepth 1 ! -name '.gitignore' -type f,d -exec rm -rf {} +
-find var/log -mindepth 1 ! -name '.gitignore' -type f,d -exec rm -rf {} +
-
-############################################################
-# DEVELOPMENT ##############################################
-############################################################
-.PHONY: qa dev cs csf phpstan tests coverage dev build
-
-qa: cs phpstan
-
-cs:
-vendor/bin/codesniffer app
-
-csf:
-vendor/bin/codefixer app
-
-phpstan:
-vendor/bin/phpstan analyse -c phpstan.neon --memory-limit=512M
-
-tests:
-echo "NO TESTS"
-
-coverage:
-echo "NO TESTS"
-
-dev:
-NETTE_DEBUG=1 NETTE_ENV=dev php -S 0.0.0.0:8000 -t www
-
-build:
-echo "OK"
-
-############################################################
-# DEPLOYMENT ###############################################
-############################################################
-.PHONY: deploy
-
-deploy:
-$(MAKE) clean
-$(MAKE) project
-$(MAKE) build
-$(MAKE) clean
diff --git a/resources/projects/_defaults/README.latte b/resources/projects/_defaults/README.latte
deleted file mode 100644
index acef429..0000000
--- a/resources/projects/_defaults/README.latte
+++ /dev/null
@@ -1 +0,0 @@
-# Generated
diff --git a/resources/projects/_defaults/github/codesniffer.latte b/resources/projects/_defaults/github/codesniffer.latte
deleted file mode 100644
index dfc76ff..0000000
--- a/resources/projects/_defaults/github/codesniffer.latte
+++ /dev/null
@@ -1,15 +0,0 @@
-name: "Codesniffer"
-
-on:
- pull_request:
-
- push:
- branches: ["*"]
-
- schedule:
- - cron: "0 8 * * 1"
-
-jobs:
- codesniffer:
- name: "Codesniffer"
- uses: contributte/.github/.github/workflows/codesniffer.yml@v1
diff --git a/resources/projects/_defaults/github/dependabot.latte b/resources/projects/_defaults/github/dependabot.latte
deleted file mode 100644
index 0f0dadb..0000000
--- a/resources/projects/_defaults/github/dependabot.latte
+++ /dev/null
@@ -1,9 +0,0 @@
-version: 2
-updates:
- - package-ecosystem: composer
- directory: "/"
- schedule:
- interval: daily
- labels:
- - "dependencies"
- - "automerge"
diff --git a/resources/projects/_defaults/github/kodiak.latte b/resources/projects/_defaults/github/kodiak.latte
deleted file mode 100644
index 60c34b6..0000000
--- a/resources/projects/_defaults/github/kodiak.latte
+++ /dev/null
@@ -1,10 +0,0 @@
-version = 1
-
-[merge]
-automerge_label = "automerge"
-blacklist_title_regex = "^WIP.*"
-blacklist_labels = ["WIP"]
-method = "rebase"
-delete_branch_on_merge = true
-notify_on_conflict = true
-optimistic_updates = false
diff --git a/resources/projects/_defaults/github/phpstan.latte b/resources/projects/_defaults/github/phpstan.latte
deleted file mode 100644
index db3ad34..0000000
--- a/resources/projects/_defaults/github/phpstan.latte
+++ /dev/null
@@ -1,15 +0,0 @@
-name: "Phpstan"
-
-on:
- pull_request:
-
- push:
- branches: ["*"]
-
- schedule:
- - cron: "0 8 * * 1"
-
-jobs:
- phpstan:
- name: "Phpstan"
- uses: contributte/.github/.github/workflows/phpstan.yml@v1
diff --git a/resources/projects/_defaults/github/tests.latte b/resources/projects/_defaults/github/tests.latte
deleted file mode 100644
index 5fa700c..0000000
--- a/resources/projects/_defaults/github/tests.latte
+++ /dev/null
@@ -1,23 +0,0 @@
-name: "Nette Tester"
-
-on:
- pull_request:
-
- push:
- branches: ["*"]
-
- schedule:
- - cron: "0 8 * * 1"
-
-jobs:
- test81:
- name: "Nette Tester"
- uses: contributte/.github/.github/workflows/nette-tester.yml@v1
- with:
- php: "8.1"
-
- test80:
- name: "Nette Tester"
- uses: contributte/.github/.github/workflows/nette-tester.yml@v1
- with:
- php: "8.0"
diff --git a/resources/projects/_defaults/phpstan.latte b/resources/projects/_defaults/phpstan.latte
deleted file mode 100644
index b5a5289..0000000
--- a/resources/projects/_defaults/phpstan.latte
+++ /dev/null
@@ -1,20 +0,0 @@
-includes:
- - vendor/phpstan/phpstan-nette/extension.neon
- - vendor/phpstan/phpstan-nette/rules.neon
- - vendor/phpstan/phpstan-doctrine/extension.neon
- - vendor/phpstan/phpstan-phpunit/rules.neon
-
-parameters:
- level: 9
- phpVersion: 80000
-
- scanDirectories:
- - app
-
- fileExtensions:
- - php
-
- paths:
- - app
-
- ignoreErrors:
diff --git a/resources/projects/_defaults/www/htaccess.latte b/resources/projects/_defaults/www/htaccess.latte
deleted file mode 100644
index da941ae..0000000
--- a/resources/projects/_defaults/www/htaccess.latte
+++ /dev/null
@@ -1,31 +0,0 @@
-# Apache configuration file (see httpd.apache.org/docs/current/mod/quickreference.html)
-
-# disable directory listing
-
- Options -Indexes
-
-
-# enable cool URL
-
- RewriteEngine On
- # RewriteBase /
-
- # use HTTPS
- # RewriteCond %{HTTPS} !on
- # RewriteRule .? https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
-
- # prevents files starting with dot to be viewed by browser
- RewriteRule /\.|^\.(?!well-known/) - [F]
-
- # front controller
- RewriteCond %{REQUEST_FILENAME} !-f
- RewriteCond %{REQUEST_FILENAME} !-d
- RewriteRule !\.(pdf|js|ico|gif|jpg|png|css|rar|zip|tar\.gz|map)$ index.php [L]
-
-
-# enable gzip compression
-
-
- AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css application/javascript application/json application/xml image/svg+xml
-
-
diff --git a/resources/projects/demo/app/UI/Home/HomePresenter.php b/resources/projects/demo/app/UI/Home/HomePresenter.php
deleted file mode 100644
index fe6be79..0000000
--- a/resources/projects/demo/app/UI/Home/HomePresenter.php
+++ /dev/null
@@ -1,17 +0,0 @@
-
+ Hello!
+
diff --git a/resources/projects/nella/composer.json.latte b/resources/projects/nella/composer.json.latte
new file mode 100644
index 0000000..12d8164
--- /dev/null
+++ b/resources/projects/nella/composer.json.latte
@@ -0,0 +1,32 @@
+{
+ "name": "crafter/nella",
+ "type": "project",
+ "require": {
+ "php": ">=8.2",
+ "contributte/nella": "^0.3"
+ },
+ "require-dev": {
+ "contributte/qa": "^0.3",
+ "contributte/dev": "^0.4",
+ "contributte/phpstan": "^0.1",
+ "contributte/tester": "^0.2"
+ },
+ "autoload": {
+ "psr-4": {
+ "App\\": "app"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Tests\\": "tests"
+ }
+ },
+ "prefer-stable": true,
+ "minimum-stability": "dev",
+ "config": {
+ "sort-packages": true,
+ "allow-plugins": {
+ "dealerdirect/phpcodesniffer-composer-installer": true
+ }
+ }
+}
diff --git a/resources/projects/demo/config/config.latte b/resources/projects/nella/config/config.neon.latte
similarity index 72%
rename from resources/projects/demo/config/config.latte
rename to resources/projects/nella/config/config.neon.latte
index d91c302..596e25b 100644
--- a/resources/projects/demo/config/config.latte
+++ b/resources/projects/nella/config/config.neon.latte
@@ -4,16 +4,13 @@ php:
date.timezone: Europe/Prague
# session.save_path: %tempDir%/session
+# ======================================
+# Parameters ===========================
+parameters:
+
# ======================================
# Extension ============================
extensions:
- sentry: Contributte\Sentry\DI\SentryExtension
-
-sentry:
- enable: %productionMode%
-
- client:
- dsn: "https://FILLME@FILLME.ingest.sentry.io/1FILLME"
# ======================================
# Services =============================
diff --git a/resources/projects/nella/config/local.neon.example.latte b/resources/projects/nella/config/local.neon.example.latte
new file mode 100644
index 0000000..12b6ebf
--- /dev/null
+++ b/resources/projects/nella/config/local.neon.example.latte
@@ -0,0 +1,3 @@
+parameters:
+
+services:
diff --git a/resources/projects/nella/crafter.neon b/resources/projects/nella/crafter.neon
new file mode 100644
index 0000000..186ff21
--- /dev/null
+++ b/resources/projects/nella/crafter.neon
@@ -0,0 +1,27 @@
+# Schema version
+version: 1
+
+# List of crafters
+crafters:
+ # Root
+ editorconfig: { input: 'raw://%cwd%/.editorconfig.latte', output: 'raw:///.editorconfig' }
+ gitignore: { input: %cwd%/.gitignore.latte, output: 'raw:///.gitignore' }
+ composer: { input: %cwd%/composer.json.latte, output: 'raw:///composer.json' }
+ makefile: { input: %cwd%/Makefile.latte, output: 'raw:///Makefile' }
+ phpstan: { input: %cwd%/phpstan.neon.latte, output: 'raw:///phpstan.neon' }
+ readme: { input: %cwd%/README.md.latte, output: 'raw:///README.md' }
+ ruleset: { input: %cwd%/ruleset.xml.latte, output: 'raw:///ruleset.xml' }
+ # App
+ app_bootstrap: { input: %cwd%/app/Bootstrap.php.latte, output: 'raw:///app/Bootstrap.php' }
+ app_ui_basepresenter: { input: %cwd%/app/UI/BasePresenter.php.latte, output: 'raw:///app/UI/BasePresenter.php' }
+ app_ui_home_homepresenter: { input: %cwd%/app/UI/Home/HomePresenter.php.latte, output: 'raw:///app/UI/Home/HomePresenter.php' }
+ app_ui_home_template_default: { input: %cwd%/app/UI/Home/Templates/default.latte.latte, output: 'raw:///app/UI/Home/Templates/default.latte' }
+ app_ui_layout: { input: %cwd%/app/UI/@Templates/@layout.latte.latte, output: 'raw:///app/UI/@Templates/@layout.latte' }
+ # Config
+ config_config: { input: %cwd%/config/config.neon.latte, output: 'raw:///config/config.neon' }
+ config_local: { input: %cwd%/config/local.neon.example.latte, output: 'raw:///config/local.neon.example' }
+ # Var
+ var_log_gitignore: { input: %cwd%/var/log/.gitignore.latte, output: 'raw:///var/log/.gitignore' }
+ var_tmp_gitignore: { input: %cwd%/var/tmp/.gitignore.latte, output: 'raw:///var/tmp/.gitignore' }
+ # Www
+ www_index: { input: %cwd%/www/index.php.latte, output: 'raw:///www/index.php' }
diff --git a/resources/projects/nella/phpstan.neon.latte b/resources/projects/nella/phpstan.neon.latte
new file mode 100644
index 0000000..9b86943
--- /dev/null
+++ b/resources/projects/nella/phpstan.neon.latte
@@ -0,0 +1,16 @@
+includes:
+ - vendor/contributte/phpstan/phpstan.neon
+
+parameters:
+ level: 9
+ phpVersion: 80200
+
+ tmpDir: %currentWorkingDirectory%/var/tmp/phpstan
+
+ fileExtensions:
+ - php
+ - phpt
+
+ paths:
+ - app
+ - config
diff --git a/resources/projects/_defaults/ruleset.latte b/resources/projects/nella/ruleset.xml.latte
similarity index 90%
rename from resources/projects/_defaults/ruleset.latte
rename to resources/projects/nella/ruleset.xml.latte
index b076ae3..66ded9d 100644
--- a/resources/projects/_defaults/ruleset.latte
+++ b/resources/projects/nella/ruleset.xml.latte
@@ -9,6 +9,7 @@
+
diff --git a/resources/projects/_defaults/var/gitignore.latte b/resources/projects/nella/var/log/.gitignore.latte
similarity index 100%
rename from resources/projects/_defaults/var/gitignore.latte
rename to resources/projects/nella/var/log/.gitignore.latte
diff --git a/resources/projects/nella/var/tmp/.gitignore.latte b/resources/projects/nella/var/tmp/.gitignore.latte
new file mode 100644
index 0000000..d6b7ef3
--- /dev/null
+++ b/resources/projects/nella/var/tmp/.gitignore.latte
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/resources/projects/demo/www/index.php b/resources/projects/nella/www/index.php.latte
similarity index 67%
rename from resources/projects/demo/www/index.php
rename to resources/projects/nella/www/index.php.latte
index 401948b..0996575 100644
--- a/resources/projects/demo/www/index.php
+++ b/resources/projects/nella/www/index.php.latte
@@ -2,4 +2,4 @@
require __DIR__ . '/../vendor/autoload.php';
-\templates\demo\app\Bootstrap::run();
+App\Bootstrap::run();
diff --git a/resources/projects/project.dsl.neon b/resources/projects/project.dsl.neon
new file mode 100644
index 0000000..d9908a4
--- /dev/null
+++ b/resources/projects/project.dsl.neon
@@ -0,0 +1,14 @@
+# Schema version
+version: 1
+
+# List of crafters
+crafters:
+ # Full
+ file:
+ input: %cwd%/templates/database/entity.latte
+ output: 'App\Domain\{$name|firstUpper}\Database\{$name|firstUpper}'
+ vars:
+ some: variable
+
+ # Compact
+ www_index: { input: %cwd%/www/index.php.latte, output: 'raw://www/index.php' }
diff --git a/ruleset.xml b/ruleset.xml
index ff48637..d613fd6 100644
--- a/ruleset.xml
+++ b/ruleset.xml
@@ -1,13 +1,15 @@
-
+
+
+
-
+
diff --git a/src/Bootstrap.php b/src/Bootstrap.php
index ab1dad0..07dc07d 100644
--- a/src/Bootstrap.php
+++ b/src/Bootstrap.php
@@ -1,12 +1,16 @@
service(ConfigLoader::class, fn (): ConfigLoader => new ConfigLoader());
+
+ // Template
$container->service(TemplateRenderer::class, fn (): TemplateRenderer => new TemplateRenderer());
- $container->service(CrafterWorker::class, fn (TemplateRenderer $templateRenderer): CrafterWorker => new CrafterWorker($templateRenderer));
- $application = new Application('Mate', '0.1.0');
+ // Generator worker
+ $container->service(GeneratorWorker::class, fn (RawResolver $rawResolver): GeneratorWorker => new GeneratorWorker($rawResolver));
+ $container->service(RawResolver::class, fn (TemplateRenderer $templateRenderer): RawResolver => new RawResolver($templateRenderer));
+
+ // Crafter worker
+ $container->service(CrafterWorker::class, fn (PhpResolver $phpResolver, LatteResolver $latteResolver): CrafterWorker => new CrafterWorker($phpResolver, $latteResolver));
+ $container->service(PhpResolver::class, fn (TemplateRenderer $templateRenderer): PhpResolver => new PhpResolver($templateRenderer));
+ $container->service(LatteResolver::class, fn (TemplateRenderer $templateRenderer): LatteResolver => new LatteResolver($templateRenderer));
+
+ // Symfony Console
+ $application = new Application('Crafter', 'magic');
$application->add($container->createInstance(CraftCommand::class));
+ $application->add($container->createInstance(GenerateCommand::class));
return $application;
}
diff --git a/src/Command/BaseCommand.php b/src/Command/BaseCommand.php
index 7391312..4579ba1 100644
--- a/src/Command/BaseCommand.php
+++ b/src/Command/BaseCommand.php
@@ -1,6 +1,6 @@
addOption('struct', 's', InputOption::VALUE_REQUIRED, 'Structure definition');
+ $this->addOption('data', 'k', InputOption::VALUE_REQUIRED, 'Data key definition');
$this->addOption('scope', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Scope definition');
}
@@ -43,11 +42,19 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$ui = (new SymfonyStyle($input, $output))->getErrorStyle();
try {
- /** @var object{ struct: string, scope: string[] } $options */
- $options = (new Processor())->process(Expect::structure([
- 'struct' => Expect::mixed()->assert(fn ($v) => $v !== null && $v !== '', 'Option --struct|-s must be filled'),
- 'scope' => Expect::arrayOf('string')->default([]),
- ])->otherItems(), $input->getOptions());
+ /** @var object{ data: string, scope: string[] } $options */
+ $options = (new Processor())->process(
+ Expect::structure([
+ 'data' => Expect::mixed()->assert(fn ($v) => $v !== null && $v !== '', 'Option --data|-k must be filled'),
+ 'scope' => Expect::arrayOf('string'),
+ ])->otherItems()
+ ->before(function (array $v) {
+ $v['scope'] = $v['scope'] === [] ? ['default'] : $v['scope'];
+
+ return $v;
+ }),
+ $input->getOptions()
+ );
} catch (ValidationException $e) {
foreach ($e->getMessageObjects() as $message) {
$ui->error($message->variables['assertion']);
@@ -57,31 +64,33 @@ protected function execute(InputInterface $input, OutputInterface $output): int
}
// Input
- $struct = $options->struct;
+ $key = $options->data;
$cwd = Safe::getcwd();
- $configFile = $cwd . '/.mate.neon';
+ $scopes = $options->scope ?? ['default'];
+ $configFile = $cwd . '/crafter.neon';
// Config
- $config = $this->configLoader->load($cwd, $cwd . '/.mate.neon');
+ $config = (new ConfigLoader())
+ ->withCwd($cwd)
+ ->withFile($configFile)
+ ->load();
// HUD
$ui->title('Input');
$ui->table([], [
['CWD', $cwd],
['Config', $configFile],
- ['Struct', $struct],
- ['Presets', implode(',', $config->mate->presets)],
- ['Scopes', implode(',', $options->scope)],
+ ['Structure', $key],
+ ['Presets', $config->app->preset],
+ ['Scopes', implode(',', $scopes)],
]);
// Context
- $workerContextFactory = new WorkerContextFactory();
- $workerContextFactory->withScopes($options->scope);
- $workerContext = $workerContextFactory->from($config);
+ $workerContext = CrafterContext::from($config, $scopes);
// Worker validation
- if (!$config->structs->has($struct)) {
- $ui->error(sprintf('Unknown struct reference "%s" in .mate.neon', $struct));
+ if (!$config->data->has($key)) {
+ $ui->error(sprintf('Unknown data reference "%s" in crafter.neon', $key));
return Command::FAILURE;
}
diff --git a/src/Command/GenerateCommand.php b/src/Command/GenerateCommand.php
new file mode 100644
index 0000000..6bccb32
--- /dev/null
+++ b/src/Command/GenerateCommand.php
@@ -0,0 +1,107 @@
+addOption('template', 't', InputOption::VALUE_REQUIRED, 'Project template');
+ $this->addOption('directory', 'd', InputOption::VALUE_REQUIRED, 'Output directory');
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output): int
+ {
+ $ui = (new SymfonyStyle($input, $output))->getErrorStyle();
+
+ try {
+ /** @var object{ template: string, directory: string } $options */
+ $options = (new Processor())->process(
+ Expect::structure([
+ 'template' => Expect::mixed()->assert(fn ($v) => $v !== null && $v !== '', 'Option --template|-t must be filled'),
+ 'directory' => Expect::mixed()->default('.')->assert(fn ($v) => $v !== null && $v !== '', 'Option --directory|-d must be filled'),
+ ])->otherItems(),
+ $input->getOptions()
+ );
+ } catch (ValidationException $e) {
+ foreach ($e->getMessageObjects() as $message) {
+ $ui->error($message->variables['assertion']);
+ }
+
+ return Command::FAILURE;
+ }
+
+ // Input
+ $template = $options->template;
+ $cwd = Safe::getcwd();
+
+ // Config
+ $config = (new ConfigLoader())
+ ->withCwd($cwd)
+ ->withConfig([
+ 'template' => $template,
+ ])
+ ->load();
+
+ // HUD
+ $ui->title('Input');
+ $ui->table([], [
+ ['CWD', $cwd],
+ ['Template', $template],
+ ]);
+
+ // Context
+ $generatorContext = GeneratorContext::from($config, dir: $options->directory);
+
+ // Worker
+ $result = $this->generatorWorker->execute($generatorContext, $this->createLogger($output));
+
+ // HUD
+ $ui->title('Crafted');
+
+ foreach ($result->items as $item) {
+ if ($item['state'] === 'skipped') {
+ continue;
+ }
+
+ $ui->block($item['crafter']);
+ $ui->table([], [
+ ['Input', $item['input']],
+ ['Output', $item['output']],
+ ['Note', $item['note']],
+ ]);
+ }
+
+ $ui->info(sprintf('Crafted: %d files', count(Arrays::filter($result->items, fn ($item) => $item['state'] === 'crafted'))));
+
+ return Command::SUCCESS;
+ }
+
+}
diff --git a/src/Command/InitCommand.php b/src/Command/InitCommand.php
index c238d05..cd142aa 100644
--- a/src/Command/InitCommand.php
+++ b/src/Command/InitCommand.php
@@ -1,6 +1,6 @@
$vars
* @param array $scopes
+ * @param array $crafters
*/
public function __construct(
- public string $appDir,
+ public string $version,
+ public string $dir,
public string $namespace,
- public array $scopes,
- public CraftersConfig $crafters,
+ public array $vars,
+ public string|null $preset,
+ public string|null $template,
+ public array $crafters,
+ public array $scopes = [],
)
{
}
diff --git a/src/Config/CrafterConfig.php b/src/Config/CrafterConfig.php
index f887108..0ee7a6b 100644
--- a/src/Config/CrafterConfig.php
+++ b/src/Config/CrafterConfig.php
@@ -1,20 +1,22 @@
$scopes
+ * @param array $vars
*/
public function __construct(
- public string $crafter,
- public string $template,
- public string $class,
- public string|null $mode = null,
- public array $scopes = [],
- public string|null $baseClass = null,
+ public string $id,
+ public string $name,
+ public string|null $mode,
+ public array $scopes,
+ public CrafterFileConfig $input,
+ public CrafterFileConfig $output,
+ public array $vars,
)
{
}
diff --git a/src/Config/CrafterFileConfig.php b/src/Config/CrafterFileConfig.php
new file mode 100644
index 0000000..a8f123b
--- /dev/null
+++ b/src/Config/CrafterFileConfig.php
@@ -0,0 +1,19 @@
+ $vars
+ */
+ public function __construct(
+ public string $resolver,
+ public string $path,
+ public array $vars,
+ )
+ {
+ }
+
+}
diff --git a/src/Config/CraftersConfig.php b/src/Config/CraftersConfig.php
deleted file mode 100644
index 6b5e20b..0000000
--- a/src/Config/CraftersConfig.php
+++ /dev/null
@@ -1,17 +0,0 @@
- $items
- */
- public function __construct(
- public array $items,
- )
- {
- }
-
-}
diff --git a/src/Config/InputConfig.php b/src/Config/CraftingConfig.php
similarity index 53%
rename from src/Config/InputConfig.php
rename to src/Config/CraftingConfig.php
index 63b5343..bcda469 100644
--- a/src/Config/InputConfig.php
+++ b/src/Config/CraftingConfig.php
@@ -1,15 +1,14 @@
$items
+ * @param array $items
*/
public function __construct(
public array $items,
diff --git a/src/Config/DataObjectConfig.php b/src/Config/DataObjectConfig.php
new file mode 100644
index 0000000..ffdebb2
--- /dev/null
+++ b/src/Config/DataObjectConfig.php
@@ -0,0 +1,20 @@
+ $vars
+ */
+ public function __construct(
+ public string $name,
+ public array $fields,
+ public array $vars,
+ )
+ {
+ }
+
+}
diff --git a/src/Config/StructFieldConfig.php b/src/Config/DataObjectField.php
similarity index 70%
rename from src/Config/StructFieldConfig.php
rename to src/Config/DataObjectField.php
index f8dbf94..955a320 100644
--- a/src/Config/StructFieldConfig.php
+++ b/src/Config/DataObjectField.php
@@ -1,8 +1,8 @@
*/
+ private array $configs = [];
+
+ /** @var array */
+ private array $files = [];
+
+ public function __construct()
+ {
+ // No-op
+ }
+
+ public function withCwd(string $cwd): self
+ {
+ $this->cwd = $cwd;
+
+ return $this;
+ }
+
+ /**
+ * @param array $config
+ */
+ public function withConfig(array $config): self
+ {
+ $this->configs[] = $config;
+
+ return $this;
+ }
+
+ public function withFile(string $file): self
+ {
+ $this->files[] = $file;
+
+ return $this;
+ }
+
+ public function load(): CraftingConfig
+ {
+ if ($this->cwd === null) {
+ throw new LogicalException('Missing cwd');
+ }
+
+ // Defaults
+ $defaults = [
+ 'version' => '1',
+ 'dir' => 'src',
+ 'namespace' => 'App',
+ 'preset' => 'default',
+ 'vars' => [],
+ 'crafters' => [],
+ 'data' => [],
+ ];
+
+ // Merge current with defaults
+ $current = $this->mergeConfig([], $defaults); // @phpstan-ignore-line
+
+ // (1) Take file configs
+ foreach ($this->files as $file) {
+ // Get file config
+ $fileConfig = $this->getFileConfig($file);
+
+ // Merge current with file config
+ $current = $this->mergeConfig($fileConfig, $current);
+ }
+
+ // (2) Take array configs
+ foreach ($this->configs as $config) {
+ // Merge current with user config
+ $current = $this->mergeConfig($config, $current); // @phpstan-ignore-line
+ }
+
+ // Process config (presets, templates)
+ $processed = $this->processConfig($current);
+
+ // Create crafting config
+ return $this->createConfig($this->cwd, $processed);
+ }
+
+ /**
+ * @phpstan-param ConfigShape $left
+ * @phpstan-param ConfigShape $right
+ * @phpstan-return ConfigShape
+ */
+ public function mergeConfig(array $left, array $right): array
{
- /** @phpstan-var ConfigShape $config */
- $config = $this->loadFile($file);
+ /** @var ConfigShape $return */
+ $return = Helpers::merge($left, $right);
- // Merge presets
- $presets = $config['mate']['presets'] ?? ['default'];
+ return $return;
+ }
- foreach ($presets as $preset) {
- $presetDir = IO::realpath(__DIR__ . '/../../../resources/presets/' . $preset);
- $presetFile = $this->loadFile($presetDir . '/config.neon');
+ /**
+ * @phpstan-param ConfigShape $config
+ * @phpstan-return ConfigShape
+ */
+ public function processConfig(array $config): array
+ {
+ // Process preset
+ $preset = $config['preset'] ?? null;
+
+ if ($preset !== null) {
+ $presetDir = __DIR__ . '/../../../resources/presets/' . $preset;
+
+ // Skip non-existing presets
+ if (!is_dir($presetDir)) {
+ throw new RuntimeException(sprintf('Preset template "%s" not found on path "%s"', $preset, $presetDir));
+ }
+
+ $presetFile = $this->getPresetConfig($presetDir . '/crafter.neon');
// Expand variables
- $presetConfig = DIHelpers::expand($presetFile, ['presetDir' => $presetDir], true);
+ /** @var array{crafter: CraftersShape} $presetConfig */
+ $presetConfig = DIHelpers::expand($presetFile, ['cwd' => $presetDir], true);
- /** @phpstan-var ConfigShape $config */
- $config = SchemaHelpers::merge($presetConfig, $config);
+ // Merge user defined crafters and template crafters
+ $config['crafters'] = Arrays::mergeTree($config['crafters'] ?? [], $presetConfig['crafters'] ?? []); // @phpstan-ignore-line
}
- return new InputConfig(
- mate: new MateConfig(
- presets: $presets,
- ),
+ // Process template
+ $template = $config['template'] ?? null;
+
+ if ($template !== null) {
+ $projectDir = __DIR__ . '/../../../resources/projects/' . $template;
+
+ // Skip non-existing presets
+ if (!is_dir($projectDir)) {
+ throw new RuntimeException(sprintf('Project template "%s" not found on path "%s"', $template, $projectDir));
+ }
+
+ $projectFile = $this->getProjectConfig($projectDir . '/crafter.neon');
+
+ // Expand variables
+ /** @var array{crafter: CraftersShape} $projectConfig */
+ $projectConfig = DIHelpers::expand($projectFile, ['cwd' => $projectDir], true);
+
+ // Merge user defined crafters and template crafters
+ $config['crafters'] = Arrays::mergeTree($config['crafters'] ?? [], $projectConfig['crafters'] ?? []); // @phpstan-ignore-line
+ }
+
+ return $config;
+ }
+
+ /**
+ * @phpstan-param ConfigShape $config
+ */
+ private function createConfig(string $cwd, array $config): CraftingConfig
+ {
+ return new CraftingConfig(
process: new ProcessConfig(
cwd: $cwd,
),
app: new AppConfig(
- appDir: $config['app']['appDir'],
- namespace: $config['app']['namespace'],
- scopes: $config['app']['scopes'] ?? [],
- crafters: new CraftersConfig(
- items: Arrays::map(
- $config['app']['crafters'] ?? [],
- fn (array $crafter): CrafterConfig => new CrafterConfig(
- crafter: $crafter['crafter'],
- template: $crafter['template'],
- class: $crafter['class'],
- mode: $crafter['mode'] ?? null,
- scopes: $crafter['scopes'] ?? [],
- baseClass: $crafter['baseClass'] ?? null
- )
- )
+ version: $config['version'],
+ dir: $config['dir'],
+ namespace: $config['namespace'],
+ vars: $config['vars'] ?? [],
+ preset: $config['preset'] ?? null,
+ template: $config['template'] ?? null,
+ crafters: Arrays::map(
+ $config['crafters'],
+ function (array $crafter, string $crafterId): CrafterConfig {
+ // Parse crafter id
+ // E.q.: presenter:create@db+admin -> [presenter:create, db+admin]
+ $matches = explode('@', $crafterId);
+
+ // Parse crafter mode
+ // E.q.: presenter:create -> [presenter, create]
+ $matches2 = explode(':', $matches[0]);
+
+ // Name
+ // E.q.: [presenter, create] -> presenter
+ $name = $matches2[0];
+
+ // Mode
+ // E.q.: presenter:create -> php
+ $mode = $matches2[1] ?? null;
+
+ // Scopes
+ // E.q.: db+admin -> [db, admin]
+ // E.q.: null -> [default]
+ $scopes = explode('+', $matches[1] ?? 'default');
+
+ // Input (@regex https://regex101.com/r/1zInYi/1)
+ // E.q.: presenter/presenter.latte [resolver: latte, path: presenter/presenter.latte]
+ // E.q.: raw://presenter/presenter.latte [resolver: raw, path: presenter/presenter.latte]
+ $inputMatch = Strings::match($crafter['input'], '#^(?:(?P\w+):\/\/)?(?P.+)$#') ?? throw new LogicalException(sprintf('Invalid input format "%s"', $crafter['input']));
+ $input = new CrafterFileConfig(
+ resolver: Validators::empty($inputMatch['schema']) ? Files::extension($crafter['input']) : $inputMatch['schema'],
+ path: $inputMatch['path'],
+ vars: []
+ );
+
+ // Output (@regex https://regex101.com/r/1zInYi/1)
+ // E.q.: presenter/presenter.latte [resolver: latte, path: presenter/presenter.latte]
+ // E.q.: raw://presenter/presenter.latte [resolver: raw, path: presenter/presenter.latte]
+ $outputMatch = Strings::match($crafter['output'], '#^(?:(?P\w+):\/\/)?(?P.+)$#') ?? throw new LogicalException(sprintf('Invalid output format "%s"', $crafter['output']));
+ $output = new CrafterFileConfig(
+ resolver: Validators::empty($outputMatch['schema']) ? Files::extension($crafter['output']) : $outputMatch['schema'],
+ path: $outputMatch['path'],
+ vars: []
+ );
+
+ return new CrafterConfig(
+ id: $crafterId,
+ name: $name,
+ mode: $mode,
+ scopes: $scopes,
+ input: $input,
+ output: $output,
+ vars: $crafter['vars'] ?? []
+ );
+ }
)
),
- structs: new StructsConfig(
+ data: new DataConfig(
items: Arrays::map(
- $config['structs'] ?? [],
- fn (array $struct, string $structKey): StructConfig => new StructConfig(
- name: $structKey,
+ $config['data'],
+ fn (array $data, string $dataKey): DataObjectConfig => new DataObjectConfig(
+ name: $dataKey,
fields: Arrays::map(
- $struct['fields'] ?? [],
- fn (array $field, string $fieldKey): StructFieldConfig => new StructFieldConfig(
+ $data['fields'],
+ fn (array $field, string $fieldKey): DataObjectField => new DataObjectField(
name: $fieldKey,
type: $field['type'],
nullable: $field['nullable'] ?? false
)
- )
+ ),
+ vars: $data['vars'] ?? []
)
)
)
@@ -87,14 +264,108 @@ class: $crafter['class'],
/**
* @phpstan-return ConfigShape
*/
- private function loadFile(string $file): array
+ private function getFileConfig(string $file): array
+ {
+ // Read file
+ $file = FileSystem::read($file);
+
+ /** @var mixed $config */
+ $config = Neon::decode($file);
+
+ // Validate
+ $schema = Expect::structure([
+ 'version' => Expect::anyOf('1')->before(fn (mixed $v) => is_scalar($v) ? strval($v) : $v)->default('1'),
+ 'dir' => Expect::string()->required(),
+ 'namespace' => Expect::string()->default('App'),
+ 'vars' => Expect::arrayOf('string')->default([]),
+ 'preset' => Expect::string(),
+ 'template' => Expect::string(),
+ 'crafters' => Expect::arrayOf(
+ Expect::structure([
+ 'input' => Expect::string()->required(),
+ 'output' => Expect::string()->required(),
+ 'vars' => Expect::arrayOf('string')->default([]),
+ ])->castTo('array'),
+ Expect::string()
+ ),
+ 'data' => Expect::arrayOf(
+ Expect::structure([
+ 'fields' => Expect::arrayOf(
+ Expect::structure([
+ 'type' => Expect::string()->required(),
+ 'nullable' => Expect::bool()->default(false),
+ ])->castTo('array'),
+ Expect::string()
+ ),
+ 'vars' => Expect::arrayOf('string')->default([]),
+ ])->castTo('array'),
+ Expect::string()
+ ),
+ ])->castTo('array');
+
+ /** @var ConfigShape $config */
+ $config = (new Processor())->process($schema, $config);
+
+ return $config;
+ }
+
+ /**
+ * @return array
+ */
+ private function getPresetConfig(string $file): array
{
// Read file
$file = FileSystem::read($file);
- /** @phpstan-var ConfigShape $config */
+ /** @var mixed $config */
$config = Neon::decode($file);
+ // Validate
+ $schema = Expect::structure([
+ 'version' => Expect::anyOf('1')->before(fn (mixed $v) => is_scalar($v) ? strval($v) : $v)->default('1'),
+ 'crafters' => Expect::arrayOf(
+ Expect::structure([
+ 'input' => Expect::string()->required(),
+ 'output' => Expect::string()->required(),
+ 'vars' => Expect::arrayOf('string')->default([]),
+ ])->castTo('array'),
+ Expect::string()
+ ),
+ ])->castTo('array');
+
+ /** @var array $config */
+ $config = (new Processor())->process($schema, $config);
+
+ return $config;
+ }
+
+ /**
+ * @return array
+ */
+ private function getProjectConfig(string $file): array
+ {
+ // Read file
+ $file = FileSystem::read($file);
+
+ /** @var mixed $config */
+ $config = Neon::decode($file);
+
+ // Validate
+ $schema = Expect::structure([
+ 'version' => Expect::anyOf('1')->before(fn (mixed $v) => is_scalar($v) ? strval($v) : $v)->default('1'),
+ 'crafters' => Expect::arrayOf(
+ Expect::structure([
+ 'input' => Expect::string()->required(),
+ 'output' => Expect::string()->required(),
+ 'vars' => Expect::arrayOf('string')->default([]),
+ ])->castTo('array'),
+ Expect::string()
+ ),
+ ])->castTo('array');
+
+ /** @var array $config */
+ $config = (new Processor())->process($schema, $config);
+
return $config;
}
diff --git a/src/Config/MateConfig.php b/src/Config/MateConfig.php
deleted file mode 100644
index 9bf4df6..0000000
--- a/src/Config/MateConfig.php
+++ /dev/null
@@ -1,17 +0,0 @@
- $presets
- */
- public function __construct(
- public array $presets,
- )
- {
- }
-
-}
diff --git a/src/Config/ProcessConfig.php b/src/Config/ProcessConfig.php
index 5ff120b..017b879 100644
--- a/src/Config/ProcessConfig.php
+++ b/src/Config/ProcessConfig.php
@@ -1,6 +1,6 @@
mate->app->scopes === []) {
- throw new LogicalException('No scope defined');
- }
-
- $result = new CrafterResult();
-
- foreach ($workerContext->mate->app->crafters->items as $crafterKey => $crafter) {
- // Skip crafter if not in scope
- if (array_intersect($crafter->scopes, $workerContext->mate->app->scopes) === []) {
- $result->add(
- crafter: $crafterKey,
- state: 'skipped',
- note: 'Scope mismatch',
- );
-
- continue;
- }
-
- foreach ($workerContext->mate->structs->items as $struct) {
- // Prepare context
- $resolvedClass = $this->templateRenderer->render($crafter->class, ['name' => $struct->name]);
- $resolvedClassName = Classes::getClassName($resolvedClass);
- $resolvedNamespace = Classes::getNamespace($resolvedClass);
- $resolvedFilename = Strings::replace($resolvedClass, '#\\\#', '/');
-
- $context = new TemplateContext(
- class: new ClassContext(
- class: $resolvedClass,
- className: $resolvedClassName,
- namespace: $resolvedNamespace,
- extends: $crafter->baseClass,
- ),
- helper: new HelperContext(
- structVar: sprintf('$%s', $struct->name),
- entityClassName: sprintf('%s', ucfirst($struct->name)),
- dtoClassName: sprintf('%sDto', ucfirst($struct->name)),
- ),
- struct: new StructContext(
- name: $struct->name,
- fields: Arrays::map(
- $struct->fields,
- fn (StructFieldConfig $field): StructFieldContext => new StructFieldContext(
- name: $field->name,
- type: $field->type,
- nullable: $field->nullable,
- )
- )
- )
- );
-
- // Craft (input & output)
- $intputFile = IO::realpath($crafter->template);
- $outputFile = $workerContext->mate->process->cwd . '/' . lcfirst($resolvedFilename) . '.php';
-
- $outputContent = $this->templateRenderer->renderFile(
- file: $intputFile,
- params: ['ctx' => $context]
- );
-
- FileSystem::write($outputFile, $outputContent);
-
- $result->add(
- crafter: $crafterKey,
- state: 'crafted',
- input: $intputFile,
- output: $outputFile,
- );
- }
- }
-
- return $result;
- }
-
-}
diff --git a/src/Crafter/Worker/WorkerContext.php b/src/Crafter/Worker/WorkerContext.php
deleted file mode 100644
index 6863d7a..0000000
--- a/src/Crafter/Worker/WorkerContext.php
+++ /dev/null
@@ -1,16 +0,0 @@
- */
- private array $scopes = [];
-
- /**
- * @param array $scopes
- */
- public function withScopes(array $scopes): self
- {
- $this->scopes = $scopes;
-
- return $this;
- }
-
- public function from(InputConfig $mateConfig): WorkerContext
- {
- if ($this->scopes !== []) {
- $mateConfig->app->scopes = $this->scopes;
- }
-
- return new WorkerContext(
- mate: $mateConfig,
- );
- }
-
-}
diff --git a/src/DI/BetterContainer.php b/src/DI/BetterContainer.php
index 5820510..da33e2a 100644
--- a/src/DI/BetterContainer.php
+++ b/src/DI/BetterContainer.php
@@ -1,6 +1,6 @@
$params
*/
- public function renderFile(string $file, array $params = []): string
+ public function renderPhp(string $file, array $params = []): string
{
return $this->render(FileSystem::read($file), $params);
}
+ /**
+ * @param array $params
+ */
+ public function renderLatte(string $file, array $params = []): string
+ {
+ return $this->render('{syntax double}' . FileSystem::read($file), $params);
+ }
+
}
diff --git a/src/Utils/Classes.php b/src/Utils/Classes.php
index fc78af4..96cbf89 100644
--- a/src/Utils/Classes.php
+++ b/src/Utils/Classes.php
@@ -1,6 +1,6 @@
true,
+ $value === '' => true,
+ default => false,
+ };
+ }
+
+}
diff --git a/src/Worker/Crafter/CrafterContext.php b/src/Worker/Crafter/CrafterContext.php
new file mode 100644
index 0000000..ad4ddfd
--- /dev/null
+++ b/src/Worker/Crafter/CrafterContext.php
@@ -0,0 +1,33 @@
+ $scopes
+ */
+ public static function from(
+ CraftingConfig $craftingConfig,
+ array $scopes = []
+ ): self
+ {
+ if ($scopes !== []) {
+ $craftingConfig->app->scopes = $scopes;
+ }
+
+ return new self(
+ craftingConfig: $craftingConfig,
+ );
+ }
+
+}
diff --git a/src/Crafter/Worker/CrafterResult.php b/src/Worker/Crafter/CrafterResult.php
similarity index 91%
rename from src/Crafter/Worker/CrafterResult.php
rename to src/Worker/Crafter/CrafterResult.php
index 5c00f2b..41f47af 100644
--- a/src/Crafter/Worker/CrafterResult.php
+++ b/src/Worker/Crafter/CrafterResult.php
@@ -1,6 +1,6 @@
craftingConfig->app->crafters as $crafterKey => $crafter) {
+ // Skip crafter if not in scope
+ if (array_intersect($crafter->scopes, $workerContext->craftingConfig->app->scopes) === []) {
+ $result->add(
+ crafter: $crafterKey,
+ state: 'skipped',
+ note: 'Scope mismatch',
+ );
+
+ continue;
+ }
+
+ foreach ($workerContext->craftingConfig->data->items as $structure) {
+ match ($crafter->output->resolver) {
+ 'php' => $this->phpResolver->resolve($workerContext, $crafter, $structure, $result),
+ 'latte' => $this->latteResolver->resolve($workerContext, $crafter, $structure, $result),
+ default => throw new LogicalException(sprintf('Unknown template resolver "%s"', $crafter->output->resolver)),
+ };
+ }
+ }
+
+ return $result;
+ }
+
+}
diff --git a/src/Worker/Crafter/Resolver/Latte/HelperContext.php b/src/Worker/Crafter/Resolver/Latte/HelperContext.php
new file mode 100644
index 0000000..ad31d50
--- /dev/null
+++ b/src/Worker/Crafter/Resolver/Latte/HelperContext.php
@@ -0,0 +1,14 @@
+templateRenderer->render($crafterConfig->output->path, ['name' => $structureConfig->name]);
+ $resolvedFilename = Strings::replace($resolvedFile, '#\\\#', '/');
+
+ $context = new TemplateContext(
+ helper: new HelperContext(
+ structVar: sprintf('$%s', $structureConfig->name),
+ ),
+ struct: new StructContext(
+ name: $structureConfig->name,
+ fields: Arrays::map(
+ $structureConfig->fields,
+ fn (DataObjectField $field): StructFieldContext => new StructFieldContext(
+ name: $field->name,
+ type: $field->type,
+ nullable: $field->nullable,
+ )
+ )
+ )
+ );
+
+ // Craft (input & output)
+ $intputFile = IO::realpath($crafterConfig->input->path);
+ $outputFile = $crafterContext->craftingConfig->process->cwd
+ . '/' . $crafterContext->craftingConfig->app->dir
+ . '/' . $resolvedFilename;
+
+ $outputContent = $this->templateRenderer->renderLatte(
+ file: $intputFile,
+ params: ['ctx' => $context]
+ );
+
+ FileSystem::write($outputFile, $outputContent);
+
+ $crafterResult->add(
+ crafter: $crafterConfig->id,
+ state: 'crafted',
+ input: $intputFile,
+ output: $outputFile,
+ );
+ }
+
+}
diff --git a/src/Config/StructConfig.php b/src/Worker/Crafter/Resolver/Latte/StructContext.php
similarity index 51%
rename from src/Config/StructConfig.php
rename to src/Worker/Crafter/Resolver/Latte/StructContext.php
index 476b331..b6298ef 100644
--- a/src/Config/StructConfig.php
+++ b/src/Worker/Crafter/Resolver/Latte/StructContext.php
@@ -1,12 +1,12 @@
MyApp\UI\HomepagePresenter.php
+ $resolvedFile = $this->templateRenderer->render($crafterConfig->output->path, [
+ 'namespace' => $crafterContext->craftingConfig->app->namespace,
+ 'name' => $structureConfig->name,
+ ]);
+
+ // Resolve classname
+ // E.q. MyApp\UI\HomepagePresenter.php -> MyApp\\UI\\HomepagePresenter
+ $resolvedClassName = Strings::replace($resolvedFile, '#\.php$#', '');
+ $resolvedClassName = Classes::getClassName($resolvedClassName);
+
+ // Resolve namespace
+ // E.q. MyApp\UI\HomepagePresenter -> MyApp\UI
+ $resolvedNamespace = Classes::getNamespace($resolvedFile);
+
+ // Resolve namespace
+ // E.q. MyApp\UI\HomepagePresenter -> MyApp
+ $resolvedRootNamespace = Classes::getRootNamespace($resolvedFile);
+
+ // Resolve filename
+ // E.q. MyApp\UI\HomepagePresenter.php -> UI/HomepagePresenter
+ $resolvedFilename = Strings::replace($resolvedFile, '#\\\#', '/');
+ $resolvedFilename = Strings::replace($resolvedFilename, '#^' . $crafterContext->craftingConfig->app->namespace . '/#', '');
+
+ $context = new TemplateContext(
+ class: new ClassContext(
+ className: $resolvedClassName,
+ namespace: $resolvedNamespace,
+ rootNamespace: $resolvedRootNamespace,
+ ),
+ helper: new HelperContext(
+ structVar: sprintf('$%s', $structureConfig->name),
+ entityClassName: sprintf('%s', ucfirst($structureConfig->name)),
+ dtoClassName: sprintf('%sDto', ucfirst($structureConfig->name)),
+ ),
+ struct: new StructContext(
+ name: $structureConfig->name,
+ fields: Arrays::map(
+ $structureConfig->fields,
+ fn (DataObjectField $field): StructFieldContext => new StructFieldContext(
+ name: $field->name,
+ type: $field->type,
+ nullable: $field->nullable,
+ )
+ )
+ )
+ );
+
+ // Craft (input & output)
+ $intputFile = IO::realpath($crafterConfig->input->path);
+ $outputFile = $crafterContext->craftingConfig->process->cwd
+ . '/' . $crafterContext->craftingConfig->app->dir
+ . '/' . $resolvedFilename;
+
+ $outputContent = $this->templateRenderer->renderPhp(
+ file: $intputFile,
+ params: ['ctx' => $context]
+ );
+
+ FileSystem::write($outputFile, $outputContent);
+
+ $crafterResult->add(
+ crafter: $crafterConfig->id,
+ state: 'crafted',
+ input: $intputFile,
+ output: $outputFile,
+ );
+ }
+
+}
diff --git a/src/Crafter/Template/StructContext.php b/src/Worker/Crafter/Resolver/Php/StructContext.php
similarity index 77%
rename from src/Crafter/Template/StructContext.php
rename to src/Worker/Crafter/Resolver/Php/StructContext.php
index 72e482f..2be627e 100644
--- a/src/Crafter/Template/StructContext.php
+++ b/src/Worker/Crafter/Resolver/Php/StructContext.php
@@ -1,6 +1,6 @@
app->dir = $dir;
+ }
+
+ return new self(
+ craftingConfig: $craftingConfig,
+ );
+ }
+
+}
diff --git a/src/Worker/Generator/GeneratorResult.php b/src/Worker/Generator/GeneratorResult.php
new file mode 100644
index 0000000..10dac32
--- /dev/null
+++ b/src/Worker/Generator/GeneratorResult.php
@@ -0,0 +1,28 @@
+ */
+ public array $items = [];
+
+ public function add(
+ string $crafter,
+ string $state,
+ string|null $note = null,
+ string|null $input = null,
+ string|null $output = null,
+ ): void
+ {
+ $this->items[] = [
+ 'crafter' => $crafter,
+ 'state' => $state,
+ 'note' => $note,
+ 'input' => $input,
+ 'output' => $output,
+ ];
+ }
+
+}
diff --git a/src/Worker/Generator/GeneratorWorker.php b/src/Worker/Generator/GeneratorWorker.php
new file mode 100644
index 0000000..d02bfed
--- /dev/null
+++ b/src/Worker/Generator/GeneratorWorker.php
@@ -0,0 +1,32 @@
+craftingConfig->app->crafters as $crafter) {
+ match ($crafter->output->resolver) {
+ 'raw' => $this->rawResolver->resolve($generatorContext, $crafter, $result),
+ default => throw new LogicalException(sprintf('Unknown template resolver "%s"', $crafter->output->resolver)),
+ };
+ }
+
+ return $result;
+ }
+
+}
diff --git a/src/Worker/Generator/Resolver/Raw/RawResolver.php b/src/Worker/Generator/Resolver/Raw/RawResolver.php
new file mode 100644
index 0000000..0a275de
--- /dev/null
+++ b/src/Worker/Generator/Resolver/Raw/RawResolver.php
@@ -0,0 +1,51 @@
+templateRenderer->render($crafterConfig->output->path);
+ $resolvedFilename = Strings::replace($resolvedFile, '#\\\#', '/');
+
+ // Craft (input & output)
+ $intputFile = IO::realpath($crafterConfig->input->path);
+ $outputFile = $generatorContext->craftingConfig->process->cwd
+ . '/' . $generatorContext->craftingConfig->app->dir
+ . '/' . $resolvedFilename;
+
+ $outputContent = FileSystem::read($intputFile);
+
+ FileSystem::write($outputFile, $outputContent);
+
+ $generatorResult->add(
+ crafter: $crafterConfig->id,
+ state: 'crafted',
+ input: $intputFile,
+ output: $outputFile,
+ );
+ }
+
+}
diff --git a/src/Worker/Generator/Resolver/ResolverInterface.php b/src/Worker/Generator/Resolver/ResolverInterface.php
new file mode 100644
index 0000000..3c4bc87
--- /dev/null
+++ b/src/Worker/Generator/Resolver/ResolverInterface.php
@@ -0,0 +1,18 @@
+in(__DIR__ . '/__files__') as $file) {
+ $case = Neon::decodeFile($file->getRealPath());
+
+ $loader = (new ConfigLoader())
+ ->withCwd(__DIR__)
+ ->withConfig($case['input'])
+ ->load();
+
+ Assert::match(
+ Json::encode($case['output'], pretty: true),
+ Json::encode($loader, pretty: true),
+ );
+ }
+});
diff --git a/tests/Cases/Config/Loader/__files__/config1.neon b/tests/Cases/Config/Loader/__files__/config1.neon
new file mode 100644
index 0000000..c5394a1
--- /dev/null
+++ b/tests/Cases/Config/Loader/__files__/config1.neon
@@ -0,0 +1,69 @@
+input:
+ dir: src
+ namespace: MyApp
+ preset: nette
+
+ data:
+ user:
+ fields:
+ username: {type: string}
+ email: {type: string}
+
+output:
+ process:
+ cwd: %a%/tests/Cases/Config/Loader
+ app:
+ version: "1"
+ dir: src
+ namespace: MyApp
+ vars: []
+ preset: nette
+ template: null
+ crafters:
+ presenter:
+ id: presenter
+ name: presenter
+ mode: null
+ scopes: [
+ default
+ ]
+ input:
+ resolver: latte
+ path: "%a%/resources/presets/nette/templates/presenter/presenter.latte"
+ vars: []
+ output:
+ resolver: php
+ path: "/{$namespace}\\UI\\{$name|firstUpper}\\{$name|firstUpper}Presenter.php"
+ vars: []
+ vars: []
+ presenter_template:
+ id: presenter_template
+ name: presenter_template
+ mode: null
+ scopes: [
+ default
+ ]
+ input:
+ resolver: latte
+ path: "%a%/resources/presets/nette/templates/presenter/template.latte"
+ vars: []
+ output:
+ resolver: latte
+ path: "/UI/{$name|firstUpper}/Templates/default.latte"
+ vars: []
+ vars: []
+ scopes: []
+ data:
+ items:
+ user:
+ name: user
+ fields:
+ username:
+ name: username
+ type: string
+ nullable: false
+ email:
+ name: email
+ type: string
+ nullable: false
+ vars: []
diff --git a/tests/Cases/Mate.phpt b/tests/Cases/Mate.phpt
index 8e111af..871706e 100644
--- a/tests/Cases/Mate.phpt
+++ b/tests/Cases/Mate.phpt
@@ -1,6 +1,6 @@