modwire 3.0.0__tar.gz → 3.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {modwire-3.0.0 → modwire-3.2.0}/.github/workflows/release.yml +11 -1
- {modwire-3.0.0 → modwire-3.2.0}/CHANGELOG.md +19 -1
- {modwire-3.0.0 → modwire-3.2.0}/PKG-INFO +73 -1
- {modwire-3.0.0 → modwire-3.2.0}/README.md +71 -0
- {modwire-3.0.0 → modwire-3.2.0}/pyproject.toml +11 -0
- {modwire-3.0.0 → modwire-3.2.0}/src/modwire/_version.py +3 -3
- modwire-3.2.0/src/modwire/modules/__init__.py +3 -0
- modwire-3.2.0/src/modwire/modules/generate.py +74 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/clean/copier.yml +48 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/php/src/Application/Ports/{{ repository_name }}.php.jinja +14 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/php/src/Application/UseCases/{{ use_case_name }}.php.jinja +32 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/php/src/Domain/Entities/{{ entity_name }}.php.jinja +45 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/php/src/Domain/Events/{{ event_name }}.php.jinja +14 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/php/src/Domain/Exceptions/{{ entity_name }}ValidationException.php.jinja +11 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/php/src/Infrastructure/Persistence/InMemory{{ repository_name }}.php.jinja +24 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/php/src/Interface/Http/{{ controller_name }}.php.jinja +23 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/__init__.py.jinja +1 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/application/__init__.py.jinja +1 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/application/ports/__init__.py.jinja +1 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/application/ports/{{ repository_name | lower }}.py.jinja +13 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/application/use_cases/__init__.py.jinja +1 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/application/use_cases/{{ use_case_name | lower }}.py.jinja +22 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/domain/__init__.py.jinja +1 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/domain/entities/__init__.py.jinja +1 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/domain/entities/{{ entity_name | lower }}.py.jinja +35 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/domain/events/__init__.py.jinja +1 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/domain/events/{{ event_name | lower }}.py.jinja +7 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/domain/exceptions/__init__.py.jinja +1 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/domain/exceptions/{{ entity_name | lower }}validationerror.py.jinja +2 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/infrastructure/__init__.py.jinja +1 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/infrastructure/persistence/__init__.py.jinja +1 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/infrastructure/persistence/inmemory{{ repository_name | lower }}.py.jinja +14 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/interface/__init__.py.jinja +1 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/interface/http/__init__.py.jinja +1 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/interface/http/{{ controller_name | lower }}.py.jinja +15 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/typescript/{{ module_name }}/application/ports/{{ repository_name }}.ts.jinja +6 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/typescript/{{ module_name }}/application/use_cases/{{ use_case_name }}.ts.jinja +19 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/typescript/{{ module_name }}/domain/entities/{{ entity_name }}.ts.jinja +31 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/typescript/{{ module_name }}/domain/events/{{ event_name }}.ts.jinja +6 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/typescript/{{ module_name }}/domain/exceptions/{{ entity_name }}ValidationError.ts.jinja +1 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/typescript/{{ module_name }}/infrastructure/persistence/InMemory{{ repository_name }}.ts.jinja +14 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/typescript/{{ module_name }}/interface/http/{{ controller_name }}.ts.jinja +10 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/copier.yml +68 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/php/src/BoundedContexts/{{ context_class_name }}/{{ module_class_name }}/Application/Ports/{{ repository_name }}.php.jinja +14 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/php/src/BoundedContexts/{{ context_class_name }}/{{ module_class_name }}/Application/UseCases/{{ use_case_name }}.php.jinja +35 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/php/src/BoundedContexts/{{ context_class_name }}/{{ module_class_name }}/Domain/Aggregates/{{ aggregate_name }}.php.jinja +44 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/php/src/BoundedContexts/{{ context_class_name }}/{{ module_class_name }}/Domain/Entities/{{ entity_name }}.php.jinja +16 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/php/src/BoundedContexts/{{ context_class_name }}/{{ module_class_name }}/Domain/Events/{{ event_name }}.php.jinja +14 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/php/src/BoundedContexts/{{ context_class_name }}/{{ module_class_name }}/Domain/Exceptions/{{ aggregate_name }}ValidationException.php.jinja +11 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/php/src/BoundedContexts/{{ context_class_name }}/{{ module_class_name }}/Domain/Services/{{ domain_service_name }}.php.jinja +15 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/php/src/BoundedContexts/{{ context_class_name }}/{{ module_class_name }}/Domain/ValueObjects/{{ value_object_name }}.php.jinja +17 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/php/src/BoundedContexts/{{ context_class_name }}/{{ module_class_name }}/Infrastructure/Persistence/InMemory{{ repository_name }}.php.jinja +24 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/php/src/BoundedContexts/{{ context_class_name }}/{{ module_class_name }}/Interface/Http/{{ controller_name }}.php.jinja +23 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/__init__.py.jinja +1 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/__init__.py.jinja +1 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/__init__.py.jinja +1 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/application/__init__.py.jinja +1 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/application/ports/__init__.py.jinja +1 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/application/ports/{{ repository_name | lower }}.py.jinja +13 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/application/use_cases/__init__.py.jinja +1 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/application/use_cases/{{ use_case_name | lower }}.py.jinja +28 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/domain/__init__.py.jinja +1 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/domain/aggregates/__init__.py.jinja +1 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/domain/aggregates/{{ aggregate_name | lower }}.py.jinja +37 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/domain/entities/__init__.py.jinja +1 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/domain/entities/{{ entity_name | lower }}.py.jinja +9 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/domain/events/__init__.py.jinja +1 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/domain/events/{{ event_name | lower }}.py.jinja +7 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/domain/exceptions/__init__.py.jinja +1 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/domain/exceptions/{{ aggregate_name | lower }}validationerror.py.jinja +2 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/domain/services/__init__.py.jinja +1 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/domain/services/{{ domain_service_name | lower }}.py.jinja +8 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/domain/value_objects/__init__.py.jinja +1 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/domain/value_objects/{{ value_object_name | lower }}.py.jinja +14 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/infrastructure/__init__.py.jinja +1 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/infrastructure/persistence/__init__.py.jinja +1 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/infrastructure/persistence/inmemory{{ repository_name | lower }}.py.jinja +14 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/interface/__init__.py.jinja +1 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/interface/http/__init__.py.jinja +1 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/interface/http/{{ controller_name | lower }}.py.jinja +17 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/typescript/bounded_contexts/{{ context_name }}/{{ module_name }}/application/ports/{{ repository_name }}.ts.jinja +6 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/typescript/bounded_contexts/{{ context_name }}/{{ module_name }}/application/use_cases/{{ use_case_name }}.ts.jinja +23 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/typescript/bounded_contexts/{{ context_name }}/{{ module_name }}/domain/aggregates/{{ aggregate_name }}.ts.jinja +29 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/typescript/bounded_contexts/{{ context_name }}/{{ module_name }}/domain/entities/{{ entity_name }}.ts.jinja +8 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/typescript/bounded_contexts/{{ context_name }}/{{ module_name }}/domain/events/{{ event_name }}.ts.jinja +6 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/typescript/bounded_contexts/{{ context_name }}/{{ module_name }}/domain/exceptions/{{ aggregate_name }}ValidationError.ts.jinja +1 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/typescript/bounded_contexts/{{ context_name }}/{{ module_name }}/domain/services/{{ domain_service_name }}.ts.jinja +7 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/typescript/bounded_contexts/{{ context_name }}/{{ module_name }}/domain/value_objects/{{ value_object_name }}.ts.jinja +9 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/typescript/bounded_contexts/{{ context_name }}/{{ module_name }}/infrastructure/persistence/InMemory{{ repository_name }}.ts.jinja +14 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/typescript/bounded_contexts/{{ context_name }}/{{ module_name }}/interface/http/{{ controller_name }}.ts.jinja +10 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/copier.yml +43 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/php/src/Adapters/Inbound/Amqp/{{ command_name }}Consumer.php.jinja +23 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/php/src/Adapters/Inbound/Web/{{ controller_name }}.php.jinja +23 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/php/src/Adapters/Inbound/{{ service_name }}.php.jinja +25 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/php/src/Adapters/Outbound/Client/{{ aggregate_name }}Client.php.jinja +14 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/php/src/Adapters/Outbound/Persistence/InMemory{{ repository_name }}.php.jinja +24 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/php/src/Domain/Events/{{ aggregate_name }}Created.php.jinja +14 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/php/src/Domain/Exceptions/{{ aggregate_name }}ValidationException.php.jinja +11 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/php/src/Domain/Models/{{ aggregate_name }}.php.jinja +45 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/php/src/Ports/Inbound/{{ command_name }}.php.jinja +14 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/php/src/Ports/Inbound/{{ service_name }}Port.php.jinja +12 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/php/src/Ports/Outbound/{{ repository_name }}.php.jinja +14 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/__init__.py.jinja +3 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/adapters/__init__.py.jinja +3 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/adapters/inbound/__init__.py.jinja +3 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/adapters/inbound/amqp/__init__.py.jinja +3 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/adapters/inbound/amqp/{{ command_name | lower }}consumer.py.jinja +17 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/adapters/inbound/web/__init__.py.jinja +3 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/adapters/inbound/web/{{ controller_name | lower }}.py.jinja +13 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/adapters/inbound/{{ service_name | lower }}.py.jinja +15 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/adapters/outbound/__init__.py.jinja +3 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/adapters/outbound/client/__init__.py.jinja +3 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/adapters/outbound/client/{{ aggregate_name | lower }}client.py.jinja +6 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/adapters/outbound/persistence/__init__.py.jinja +3 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/adapters/outbound/persistence/inmemory{{ repository_name | lower }}.py.jinja +14 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/domain/__init__.py.jinja +3 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/domain/events/__init__.py.jinja +3 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/domain/events/{{ aggregate_name | lower }}created.py.jinja +9 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/domain/exceptions/__init__.py.jinja +3 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/domain/exceptions/{{ aggregate_name | lower }}validationerror.py.jinja +5 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/domain/models/__init__.py.jinja +3 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/domain/models/{{ aggregate_name | lower }}.py.jinja +37 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/ports/__init__.py.jinja +3 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/ports/inbound/__init__.py.jinja +3 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/ports/inbound/{{ command_name | lower }}.py.jinja +9 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/ports/inbound/{{ service_name | lower }}.py.jinja +11 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/ports/outbound/__init__.py.jinja +3 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/ports/outbound/{{ repository_name | lower }}.py.jinja +13 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/typescript/{{ module_name }}/adapters/inbound/amqp/{{ command_name }}Consumer.ts.jinja +10 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/typescript/{{ module_name }}/adapters/inbound/web/{{ controller_name }}.ts.jinja +11 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/typescript/{{ module_name }}/adapters/inbound/{{ service_name }}.ts.jinja +13 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/typescript/{{ module_name }}/adapters/outbound/client/{{ aggregate_name }}Client.ts.jinja +5 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/typescript/{{ module_name }}/adapters/outbound/persistence/InMemory{{ repository_name }}.ts.jinja +14 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/typescript/{{ module_name }}/domain/events/{{ aggregate_name }}Created.ts.jinja +6 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/typescript/{{ module_name }}/domain/exceptions/{{ aggregate_name }}ValidationError.ts.jinja +1 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/typescript/{{ module_name }}/domain/models/{{ aggregate_name }}.ts.jinja +31 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/typescript/{{ module_name }}/ports/inbound/{{ command_name }}.ts.jinja +6 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/typescript/{{ module_name }}/ports/inbound/{{ service_name }}Port.ts.jinja +6 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/typescript/{{ module_name }}/ports/outbound/{{ repository_name }}.ts.jinja +6 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/layered/copier.yml +23 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/layered/template/{{ module_name }}/application.py.jinja +18 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/layered/template/{{ module_name }}/domain.py.jinja +12 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/layered/template/{{ module_name }}/infrastructure.py.jinja +11 -0
- modwire-3.2.0/src/modwire/modules/scaffoldings/layered/template/{{ module_name }}/ui.py.jinja +20 -0
- modwire-3.2.0/src/modwire/projects/__init__.py +13 -0
- modwire-3.2.0/src/modwire/projects/_operations.py +287 -0
- modwire-3.2.0/src/modwire/projects/generate.py +126 -0
- modwire-3.2.0/src/modwire/projects/profile.py +321 -0
- modwire-3.2.0/src/modwire/projects/root.py +70 -0
- modwire-3.2.0/src/modwire/projects/scaffoldings/php-symfony-ddd-composer/copier.yml +33 -0
- modwire-3.2.0/src/modwire/projects/scaffoldings/php-symfony-ddd-composer/template/.gitignore.jinja +5 -0
- modwire-3.2.0/src/modwire/projects/scaffoldings/php-symfony-ddd-composer/template/.modwire/project.json.jinja +1 -0
- modwire-3.2.0/src/modwire/projects/scaffoldings/php-symfony-ddd-composer/template/README.md.jinja +6 -0
- modwire-3.2.0/src/modwire/projects/scaffoldings/php-symfony-ddd-composer/template/bin/console.jinja +6 -0
- modwire-3.2.0/src/modwire/projects/scaffoldings/php-symfony-ddd-composer/template/composer.json.jinja +29 -0
- modwire-3.2.0/src/modwire/projects/scaffoldings/php-symfony-ddd-composer/template/config/routes.yaml.jinja +3 -0
- modwire-3.2.0/src/modwire/projects/scaffoldings/php-symfony-ddd-composer/template/openapi/.gitkeep.jinja +1 -0
- modwire-3.2.0/src/modwire/projects/scaffoldings/php-symfony-ddd-composer/template/src/Infrastructure/Clients/Generated/.gitkeep.jinja +1 -0
- modwire-3.2.0/src/modwire/projects/scaffoldings/php-symfony-ddd-composer/template/src/Kernel.php.jinja +13 -0
- modwire-3.2.0/src/modwire/projects/scaffoldings/php-symfony-ddd-composer/template/tests/KernelTest.php.jinja +16 -0
- modwire-3.2.0/src/modwire/projects/scaffoldings/python-fastapi-ddd-uv/copier.yml +90 -0
- modwire-3.2.0/src/modwire/projects/scaffoldings/python-fastapi-ddd-uv/template/.gitignore.jinja +10 -0
- modwire-3.2.0/src/modwire/projects/scaffoldings/python-fastapi-ddd-uv/template/.modwire/project.json.jinja +1 -0
- modwire-3.2.0/src/modwire/projects/scaffoldings/python-fastapi-ddd-uv/template/README.md.jinja +25 -0
- modwire-3.2.0/src/modwire/projects/scaffoldings/python-fastapi-ddd-uv/template/openapi/.gitkeep.jinja +1 -0
- modwire-3.2.0/src/modwire/projects/scaffoldings/python-fastapi-ddd-uv/template/pyproject.toml.jinja +38 -0
- modwire-3.2.0/src/modwire/projects/scaffoldings/python-fastapi-ddd-uv/template/src/{{ package_name }}/__init__.py.jinja +1 -0
- modwire-3.2.0/src/modwire/projects/scaffoldings/python-fastapi-ddd-uv/template/src/{{ package_name }}/cli.py.jinja +15 -0
- modwire-3.2.0/src/modwire/projects/scaffoldings/python-fastapi-ddd-uv/template/src/{{ package_name }}/infrastructure/__init__.py.jinja +1 -0
- modwire-3.2.0/src/modwire/projects/scaffoldings/python-fastapi-ddd-uv/template/src/{{ package_name }}/infrastructure/clients/__init__.py.jinja +1 -0
- modwire-3.2.0/src/modwire/projects/scaffoldings/python-fastapi-ddd-uv/template/src/{{ package_name }}/infrastructure/clients/generated/.gitkeep.jinja +1 -0
- modwire-3.2.0/src/modwire/projects/scaffoldings/python-fastapi-ddd-uv/template/src/{{ package_name }}/interface/__init__.py.jinja +1 -0
- modwire-3.2.0/src/modwire/projects/scaffoldings/python-fastapi-ddd-uv/template/src/{{ package_name }}/interface/http/__init__.py.jinja +1 -0
- modwire-3.2.0/src/modwire/projects/scaffoldings/python-fastapi-ddd-uv/template/src/{{ package_name }}/interface/http/router.py.jinja +8 -0
- modwire-3.2.0/src/modwire/projects/scaffoldings/python-fastapi-ddd-uv/template/src/{{ package_name }}/main.py.jinja +14 -0
- modwire-3.2.0/src/modwire/projects/scaffoldings/python-fastapi-ddd-uv/template/src/{{ package_name }}/settings.py.jinja +7 -0
- modwire-3.2.0/src/modwire/projects/scaffoldings/python-fastapi-ddd-uv/template/tests/test_health.py.jinja +12 -0
- modwire-3.2.0/src/modwire/projects/scaffoldings/typescript-nestjs-ddd-pnpm/copier.yml +33 -0
- modwire-3.2.0/src/modwire/projects/scaffoldings/typescript-nestjs-ddd-pnpm/template/.gitignore.jinja +5 -0
- modwire-3.2.0/src/modwire/projects/scaffoldings/typescript-nestjs-ddd-pnpm/template/.modwire/project.json.jinja +1 -0
- modwire-3.2.0/src/modwire/projects/scaffoldings/typescript-nestjs-ddd-pnpm/template/README.md.jinja +6 -0
- modwire-3.2.0/src/modwire/projects/scaffoldings/typescript-nestjs-ddd-pnpm/template/nest-cli.json.jinja +4 -0
- modwire-3.2.0/src/modwire/projects/scaffoldings/typescript-nestjs-ddd-pnpm/template/openapi/.gitkeep.jinja +1 -0
- modwire-3.2.0/src/modwire/projects/scaffoldings/typescript-nestjs-ddd-pnpm/template/package.json.jinja +22 -0
- modwire-3.2.0/src/modwire/projects/scaffoldings/typescript-nestjs-ddd-pnpm/template/src/app.module.ts.jinja +4 -0
- modwire-3.2.0/src/modwire/projects/scaffoldings/typescript-nestjs-ddd-pnpm/template/src/infrastructure/clients/generated/.gitkeep.jinja +1 -0
- modwire-3.2.0/src/modwire/projects/scaffoldings/typescript-nestjs-ddd-pnpm/template/src/main.ts.jinja +10 -0
- modwire-3.2.0/src/modwire/projects/scaffoldings/typescript-nestjs-ddd-pnpm/template/test/app.spec.ts.jinja +7 -0
- modwire-3.2.0/src/modwire/projects/scaffoldings/typescript-nestjs-ddd-pnpm/template/tsconfig.json.jinja +12 -0
- {modwire-3.0.0 → modwire-3.2.0}/src/modwire.egg-info/PKG-INFO +73 -1
- modwire-3.2.0/src/modwire.egg-info/SOURCES.txt +251 -0
- {modwire-3.0.0 → modwire-3.2.0}/src/modwire.egg-info/requires.txt +1 -0
- modwire-3.2.0/tests/modules/test_generate.py +210 -0
- modwire-3.2.0/tests/projects/test_project_generate.py +225 -0
- modwire-3.2.0/tests/projects/test_project_operations.py +156 -0
- {modwire-3.0.0 → modwire-3.2.0}/uv.lock +264 -0
- modwire-3.0.0/src/modwire.egg-info/SOURCES.txt +0 -67
- modwire-3.0.0/src/modwire.egg-info/scm_file_list.json +0 -63
- modwire-3.0.0/src/modwire.egg-info/scm_version.json +0 -8
- {modwire-3.0.0 → modwire-3.2.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/.github/workflows/ci.yml +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/.gitignore +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/CONTRIBUTING.md +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/LICENSE +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/docs/wiki/Development-checks.md +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/docs/wiki/Home.md +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/docs/wiki/Reporting-bugs.md +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/docs/wiki/Requesting-features.md +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/setup.cfg +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/src/modwire/__init__.py +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/__init__.py +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/boundaries/__init__.py +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/boundaries/analyzers/__init__.py +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/boundaries/analyzers/backward.py +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/boundaries/analyzers/no_cycles.py +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/boundaries/analyzers/no_reentry.py +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/boundaries/base.py +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/boundaries/config.py +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/boundaries/map.py +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/boundaries/pipeline.py +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/boundaries/tags/__init__.py +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/boundaries/tags/matcher.py +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/boundaries/tags/tag_map.py +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/config.py +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/insight/__init__.py +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/insight/base.py +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/insight/pipeline.py +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/insight/reports/__init__.py +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/insight/reports/callables.py +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/insight/reports/clusters.py +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/insight/reports/coherence.py +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/insight/reports/exports.py +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/insight/reports/hotspots.py +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/report.py +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/root.py +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/shape/__init__.py +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/shape/base.py +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/shape/config.py +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/shape/pipeline.py +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/shape/rules/__init__.py +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/shape/rules/abstract_class_resolver.py +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/shape/rules/callable_resolver.py +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/shape/rules/class_resolver.py +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/shape/rules/file_resolver.py +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/shape/rules/import_resolver.py +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/shape/rules/property_resolver.py +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/shape/rules/signature_resolver.py +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/shape/rules/symbol_resolver.py +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/src/modwire.egg-info/dependency_links.txt +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/src/modwire.egg-info/top_level.txt +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/tests/architecture/boundaries/test_map.py +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/tests/architecture/boundaries/test_pipeline.py +0 -0
- {modwire-3.0.0 → modwire-3.2.0}/tests/architecture/test_report.py +0 -0
|
@@ -46,6 +46,15 @@ jobs:
|
|
|
46
46
|
exit 1
|
|
47
47
|
fi
|
|
48
48
|
|
|
49
|
+
- name: Use release tag as package version
|
|
50
|
+
if: github.event_name == 'release'
|
|
51
|
+
run: |
|
|
52
|
+
tag_name="${{ github.event.release.tag_name }}"
|
|
53
|
+
release_version="${tag_name#v}"
|
|
54
|
+
|
|
55
|
+
echo "MODWIRE_RELEASE_VERSION=$release_version" >> "$GITHUB_ENV"
|
|
56
|
+
echo "SETUPTOOLS_SCM_PRETEND_VERSION_FOR_MODWIRE=$release_version" >> "$GITHUB_ENV"
|
|
57
|
+
|
|
49
58
|
- name: Set up Python
|
|
50
59
|
uses: actions/setup-python@v5
|
|
51
60
|
with:
|
|
@@ -90,12 +99,13 @@ jobs:
|
|
|
90
99
|
if: github.event_name == 'release'
|
|
91
100
|
run: |
|
|
92
101
|
python - <<'PY'
|
|
102
|
+
import os
|
|
93
103
|
import sys
|
|
94
104
|
import zipfile
|
|
95
105
|
from email.parser import Parser
|
|
96
106
|
from pathlib import Path
|
|
97
107
|
|
|
98
|
-
expected_version =
|
|
108
|
+
expected_version = os.environ["MODWIRE_RELEASE_VERSION"]
|
|
99
109
|
wheels = sorted(Path("dist").glob("*.whl"))
|
|
100
110
|
versions: dict[str, str] = {}
|
|
101
111
|
|
|
@@ -1,6 +1,24 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 3.
|
|
3
|
+
## 3.2.0 - Unreleased
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- Project generation through `modwire.projects.generate_project`.
|
|
8
|
+
- Bundled project profiles for Python/FastAPI/uv, TypeScript/NestJS/pnpm, and
|
|
9
|
+
PHP/Symfony/Composer.
|
|
10
|
+
- Project authority loading and project-aware context/module operations through
|
|
11
|
+
`modwire.projects.open_project`.
|
|
12
|
+
- Bundled `clean` and `ddd_context` module scaffoldings alongside the existing
|
|
13
|
+
`layered` and `hexagonal` scaffoldings.
|
|
14
|
+
- Python, TypeScript, and PHP outputs for bundled DDD context module generation.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- README project-generation documentation now covers project-aware operations and
|
|
19
|
+
the currently bundled project profiles.
|
|
20
|
+
|
|
21
|
+
## 3.0.0
|
|
4
22
|
|
|
5
23
|
### Breaking Changes
|
|
6
24
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: modwire
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.2.0
|
|
4
4
|
Summary: Map architecture boundaries and analyze extracted code maps.
|
|
5
5
|
Author: Tomasz Szpak
|
|
6
6
|
License-Expression: MIT
|
|
@@ -23,6 +23,7 @@ Classifier: Topic :: Software Development :: Quality Assurance
|
|
|
23
23
|
Requires-Python: >=3.11
|
|
24
24
|
Description-Content-Type: text/markdown
|
|
25
25
|
License-File: LICENSE
|
|
26
|
+
Requires-Dist: copier>=9.16.0
|
|
26
27
|
Requires-Dist: modwire-extraction>=1.0.1
|
|
27
28
|
Requires-Dist: pydantic>=2.8
|
|
28
29
|
Provides-Extra: dev
|
|
@@ -113,6 +114,77 @@ Reports are Pydantic models, so they can be serialized with `model_dump()` or
|
|
|
113
114
|
payload = report.model_dump(mode="json")
|
|
114
115
|
```
|
|
115
116
|
|
|
117
|
+
## Module Generation
|
|
118
|
+
|
|
119
|
+
`modwire.modules` can generate a module from any Copier template. A caller only
|
|
120
|
+
needs to create a normal Copier template directory and pass it to
|
|
121
|
+
`generate_module`.
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
from pathlib import Path
|
|
125
|
+
|
|
126
|
+
from modwire.modules import generate_module
|
|
127
|
+
|
|
128
|
+
generate_module(
|
|
129
|
+
"billing",
|
|
130
|
+
Path("src/features"),
|
|
131
|
+
Path("templates/modwire-module"),
|
|
132
|
+
data={"service_name": "BillingService"},
|
|
133
|
+
)
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
If no template path is provided, `generate_module` uses the bundled `layered`
|
|
137
|
+
scaffolding. Pass `scaffolding="hexagonal"` for a pluggable domain/ports/adapters
|
|
138
|
+
structure, `scaffolding="clean"` for a domain/application/infrastructure/interface
|
|
139
|
+
module, or `scaffolding="ddd_context"` for a bounded-context module. Bundled
|
|
140
|
+
scaffoldings are packaged with the distribution wheel.
|
|
141
|
+
|
|
142
|
+
## Project Generation
|
|
143
|
+
|
|
144
|
+
`modwire.projects` can generate a project authority and starter layout. The
|
|
145
|
+
default bundled project profile is `python-fastapi-ddd-uv`: Python, uv,
|
|
146
|
+
FastAPI, and a DDD-oriented package layout that mounts reusable `ddd_context`
|
|
147
|
+
module scaffolding under the application package.
|
|
148
|
+
|
|
149
|
+
```python
|
|
150
|
+
from pathlib import Path
|
|
151
|
+
|
|
152
|
+
from modwire.projects import generate_project
|
|
153
|
+
|
|
154
|
+
generate_project("acme", Path("services/acme"))
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
The generated project includes `.modwire/project.json`, which records the
|
|
158
|
+
resolved profile, layout, dependencies, module scaffolding, and operation names
|
|
159
|
+
for later project-aware automation.
|
|
160
|
+
|
|
161
|
+
Open an existing generated project with `open_project` to run project-aware
|
|
162
|
+
module operations against the recorded authority:
|
|
163
|
+
|
|
164
|
+
```python
|
|
165
|
+
from pathlib import Path
|
|
166
|
+
|
|
167
|
+
from modwire.projects import open_project
|
|
168
|
+
|
|
169
|
+
project = open_project(Path("services/acme"))
|
|
170
|
+
|
|
171
|
+
project.add_context("commerce")
|
|
172
|
+
project.add_module("billing", context_name="commerce")
|
|
173
|
+
project.remove_module("billing", context_name="commerce", dry_run=True)
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
The currently exposed project helpers cover reading the project authority,
|
|
177
|
+
adding contexts, adding modules, removing modules, and removing contexts. Module
|
|
178
|
+
generation uses the project's configured `module_scaffolding` and language output
|
|
179
|
+
root, so Python, TypeScript, and PHP profiles place generated files under their
|
|
180
|
+
own layout conventions.
|
|
181
|
+
|
|
182
|
+
Bundled project profiles currently include:
|
|
183
|
+
|
|
184
|
+
- `python-fastapi-ddd-uv`
|
|
185
|
+
- `typescript-nestjs-ddd-pnpm`
|
|
186
|
+
- `php-symfony-ddd-composer`
|
|
187
|
+
|
|
116
188
|
## Configuration
|
|
117
189
|
|
|
118
190
|
Boundary tags classify source IDs. Flow rules then use those tags to detect
|
|
@@ -79,6 +79,77 @@ Reports are Pydantic models, so they can be serialized with `model_dump()` or
|
|
|
79
79
|
payload = report.model_dump(mode="json")
|
|
80
80
|
```
|
|
81
81
|
|
|
82
|
+
## Module Generation
|
|
83
|
+
|
|
84
|
+
`modwire.modules` can generate a module from any Copier template. A caller only
|
|
85
|
+
needs to create a normal Copier template directory and pass it to
|
|
86
|
+
`generate_module`.
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
from pathlib import Path
|
|
90
|
+
|
|
91
|
+
from modwire.modules import generate_module
|
|
92
|
+
|
|
93
|
+
generate_module(
|
|
94
|
+
"billing",
|
|
95
|
+
Path("src/features"),
|
|
96
|
+
Path("templates/modwire-module"),
|
|
97
|
+
data={"service_name": "BillingService"},
|
|
98
|
+
)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
If no template path is provided, `generate_module` uses the bundled `layered`
|
|
102
|
+
scaffolding. Pass `scaffolding="hexagonal"` for a pluggable domain/ports/adapters
|
|
103
|
+
structure, `scaffolding="clean"` for a domain/application/infrastructure/interface
|
|
104
|
+
module, or `scaffolding="ddd_context"` for a bounded-context module. Bundled
|
|
105
|
+
scaffoldings are packaged with the distribution wheel.
|
|
106
|
+
|
|
107
|
+
## Project Generation
|
|
108
|
+
|
|
109
|
+
`modwire.projects` can generate a project authority and starter layout. The
|
|
110
|
+
default bundled project profile is `python-fastapi-ddd-uv`: Python, uv,
|
|
111
|
+
FastAPI, and a DDD-oriented package layout that mounts reusable `ddd_context`
|
|
112
|
+
module scaffolding under the application package.
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
from pathlib import Path
|
|
116
|
+
|
|
117
|
+
from modwire.projects import generate_project
|
|
118
|
+
|
|
119
|
+
generate_project("acme", Path("services/acme"))
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
The generated project includes `.modwire/project.json`, which records the
|
|
123
|
+
resolved profile, layout, dependencies, module scaffolding, and operation names
|
|
124
|
+
for later project-aware automation.
|
|
125
|
+
|
|
126
|
+
Open an existing generated project with `open_project` to run project-aware
|
|
127
|
+
module operations against the recorded authority:
|
|
128
|
+
|
|
129
|
+
```python
|
|
130
|
+
from pathlib import Path
|
|
131
|
+
|
|
132
|
+
from modwire.projects import open_project
|
|
133
|
+
|
|
134
|
+
project = open_project(Path("services/acme"))
|
|
135
|
+
|
|
136
|
+
project.add_context("commerce")
|
|
137
|
+
project.add_module("billing", context_name="commerce")
|
|
138
|
+
project.remove_module("billing", context_name="commerce", dry_run=True)
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
The currently exposed project helpers cover reading the project authority,
|
|
142
|
+
adding contexts, adding modules, removing modules, and removing contexts. Module
|
|
143
|
+
generation uses the project's configured `module_scaffolding` and language output
|
|
144
|
+
root, so Python, TypeScript, and PHP profiles place generated files under their
|
|
145
|
+
own layout conventions.
|
|
146
|
+
|
|
147
|
+
Bundled project profiles currently include:
|
|
148
|
+
|
|
149
|
+
- `python-fastapi-ddd-uv`
|
|
150
|
+
- `typescript-nestjs-ddd-pnpm`
|
|
151
|
+
- `php-symfony-ddd-composer`
|
|
152
|
+
|
|
82
153
|
## Configuration
|
|
83
154
|
|
|
84
155
|
Boundary tags classify source IDs. Flow rules then use those tags to detect
|
|
@@ -33,6 +33,7 @@ classifiers = [
|
|
|
33
33
|
"Topic :: Software Development :: Quality Assurance",
|
|
34
34
|
]
|
|
35
35
|
dependencies = [
|
|
36
|
+
"copier>=9.16.0",
|
|
36
37
|
"modwire-extraction>=1.0.1",
|
|
37
38
|
"pydantic>=2.8",
|
|
38
39
|
]
|
|
@@ -72,6 +73,16 @@ cache-dir = ".dev/ruff_cache"
|
|
|
72
73
|
package-dir = {"" = "src"}
|
|
73
74
|
include-package-data = true
|
|
74
75
|
|
|
76
|
+
[tool.setuptools.package-data]
|
|
77
|
+
"modwire.modules" = [
|
|
78
|
+
"scaffoldings/*/copier.yml",
|
|
79
|
+
"scaffoldings/*/template/**/*.jinja",
|
|
80
|
+
]
|
|
81
|
+
"modwire.projects" = [
|
|
82
|
+
"scaffoldings/*/copier.yml",
|
|
83
|
+
"scaffoldings/*/template/**/*.jinja",
|
|
84
|
+
]
|
|
85
|
+
|
|
75
86
|
[tool.setuptools.packages.find]
|
|
76
87
|
where = ["src"]
|
|
77
88
|
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '3.
|
|
22
|
-
__version_tuple__ = version_tuple = (3,
|
|
21
|
+
__version__ = version = '3.2.0'
|
|
22
|
+
__version_tuple__ = version_tuple = (3, 2, 0)
|
|
23
23
|
|
|
24
|
-
__commit_id__ = commit_id =
|
|
24
|
+
__commit_id__ = commit_id = None
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
from collections.abc import Iterator, Mapping
|
|
2
|
+
from contextlib import contextmanager
|
|
3
|
+
from importlib import resources
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
import copier
|
|
8
|
+
|
|
9
|
+
PathLike = str | Path
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@contextmanager
|
|
13
|
+
def _bundled_scaffolding_path(scaffolding: str) -> Iterator[Path]:
|
|
14
|
+
scaffoldings = resources.files("modwire.modules") / "scaffoldings" / scaffolding
|
|
15
|
+
with resources.as_file(scaffoldings) as path:
|
|
16
|
+
yield path
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def generate_module(
|
|
20
|
+
module_name: str,
|
|
21
|
+
target_root: PathLike,
|
|
22
|
+
template_root: PathLike | None = None,
|
|
23
|
+
*,
|
|
24
|
+
scaffolding: str = "layered",
|
|
25
|
+
data: Mapping[str, Any] | None = None,
|
|
26
|
+
overwrite: bool = False,
|
|
27
|
+
skip_tasks: bool = True,
|
|
28
|
+
) -> None:
|
|
29
|
+
if template_root is not None:
|
|
30
|
+
_run_copy(
|
|
31
|
+
Path(template_root),
|
|
32
|
+
target_root,
|
|
33
|
+
module_name,
|
|
34
|
+
data=data,
|
|
35
|
+
overwrite=overwrite,
|
|
36
|
+
skip_tasks=skip_tasks,
|
|
37
|
+
)
|
|
38
|
+
return
|
|
39
|
+
|
|
40
|
+
with _bundled_scaffolding_path(scaffolding) as resolved_template_root:
|
|
41
|
+
_run_copy(
|
|
42
|
+
resolved_template_root,
|
|
43
|
+
target_root,
|
|
44
|
+
module_name,
|
|
45
|
+
data=data,
|
|
46
|
+
overwrite=overwrite,
|
|
47
|
+
skip_tasks=skip_tasks,
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _run_copy(
|
|
52
|
+
template_root: Path,
|
|
53
|
+
target_root: PathLike,
|
|
54
|
+
module_name: str,
|
|
55
|
+
*,
|
|
56
|
+
data: Mapping[str, Any] | None,
|
|
57
|
+
overwrite: bool,
|
|
58
|
+
skip_tasks: bool,
|
|
59
|
+
) -> None:
|
|
60
|
+
resolved_template_root = template_root
|
|
61
|
+
if not resolved_template_root.exists():
|
|
62
|
+
raise FileNotFoundError(f"Copier template does not exist: {resolved_template_root}")
|
|
63
|
+
|
|
64
|
+
template_data = dict(data or {})
|
|
65
|
+
template_data["module_name"] = module_name
|
|
66
|
+
|
|
67
|
+
copier.run_copy(
|
|
68
|
+
str(resolved_template_root),
|
|
69
|
+
dst_path=target_root,
|
|
70
|
+
data=template_data,
|
|
71
|
+
defaults=True,
|
|
72
|
+
overwrite=overwrite,
|
|
73
|
+
skip_tasks=skip_tasks,
|
|
74
|
+
)
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
_min_copier_version: "9.0.0"
|
|
2
|
+
_templates_suffix: ".jinja"
|
|
3
|
+
_subdirectory: template
|
|
4
|
+
|
|
5
|
+
module_name:
|
|
6
|
+
type: str
|
|
7
|
+
default: sample_module
|
|
8
|
+
help: Importable module or package directory name.
|
|
9
|
+
|
|
10
|
+
module_class_name:
|
|
11
|
+
type: str
|
|
12
|
+
default: "{{ module_name | replace('-', '_') | replace(' ', '_') | title | replace('_', '') }}"
|
|
13
|
+
help: PascalCase module name used to derive default class names.
|
|
14
|
+
|
|
15
|
+
aggregate_name:
|
|
16
|
+
type: str
|
|
17
|
+
default: "{{ module_class_name }}Aggregate"
|
|
18
|
+
help: Domain aggregate class name.
|
|
19
|
+
|
|
20
|
+
entity_name:
|
|
21
|
+
type: str
|
|
22
|
+
default: "{{ module_class_name }}Entity"
|
|
23
|
+
help: Domain entity class name.
|
|
24
|
+
|
|
25
|
+
use_case_name:
|
|
26
|
+
type: str
|
|
27
|
+
default: "Create{{ module_class_name }}"
|
|
28
|
+
help: Application use case class name.
|
|
29
|
+
|
|
30
|
+
repository_name:
|
|
31
|
+
type: str
|
|
32
|
+
default: "{{ module_class_name }}Repository"
|
|
33
|
+
help: Repository port and adapter class suffix.
|
|
34
|
+
|
|
35
|
+
controller_name:
|
|
36
|
+
type: str
|
|
37
|
+
default: "{{ module_class_name }}Controller"
|
|
38
|
+
help: Interface controller class name.
|
|
39
|
+
|
|
40
|
+
event_name:
|
|
41
|
+
type: str
|
|
42
|
+
default: "{{ module_class_name }}Created"
|
|
43
|
+
help: Domain event class name.
|
|
44
|
+
|
|
45
|
+
php_namespace:
|
|
46
|
+
type: str
|
|
47
|
+
default: "App\\{{ module_class_name }}"
|
|
48
|
+
help: PHP namespace root for the generated classes.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
declare(strict_types=1);
|
|
4
|
+
|
|
5
|
+
namespace {{ php_namespace }}\Application\Ports;
|
|
6
|
+
|
|
7
|
+
use {{ php_namespace }}\Domain\Entities\{{ entity_name }};
|
|
8
|
+
|
|
9
|
+
interface {{ repository_name }}
|
|
10
|
+
{
|
|
11
|
+
public function save({{ entity_name }} $entity): void;
|
|
12
|
+
|
|
13
|
+
public function get(string $entityId): ?{{ entity_name }};
|
|
14
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
declare(strict_types=1);
|
|
4
|
+
|
|
5
|
+
namespace {{ php_namespace }}\Application\UseCases;
|
|
6
|
+
|
|
7
|
+
use {{ php_namespace }}\Application\Ports\{{ repository_name }};
|
|
8
|
+
use {{ php_namespace }}\Domain\Entities\{{ entity_name }};
|
|
9
|
+
|
|
10
|
+
final class {{ use_case_name }}Command
|
|
11
|
+
{
|
|
12
|
+
public function __construct(
|
|
13
|
+
public readonly string $entityId,
|
|
14
|
+
public readonly string $name,
|
|
15
|
+
) {
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
final class {{ use_case_name }}
|
|
20
|
+
{
|
|
21
|
+
public function __construct(private readonly {{ repository_name }} $repository)
|
|
22
|
+
{
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
public function execute({{ use_case_name }}Command $command): {{ entity_name }}
|
|
26
|
+
{
|
|
27
|
+
$entity = {{ entity_name }}::create($command->entityId, $command->name);
|
|
28
|
+
$this->repository->save($entity);
|
|
29
|
+
|
|
30
|
+
return $entity;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
declare(strict_types=1);
|
|
4
|
+
|
|
5
|
+
namespace {{ php_namespace }}\Domain\Entities;
|
|
6
|
+
|
|
7
|
+
use {{ php_namespace }}\Domain\Events\{{ event_name }};
|
|
8
|
+
use {{ php_namespace }}\Domain\Exceptions\{{ entity_name }}ValidationException;
|
|
9
|
+
|
|
10
|
+
final class {{ entity_name }}
|
|
11
|
+
{
|
|
12
|
+
/** @var list<{{ event_name }}> */
|
|
13
|
+
private array $events = [];
|
|
14
|
+
|
|
15
|
+
private function __construct(
|
|
16
|
+
public readonly string $entityId,
|
|
17
|
+
public readonly string $name,
|
|
18
|
+
) {
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
public static function create(string $entityId, string $name): self
|
|
22
|
+
{
|
|
23
|
+
if ($entityId === '') {
|
|
24
|
+
throw new {{ entity_name }}ValidationException('Entity id cannot be empty');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if ($name === '') {
|
|
28
|
+
throw new {{ entity_name }}ValidationException('Entity name cannot be empty');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
$entity = new self($entityId, $name);
|
|
32
|
+
$entity->events[] = new {{ event_name }}($entityId, $name);
|
|
33
|
+
|
|
34
|
+
return $entity;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** @return list<{{ event_name }}> */
|
|
38
|
+
public function pullEvents(): array
|
|
39
|
+
{
|
|
40
|
+
$events = $this->events;
|
|
41
|
+
$this->events = [];
|
|
42
|
+
|
|
43
|
+
return $events;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
declare(strict_types=1);
|
|
4
|
+
|
|
5
|
+
namespace {{ php_namespace }}\Infrastructure\Persistence;
|
|
6
|
+
|
|
7
|
+
use {{ php_namespace }}\Application\Ports\{{ repository_name }};
|
|
8
|
+
use {{ php_namespace }}\Domain\Entities\{{ entity_name }};
|
|
9
|
+
|
|
10
|
+
final class InMemory{{ repository_name }} implements {{ repository_name }}
|
|
11
|
+
{
|
|
12
|
+
/** @var array<string, {{ entity_name }}> */
|
|
13
|
+
private array $items = [];
|
|
14
|
+
|
|
15
|
+
public function save({{ entity_name }} $entity): void
|
|
16
|
+
{
|
|
17
|
+
$this->items[$entity->entityId] = $entity;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
public function get(string $entityId): ?{{ entity_name }}
|
|
21
|
+
{
|
|
22
|
+
return $this->items[$entityId] ?? null;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
declare(strict_types=1);
|
|
4
|
+
|
|
5
|
+
namespace {{ php_namespace }}\Interface\Http;
|
|
6
|
+
|
|
7
|
+
use {{ php_namespace }}\Application\UseCases\{{ use_case_name }};
|
|
8
|
+
use {{ php_namespace }}\Application\UseCases\{{ use_case_name }}Command;
|
|
9
|
+
|
|
10
|
+
final class {{ controller_name }}
|
|
11
|
+
{
|
|
12
|
+
public function __construct(private readonly {{ use_case_name }} $useCase)
|
|
13
|
+
{
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** @return array{id: string, name: string} */
|
|
17
|
+
public function create(string $entityId, string $name): array
|
|
18
|
+
{
|
|
19
|
+
$entity = $this->useCase->execute(new {{ use_case_name }}Command($entityId, $name));
|
|
20
|
+
|
|
21
|
+
return ['id' => $entity->entityId, 'name' => $entity->name];
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Clean architecture module for {{ module_name }}."""
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Application business rules for {{ module_name }}."""
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Application ports."""
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Protocol
|
|
4
|
+
|
|
5
|
+
from ...domain.entities.{{ entity_name | lower }} import {{ entity_name }}
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class {{ repository_name }}(Protocol):
|
|
9
|
+
def save(self, entity: {{ entity_name }}) -> None:
|
|
10
|
+
...
|
|
11
|
+
|
|
12
|
+
def get(self, entity_id: str) -> {{ entity_name }} | None:
|
|
13
|
+
...
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Application use cases."""
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
|
|
5
|
+
from ...domain.entities.{{ entity_name | lower }} import {{ entity_name }}
|
|
6
|
+
from ..ports.{{ repository_name | lower }} import {{ repository_name }}
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass(frozen=True)
|
|
10
|
+
class {{ use_case_name }}Command:
|
|
11
|
+
entity_id: str
|
|
12
|
+
name: str
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class {{ use_case_name }}:
|
|
16
|
+
def __init__(self, repository: {{ repository_name }}) -> None:
|
|
17
|
+
self._repository = repository
|
|
18
|
+
|
|
19
|
+
def execute(self, command: {{ use_case_name }}Command) -> {{ entity_name }}:
|
|
20
|
+
entity = {{ entity_name }}.create(command.entity_id, command.name)
|
|
21
|
+
self._repository.save(entity)
|
|
22
|
+
return entity
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Enterprise business rules for {{ module_name }}."""
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Domain entities."""
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
|
|
5
|
+
from ..events.{{ event_name | lower }} import {{ event_name }}
|
|
6
|
+
from ..exceptions.{{ entity_name | lower }}validationerror import (
|
|
7
|
+
{{ entity_name }}ValidationError,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dataclass
|
|
12
|
+
class {{ entity_name }}:
|
|
13
|
+
entity_id: str
|
|
14
|
+
name: str
|
|
15
|
+
_events: list[{{ event_name }}] = field(
|
|
16
|
+
default_factory=list,
|
|
17
|
+
init=False,
|
|
18
|
+
repr=False,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
@classmethod
|
|
22
|
+
def create(cls, entity_id: str, name: str) -> "{{ entity_name }}":
|
|
23
|
+
if not entity_id:
|
|
24
|
+
raise {{ entity_name }}ValidationError("Entity id cannot be empty")
|
|
25
|
+
if not name:
|
|
26
|
+
raise {{ entity_name }}ValidationError("Entity name cannot be empty")
|
|
27
|
+
|
|
28
|
+
entity = cls(entity_id=entity_id, name=name)
|
|
29
|
+
entity._events.append({{ event_name }}(entity_id=entity_id, name=name))
|
|
30
|
+
return entity
|
|
31
|
+
|
|
32
|
+
def pull_events(self) -> tuple[{{ event_name }}, ...]:
|
|
33
|
+
events = tuple(self._events)
|
|
34
|
+
self._events.clear()
|
|
35
|
+
return events
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Domain events."""
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Domain exceptions."""
|