Skip to content

Commit beb009b

Browse files
authored
feat(csharp): derive C# namespace from metadata packages by default (#512)
* fix(csharp): derive namespaces from the metadata package when none is configured * no-mistakes(review): Add package usings to home-namespace C# generators * no-mistakes(review): Scope derived home to in-scope packages; widen compile test * no-mistakes(review): Derive home namespace from in-scope packages only * no-mistakes(document): Docs updated for derived C# namespace default. 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. * no-mistakes(lint): Regenerate showcase site payload for derived C# namespace
1 parent 8957798 commit beb009b

23 files changed

Lines changed: 348 additions & 52 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -249,13 +249,15 @@ here.**
249249
committed output, so output generated under another namespace is drift. A C# namespace comes
250250
from the package bindings (`GenConfig.TypeOverrides`, then `PackageNamespaces`, then the
251251
`Convention` rule, then `UnmappedStrategy`, each keyed by an object's own metadata package);
252-
the default `Flatten` strategy places every type in one namespace, `--namespace` or else the
253-
new `csharp.namespace` key in `.metaobjects/config.json`. There is no default value: the
254-
constant `Generated` is gone, and a run that emits a file needing the namespace without one
255-
set stops and asks for it (a run that emits nothing never does). A namespace that is not a
256-
dotted path of C# identifiers fails generation. **Upgrade step:** set
257-
`"csharp": { "namespace": "<ns>" }` to the namespace your committed output uses (`Generated`
258-
if you never passed `--namespace`), so `gen` and a bare `dotnet meta verify` both use it. `dotnet meta gen`, `verify --codegen`, `init`
252+
with nothing configured, each type's namespace is derived from its own metadata package (each
253+
`::` segment PascalCased, joined with `.`: `acme::billing` is `Acme.Billing`), and the types that
254+
belong to no single package (`AppDbContext`, routes) land in the namespace every package shares.
255+
`csharp.namespace` in `.metaobjects/config.json` (or `--namespace`) replaces the derived default
256+
with one flat namespace for types no binding places. A namespace that is not a dotted path of C#
257+
identifiers fails generation, naming the metadata package it came from. **Upgrade step:** a
258+
project that set no namespace now gets namespaces derived from its packages instead of
259+
`Generated`; to keep the namespace you generated with before, set
260+
`"csharp": { "namespace": "Generated" }` (or whatever your committed output uses). `dotnet meta gen`, `verify --codegen`, `init`
259261
and `eject` no longer check whether `codegen/Program.cs` runs `Generators.All`.
260262
**Upgrade step:** if `codegen/Program.cs` builds its own generator list, replace that list
261263
with `Generators.All`. Such a project still runs its own list and ignores

‎agent-context/skills/metaobjects-codegen/references/csharp.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,9 @@ set and no separate docs command. `--generators <names>` narrows a run to entrie
106106
list already declares, by stable name; it never adds one, and naming an entry the list
107107
does not declare is refused. `dotnet meta gen --list` is the catalog of what the port
108108
registers, not what this project runs; under each name it prints the expression that lists
109-
that generator in `codegen/Generators.cs` and its options. Output lands under `--namespace` in
110-
`--out` unless a generator's own init properties say otherwise — documentation
111-
does (below).
109+
that generator in `codegen/Generators.cs` and its options. Output lands in `--out`, in the
110+
namespace its metadata package maps to (see `docs/ports/csharp.md`), unless a generator's own
111+
init properties say otherwise — documentation does (below).
112112

113113
| Stable name | Entry in `codegen/Generators.cs` (`new MetaObjects.Codegen.Generators.…`) | Output |
114114
|---|---|---|

‎docs/features/cli.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -217,9 +217,9 @@ the committed `--out` tree, never touching it), and a **clean `--db` rejection
217217
directory and `codegen/Generators.cs` are present, `--codegen`. The output directory is
218218
`csharp.outDir` in `.metaobjects/config.json` (the same setting `gen` writes to); `--out <dir>`
219219
wins over it. With neither, the codegen gate is skipped with a note that names the setting. The
220-
namespace for types no package binding places is `--namespace`, else `csharp.namespace` there,
221-
read the same way by `gen` and `verify`; a run that emits such a type with neither set stops and
222-
asks for one. A bare run prints the subverb note. The **Java/Kotlin `mvn metaobjects:verify`** port expresses the same vocabulary as a
220+
namespace of each type comes from its metadata package (`acme::billing` is `Acme.Billing`);
221+
`csharp.namespace` there (or `--namespace`) replaces that with one flat namespace for types no
222+
package binding places, read the same way by `gen` and `verify`. A bare run prints the subverb note. The **Java/Kotlin `mvn metaobjects:verify`** port expresses the same vocabulary as a
223223
`mode` parameter (Maven goals are parameter-driven, not flag-driven). With `mode` unset the goal
224224
runs both gates below, skipping the template gate with a note when no `templateRoot` is set.
225225
`-Dmeta.verify.mode=codegen`

