Problem
Filesystem layout rules for Language (KTS, GROOVY, BOTH) are duplicated across cli/src/main/kotlin/io/github/cdsap/projectgenerator/cli/GenerateProjectRequest.kt (resolveProjectRootPath) and project-generator/src/main/kotlin/io/github/cdsap/projectgenerator/ProjectGenerator.kt (getProjectLanguageAttributes). The CLI picks a root path and the generator expands it into LanguageAttributes, but both encode the same policy with no single source of truth.
Why This Matters
This is domain policy, not CLI or I/O detail. If one side changes (for example how --output-dir interacts with Language.BOTH) without the other, the CLI can report one location while files are written elsewhere. Tests are split across GenerateProjectsCliTest and ProjectGeneratorTest, so regressions are easy to miss.
Proposed Change
Add ProjectLayout in project-generator/src/main/kotlin/io/github/cdsap/projectgenerator/model/ with two pure functions: defaultRootPath(outputDir, language, projectName) (replacing resolveProjectRootPath) and languageAttributes(rootPath, language) (replacing getProjectLanguageAttributes). Update GenerateProjectRequest.resolve and ProjectGenerator.write() to delegate to it. Add focused unit tests in project-generator for all language/output-dir combinations.
Files
project-generator/src/main/kotlin/io/github/cdsap/projectgenerator/model/ProjectLayout.kt
project-generator/src/main/kotlin/io/github/cdsap/projectgenerator/ProjectGenerator.kt
cli/src/main/kotlin/io/github/cdsap/projectgenerator/cli/GenerateProjectRequest.kt
project-generator/src/test/kotlin/io/github/cdsap/projectgenerator/model/ProjectLayoutTest.kt
Constraints
- Preserve behavior.
- Preserve current generated directory structure and CLI flag behavior.
- Keep
--output-dir precedence over default projects_generated/<name>/... paths.
- Do not change
LanguageAttributes field semantics (extension, projectName).
- Keep this as a small refactor; do not perform a broad architecture migration.
- Do not change public APIs unless the issue explicitly requires it.
Acceptance Criteria
ProjectGenerator and GenerateProjectRequest both call ProjectLayout; no duplicate layout logic remains in those files.
- New
ProjectLayoutTest covers KTS, GROOVY, BOTH with and without outputDir.
./gradlew :project-generator:unitTest, ./gradlew :cli:test, and ./gradlew ktlintCheck pass without behavior changes.
- Existing behavior is preserved.
Validation
./gradlew :project-generator:unitTest
./gradlew :cli:test
./gradlew ktlintCheck
Notes
In clean-architecture terms, output layout is a domain policy consumed by the CLI adapter and the generation use case. Centralizing it in model/ keeps infrastructure (Clikt, File writers) separate from the rule of where each language variant lives on disk, and gives library callers the same layout contract the CLI uses.
Problem
Filesystem layout rules for Language (KTS, GROOVY, BOTH) are duplicated across
cli/src/main/kotlin/io/github/cdsap/projectgenerator/cli/GenerateProjectRequest.kt(resolveProjectRootPath) andproject-generator/src/main/kotlin/io/github/cdsap/projectgenerator/ProjectGenerator.kt(getProjectLanguageAttributes). The CLI picks a root path and the generator expands it intoLanguageAttributes, but both encode the same policy with no single source of truth.Why This Matters
This is domain policy, not CLI or I/O detail. If one side changes (for example how
--output-dirinteracts withLanguage.BOTH) without the other, the CLI can report one location while files are written elsewhere. Tests are split acrossGenerateProjectsCliTestandProjectGeneratorTest, so regressions are easy to miss.Proposed Change
Add
ProjectLayoutinproject-generator/src/main/kotlin/io/github/cdsap/projectgenerator/model/with two pure functions:defaultRootPath(outputDir, language, projectName)(replacingresolveProjectRootPath) andlanguageAttributes(rootPath, language)(replacinggetProjectLanguageAttributes). UpdateGenerateProjectRequest.resolveandProjectGenerator.write()to delegate to it. Add focused unit tests inproject-generatorfor all language/output-dir combinations.Files
project-generator/src/main/kotlin/io/github/cdsap/projectgenerator/model/ProjectLayout.ktproject-generator/src/main/kotlin/io/github/cdsap/projectgenerator/ProjectGenerator.ktcli/src/main/kotlin/io/github/cdsap/projectgenerator/cli/GenerateProjectRequest.ktproject-generator/src/test/kotlin/io/github/cdsap/projectgenerator/model/ProjectLayoutTest.ktConstraints
--output-dirprecedence over defaultprojects_generated/<name>/...paths.LanguageAttributesfield semantics (extension,projectName).Acceptance Criteria
ProjectGeneratorandGenerateProjectRequestboth callProjectLayout; no duplicate layout logic remains in those files.ProjectLayoutTestcovers KTS, GROOVY, BOTH with and withoutoutputDir../gradlew :project-generator:unitTest,./gradlew :cli:test, and./gradlew ktlintCheckpass without behavior changes.Validation
./gradlew :project-generator:unitTest./gradlew :cli:test./gradlew ktlintCheckNotes
In clean-architecture terms, output layout is a domain policy consumed by the CLI adapter and the generation use case. Centralizing it in
model/keeps infrastructure (Clikt,Filewriters) separate from the rule of where each language variant lives on disk, and gives library callers the same layout contract the CLI uses.