Cohesive.CodeGen.Cli
0.1.0-alpha.120
See the version list below for details.
dotnet add package Cohesive.CodeGen.Cli --version 0.1.0-alpha.120
NuGet\Install-Package Cohesive.CodeGen.Cli -Version 0.1.0-alpha.120
<PackageReference Include="Cohesive.CodeGen.Cli" Version="0.1.0-alpha.120" />
<PackageVersion Include="Cohesive.CodeGen.Cli" Version="0.1.0-alpha.120" />
<PackageReference Include="Cohesive.CodeGen.Cli" />
paket add Cohesive.CodeGen.Cli --version 0.1.0-alpha.120
#r "nuget: Cohesive.CodeGen.Cli, 0.1.0-alpha.120"
#:package Cohesive.CodeGen.Cli@0.1.0-alpha.120
#addin nuget:?package=Cohesive.CodeGen.Cli&version=0.1.0-alpha.120&prerelease
#tool nuget:?package=Cohesive.CodeGen.Cli&version=0.1.0-alpha.120&prerelease
Cohesive.CodeGen.Cli
Cohesive.CodeGen.Cli is the build-facing entry point for Cohesive code generation.
Install
dotnet add package Cohesive.CodeGen.Cli
Its current job is:
- load a compiled contracts assembly
- project exported CLR contract types into Cohesive shape IR
- emit TypeScript, OpenAPI, and GraphQL artifacts into a target directory under a frontend app
The CLI is designed for build integration, idempotent writes, and incremental frontend workflows.
Current Scope
Implemented today:
shapes→ TypeScript declarations generated from exported CLR contractsapis→ TypeScript client functions generated from exportedApiDefinitionmembersopenapi→ OpenAPI 3.1 JSON generated from exportedApiDefinitionmembersgraphql→ GraphQL SDL and introspection JSON generated from exportedApiDefinitionmembers
Reserved for follow-on work:
transitionsprocessesinvariants
Usage
dotnet exec path/to/cohesive-codegen.dll \
--contracts path/to/MyApp.Contracts.dll \
--out path/to/generated \
--emit shapes,apis,openapi,graphql \
--module myapp
Equivalent conceptual tool form:
cohesive-codegen \
--contracts path/to/MyApp.Api.Contracts.dll \
--out path/to/generated \
--emit shapes,apis,openapi,graphql \
--module myapp
Arguments
--contractsPath to the compiled .NET assembly that contains exported API contract types.--outOutput directory for generated artifacts. For React + Vite this should usually be a folder undersrc/generated.--emitComma-separated list of artifact kinds. Todayshapes,apis,openapi, andgraphqlare implemented.--moduleLogical module name used in output filenames, for examplemyapp.shapes.generated.ts.--helpPrints CLI usage.
Output Behavior
For --emit shapes,apis,openapi,graphql, the CLI currently writes:
<module>.shapes.generated.ts<module>.api.generated.ts<module>.openapi.generated.json<module>.graphql.generated.graphql<module>.graphql.introspection.generated.json
Example:
myapp.shapes.generated.tsmyapp.api.generated.tsmyapp.openapi.generated.jsonmyapp.graphql.generated.graphqlmyapp.graphql.introspection.generated.json
Writes are content-aware:
- if the generated content is unchanged, the file is left untouched
- if the generated content changes, the file is atomically replaced
This matters for frontend dev servers because it avoids unnecessary file watcher churn.
React / Vite Workflow
Recommended layout:
src/
MyApp.Contracts/
myapp-web/
src/
generated/
myapp.shapes.generated.ts
Recommended loop:
dotnet build src/MyApp.Contracts/MyApp.Contracts.csprojnpm run devinside the frontend app
Because the generated file lives under the Vite app's src tree, real contract changes trigger hot reload naturally.
MSBuild Integration
The intended integration point is an AfterTargets="Build" target on the contracts project.
Typical shape:
<Target Name="GenerateTypeScriptContracts"
AfterTargets="Build"
Inputs="$(TargetPath);$(CohesiveCodeGenCliDll)"
Outputs="$(CohesiveGeneratedShapesFile)"
Condition="'$(CohesiveCodeGenEnabled)' == 'true'">
<MakeDir Directories="$(CohesiveTypeScriptOutDir)" />
<Exec Command="dotnet exec "$(CohesiveCodeGenCliDll)" --contracts "$(TargetPath)" --out "$(CohesiveTypeScriptOutDir)" --emit shapes,apis,openapi,graphql --module "$(CohesiveCodeGenModule)"" />
</Target>
Two separate mechanisms prevent rebuild churn:
- MSBuild
Inputs/Outputscan skip the target entirely when the generated file is already up to date. - The CLI itself skips rewriting the file when the generated text is identical.
Both are useful. The first avoids unnecessary process execution. The second protects correctness when the target does execute.
Type Discovery
The CLI currently:
- loads the target assembly in an isolated
AssemblyLoadContext - inspects exported public CLR types
- filters to contract-like object types with readable public instance properties
- builds a
ShapeGraph - emits TypeScript from that graph
- discovers exported public static
ApiDefinitionmembers namedDefinition,Api, orApiDefinition - emits TypeScript client functions that call an injected
httpfunction - emits OpenAPI and GraphQL schema projections from the same API definitions
This supports a POCO-first workflow while still targeting Cohesive IR internally.
Direction
The longer-term model is:
- author shapes as CLR POCOs, or directly as Cohesive IR
- project those shapes into a common IR
- emit multiple target languages from the same semantic graph
TypeScript is the first target, not the terminal abstraction.
Declared JSON authority
For public contracts, --shape-projection declared-json reads one explicit assembly declaration:
[assembly: JsonContractOptions(typeof(AppJson), nameof(AppJson.CreateOptions))]
The factory must be public, static and parameterless, returning JsonSerializerOptions. It is trusted,
deterministic authoring code and must not resolve runtime services or request context. Share its
configuration with the HTTP host; the generator snapshots and freezes the returned options. Missing,
invalid or failing declarations are reported instead of selecting a naming convention implicitly.
The relation contracts assembly points directly to its native serializer options factory.
The declared profile applies to shapes and OpenAPI. API and Playwright clients retain references to
those generated shape types. GraphQL currently rejects this profile before writing artifacts; its
public serializer projection remains a separate capability. Existing clr (default) and
canonical-json modes remain available. Custom converter/schema restrictions of each emitter still
apply; declaring a factory does not grant an emitter knowledge of arbitrary converter output.
The public JSON profile also governs TypeScript client and Playwright mock query-object member
names. URL query parameter names still follow the HTTP binding convention. For example, a CLR
SearchTerm property may project to searchTerm in the client object while its URL parameter is
search_term. An explicit JSON name overrides the corresponding conventions. Both emitters use
the same serializer metadata provider as shape generation; punctuation-containing names use
quoted property access. The default CLR projection remains unchanged.
Contract loading shares dependencies resolvable by the generator's default load context, including ones not yet loaded when discovery begins. Application-only dependencies are loaded in the collectible contracts context. This preserves type identity across API signatures: a service declaration using a relation parameter must not receive a second copy of that parameter's assembly merely because API discovery ran before the generator first used relations. Loader tests cover this cold dependency case.
Declared JSON projection follows property converters that expose IJsonValueSerializerProfile.
The CLR shape builder contributes separate nested-profile type identities through its existing metadata
hooks, preserving recursive value references, dictionaries and collection cardinality. Preparation is
cached per property for the metadata provider's lifetime; the builder/provider are mutable authoring
objects and are not intended for concurrent use. Recursive converter re-entry is rejected explicitly.
TypeScript allocates deterministic unique declaration names when profile identities share a readable
suffix. CLR authoring identity maps describe the envelope profile; contributed nested definitions live
in the resulting graph rather than overwriting those maps.
IJsonStringValueConverter declares open string output (including code-enum and lossless Int64
converters). It does not enumerate every compatibility form accepted by a reader. These declarations
describe emitted representation, not an exhaustive external-input validator. OpenAPI rejects unsupported property converters. This does not establish complete TypeScript
coverage for arbitrary converter implementations. GraphQL remains a separate CLR projection.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Cohesive (>= 0.1.0-alpha.120)
- Cohesive.Adapters.GraphQL (>= 0.1.0-alpha.120)
- Cohesive.Adapters.OpenApi (>= 0.1.0-alpha.120)
- Cohesive.Adapters.TypeScript (>= 0.1.0-alpha.120)
- Cohesive.Api (>= 0.1.0-alpha.120)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.1.0-alpha.121 | 0 | 10/2/2026 |
| 0.1.0-alpha.120 | 45 | 9/29/2026 |
| 0.1.0-alpha.119 | 37 | 9/29/2026 |
| 0.1.0-alpha.118 | 52 | 9/29/2026 |
| 0.1.0-alpha.117 | 61 | 9/27/2026 |
| 0.1.0-alpha.116 | 52 | 9/26/2026 |
| 0.1.0-alpha.115 | 80 | 9/26/2026 |
| 0.1.0-alpha.114 | 59 | 9/24/2026 |
| 0.1.0-alpha.113 | 63 | 9/24/2026 |
| 0.1.0-alpha.112 | 59 | 9/23/2026 |
| 0.1.0-alpha.111 | 58 | 9/23/2026 |
| 0.1.0-alpha.110 | 60 | 9/23/2026 |
| 0.1.0-alpha.109.1 | 66 | 9/23/2026 |
| 0.1.0-alpha.109 | 62 | 9/23/2026 |
| 0.1.0-alpha.108 | 67 | 9/21/2026 |
| 0.1.0-alpha.107 | 53 | 9/21/2026 |
| 0.1.0-alpha.106 | 60 | 9/21/2026 |
| 0.1.0-alpha.105 | 53 | 9/21/2026 |
| 0.1.0-alpha.104 | 60 | 9/21/2026 |
| 0.1.0-alpha.103 | 62 | 9/21/2026 |