‎docs/ports/csharp.md‎

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -207,12 +207,14 @@ directory holding `.metaobjects/`:
207207
Each generated type's namespace comes from the package bindings, keyed by that type's own
208208
metadata package: a type-level override (`GenConfig.TypeOverrides`), then a package-level one
209209
(`PackageNamespaces`), then the `Convention` rule (strip a package prefix, prepend a root, case
210-
each `::` segment), then `UnmappedStrategy`. The default strategy, `Flatten`, puts every type in
211-
one namespace: `--namespace` when given, else `csharp.namespace`. There is no built-in value, so
212-
a run that emits a file needing it with neither set stops and names both; a run that emits
213-
nothing never asks. The namespace must be a dotted path of C# identifiers. `dotnet meta gen` and
214-
`verify` set only that flat namespace; the per-package bindings are `GenConfig` properties, set
215-
when you run codegen from your own code with `CodegenRunner`.
210+
each `::` segment), then `UnmappedStrategy`. With none of those configured, the default
211+
convention applies: each `::` segment PascalCased and joined with `.` (`acme::billing` is
212+
`Acme.Billing`), and the artifacts that belong to no single package (`AppDbContext`, routes) land in
213+
the namespace all the packages share. When they share no root, generation stops and asks for a
214+
namespace. Setting `--namespace` or `csharp.namespace` switches the default off and puts every type
215+
no binding places in that one flat namespace. The namespace must be a dotted path of C#
216+
identifiers. `dotnet meta gen` and `verify` set only that flat namespace; the per-package bindings
217+
are `GenConfig` properties, set when you run codegen from your own code with `CodegenRunner`.
216218

217219
With that, `dotnet meta gen` writes there, `dotnet meta verify --codegen` diffs against it, and
218220
a plain `dotnet meta verify` in CI runs the codegen gate with no flags. `--out <dir>` still works

‎examples/showcase/.metaobjects/.gen-state/.hashes.json‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
{
2-
"generated/csharp/AppDbContext.g.cs": "314c6078030ba151687430b37e6b6ea936238bb5df02df238e4acce2f95a430d",
3-
"generated/csharp/Subscriber.g.cs": "3ca160941378fbb8b6ad6acf080ff85573f463931e21b8756873a4476e5dd163",
4-
"generated/csharp/SubscriberBlurbPayload.g.cs": "6b1ce5b5a4018c647586d86125718c4764ae5d6eeb94e9545e8006a7ec2b2b6f",
5-
"generated/csharp/SubscriberFilterAllowlist.g.cs": "7428d47f6ccb64bb315266ee0564fa3803736623a34ab491435c042848c5d472",
6-
"generated/csharp/SubscriberNames.g.cs": "91f6eba78657b31fceef7021c6ca6bd799524dcb5120acbc8fcbe18786787174",
7-
"generated/csharp/SubscriberRoutes.g.cs": "acb153e2aac648a487d78d6d5321c0f250451f47b691f988e3b99ff410bcfa06",
2+
"generated/csharp/AppDbContext.g.cs": "4d441b4283d074cd98d11385bd8c9a2294a9378d3b392b451aea3130b5d2ca28",
3+
"generated/csharp/Subscriber.g.cs": "a7701fda82e3eb27dad5a01f326c0893ecd2ac418eea6e3afc5c4a2b81535bc2",
4+
"generated/csharp/SubscriberBlurbPayload.g.cs": "29eb3a6ce64496ffe734cba55d0213994316b4281d3fa6791917393bae36c9ed",
5+
"generated/csharp/SubscriberFilterAllowlist.g.cs": "3839b04884e4e393d4f7d7bf4c7d4fe5b3852bd3a92b1ecb282cb8935a3c98e5",
6+
"generated/csharp/SubscriberNames.g.cs": "c2cf0248c2ecde155ec2623604771e39bed23783603d6f18a2ed82967227a732",
7+
"generated/csharp/SubscriberRoutes.g.cs": "15450e230d396a739d789340c42488da354c22265193b5ac61b074b0ba6fb1ff",
88
"generated/python/Subscriber.py": "9dd4c0acea47f99d1daf79930f9de2e400f30780ebce6c63f023be528a72b762",
99
"generated/python/SubscriberBlurbPayload.py": "a5ef8a08e63efbe0f73e39a21a368cff5150c68cc8beeea6e8aab0c755f8bbdd",
1010
"generated/python/__init__.py": "daa04cec586768866d0996c779f62073e6773fe63750ff668327991fac2fd0f5",

‎examples/showcase/generated/csharp/AppDbContext.g.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
#nullable enable
44
using Microsoft.EntityFrameworkCore;
55

6-
namespace Generated;
6+
namespace Acme;
77

88
public class AppDbContext : DbContext
99
{

‎examples/showcase/generated/csharp/Subscriber.g.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
using System.ComponentModel.DataAnnotations;
77
using System.ComponentModel.DataAnnotations.Schema;
88

9-
namespace Generated;
9+
namespace Acme;
1010

1111
[Table(SubscriberNames.SourcePrimaryTable)]
1212
public class Subscriber

‎examples/showcase/generated/csharp/SubscriberBlurbPayload.g.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
using System.ComponentModel.DataAnnotations.Schema;
88
using System.Text.Json.Serialization;
99

10-
namespace Generated;
10+
namespace Acme;
1111

1212
public class SubscriberBlurbPayload
1313
{

‎examples/showcase/generated/csharp/SubscriberFilterAllowlist.g.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
#nullable enable
44
using System.Collections.Generic;
55

6-
namespace Generated;
6+
namespace Acme;
77

88
/// <summary>
99
/// GENERATED — per-entity FR-009 filter allowlist for Subscriber.

‎examples/showcase/generated/csharp/SubscriberNames.g.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
#nullable enable
44
using System.Collections.Generic;
55

6-
namespace Generated;
6+
namespace Acme;
77

88
/// <summary>
99
/// GENERATED — per-object physical database names for Subscriber (spec A1/A2/A6).

0 commit comments

Comments
 (0)