Skip to content

Add InterfaceObjectAttribute - #10371

Open
michaelstaib wants to merge 14 commits into
mainfrom
mst/interface-object
Open

Add InterfaceObjectAttribute#10371
michaelstaib wants to merge 14 commits into
mainfrom
mst/interface-object

Conversation

@michaelstaib

Copy link
Copy Markdown
Member

No description provided.

Adds InterfaceObjectAttribute and the matching InterfaceObject()
descriptor extension to HotChocolate.Types.Composite, mirroring the
sibling composite directive attributes. The attribute implements
ITypeAttribute so a class annotated only with [InterfaceObject] and
registered via AddType<T>() becomes an object type stand-in with the
@interfaceObject directive applied, with no extra [ObjectType] needed.
…<T>] in the source generator

Adds the generic InterfaceObjectAttribute<T> marker next to the existing reflection
attribute so a static partial resolver class can declare an @interfaceObject stand-in
without also needing [ObjectType<T>]. The generator now emits the @interfaceObject
directive for the generic form and auto-registers a bare runtime class carrying the
non-generic attribute through the generated module's AddTypes(), matching how
[ObjectType] already self-registers. The non-generic attribute combined with
[ObjectType<T>] on a resolver class keeps flowing through as a plain descriptor
attribute, so that existing usage is unaffected.
…leak

Wraps three lines that exceeded 120 characters in the InterfaceObject
descriptor extension, the analyzer inspector, and the integration test
method name. Also turns the ProgrammeLookupType XML doc comment into a
plain comment so it no longer leaks into the shared Query type
description in the integration test schema snapshots.
…ceObject<T>]

Reporting HC0134 and skipping generation when both attributes are present
on the same class, regardless of declaration order.
…e descriptor extensions

Adds a generic IObjectTypeDescriptor<T> overload for each existing
composite descriptor extension declared on the non-generic
IObjectTypeDescriptor (InterfaceObject, EntityKey, Inaccessible,
Shareable, Internal). Each overload delegates to the existing
non-generic implementation via a cast, since the concrete
ObjectTypeDescriptorBase<T> already implements both interfaces. This
lets ObjectType<T>.Configure(IObjectTypeDescriptor<T>) call these
fluent methods without an explicit cast.
Adds one ObjectType<T>.Configure snapshot test per generic overload
(InterfaceObject, EntityKey, Inaccessible, Shareable, Internal),
exercising each through IObjectTypeDescriptor<T> without a cast.
…fixture

InterfaceObject() and EntityKey() now have IObjectTypeDescriptor<T>
overloads, so the fluent MediaType fixture no longer needs to cast
to the non-generic IObjectTypeDescriptor to call them.
Copilot AI lite review requested due to automatic review settings September 8, 2026 11:19

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

There are a few doc-comment issues in newly added/modified regions (including malformed XML) that should be fixed to avoid documentation build breaks and incorrect API docs.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Adds first-class support for @interfaceObject in code-first scenarios by introducing InterfaceObjectAttribute (runtime + source-generator forms), wiring it into the source generator/analyzers, and expanding the fluent descriptor API to work cleanly with generic IObjectTypeDescriptor<T>.

Changes:

  • Introduce InterfaceObjectAttribute / InterfaceObjectAttribute<T> plus fluent InterfaceObject() extensions and generator/analyzer support (including a conflict diagnostic with [ObjectType<T>]).
  • Add generic fluent descriptor overloads for composite directives (Shareable, Internal, Inaccessible, EntityKey) and corresponding tests/snapshots.
  • Add Fusion gateway coverage for interface-object stand-ins declared via attribute and via fluent descriptor.
