Files
SpacetimeDB/crates/codegen/examples/regen-csharp-moduledef.rs
clockwork-labs-bot dd2c95f113 Move CaseConversionPolicy to public SpacetimeDB namespace (#4382)
Move `CaseConversionPolicy` from `SpacetimeDB.Internal` to the public
`SpacetimeDB` namespace so module authors can write:

```csharp
[SpacetimeDB.Settings]
public const CaseConversionPolicy CASE_CONVERSION_POLICY = CaseConversionPolicy.SnakeCase;
```

instead of the verbose:

```csharp
public const SpacetimeDB.Internal.CaseConversionPolicy CASE_CONVERSION_POLICY = SpacetimeDB.Internal.CaseConversionPolicy.SnakeCase;
```

### Changes
- Move enum definition from `SpacetimeDB.Internal` to `SpacetimeDB`
namespace in autogen
- Fully qualify all `Internal` references to
`SpacetimeDB.CaseConversionPolicy`
- Codegen source generator accepts both
`SpacetimeDB.CaseConversionPolicy` and
`SpacetimeDB.Internal.CaseConversionPolicy` for backward compatibility
- Updated test fixture and verified snapshots
- All 4 codegen tests pass

---------

Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
2026-02-20 22:21:46 +00:00

91 lines
3.3 KiB
Rust

//! This script is used to generate the C# bindings for the `RawModuleDef` type.
//! Run `cargo run --example regen-csharp-moduledef` to update C# bindings whenever the module definition changes.
use fs_err as fs;
use regex::Regex;
use spacetimedb_codegen::{csharp, generate, CodegenOptions, OutputFile};
use spacetimedb_lib::{RawModuleDef, RawModuleDefV8};
use spacetimedb_schema::def::ModuleDef;
use std::path::Path;
use std::sync::OnceLock;
macro_rules! regex_replace {
($value:expr, $re:expr, $replace:expr) => {{
static RE: OnceLock<Regex> = OnceLock::new();
RE.get_or_init(|| Regex::new($re).unwrap())
.replace_all($value, $replace)
}};
}
fn main() -> anyhow::Result<()> {
let module = RawModuleDefV8::with_builder(|module| {
module.add_type::<RawModuleDef>();
});
let dir = &Path::new(concat!(
env!("CARGO_MANIFEST_DIR"),
"/../bindings-csharp/Runtime/Internal/Autogen"
))
.canonicalize()?;
fs::remove_dir_all(dir)?;
fs::create_dir(dir)?;
let module: ModuleDef = module.try_into()?;
generate(
&module,
&csharp::Csharp {
namespace: "SpacetimeDB.Internal",
},
&CodegenOptions::default(),
)
.into_iter()
.try_for_each(|OutputFile { filename, code }| {
// Skip anything but raw types (in particular, this will skip top-level SpacetimeDBClient.g.cs which we don't need).
let Some(filename) = filename.strip_prefix("Types/") else {
return Ok(());
};
// Someday we might replace custom BSATN types with autogenerated ones as well,
// but for now they're not very large and our copies are somewhat more optimised.
//
// Ignore those types and replace their references with our own with plain old regexes.
if filename == "AlgebraicType.g.cs" || filename.starts_with("SumType") || filename.starts_with("ProductType") {
return Ok(());
}
// CaseConversionPolicy is part of the public API — move it to
// the SpacetimeDB namespace so users don't have to write
// SpacetimeDB.Internal.CaseConversionPolicy.
let code = if filename == "CaseConversionPolicy.g.cs" {
regex_replace!(&code, r"namespace SpacetimeDB\.Internal", "namespace SpacetimeDB")
} else {
// In other autogen files, qualify the type name in type position
// (before a space+identifier) so it resolves after the namespace move.
// The pattern "CaseConversionPolicy CaseConversionPolicy" becomes
// "SpacetimeDB.CaseConversionPolicy CaseConversionPolicy".
regex_replace!(
&code,
r"\bCaseConversionPolicy(\s+)CaseConversionPolicy\b",
"SpacetimeDB.CaseConversionPolicy${1}CaseConversionPolicy"
)
};
let code = regex_replace!(&code, r"\bAlgebraicType\b", "SpacetimeDB.BSATN.$0");
let code = regex_replace!(
&code,
r"\b(ProductTypeElement|SumTypeVariant)\b",
"SpacetimeDB.BSATN.AggregateElement"
);
let code = regex_replace!(
&code,
r"\b(Product|Sum)Type\b",
"List<SpacetimeDB.BSATN.AggregateElement>"
);
fs::write(dir.join(filename), code.as_ref())
})?;
Ok(())
}