Skip to content

Kontent.Ai.ModelGenerator 11.0.0-rc.1

Pre-release
Pre-release

Choose a tag to compare

Targets .NET 10. Both packages move from net8.0 to net10.0, which is why this is a major release rather than a continuation of the 10.3.0 line. Generated output is unchanged.

Breaking changes

  • net8.0net10.0. Kontent.Ai.ModelGenerator.Core is a library, so a project on .NET 8 cannot reference this release at all — restore fails with NU1202. The Kontent.Ai.ModelGenerator CLI likewise needs the .NET 10 runtime to run. Move to .NET 10 first.

  • Two generator base-class properties became methods. ClassCodeGenerator.Properties is now GetProperties(), and the Delivery generator's PropertyCodenameConstants is now GetPropertyCodenameConstants(). Both re-sort their input and build a fresh set of Roslyn syntax nodes on every access, so a property was misleading about the cost — two reads returned two different arrays. GetProperties() remains virtual, so overriding it still works; a derived generator changes override … Properties to override … GetProperties(). Only affects code that subclasses these base classes.

  • --withtypeprovider / -t and CodeGeneratorOptions.WithTypeProvider are removed, along with the TypeProviderCodeGenerator that backed them. The Delivery SDK generates its own GeneratedTypeProvider at compile time from Kontent.Ai.Delivery.SourceGeneration and discovers it at runtime, so nothing needs a hand-written provider any more.

    The flag had in fact stopped doing anything before this release: the code path behind it lived on a method that hid its base rather than overriding it, and the CLI invokes the base, so passing -t generated no provider and printed no warning. Passing it now fails with Unsupported parameter: -t rather than being silently ignored. Remove it from your scripts and reference Kontent.Ai.Delivery.SourceGeneration from the project your models are generated into.

  • CodeGeneratorBase.FilenameSuffix and GetFileClassName are removed. The suffix has been the empty string since single-file generation landed, which made GetFileClassName(name) an identity function. Generated file names are unchanged. Only affects code that subclasses CodeGeneratorBase.

  • IOutputProvider.Output returns bool instead of voidtrue when it wrote the file, false when the file already existed and overwriteExisting was not set. The generator reports each file's outcome and had no way to tell the two apart. Only affects code that implements IOutputProvider; a custom implementation adds a return true;.

  • The dropped custom-partial emission path is gone. PartialClassCodeGenerator, the customPartial flag on IClassCodeGeneratorFactory.CreateClassCodeGenerator, and ClassCodeGenerator.OverwriteExisting all existed to support emitting a second, user-extensible partial file. The CLI never asked for it — the flag was never passed as true — so the generator was unreachable, and OverwriteExisting was a GetType() != typeof(PartialClassCodeGenerator) check that could only ever answer true. The factory method also took an IUserMessageLogger it null-checked and never used; that parameter is gone too.

  • IDeliveryElementService and DeliveryElementService are removed. GetElementType(string) returned its argument unchanged, and the injected options were never read — an interface, an implementation, a DI registration and an inheritance layer computing the identity function. DeliveryCodeGenerator now reads element.Value.Type directly and derives from CodeGeneratorBase; DeliveryCodeGeneratorBase, whose only purpose was carrying the service, is gone with it.

  • The always-true emission seams are gone. ClassCodeGenerator.IsRecord and UseFileScopedNamespace were virtual and defaulted to false, but every concrete generator overrode both to true, so the class-emitting and block-namespace branches were unreachable. DeliveryClassCodeGeneratorBase had one subclass left after the custom-partial removal and is folded into DeliveryClassCodeGenerator, which is now sealed.

  • Dead public members are removed from Property and TextHelpers. On Property: ObjectType, IsNullable, HasInitializer, the already-obsolete RequiresDefaultInitializer, and the IsDateTimeElementType / IsRichTextElementType / IsModularContentElementType predicates — none reachable from any emission path. On TextHelpers: GetEnumerableType, and GetUpperSnakeCasedIdentifierName, which despite its name produced Pascal_Snake_Case rather than upper snake case and was called by nothing.

    Generated output is unaffected. Verified by generating against a live environment before and after: all 15 files, including the --baserecord extender, are byte-identical.

  • ClassDefinition.AddPropertyCodenameConstant is removed; AddProperty now registers both the property and its codename constant. The two were always called as a pair, and calling them separately is what allowed a rejected property to leave its constant behind. CodeGeneratorBase.AddProperty(Property, ref ClassDefinition), which wrapped the pair and had no callers, is removed with it. Only affects code that drives ClassDefinition directly.

Changed

  • Arguments are validated against the SDKs' own rules instead of a hand-written subset. The tool checked only that an environment id was present and non-blank, so -i not-a-guid was accepted and the run failed later against the API with a less obvious message. It now runs the validation the SDK options already declare — data annotations plus IValidatableObject — which is what the SDKs' own container-free constructors do. Every problem is reported at once rather than the first, so a run started with several bad arguments does not have to be repeated once per mistake.

    $ KontentModelGenerator -i not-a-guid
    The delivery configuration is not valid:
      - EnvironmentId: The environment ID must be a valid GUID.
    See http://bit.ly/k-params for more details on configuration.
    

    Configurations that were valid before remain valid. A configuration the tool used to accept and the API would then reject now fails at startup.

  • --baserecord no longer fetches the content model twice. Generating the base record re-read the whole content model rather than reusing what had just been fetched, so a run with -b made every request twice — in management mode, both the content-type and snippet listings. The generated output was identical either way; only the number of API calls changes.

  • Nothing about the code the generator emits, for any content model that generated valid code before. Model classes, enums and the mapping attributes are byte-identical to 10.3.0-beta-2, verified by the generator's own output assertions. Models that previously came out uncompilable are covered under Fixed.