File summaries
File Description
src/HotChocolate/Primitives/src/Primitives/ErrorCodes.cs Adds analyzer error code for ObjectType/InterfaceObject attribute conflicts.
src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/InterfaceObjectTests.cs Adds Fusion integration tests covering attribute- and fluent-declared interface-object stand-ins.
src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/snapshots/InterfaceObjectTests.CodeFirst_StandIn_With_Fluent_Descriptor_Resolves_Lookup_Through_Covering_Schema.yaml Snapshot for fluent stand-in lookup resolution through covering schema.
src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/snapshots/InterfaceObjectTests.CodeFirst_StandIn_With_Fluent_Descriptor_Recovers_TypeName_Through_Covering_Lookup.yaml Snapshot for fluent stand-in __typename recovery through covering lookup.
src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/snapshots/InterfaceObjectTests.CodeFirst_StandIn_With_Attribute_Resolves_Lookup_Through_Covering_Schema.yaml Snapshot for attribute stand-in lookup resolution through covering schema.
src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/snapshots/InterfaceObjectTests.CodeFirst_StandIn_With_Attribute_Recovers_TypeName_Through_Covering_Lookup.yaml Snapshot for attribute stand-in __typename recovery through covering lookup.
src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/snapshots/InterfaceObjectTests.CodeFirst_StandIn_Declared_With_InterfaceObjectAttribute_Resolves.yaml Snapshot for a stand-in declared solely via [InterfaceObject].
src/HotChocolate/Core/test/Types.Tests/Types/Composite/ShareableTests.cs Adds test ensuring descriptor.Shareable() works on IObjectTypeDescriptor<T> without casting.
src/HotChocolate/Core/test/Types.Tests/Types/Composite/InternalTests.cs New test ensuring descriptor.Internal() works on IObjectTypeDescriptor<T>.
src/HotChocolate/Core/test/Types.Tests/Types/Composite/InterfaceObjectTests.cs New tests for [InterfaceObject] and fluent InterfaceObject() APIs (including generic descriptor).
src/HotChocolate/Core/test/Types.Tests/Types/Composite/InaccessibleTests.cs New test ensuring descriptor.Inaccessible() works on IObjectTypeDescriptor<T>.
src/HotChocolate/Core/test/Types.Tests/Types/Composite/snapshots/ShareableTests.GenericShareableType_Is_Shareable_Fluent_Generic.graphql Snapshot for generic shareable fluent test schema.
src/HotChocolate/Core/test/Types.Tests/Types/Composite/snapshots/InternalTests.Internal_Should_ApplyDirective_When_UsedOnGenericObjectTypeDescriptor.graphql Snapshot for generic internal fluent test schema.
src/HotChocolate/Core/test/Types.Tests/Types/Composite/snapshots/InterfaceObjectTests.Programme_Is_InterfaceObject.graphql Snapshot for attribute-driven interface object schema.
src/HotChocolate/Core/test/Types.Tests/Types/Composite/snapshots/InterfaceObjectTests.Programme_Is_InterfaceObject_Fluent.graphql Snapshot for non-generic fluent interface object schema.
src/HotChocolate/Core/test/Types.Tests/Types/Composite/snapshots/InterfaceObjectTests.Programme_Is_InterfaceObject_Fluent_Generic.graphql Snapshot for generic fluent interface object schema.
src/HotChocolate/Core/test/Types.Tests/Types/Composite/snapshots/InterfaceObjectTests.InterfaceObject_With_Explicit_Name_Renames_Type.graphql Snapshot for named [InterfaceObject("...")] behavior.
src/HotChocolate/Core/test/Types.Tests/Types/Composite/snapshots/InaccessibleTests.Inaccessible_Should_ApplyDirective_When_UsedOnGenericObjectTypeDescriptor.graphql Snapshot for generic inaccessible fluent test schema.
src/HotChocolate/Core/test/Types.Analyzers.Tests/TypeModuleSyntaxGeneratorTests.cs Adds generator test ensuring non-generic [InterfaceObject] on runtime class is module-registered.
src/HotChocolate/Core/test/Types.Analyzers.Tests/InterfaceObjectTests.cs New analyzer snapshot tests for InterfaceObject attribute handling and error cases.
src/HotChocolate/Core/test/Types.Analyzers.Tests/snapshots/TypeModuleSyntaxGeneratorTests.GenerateSource_NonGeneric_InterfaceObject_On_RuntimeClass_RegistersType.md Snapshot verifying type module registers [InterfaceObject] runtime class.
src/HotChocolate/Core/test/Types.Analyzers.Tests/snapshots/InterfaceObjectTests.NonGeneric_Attribute_On_Runtime_Class_MatchesSnapshot.md Snapshot verifying module registration for runtime [InterfaceObject].
src/HotChocolate/Core/test/Types.Analyzers.Tests/snapshots/InterfaceObjectTests.NonGeneric_Attribute_Combined_With_ObjectType_MatchesSnapshot.md Snapshot verifying [ObjectType<T>] + non-generic [InterfaceObject] stays descriptor-only.
src/HotChocolate/Core/test/Types.Analyzers.Tests/snapshots/InterfaceObjectTests.Generic_ObjectType_And_Generic_InterfaceObject_Combined_RaisesError.md Snapshot verifying new HC0134 conflict diagnostic.
src/HotChocolate/Core/test/Types.Analyzers.Tests/snapshots/InterfaceObjectTests.Generic_InterfaceObject_And_Generic_ObjectType_Combined_RaisesError.md Snapshot verifying conflict diagnostic regardless of attribute order.
src/HotChocolate/Core/test/Types.Analyzers.Tests/snapshots/InterfaceObjectTests.Generic_Attribute_On_Static_Resolver_Class_MatchesSnapshot.md Snapshot verifying generic [InterfaceObject<T>] is emitted correctly.
src/HotChocolate/Core/test/Types.Analyzers.Tests/snapshots/InterfaceObjectTests.Generic_Attribute_On_NonStatic_Class_RaisesError.md Snapshot verifying error for invalid (non-static) resolver class usage.
src/HotChocolate/Core/test/Types.Analyzers.Tests/snapshots/InterfaceObjectTests.Generic_Attribute_On_NonPartial_Class_RaisesError.md Snapshot verifying error for invalid (non-partial) resolver class usage.
src/HotChocolate/Core/test/Types.Analyzers.Integration.Tests/InterfaceObjectTypes.cs Adds integration types using both generic and non-generic InterfaceObject attribute forms.
src/HotChocolate/Core/test/Types.Analyzers.Integration.Tests/InterfaceObjectTests.cs Adds integration assertions for SDL printing and lookup behavior.
src/HotChocolate/Core/test/Types.Analyzers.Integration.Tests/snapshots/IntegrationTests.Schema_Snapshot.snap Updates integration schema snapshot with interface object additions.
src/HotChocolate/Core/test/Types.Analyzers.Integration.Tests/snapshots/IntegrationTests.Schema_Snapshot_Without_ConnectionName_Inference.snap Updates alternate integration schema snapshot accordingly.
src/HotChocolate/Core/src/Types/Types/Composite/Directives/ShareableDirectiveExtensions.cs Adds generic Shareable<T> fluent overload.
src/HotChocolate/Core/src/Types/Types/Composite/Directives/InternalDirectiveExtensions.cs Adds generic Internal<T> fluent overload.
src/HotChocolate/Core/src/Types/Types/Composite/Directives/InterfaceObjectDescriptorExtensions.cs New fluent InterfaceObject() extensions (generic + non-generic descriptors).
src/HotChocolate/Core/src/Types/Types/Composite/Directives/InterfaceObjectAttribute.cs New attribute(s) enabling runtime and generator-based interface-object declarations.
src/HotChocolate/Core/src/Types/Types/Composite/Directives/InaccessibleDescriptorExtensions.cs Adds generic Inaccessible<T> fluent overload.
src/HotChocolate/Core/src/Types/Types/Composite/Directives/EntityKeyDescriptorExtensions.cs Adds generic EntityKey<T> fluent overload.
src/HotChocolate/Core/src/Types.Analyzers/WellKnownTypes.cs Adds well-known directive type constant for InterfaceObject.
src/HotChocolate/Core/src/Types.Analyzers/WellKnownAttributes.cs Registers InterfaceObjectAttribute as a recognized/bindable attribute for generation.
src/HotChocolate/Core/src/Types.Analyzers/Models/ObjectTypeInfo.cs Tracks whether an object type is an interface object for generation.
src/HotChocolate/Core/src/Types.Analyzers/Models/InvalidSyntaxInfo.cs Adds a syntax-info carrier for diagnostics-only (no generation) cases.
src/HotChocolate/Core/src/Types.Analyzers/Inspectors/TypeAttributeInspector.cs Prevents accidental runtime-type registration for resolver classes with [ObjectType<T>] + [InterfaceObject].
src/HotChocolate/Core/src/Types.Analyzers/Inspectors/ObjectTypeInspector.cs Adds detection of [InterfaceObject<T>], conflict diagnostic, and propagation of interface-object flag.
src/HotChocolate/Core/src/Types.Analyzers/FileBuilders/ObjectTypeFileBuilder.cs Emits @interfaceObject directive when the inspected object type is marked as interface object.
src/HotChocolate/Core/src/Types.Analyzers/Errors.cs Adds the new diagnostic descriptor for conflicting object-type attributes.
Review details
  • Files reviewed: 46/46 changed files
  • Comments generated: 3
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +72 to +74
/// <exception cref="ArgumentNullException">
/// The <paramref name="descriptor"/> or the paramref name="fields"/> parameter is <c>null</c>.
/// </exception>
Comment on lines +344 to +349
/// <param name="scoped">
/// if <c>true</c> and this directive is applied to an object type extension,
/// it will only be applied to the fields that this object type extension exposes.
/// if scoped is <c>false</c> the directive will be applied to the type and will thus make all
/// fields of the type sharable.
/// </param>
Comment on lines +114 to +119
/// <param name="scoped">
/// if <c>true</c> and this directive is applied to an object type extension,
/// it will only be applied to the fields that this object type extension exposes.
/// if scoped is <c>false</c> the directive will be applied to the type and will thus make all
/// fields of the type sharable.
/// </param>
…Provider

