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.
Files changed (256) hide show
  1. {modwire-3.0.0 → modwire-3.2.0}/.github/workflows/release.yml +11 -1
  2. {modwire-3.0.0 → modwire-3.2.0}/CHANGELOG.md +19 -1
  3. {modwire-3.0.0 → modwire-3.2.0}/PKG-INFO +73 -1
  4. {modwire-3.0.0 → modwire-3.2.0}/README.md +71 -0
  5. {modwire-3.0.0 → modwire-3.2.0}/pyproject.toml +11 -0
  6. {modwire-3.0.0 → modwire-3.2.0}/src/modwire/_version.py +3 -3
  7. modwire-3.2.0/src/modwire/modules/__init__.py +3 -0
  8. modwire-3.2.0/src/modwire/modules/generate.py +74 -0
  9. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/copier.yml +48 -0
  10. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/php/src/Application/Ports/{{ repository_name }}.php.jinja +14 -0
  11. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/php/src/Application/UseCases/{{ use_case_name }}.php.jinja +32 -0
  12. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/php/src/Domain/Entities/{{ entity_name }}.php.jinja +45 -0
  13. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/php/src/Domain/Events/{{ event_name }}.php.jinja +14 -0
  14. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/php/src/Domain/Exceptions/{{ entity_name }}ValidationException.php.jinja +11 -0
  15. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/php/src/Infrastructure/Persistence/InMemory{{ repository_name }}.php.jinja +24 -0
  16. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/php/src/Interface/Http/{{ controller_name }}.php.jinja +23 -0
  17. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/__init__.py.jinja +1 -0
  18. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/application/__init__.py.jinja +1 -0
  19. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/application/ports/__init__.py.jinja +1 -0
  20. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/application/ports/{{ repository_name | lower }}.py.jinja +13 -0
  21. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/application/use_cases/__init__.py.jinja +1 -0
  22. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/application/use_cases/{{ use_case_name | lower }}.py.jinja +22 -0
  23. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/domain/__init__.py.jinja +1 -0
  24. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/domain/entities/__init__.py.jinja +1 -0
  25. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/domain/entities/{{ entity_name | lower }}.py.jinja +35 -0
  26. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/domain/events/__init__.py.jinja +1 -0
  27. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/domain/events/{{ event_name | lower }}.py.jinja +7 -0
  28. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/domain/exceptions/__init__.py.jinja +1 -0
  29. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/domain/exceptions/{{ entity_name | lower }}validationerror.py.jinja +2 -0
  30. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/infrastructure/__init__.py.jinja +1 -0
  31. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/infrastructure/persistence/__init__.py.jinja +1 -0
  32. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/infrastructure/persistence/inmemory{{ repository_name | lower }}.py.jinja +14 -0
  33. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/interface/__init__.py.jinja +1 -0
  34. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/interface/http/__init__.py.jinja +1 -0
  35. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/interface/http/{{ controller_name | lower }}.py.jinja +15 -0
  36. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/typescript/{{ module_name }}/application/ports/{{ repository_name }}.ts.jinja +6 -0
  37. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/typescript/{{ module_name }}/application/use_cases/{{ use_case_name }}.ts.jinja +19 -0
  38. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/typescript/{{ module_name }}/domain/entities/{{ entity_name }}.ts.jinja +31 -0
  39. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/typescript/{{ module_name }}/domain/events/{{ event_name }}.ts.jinja +6 -0
  40. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/typescript/{{ module_name }}/domain/exceptions/{{ entity_name }}ValidationError.ts.jinja +1 -0
  41. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/typescript/{{ module_name }}/infrastructure/persistence/InMemory{{ repository_name }}.ts.jinja +14 -0
  42. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/typescript/{{ module_name }}/interface/http/{{ controller_name }}.ts.jinja +10 -0
  43. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/copier.yml +68 -0
  44. 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
  45. 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
  46. 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
  47. 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
  48. 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
  49. 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
  50. 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
  51. 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
  52. 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
  53. 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
  54. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/__init__.py.jinja +1 -0
  55. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/__init__.py.jinja +1 -0
  56. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/__init__.py.jinja +1 -0
  57. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/application/__init__.py.jinja +1 -0
  58. 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
  59. 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
  60. 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
  61. 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
  62. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/domain/__init__.py.jinja +1 -0
  63. 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
  64. 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
  65. 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
  66. 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
  67. 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
  68. 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
  69. 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
  70. 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
  71. 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
  72. 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
  73. 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
  74. 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
  75. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/infrastructure/__init__.py.jinja +1 -0
  76. 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
  77. 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
  78. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/interface/__init__.py.jinja +1 -0
  79. 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
  80. 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
  81. 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
  82. 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
  83. 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
  84. 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
  85. 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
  86. 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
  87. 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
  88. 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
  89. 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
  90. 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
  91. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/copier.yml +43 -0
  92. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/php/src/Adapters/Inbound/Amqp/{{ command_name }}Consumer.php.jinja +23 -0
  93. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/php/src/Adapters/Inbound/Web/{{ controller_name }}.php.jinja +23 -0
  94. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/php/src/Adapters/Inbound/{{ service_name }}.php.jinja +25 -0
  95. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/php/src/Adapters/Outbound/Client/{{ aggregate_name }}Client.php.jinja +14 -0
  96. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/php/src/Adapters/Outbound/Persistence/InMemory{{ repository_name }}.php.jinja +24 -0
  97. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/php/src/Domain/Events/{{ aggregate_name }}Created.php.jinja +14 -0
  98. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/php/src/Domain/Exceptions/{{ aggregate_name }}ValidationException.php.jinja +11 -0
  99. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/php/src/Domain/Models/{{ aggregate_name }}.php.jinja +45 -0
  100. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/php/src/Ports/Inbound/{{ command_name }}.php.jinja +14 -0
  101. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/php/src/Ports/Inbound/{{ service_name }}Port.php.jinja +12 -0
  102. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/php/src/Ports/Outbound/{{ repository_name }}.php.jinja +14 -0
  103. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/__init__.py.jinja +3 -0
  104. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/adapters/__init__.py.jinja +3 -0
  105. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/adapters/inbound/__init__.py.jinja +3 -0
  106. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/adapters/inbound/amqp/__init__.py.jinja +3 -0
  107. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/adapters/inbound/amqp/{{ command_name | lower }}consumer.py.jinja +17 -0
  108. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/adapters/inbound/web/__init__.py.jinja +3 -0
  109. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/adapters/inbound/web/{{ controller_name | lower }}.py.jinja +13 -0
  110. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/adapters/inbound/{{ service_name | lower }}.py.jinja +15 -0
  111. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/adapters/outbound/__init__.py.jinja +3 -0
  112. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/adapters/outbound/client/__init__.py.jinja +3 -0
  113. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/adapters/outbound/client/{{ aggregate_name | lower }}client.py.jinja +6 -0
  114. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/adapters/outbound/persistence/__init__.py.jinja +3 -0
  115. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/adapters/outbound/persistence/inmemory{{ repository_name | lower }}.py.jinja +14 -0
  116. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/domain/__init__.py.jinja +3 -0
  117. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/domain/events/__init__.py.jinja +3 -0
  118. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/domain/events/{{ aggregate_name | lower }}created.py.jinja +9 -0
  119. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/domain/exceptions/__init__.py.jinja +3 -0
  120. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/domain/exceptions/{{ aggregate_name | lower }}validationerror.py.jinja +5 -0
  121. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/domain/models/__init__.py.jinja +3 -0
  122. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/domain/models/{{ aggregate_name | lower }}.py.jinja +37 -0
  123. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/ports/__init__.py.jinja +3 -0
  124. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/ports/inbound/__init__.py.jinja +3 -0
  125. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/ports/inbound/{{ command_name | lower }}.py.jinja +9 -0
  126. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/ports/inbound/{{ service_name | lower }}.py.jinja +11 -0
  127. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/ports/outbound/__init__.py.jinja +3 -0
  128. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/ports/outbound/{{ repository_name | lower }}.py.jinja +13 -0
  129. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/typescript/{{ module_name }}/adapters/inbound/amqp/{{ command_name }}Consumer.ts.jinja +10 -0
  130. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/typescript/{{ module_name }}/adapters/inbound/web/{{ controller_name }}.ts.jinja +11 -0
  131. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/typescript/{{ module_name }}/adapters/inbound/{{ service_name }}.ts.jinja +13 -0
  132. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/typescript/{{ module_name }}/adapters/outbound/client/{{ aggregate_name }}Client.ts.jinja +5 -0
  133. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/typescript/{{ module_name }}/adapters/outbound/persistence/InMemory{{ repository_name }}.ts.jinja +14 -0
  134. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/typescript/{{ module_name }}/domain/events/{{ aggregate_name }}Created.ts.jinja +6 -0
  135. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/typescript/{{ module_name }}/domain/exceptions/{{ aggregate_name }}ValidationError.ts.jinja +1 -0
  136. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/typescript/{{ module_name }}/domain/models/{{ aggregate_name }}.ts.jinja +31 -0
  137. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/typescript/{{ module_name }}/ports/inbound/{{ command_name }}.ts.jinja +6 -0
  138. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/typescript/{{ module_name }}/ports/inbound/{{ service_name }}Port.ts.jinja +6 -0
  139. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/typescript/{{ module_name }}/ports/outbound/{{ repository_name }}.ts.jinja +6 -0
  140. modwire-3.2.0/src/modwire/modules/scaffoldings/layered/copier.yml +23 -0
  141. modwire-3.2.0/src/modwire/modules/scaffoldings/layered/template/{{ module_name }}/application.py.jinja +18 -0
  142. modwire-3.2.0/src/modwire/modules/scaffoldings/layered/template/{{ module_name }}/domain.py.jinja +12 -0
  143. modwire-3.2.0/src/modwire/modules/scaffoldings/layered/template/{{ module_name }}/infrastructure.py.jinja +11 -0
  144. modwire-3.2.0/src/modwire/modules/scaffoldings/layered/template/{{ module_name }}/ui.py.jinja +20 -0
  145. modwire-3.2.0/src/modwire/projects/__init__.py +13 -0
  146. modwire-3.2.0/src/modwire/projects/_operations.py +287 -0
  147. modwire-3.2.0/src/modwire/projects/generate.py +126 -0
  148. modwire-3.2.0/src/modwire/projects/profile.py +321 -0
  149. modwire-3.2.0/src/modwire/projects/root.py +70 -0
  150. modwire-3.2.0/src/modwire/projects/scaffoldings/php-symfony-ddd-composer/copier.yml +33 -0
  151. modwire-3.2.0/src/modwire/projects/scaffoldings/php-symfony-ddd-composer/template/.gitignore.jinja +5 -0
  152. modwire-3.2.0/src/modwire/projects/scaffoldings/php-symfony-ddd-composer/template/.modwire/project.json.jinja +1 -0
  153. modwire-3.2.0/src/modwire/projects/scaffoldings/php-symfony-ddd-composer/template/README.md.jinja +6 -0
  154. modwire-3.2.0/src/modwire/projects/scaffoldings/php-symfony-ddd-composer/template/bin/console.jinja +6 -0
  155. modwire-3.2.0/src/modwire/projects/scaffoldings/php-symfony-ddd-composer/template/composer.json.jinja +29 -0
  156. modwire-3.2.0/src/modwire/projects/scaffoldings/php-symfony-ddd-composer/template/config/routes.yaml.jinja +3 -0
  157. modwire-3.2.0/src/modwire/projects/scaffoldings/php-symfony-ddd-composer/template/openapi/.gitkeep.jinja +1 -0
  158. modwire-3.2.0/src/modwire/projects/scaffoldings/php-symfony-ddd-composer/template/src/Infrastructure/Clients/Generated/.gitkeep.jinja +1 -0
  159. modwire-3.2.0/src/modwire/projects/scaffoldings/php-symfony-ddd-composer/template/src/Kernel.php.jinja +13 -0
  160. modwire-3.2.0/src/modwire/projects/scaffoldings/php-symfony-ddd-composer/template/tests/KernelTest.php.jinja +16 -0
  161. modwire-3.2.0/src/modwire/projects/scaffoldings/python-fastapi-ddd-uv/copier.yml +90 -0
  162. modwire-3.2.0/src/modwire/projects/scaffoldings/python-fastapi-ddd-uv/template/.gitignore.jinja +10 -0
  163. modwire-3.2.0/src/modwire/projects/scaffoldings/python-fastapi-ddd-uv/template/.modwire/project.json.jinja +1 -0
  164. modwire-3.2.0/src/modwire/projects/scaffoldings/python-fastapi-ddd-uv/template/README.md.jinja +25 -0
  165. modwire-3.2.0/src/modwire/projects/scaffoldings/python-fastapi-ddd-uv/template/openapi/.gitkeep.jinja +1 -0
  166. modwire-3.2.0/src/modwire/projects/scaffoldings/python-fastapi-ddd-uv/template/pyproject.toml.jinja +38 -0
  167. modwire-3.2.0/src/modwire/projects/scaffoldings/python-fastapi-ddd-uv/template/src/{{ package_name }}/__init__.py.jinja +1 -0
  168. modwire-3.2.0/src/modwire/projects/scaffoldings/python-fastapi-ddd-uv/template/src/{{ package_name }}/cli.py.jinja +15 -0
  169. modwire-3.2.0/src/modwire/projects/scaffoldings/python-fastapi-ddd-uv/template/src/{{ package_name }}/infrastructure/__init__.py.jinja +1 -0
  170. modwire-3.2.0/src/modwire/projects/scaffoldings/python-fastapi-ddd-uv/template/src/{{ package_name }}/infrastructure/clients/__init__.py.jinja +1 -0
  171. modwire-3.2.0/src/modwire/projects/scaffoldings/python-fastapi-ddd-uv/template/src/{{ package_name }}/infrastructure/clients/generated/.gitkeep.jinja +1 -0
  172. modwire-3.2.0/src/modwire/projects/scaffoldings/python-fastapi-ddd-uv/template/src/{{ package_name }}/interface/__init__.py.jinja +1 -0
  173. modwire-3.2.0/src/modwire/projects/scaffoldings/python-fastapi-ddd-uv/template/src/{{ package_name }}/interface/http/__init__.py.jinja +1 -0
  174. modwire-3.2.0/src/modwire/projects/scaffoldings/python-fastapi-ddd-uv/template/src/{{ package_name }}/interface/http/router.py.jinja +8 -0
  175. modwire-3.2.0/src/modwire/projects/scaffoldings/python-fastapi-ddd-uv/template/src/{{ package_name }}/main.py.jinja +14 -0
  176. modwire-3.2.0/src/modwire/projects/scaffoldings/python-fastapi-ddd-uv/template/src/{{ package_name }}/settings.py.jinja +7 -0
  177. modwire-3.2.0/src/modwire/projects/scaffoldings/python-fastapi-ddd-uv/template/tests/test_health.py.jinja +12 -0
  178. modwire-3.2.0/src/modwire/projects/scaffoldings/typescript-nestjs-ddd-pnpm/copier.yml +33 -0
  179. modwire-3.2.0/src/modwire/projects/scaffoldings/typescript-nestjs-ddd-pnpm/template/.gitignore.jinja +5 -0
  180. modwire-3.2.0/src/modwire/projects/scaffoldings/typescript-nestjs-ddd-pnpm/template/.modwire/project.json.jinja +1 -0
  181. modwire-3.2.0/src/modwire/projects/scaffoldings/typescript-nestjs-ddd-pnpm/template/README.md.jinja +6 -0
  182. modwire-3.2.0/src/modwire/projects/scaffoldings/typescript-nestjs-ddd-pnpm/template/nest-cli.json.jinja +4 -0
  183. modwire-3.2.0/src/modwire/projects/scaffoldings/typescript-nestjs-ddd-pnpm/template/openapi/.gitkeep.jinja +1 -0
  184. modwire-3.2.0/src/modwire/projects/scaffoldings/typescript-nestjs-ddd-pnpm/template/package.json.jinja +22 -0
  185. modwire-3.2.0/src/modwire/projects/scaffoldings/typescript-nestjs-ddd-pnpm/template/src/app.module.ts.jinja +4 -0
  186. modwire-3.2.0/src/modwire/projects/scaffoldings/typescript-nestjs-ddd-pnpm/template/src/infrastructure/clients/generated/.gitkeep.jinja +1 -0
  187. modwire-3.2.0/src/modwire/projects/scaffoldings/typescript-nestjs-ddd-pnpm/template/src/main.ts.jinja +10 -0
  188. modwire-3.2.0/src/modwire/projects/scaffoldings/typescript-nestjs-ddd-pnpm/template/test/app.spec.ts.jinja +7 -0
  189. modwire-3.2.0/src/modwire/projects/scaffoldings/typescript-nestjs-ddd-pnpm/template/tsconfig.json.jinja +12 -0
  190. {modwire-3.0.0 → modwire-3.2.0}/src/modwire.egg-info/PKG-INFO +73 -1
  191. modwire-3.2.0/src/modwire.egg-info/SOURCES.txt +251 -0
  192. {modwire-3.0.0 → modwire-3.2.0}/src/modwire.egg-info/requires.txt +1 -0
  193. modwire-3.2.0/tests/modules/test_generate.py +210 -0
  194. modwire-3.2.0/tests/projects/test_project_generate.py +225 -0
  195. modwire-3.2.0/tests/projects/test_project_operations.py +156 -0
  196. {modwire-3.0.0 → modwire-3.2.0}/uv.lock +264 -0
  197. modwire-3.0.0/src/modwire.egg-info/SOURCES.txt +0 -67
  198. modwire-3.0.0/src/modwire.egg-info/scm_file_list.json +0 -63
  199. modwire-3.0.0/src/modwire.egg-info/scm_version.json +0 -8
  200. {modwire-3.0.0 → modwire-3.2.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  201. {modwire-3.0.0 → modwire-3.2.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  202. {modwire-3.0.0 → modwire-3.2.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  203. {modwire-3.0.0 → modwire-3.2.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  204. {modwire-3.0.0 → modwire-3.2.0}/.github/workflows/ci.yml +0 -0
  205. {modwire-3.0.0 → modwire-3.2.0}/.gitignore +0 -0
  206. {modwire-3.0.0 → modwire-3.2.0}/CONTRIBUTING.md +0 -0
  207. {modwire-3.0.0 → modwire-3.2.0}/LICENSE +0 -0
  208. {modwire-3.0.0 → modwire-3.2.0}/docs/wiki/Development-checks.md +0 -0
  209. {modwire-3.0.0 → modwire-3.2.0}/docs/wiki/Home.md +0 -0
  210. {modwire-3.0.0 → modwire-3.2.0}/docs/wiki/Reporting-bugs.md +0 -0
  211. {modwire-3.0.0 → modwire-3.2.0}/docs/wiki/Requesting-features.md +0 -0
  212. {modwire-3.0.0 → modwire-3.2.0}/setup.cfg +0 -0
  213. {modwire-3.0.0 → modwire-3.2.0}/src/modwire/__init__.py +0 -0
  214. {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/__init__.py +0 -0
  215. {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/boundaries/__init__.py +0 -0
  216. {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/boundaries/analyzers/__init__.py +0 -0
  217. {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/boundaries/analyzers/backward.py +0 -0
  218. {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/boundaries/analyzers/no_cycles.py +0 -0
  219. {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/boundaries/analyzers/no_reentry.py +0 -0
  220. {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/boundaries/base.py +0 -0
  221. {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/boundaries/config.py +0 -0
  222. {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/boundaries/map.py +0 -0
  223. {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/boundaries/pipeline.py +0 -0
  224. {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/boundaries/tags/__init__.py +0 -0
  225. {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/boundaries/tags/matcher.py +0 -0
  226. {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/boundaries/tags/tag_map.py +0 -0
  227. {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/config.py +0 -0
  228. {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/insight/__init__.py +0 -0
  229. {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/insight/base.py +0 -0
  230. {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/insight/pipeline.py +0 -0
  231. {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/insight/reports/__init__.py +0 -0
  232. {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/insight/reports/callables.py +0 -0
  233. {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/insight/reports/clusters.py +0 -0
  234. {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/insight/reports/coherence.py +0 -0
  235. {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/insight/reports/exports.py +0 -0
  236. {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/insight/reports/hotspots.py +0 -0
  237. {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/report.py +0 -0
  238. {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/root.py +0 -0
  239. {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/shape/__init__.py +0 -0
  240. {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/shape/base.py +0 -0
  241. {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/shape/config.py +0 -0
  242. {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/shape/pipeline.py +0 -0
  243. {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/shape/rules/__init__.py +0 -0
  244. {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/shape/rules/abstract_class_resolver.py +0 -0
  245. {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/shape/rules/callable_resolver.py +0 -0
  246. {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/shape/rules/class_resolver.py +0 -0
  247. {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/shape/rules/file_resolver.py +0 -0
  248. {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/shape/rules/import_resolver.py +0 -0
  249. {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/shape/rules/property_resolver.py +0 -0
  250. {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/shape/rules/signature_resolver.py +0 -0
  251. {modwire-3.0.0 → modwire-3.2.0}/src/modwire/architecture/shape/rules/symbol_resolver.py +0 -0
  252. {modwire-3.0.0 → modwire-3.2.0}/src/modwire.egg-info/dependency_links.txt +0 -0
  253. {modwire-3.0.0 → modwire-3.2.0}/src/modwire.egg-info/top_level.txt +0 -0
  254. {modwire-3.0.0 → modwire-3.2.0}/tests/architecture/boundaries/test_map.py +0 -0
  255. {modwire-3.0.0 → modwire-3.2.0}/tests/architecture/boundaries/test_pipeline.py +0 -0
  256. {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 = "${{ github.event.release.tag_name }}".removeprefix("v")
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.0.0 - Unreleased
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.0.0
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.0.0'
22
- __version_tuple__ = version_tuple = (3, 0, 0)
21
+ __version__ = version = '3.2.0'
22
+ __version_tuple__ = version_tuple = (3, 2, 0)
23
23
 
24
- __commit_id__ = commit_id = 'g84d5eeaca'
24
+ __commit_id__ = commit_id = None
@@ -0,0 +1,3 @@
1
+ from .generate import generate_module
2
+
3
+ __all__ = ["generate_module"]
@@ -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,14 @@
1
+ <?php
2
+
3
+ declare(strict_types=1);
4
+
5
+ namespace {{ php_namespace }}\Domain\Events;
6
+
7
+ final class {{ event_name }}
8
+ {
9
+ public function __construct(
10
+ public readonly string $entityId,
11
+ public readonly string $name,
12
+ ) {
13
+ }
14
+ }
@@ -0,0 +1,11 @@
1
+ <?php
2
+
3
+ declare(strict_types=1);
4
+
5
+ namespace {{ php_namespace }}\Domain\Exceptions;
6
+
7
+ use InvalidArgumentException;
8
+
9
+ final class {{ entity_name }}ValidationException extends InvalidArgumentException
10
+ {
11
+ }
@@ -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,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,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,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,7 @@
1
+ from dataclasses import dataclass
2
+
3
+
4
+ @dataclass(frozen=True)
5
+ class {{ event_name }}:
6
+ entity_id: str
7
+ name: str