Fixed

  • Element codenames that differ but produce the same C# identifier no longer emit uncompilable models. Duplicate detection compared raw codenames while emission used the PascalCased identifier, so my_element and my__element — two codenames, one identifier — both got through. The generated record then declared MyElementCodename twice and did not compile. The same hole existed between the two kinds of member: an element named title and one named title_codename produced a constant and a property that were both called TitleCodename, and that case emitted no warning at all. Everything a record declares is now checked against one registry of identifiers, and the offending element is skipped with a message naming both codenames and the identifier they collide on.

    Warning: Skipping element 'my__element'. Content type 'article': 'my__element' and 'my_element'
    both produce the identifier 'MyElement'. Rename one of the elements in Kontent.ai.
    

    A rejected element no longer half-registers either — the constant used to be recorded before the property could be refused, so skipping one element still corrupted the output.

  • An element that fails for an unanticipated reason is now reported instead of vanishing. Per-element failures were classified by a switch with arms for the three expected exception types and no default, so anything else was caught, matched nothing, and left the element out of the generated model with nothing written to the console.

  • The tool no longer claims to have created a base record it did not write. --baserecord deliberately does not overwrite an existing file, so hand-written additions survive a rerun — but the run printed "<name> class was successfully created" either way. It now says the file was kept, and IOutputProvider.Output returns whether it wrote (see Breaking changes).

  • The "no content type available" message names the environment in management mode. It read the Delivery options only, so a --managementapi run against an empty environment reported the id as blank.

  • A failure with more than one inner exception no longer exits silently. Main had a special case for AggregateException that printed the message only when there was exactly one inner exception and otherwise returned exit code 1 with no output at all. await unwraps these anyway, so the case was vestigial; it is removed and the general handler reports every failure.

  • Two content types that map to the same file no longer silently overwrite each other. Type codenames sanitize to a class name the same way element codenames do, so my_type and my__type both wrote MyType.cs — the second overwrote the first, and the run reported both as created. The duplicate is now skipped with a warning, and the "N content type models were successfully created" count reflects what was actually written.

Dependencies

Shipped floors moved up:

  • Kontent.Ai.Delivery, Kontent.Ai.Delivery.Abstractions, Kontent.Ai.Urls and Kontent.Ai.Delivery.SourceGeneration 19.4.020.0.0-rc.1, and Kontent.Ai.Management 9.0.0-beta-59.0.0-rc.1. The CLI packages these assemblies inside the tool, so until now a .NET 10 tool carried .NET 8 builds of both SDKs.
  • Microsoft.CodeAnalysis 4.13.05.6.0, aligning the generator with the Roslyn version the rest of the repo builds against.
  • Microsoft.Extensions.* (Options, Configuration.CommandLine, Configuration.Json, DependencyInjection) 9.0.1510.0.10.

Internal

No consumer-visible effect:

  • The generator's output no longer reaches for Console from three different places. UserMessageLogger now takes the writers it should use, defaulting to standard output and standard error, and the two places that bypassed it - command-line validation and the SDK-version banner - go through it. Command-line validation returns the problems it finds rather than printing them, since it runs before there is any container to resolve a logger from. Terminal output is unchanged, character for character.

    This also lets the tool's test assembly run in parallel again. It had been forced sequential because one test captured output by reassigning Console.Out, which is process-wide, and collided with another test writing to Console.Error.

  • A transient HttpClient was registered in delivery mode and resolved by nothing. AddDeliveryClient builds its transport through IHttpClientFactory, so the registration was inert - and had anything picked it up, it would have bypassed the SDK's whole handler chain: no authentication, no tracking headers, no resilience.

  • Three JSON fixtures under the Core test project were copied to the build output and referenced by no test. The tests construct their inputs in memory instead. Recoverable from history if realistic payloads are wanted later.

  • Identifier-sanitizing regular expressions are compiled at build time and carry an execution timeout. Codenames arrive from the environment's content model, so they are external input, and a generator that hangs on one malformed codename is worse than one that fails.

  • Kontent.Ai.ModelGenerator.Options is now Kontent.Ai.ModelGenerator.CommandLine. The namespace holds command-line argument handling — ArgHelpers, ArgMappingsRegister, UsedSdkInfo, ValidationExtensions — and nothing to do with IOptions. Sitting directly under Kontent.Ai.ModelGenerator, it shadowed Microsoft.Extensions.Options throughout the assembly and both test projects, so Options.Create(...) bound to the namespace and had to be written fully qualified to compile. Only the CLI tool assembly is affected: Kontent.Ai.ModelGenerator.Core has no such namespace, and the tool is installed rather than referenced.

Installation

dotnet add package Kontent.Ai.ModelGenerator --prerelease

Full changelog: src/model-generator/CHANGELOG.md