AppendText now recurses into <para> children instead of using their raw
.Value, so a paragraph that only wraps <see href> keeps its link. Blocks
(<para>, <code>) are normalized independently and joined by a single blank
line, and whitespace-only lines inside a block become fully empty instead
of leaking a shorter or longer indent run into the rendered description.
The XmlDocumentationProvider fix changes how <para>/<code> blocks in the
composite directive XML docs render: consecutive paragraphs now join with
a single blank line, a <see href> wrapped in its own <para> keeps its
link, and blank lines inside a <code> block no longer leak leftover
indentation. Every refreshed snapshot and inline snapshot below differs
only in that description text.
@github-actions

Copy link
Copy Markdown
Contributor

Patch coverage

93.1% of changed lines covered (231/248)

File Covered Changed Patch %
…/Core/src/Types.Analyzers/Models/InvalidSyntaxInfo.cs 2 6 33.3% 🔴
…/Types/Types/Composite/Directives/InterfaceObjectAttribute.cs 15 17 88.2% 🟡
…/src/Types.Analyzers/Inspectors/TypeAttributeInspector.cs 20 22 90.9% 🟡
…/Types/Descriptors/Conventions/XmlDocumentationProvider.cs 90 99 90.9% 🟡
src/HotChocolate/Core/src/Types.Analyzers/Errors.cs 8 8 100.0% 🟢
…/src/Types.Analyzers/FileBuilders/ObjectTypeFileBuilder.cs 5 5 100.0% 🟢
…/Core/src/Types.Analyzers/Inspectors/ObjectTypeInspector.cs 58 58 100.0% 🟢
…/Core/src/Types.Analyzers/Models/ObjectTypeInfo.cs 4 4 100.0% 🟢
…/HotChocolate/Core/src/Types.Analyzers/WellKnownAttributes.cs 2 2 100.0% 🟢
…/Types/Composite/Directives/EntityKeyDescriptorExtensions.cs 5 5 100.0% 🟢
…/Composite/Directives/InaccessibleDescriptorExtensions.cs 5 5 100.0% 🟢
…/Composite/Directives/InterfaceObjectDescriptorExtensions.cs 9 9 100.0% 🟢
…/Types/Composite/Directives/InternalDirectiveExtensions.cs 4 4 100.0% 🟢
…/Types/Composite/Directives/ShareableDirectiveExtensions.cs 4 4 100.0% 🟢
Uncovered changed lines (JSON)
{
  "sha": "2614e74a48271055b30c91dbc29d425fb92ec6bb",
  "files": [
    { "path": "src/HotChocolate/Core/src/Types.Analyzers/Models/InvalidSyntaxInfo.cs", "ranges": [[11, 11], [14, 14], [17, 17], [20, 20]] },
    { "path": "src/HotChocolate/Core/src/Types/Types/Composite/Directives/InterfaceObjectAttribute.cs", "ranges": [[36, 36], [64, 64]] },
    { "path": "src/HotChocolate/Core/src/Types.Analyzers/Inspectors/TypeAttributeInspector.cs", "ranges": [[138, 139]] },
    { "path": "src/HotChocolate/Core/src/Types/Types/Descriptors/Conventions/XmlDocumentationProvider.cs", "ranges": [[231, 233], [242, 243], [269, 270], [289, 290]] }
  ]
}

Project coverage: 57.9% (288471/498098 lines)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants