Summary
sm new module <Name> produces an entity type whose name equals the module name when the singular form of <Name> equals <Name> itself (e.g. PageBuilder, Marketplace, Map). The generated code then has the entity type collide with the namespace, and the project fails to compile out of the box.
Repro
dotnet tool install -g SimpleModule.Cli # 0.0.36
sm new project Repro
cd Repro
sm new module PageBuilder
dotnet build
Expected
Module compiles cleanly. The generator either:
- Picks a different entity name when the singular collides with the module name (e.g.
PageBuilderItem, or singularize-then-suffix), or
- Uses an
--entity <Name> flag to let the user choose, or
- Errors at scaffold time with a friendly message asking for a non-colliding entity name.
Actual
3 build errors:
PageBuilderService.cs(8,35): error CS0118: 'PageBuilder' is a namespace but is used like a type
PageBuilderDbContext.cs(13,18): error CS0118: 'PageBuilder' is a namespace but is used like a type
PageBuilderService.cs(6,60): error CS0738: 'PageBuilderService' does not implement interface member 'IPageBuilderContracts.GetAllPageBuilderAsync()'. Cannot implement because of mismatched return type Task<IEnumerable<PageBuilder>>.
The generated files declare class PageBuilder inside namespace SimpleModule.PageBuilder.Contracts — and reference PageBuilder (the type) from sibling namespace SimpleModule.PageBuilder. Resolution picks the namespace, not the type, so PageBuilder in IEnumerable<PageBuilder> and DbSet<PageBuilder> won't compile.
Generated files involved
src/modules/PageBuilder/src/PageBuilder.Contracts/PageBuilder.cs — public class PageBuilder
src/modules/PageBuilder/src/PageBuilder.Contracts/IPageBuilderContracts.cs — Task<IEnumerable<PageBuilder>>
src/modules/PageBuilder/src/PageBuilder/PageBuilderDbContext.cs — DbSet<PageBuilder>
src/modules/PageBuilder/src/PageBuilder/PageBuilderService.cs — IEnumerable<PageBuilder>
Code path: ModuleTemplates.GetSingularName("PageBuilder") returns "PageBuilder" (no -s/-es to strip); the templates then use that singular as both the entity class name and as a member name, where it collides with the <Name> namespace.
Environment
sm --version: 0.0.36
dotnet --version: 10.0.201
- macOS (Darwin 25.4.0)
Suggestion
When singularName == moduleName, suffix the entity (e.g. ${moduleName}Entity or ${moduleName}Record) or add a --entity <Name> flag to sm new module that overrides the inferred entity name. The flag form is most flexible — and analogous to how sm new feature would benefit too.
Summary
sm new module <Name>produces an entity type whose name equals the module name when the singular form of<Name>equals<Name>itself (e.g.PageBuilder,Marketplace,Map). The generated code then has the entity type collide with the namespace, and the project fails to compile out of the box.Repro
Expected
Module compiles cleanly. The generator either:
PageBuilderItem, or singularize-then-suffix), or--entity <Name>flag to let the user choose, orActual
3 build errors:
The generated files declare
class PageBuilderinsidenamespace SimpleModule.PageBuilder.Contracts— and referencePageBuilder(the type) from sibling namespaceSimpleModule.PageBuilder. Resolution picks the namespace, not the type, soPageBuilderinIEnumerable<PageBuilder>andDbSet<PageBuilder>won't compile.Generated files involved
src/modules/PageBuilder/src/PageBuilder.Contracts/PageBuilder.cs—public class PageBuildersrc/modules/PageBuilder/src/PageBuilder.Contracts/IPageBuilderContracts.cs—Task<IEnumerable<PageBuilder>>src/modules/PageBuilder/src/PageBuilder/PageBuilderDbContext.cs—DbSet<PageBuilder>src/modules/PageBuilder/src/PageBuilder/PageBuilderService.cs—IEnumerable<PageBuilder>Code path:
ModuleTemplates.GetSingularName("PageBuilder")returns"PageBuilder"(no -s/-es to strip); the templates then use that singular as both the entity class name and as a member name, where it collides with the<Name>namespace.Environment
sm --version: 0.0.36dotnet --version: 10.0.201Suggestion
When
singularName == moduleName, suffix the entity (e.g.${moduleName}Entityor${moduleName}Record) or add a--entity <Name>flag tosm new modulethat overrides the inferred entity name. The flag form is most flexible — and analogous to howsm new featurewould benefit too.