Repository navigation
feat(csharp): derive C# namespace from metadata packages by default - #512
Merged
Merged
Conversation
… Two stale spots fixed: the port doc paragraph (added the no-common-root failure, rewrapped) and the codegen skill reference, which now points to docs/ports/csharp.md. CHANGELOG and docs/features/cli.md were already updated by the change. No executable code or tests touched.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What Changed
::segment is PascalCased and joined with., soacme::billingbecomesAcme.Billing. Implemented asPackageBindingResolver.DefaultConvention, applied only when noConventionand no flat namespace are set.AppDbContext, routes) land in the common root of the model's packages.PackageBindingResolver.WithDerivedHomecomputes it per run, andCodegenRunnerapplies it. A model whose packages share no root still fails, with a message that names the setting.csharp.namespaceand--namespacestill set one flat namespace and replace the derived default. Generators that emit into the home namespace addusingdirectives for types resolved elsewhere (HomeUsings). Changes are covered by the newDerivedNamespaceTests.csand updated namespace tests, and by regenerated showcase output.Validation
Risk Assessment
✅ Low: Default package-derived C# namespace with a derived home is implemented, now filters to in-scope packages, emits usings for cross-package references, and tests exercise zero-config, override, dependency-import and multi-package compile cases.
Testing
Baseline ts-fast/ts-unit green. Drove six live CLI scenarios with the branch-built dotnet meta gen in disposable projects: single-package default, multi-package default, out-of-scope dependency default, a dependency with a different root, the no-shared-root guard, and explicit namespace override. All behaved as the intent requires. Multi-package generated output compiles as a library with 0 errors. Full C# solution suite passed. Not live: report-export, TPH routes, shared Enums, output prompt/parser, extractor, callable and render helper were not generated or compiled live. They rely on unit tests only.</testing_summary> <artifacts>[{"label":"Live gen transcripts for the six C# namespace scenarios","kind":"log","path":"/csharp-default-namespace-gen-transcripts.txt"}]Evidence: Live gen transcripts for the six C# namespace scenarios
Pipeline
Updates from git push no-mistakes
✅ **Intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
🔧 **Review** - 1 issue found → auto-fixed (3) ✅
server/csharp/MetaObjects.Codegen/Generators/RoutesGenerator.cs:290- Default per-package namespaces put routes in the shared home namespace, but they emit nousingfor the entity's package namespace. A multi-package model with nothing configured now generates C# that does not compile. Example: packagesacme::billingandacme::crm, nocsharp.namespace.Invoicegoes toAcme.Billing;InvoiceRoutes.g.csgoes toAcmeand referencesInvoiceandInvoiceNames.*with only framework usings. Result: CS0246 in the adopter's build, whilegenexits 0. Before this change that split layout needed explicit PackageNamespaces/Convention; now it is the default for every multi-package model.DerivedNamespaceTests.A_multi_package_model_compilescompiles only Entity, DbContext and FilterAllowlist, so it skips the broken tier. Remedy: emitusingfor the entity's resolved namespace (as the ReverseFinders hunk does) or emit per-entity artifacts into the entity namespace, then add Routes, ReportExport and the other home-namespace generators to the compile test. Same invariant at: RoutesGenerator.cs:600 (TPH routes, same missing using); ReportExportGenerator.cs:103,138 (export class in home ns, row type in package ns); EntityGenerator.cs:969 (shared Enums.g.cs in home ns); CSharpNaming.cs:1131 (QualifiedOwnerTypeRefusesglobal::{config.Namespace}.{owner}, wrong for a package-namespaced owner); OutputPromptGenerator.cs:68, OutputParserGenerator.cs:113 and ExtractorGenerator.cs:73,138 (home ns; need a check that their entity/payload references resolve).🔧 Fix applied.
2 warnings still open:
server/csharp/MetaObjects.Codegen/PackageBindingResolver.cs:38- WithDerivedHome computes the home namespace from every root-level object (root.Objects()), including objects imported from metadata dependencies (FR-023). CodegenRunner only generates forroot.InScope(o)objects (CodegenRunner.cs:66,77). With nothing configured, a project inacme::shopthat imports a dependency invendor::libgets no common prefix.DerivedHomestays unset, andAppDbContext, routes, filter allowlists, sharedEnums.g.csand the other home-namespace artifacts throw "no C# namespace ... (the metadata packages share no common root ...)". The failure is caused by objects the project does not generate. This is the exact zero-config case the intent targets. Remedy: filter the package set withroot.InScope(o), matching the runner. Same invariant at the call site CodegenRunner.cs:48 (the only caller that passes the full root).server/csharp/MetaObjects.Codegen.Tests/DerivedNamespaceTests.cs:126- The previous round's instruction was to add every home-namespace generator to a multi-package, no-namespace compile test.A_multi_package_model_compilesstill compiles only Entity, DbContext, FilterAllowlist, Names and ReportExport, with Routes excluded (checked by parsing its usings instead). OutputParser, OutputPrompt, Extractor, Callable, RenderHelper and the sharedEnums.g.cs(a shared field.enum consumed from a package namespace) have no multi-package fixture. They resolve today because they useglobal::-qualified refs or the enclosing-namespace lookup from the derived home. A regression in any of them would ship as CS0246 whilegenexits 0. Remedy: add a template.prompt with @responseRef/@payloadRef, a stored-proc callable and a shared enum in the second package to the fixture, and include those generators in the compile list.🔧 Fix applied.
2 warnings still open:
server/csharp/MetaObjects.Codegen/PackageBindingResolver.cs:38- WithDerivedHome computes the home namespace from every root-level object (root.Objects()), including objects imported from metadata dependencies (FR-023). CodegenRunner only generates forroot.InScope(o)objects (CodegenRunner.cs:66,77). With nothing configured, a project inacme::shopthat imports a dependency invendor::libgets no common prefix.DerivedHomestays unset, andAppDbContext, routes, filter allowlists, sharedEnums.g.csand the other home-namespace artifacts throw "no C# namespace ... (the metadata packages share no common root ...)". The failure is caused by objects the project does not generate. This is the exact zero-config case the intent targets. Remedy: filter the package set withroot.InScope(o), matching the runner. Same invariant at the call site CodegenRunner.cs:48 (the only caller that passes the full root).server/csharp/MetaObjects.Codegen/PackageBindingResolver.cs:38- Round 2 fix not applied. WithDerivedHome still readsroot.Objects(), including objects imported from metadata dependencies (FR-023), while CodegenRunner generates onlyroot.InScope(o)objects (CodegenRunner.cs:66,77). The round-2 commit (48d03ec) touched only DerivedNamespaceTests.cs and left this source unchanged, despite its message. With nothing configured, a project inacme::shopimportingvendor::libgets no common prefix. DerivedHome stays unset, and AppDbContext, routes, filter allowlists, shared Enums.g.cs and the other home-namespace artifacts throw "no C# namespace ... (the metadata packages share no common root ...)". The failure comes from objects the project does not generate, in the zero-config case the intent targets. Remedy: filter with.Where(root.InScope)beforeEffectivePackage. The fixture has no dependency import, so no test catches this; add one with an out-of-scope package in a different root.🔧 Fix applied.
✅ Re-checked - no issues remain.
✅ **Test** - passed
✅ No issues found.
scripts/ci-local.sh --only ts-fast --only ts-unit --strict-toolchainscd server/csharp && dotnet build MetaObjects.Cli -c Release -o <tmp>/cli (branch CLI built into a temp dir outside the worktree)dotnet <tmp>/cli/MetaObjects.Cli.dll init then gen in disposable projects; codegen/Codegen.csproj ProjectReferences the worktree MetaObjects.Codegens1: package acme::shop, nothing configured -> Subscriber.g.cs namespace Acme.Shop, exit 0s2: packages acme::billing + acme::crm, nothing configured -> Acme.Billing, Acme.Crm, shared files in Acme, exit 0s2 compile: scratch Sdk.Web library csproj over Generated/**/*.cs with ProjectReference to worktree MetaObjects, MetaObjects.Render, MetaObjects.Codegen -> Build succeeded, 0 errorss3: acme::billing + acme::crm plus dependency acme-common (acme::common, out of scope), nothing configured -> exit 0s6: entity app::orders plus dependency acme::common, nothing configured -> exit 0, all artifacts in App.Orderss4 guard: alpha::x and beta::y, nothing configured -> exit 1 with the named csharp.namespace / --namespace errors5: acme::billing + acme::crm with csharp.namespace Acme.Blog -> all files Acme.Blog, exit 0Transcripts: <evidence-dir>/csharp-default-namespace-gen-transcripts.txtcd server/csharp && dotnet test MetaObjects.sln -> Render 364, Conformance 2195, Codegen 1086 (1 skipped), Cli 345, all passedgit status in worktree after testing: clean✅ **Document** - passed
✅ No issues found.
🔧 **Lint** - 1 issue found → auto-fixed ✅
🔧 Fix applied.
✅ Re-checked - no issues remain.
✅ **Push** - passed
✅ No issues found.