diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/Collections/MultiValueDictionary.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/Collections/MultiValueDictionary.cs new file mode 100644 index 00000000000..1be86756585 --- /dev/null +++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/Collections/MultiValueDictionary.cs @@ -0,0 +1,28 @@ +namespace HotChocolate.Fusion.Collections; + +internal sealed class MultiValueDictionary + : Dictionary> where TKey : notnull +{ + public void Add(TKey key, TValue value) + { + ArgumentNullException.ThrowIfNull(key); + + if (!TryGetValue(key, out var list)) + { + list = []; + Add(key, list); + } + + list.Add(value); + } + + public void Remove(TKey key, TValue value) + { + ArgumentNullException.ThrowIfNull(key); + + if (TryGetValue(key, out var list)) + { + list.Remove(value); + } + } +} diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/Errors/ErrorHelper.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/Errors/ErrorHelper.cs index 4841f244835..800b1db42f9 100644 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/Errors/ErrorHelper.cs +++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/Errors/ErrorHelper.cs @@ -1,10 +1,9 @@ -using HotChocolate.Fusion.PreMergeValidation.Contracts; using static HotChocolate.Fusion.Properties.CompositionResources; namespace HotChocolate.Fusion.Errors; internal static class ErrorHelper { - public static CompositionError PreMergeValidationRuleFailed(IPreMergeValidationRule rule) - => new(string.Format(ErrorHelper_PreMergeValidationRuleFailed, rule.GetType().Name)); + public static CompositionError PreMergeValidationFailed() + => new(ErrorHelper_PreMergeValidationFailed); } diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/Events/IEvent.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/Events/IEvent.cs new file mode 100644 index 00000000000..fc4b2354184 --- /dev/null +++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/Events/IEvent.cs @@ -0,0 +1,3 @@ +namespace HotChocolate.Fusion.Events; + +internal interface IEvent; diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/Logging/CompositionLog.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/Logging/CompositionLog.cs index 2f9cc4b9cea..3f51bdfed5f 100644 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/Logging/CompositionLog.cs +++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/Logging/CompositionLog.cs @@ -5,6 +5,8 @@ namespace HotChocolate.Fusion.Logging; public sealed class CompositionLog : ICompositionLog, IEnumerable { + public bool HasErrors { get; private set; } + public bool IsEmpty => _entries.Count == 0; private readonly List _entries = []; @@ -13,12 +15,12 @@ public void Write(LogEntry entry) { ArgumentNullException.ThrowIfNull(entry); - _entries.Add(entry); - } + if (entry.Severity == LogSeverity.Error) + { + HasErrors = true; + } - public ILoggingSession CreateSession() - { - return new LoggingSession(this); + _entries.Add(entry); } public IEnumerator GetEnumerator() => _entries.GetEnumerator(); diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/Logging/Contracts/ICompositionLog.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/Logging/Contracts/ICompositionLog.cs index 1251c6adf64..84e325c8089 100644 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/Logging/Contracts/ICompositionLog.cs +++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/Logging/Contracts/ICompositionLog.cs @@ -5,6 +5,10 @@ namespace HotChocolate.Fusion.Logging.Contracts; /// public interface ICompositionLog { + // FIXME: Docs. + bool HasErrors { get; } + + // FIXME: Docs. bool IsEmpty { get; } /// @@ -12,10 +16,4 @@ public interface ICompositionLog /// /// The to write. void Write(LogEntry entry); - - /// - /// Creates a new logging session that keeps track of the number of info, warning, and error - /// entries logged. - /// - ILoggingSession CreateSession(); } diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/Logging/LoggingSession.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/Logging/LoggingSession.cs deleted file mode 100644 index 6ee1b23df63..00000000000 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/Logging/LoggingSession.cs +++ /dev/null @@ -1,37 +0,0 @@ -using HotChocolate.Fusion.Logging.Contracts; - -namespace HotChocolate.Fusion.Logging; - -public sealed class LoggingSession(ICompositionLog compositionLog) : ILoggingSession -{ - public int InfoCount { get; private set; } - - public int WarningCount { get; private set; } - - public int ErrorCount { get; private set; } - - public void Write(LogEntry entry) - { - ArgumentNullException.ThrowIfNull(entry); - - switch (entry.Severity) - { - case LogSeverity.Info: - InfoCount++; - break; - - case LogSeverity.Warning: - WarningCount++; - break; - - case LogSeverity.Error: - ErrorCount++; - break; - - default: - throw new InvalidOperationException(); - } - - compositionLog.Write(entry); - } -} diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/PreMergeValidation/Contracts/IPreMergeValidationRule.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/PreMergeValidation/Contracts/IPreMergeValidationRule.cs index a9a60320a91..377ce5c358d 100644 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/PreMergeValidation/Contracts/IPreMergeValidationRule.cs +++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/PreMergeValidation/Contracts/IPreMergeValidationRule.cs @@ -1,8 +1,20 @@ -using HotChocolate.Fusion.Results; - namespace HotChocolate.Fusion.PreMergeValidation.Contracts; internal interface IPreMergeValidationRule { - CompositionResult Run(PreMergeValidationContext context); + void OnEachType(EachTypeEvent @event); + + void OnEachOutputField(EachOutputFieldEvent @event); + + void OnEachFieldArgument(EachFieldArgumentEvent @event); + + void OnEachDirective(EachDirectiveEvent @event); + + void OnEachDirectiveArgument(EachDirectiveArgumentEvent @event); + + void OnEachTypeGroup(EachTypeGroupEvent @event); + + void OnEachOutputFieldGroup(EachOutputFieldGroupEvent @event); + + void OnEachFieldArgumentGroup(EachFieldArgumentGroupEvent @event); } diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/PreMergeValidation/Events.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/PreMergeValidation/Events.cs new file mode 100644 index 00000000000..c50e73cd381 --- /dev/null +++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/PreMergeValidation/Events.cs @@ -0,0 +1,52 @@ +using System.Collections.Immutable; +using HotChocolate.Fusion.Events; +using HotChocolate.Skimmed; + +namespace HotChocolate.Fusion.PreMergeValidation; + +internal record EachDirectiveArgumentEvent( + CompositionContext Context, + InputFieldDefinition Argument, + DirectiveDefinition Directive, + SchemaDefinition Schema) : IEvent; + +internal record EachDirectiveEvent( + CompositionContext Context, + DirectiveDefinition Directive, + SchemaDefinition Schema) : IEvent; + +internal record EachFieldArgumentEvent( + CompositionContext Context, + InputFieldDefinition Argument, + OutputFieldDefinition Field, + INamedTypeDefinition Type, + SchemaDefinition Schema) : IEvent; + +internal record EachFieldArgumentGroupEvent( + CompositionContext Context, + string ArgumentName, + ImmutableArray ArgumentGroup, + string FieldName, + string TypeName) : IEvent; + +internal record EachOutputFieldEvent( + CompositionContext Context, + OutputFieldDefinition Field, + INamedTypeDefinition Type, + SchemaDefinition Schema) : IEvent; + +internal record EachOutputFieldGroupEvent( + CompositionContext Context, + string FieldName, + ImmutableArray FieldGroup, + string TypeName) : IEvent; + +internal record EachTypeEvent( + CompositionContext Context, + INamedTypeDefinition Type, + SchemaDefinition Schema) : IEvent; + +internal record EachTypeGroupEvent( + CompositionContext Context, + string TypeName, + ImmutableArray TypeGroup) : IEvent; diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/PreMergeValidation/PreMergeValidationContext.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/PreMergeValidation/PreMergeValidationContext.cs deleted file mode 100644 index 538df65d0ca..00000000000 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/PreMergeValidation/PreMergeValidationContext.cs +++ /dev/null @@ -1,77 +0,0 @@ -using System.Collections.Immutable; -using HotChocolate.Fusion.Logging.Contracts; -using HotChocolate.Skimmed; - -namespace HotChocolate.Fusion.PreMergeValidation; - -internal sealed class PreMergeValidationContext(CompositionContext context) -{ - public ImmutableArray SchemaDefinitions => context.SchemaDefinitions; - public ICompositionLog Log => context.Log; - public ImmutableArray OutputTypeInfo = []; - - public void Initialize() - { - InitializeOutputTypeInfo(); - } - - /// - /// Initializes a structure that makes it easier to access combined output types, fields, and - /// arguments for validation purposes. - /// - private void InitializeOutputTypeInfo() - { - OutputTypeInfo = - [ - .. SchemaDefinitions - .SelectMany(s => s.Types) - .Where(t => t.IsOutputType()) - .OfType() - .GroupBy( - t => t.Name, - (typeName, types) => - { - types = types.ToImmutableArray(); - - var fieldInfo = types - .SelectMany(t => t.Fields) - .GroupBy( - f => f.Name, - (fieldName, fields) => - { - fields = fields.ToImmutableArray(); - - var argumentInfo = fields - .SelectMany(f => f.Arguments) - .GroupBy( - a => a.Name, - (argumentName, arguments) => - new OutputArgumentInfo( - argumentName, - [.. arguments])); - - return new OutputFieldInfo( - fieldName, - [.. fields], - [.. argumentInfo]); - }); - - return new OutputTypeInfo(typeName, [.. types], [.. fieldInfo]); - }) - ]; - } -} - -internal record OutputTypeInfo( - string TypeName, - ImmutableArray Types, - ImmutableArray FieldInfo); - -internal record OutputFieldInfo( - string FieldName, - ImmutableArray Fields, - ImmutableArray Arguments); - -internal record OutputArgumentInfo( - string ArgumentName, - ImmutableArray Arguments); diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/PreMergeValidation/PreMergeValidationRule.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/PreMergeValidation/PreMergeValidationRule.cs new file mode 100644 index 00000000000..ad73e69bf85 --- /dev/null +++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/PreMergeValidation/PreMergeValidationRule.cs @@ -0,0 +1,38 @@ +using HotChocolate.Fusion.PreMergeValidation.Contracts; + +namespace HotChocolate.Fusion.PreMergeValidation; + +internal abstract class PreMergeValidationRule : IPreMergeValidationRule +{ + public virtual void OnEachType(EachTypeEvent @event) + { + } + + public virtual void OnEachOutputField(EachOutputFieldEvent @event) + { + } + + public virtual void OnEachFieldArgument(EachFieldArgumentEvent @event) + { + } + + public virtual void OnEachDirective(EachDirectiveEvent @event) + { + } + + public virtual void OnEachDirectiveArgument(EachDirectiveArgumentEvent @event) + { + } + + public virtual void OnEachTypeGroup(EachTypeGroupEvent @event) + { + } + + public virtual void OnEachOutputFieldGroup(EachOutputFieldGroupEvent @event) + { + } + + public virtual void OnEachFieldArgumentGroup(EachFieldArgumentGroupEvent @event) + { + } +} diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/PreMergeValidation/PreMergeValidator.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/PreMergeValidation/PreMergeValidator.cs index 1d812523f12..163d6c8e523 100644 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/PreMergeValidation/PreMergeValidator.cs +++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/PreMergeValidation/PreMergeValidator.cs @@ -1,36 +1,166 @@ using System.Collections.Immutable; +using HotChocolate.Fusion.Collections; using HotChocolate.Fusion.Errors; +using HotChocolate.Fusion.Events; using HotChocolate.Fusion.PreMergeValidation.Contracts; -using HotChocolate.Fusion.PreMergeValidation.Rules; using HotChocolate.Fusion.Results; +using HotChocolate.Skimmed; namespace HotChocolate.Fusion.PreMergeValidation; -internal sealed class PreMergeValidator +internal sealed class PreMergeValidator(IEnumerable rules) { - private readonly ImmutableArray _validationRules = - [ - new DisallowedInaccessibleElementsRule(), - new OutputFieldTypesMergeableRule() - ]; + private readonly ImmutableArray _rules = [.. rules]; - public CompositionResult Validate(CompositionContext compositionContext) + public CompositionResult Validate(CompositionContext context) { - var preMergeValidationContext = new PreMergeValidationContext(compositionContext); - preMergeValidationContext.Initialize(); + PublishEvents(context); - var errors = new List(); + return context.Log.HasErrors + ? ErrorHelper.PreMergeValidationFailed() + : CompositionResult.Success(); + } + + private void PublishEvents(CompositionContext context) + { + MultiValueDictionary typeGroupByName = []; - foreach (var validationRule in _validationRules) + foreach (var schema in context.SchemaDefinitions) { - var result = validationRule.Run(preMergeValidationContext); + foreach (var type in schema.Types) + { + PublishEvent(new EachTypeEvent(context, type, schema)); + + typeGroupByName.Add(type.Name, new TypeInfo(type, schema)); + + if (type is ComplexTypeDefinition complexType) + { + foreach (var field in complexType.Fields) + { + PublishEvent(new EachOutputFieldEvent(context, field, type, schema)); + + foreach (var argument in field.Arguments) + { + PublishEvent( + new EachFieldArgumentEvent(context, argument, field, type, schema)); + } + } + } + } + + foreach (var directive in schema.DirectiveDefinitions) + { + PublishEvent(new EachDirectiveEvent(context, directive, schema)); + + foreach (var argument in directive.Arguments) + { + PublishEvent( + new EachDirectiveArgumentEvent(context, argument, directive, schema)); + } + } + } + + foreach (var (typeName, typeGroup) in typeGroupByName) + { + PublishEvent(new EachTypeGroupEvent(context, typeName, [.. typeGroup])); + + MultiValueDictionary fieldGroupByName = []; + + foreach (var (type, schema) in typeGroup) + { + if (type is ComplexTypeDefinition complexType) + { + foreach (var field in complexType.Fields) + { + fieldGroupByName.Add(field.Name, new OutputFieldInfo(field, type, schema)); + } + } + } - if (result.IsFailure) + foreach (var (fieldName, fieldGroup) in fieldGroupByName) { - errors.AddRange(result.Errors); + PublishEvent( + new EachOutputFieldGroupEvent(context, fieldName, [.. fieldGroup], typeName)); + + MultiValueDictionary argumentGroupByName = []; + + foreach (var (field, type, schema) in fieldGroup) + { + foreach (var argument in field.Arguments) + { + argumentGroupByName.Add( + argument.Name, + new FieldArgumentInfo(argument, field, type, schema)); + } + } + + foreach (var (argumentName, argumentGroup) in argumentGroupByName) + { + PublishEvent( + new EachFieldArgumentGroupEvent( + context, + argumentName, + [.. argumentGroup], + fieldName, + typeName)); + } } } + } + + private void PublishEvent(IEvent @event) + { + foreach (var rule in _rules) + { + switch (@event) + { + case EachTypeEvent e: + rule.OnEachType(e); + break; + + case EachOutputFieldEvent e: + rule.OnEachOutputField(e); + break; + + case EachFieldArgumentEvent e: + rule.OnEachFieldArgument(e); + break; - return errors; + case EachDirectiveEvent e: + rule.OnEachDirective(e); + break; + + case EachDirectiveArgumentEvent e: + rule.OnEachDirectiveArgument(e); + break; + + case EachTypeGroupEvent e: + rule.OnEachTypeGroup(e); + break; + + case EachOutputFieldGroupEvent e: + rule.OnEachOutputFieldGroup(e); + break; + + case EachFieldArgumentGroupEvent e: + rule.OnEachFieldArgumentGroup(e); + break; + } + } } } + +internal record TypeInfo( + INamedTypeDefinition Type, + SchemaDefinition Schema); + +internal record OutputFieldInfo( + OutputFieldDefinition Field, + INamedTypeDefinition Type, + SchemaDefinition Schema); + +internal record FieldArgumentInfo( + InputFieldDefinition Argument, + OutputFieldDefinition Field, + INamedTypeDefinition Type, + SchemaDefinition Schema); diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/PreMergeValidation/Rules/DisallowedInaccessibleElementsRule.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/PreMergeValidation/Rules/DisallowedInaccessibleElementsRule.cs index b01d1f11c78..3421ec08e66 100644 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/PreMergeValidation/Rules/DisallowedInaccessibleElementsRule.cs +++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/PreMergeValidation/Rules/DisallowedInaccessibleElementsRule.cs @@ -1,6 +1,3 @@ -using HotChocolate.Fusion.Errors; -using HotChocolate.Fusion.PreMergeValidation.Contracts; -using HotChocolate.Fusion.Results; using HotChocolate.Skimmed; using static HotChocolate.Fusion.Logging.LogEntryHelper; @@ -15,80 +12,69 @@ namespace HotChocolate.Fusion.PreMergeValidation.Rules; /// /// Specification /// -internal sealed class DisallowedInaccessibleElementsRule : IPreMergeValidationRule +internal sealed class DisallowedInaccessibleElementsRule : PreMergeValidationRule { - public CompositionResult Run(PreMergeValidationContext context) + public override void OnEachType(EachTypeEvent @event) { - var loggingSession = context.Log.CreateSession(); + var (context, type, schema) = @event; - foreach (var schema in context.SchemaDefinitions) + // Built-in scalar types must be accessible. + if (type is ScalarTypeDefinition { IsSpecScalar: true } scalar + && !ValidationHelper.IsAccessible(scalar)) { - foreach (var type in schema.Types) - { - if (type is ScalarTypeDefinition { IsSpecScalar: true } scalar - && !ValidationHelper.IsAccessible(type)) - { - loggingSession.Write(DisallowedInaccessibleScalar(scalar, schema)); - } + context.Log.Write(DisallowedInaccessibleScalar(scalar, schema)); + } + + // Introspection types must be accessible. + if (type.IsIntrospectionType && !ValidationHelper.IsAccessible(type)) + { + context.Log.Write(DisallowedInaccessibleIntrospectionType(type, schema)); + } + } - if (type.IsIntrospectionType) - { - if (!ValidationHelper.IsAccessible(type)) - { - loggingSession.Write(DisallowedInaccessibleIntrospectionType(type, schema)); - } + public override void OnEachOutputField(EachOutputFieldEvent @event) + { + var (context, field, type, schema) = @event; - if (type is ComplexTypeDefinition complexType) - { - foreach (var field in complexType.Fields) - { - if (!ValidationHelper.IsAccessible(field)) - { - loggingSession.Write( - DisallowedInaccessibleIntrospectionField( - field, - type.Name, - schema)); - } + // Introspection fields must be accessible. + if (type.IsIntrospectionType && !ValidationHelper.IsAccessible(field)) + { + context.Log.Write( + DisallowedInaccessibleIntrospectionField( + field, + type.Name, + schema)); + } + } - foreach (var argument in field.Arguments) - { - if (!ValidationHelper.IsAccessible(argument)) - { - loggingSession.Write( - DisallowedInaccessibleIntrospectionArgument( - argument, - field.Name, - type.Name, - schema)); - } - } - } - } - } - } + public override void OnEachFieldArgument(EachFieldArgumentEvent @event) + { + var (context, argument, field, type, schema) = @event; - foreach (var directive in schema.DirectiveDefinitions) - { - if (BuiltIns.IsBuiltInDirective(directive.Name)) - { - foreach (var argument in directive.Arguments) - { - if (!ValidationHelper.IsAccessible(argument)) - { - loggingSession.Write( - DisallowedInaccessibleDirectiveArgument( - argument, - directive.Name, - schema)); - } - } - } - } + // Introspection arguments must be accessible. + if (type.IsIntrospectionType && !ValidationHelper.IsAccessible(argument)) + { + context.Log.Write( + DisallowedInaccessibleIntrospectionArgument( + argument, + field.Name, + type.Name, + schema)); } + } - return loggingSession.ErrorCount == 0 - ? CompositionResult.Success() - : ErrorHelper.PreMergeValidationRuleFailed(this); + public override void OnEachDirectiveArgument(EachDirectiveArgumentEvent @event) + { + var (context, argument, directive, schema) = @event; + + // Built-in directive arguments must be accessible. + if (BuiltIns.IsBuiltInDirective(directive.Name) && !ValidationHelper.IsAccessible(argument)) + { + context.Log.Write( + DisallowedInaccessibleDirectiveArgument( + argument, + directive.Name, + schema)); + } } } diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/PreMergeValidation/Rules/OutputFieldTypesMergeableRule.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/PreMergeValidation/Rules/OutputFieldTypesMergeableRule.cs index e93c6e91b14..cb111bc86a9 100644 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/PreMergeValidation/Rules/OutputFieldTypesMergeableRule.cs +++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/PreMergeValidation/Rules/OutputFieldTypesMergeableRule.cs @@ -1,7 +1,4 @@ -using HotChocolate.Fusion.Errors; using HotChocolate.Fusion.Logging; -using HotChocolate.Fusion.PreMergeValidation.Contracts; -using HotChocolate.Fusion.Results; namespace HotChocolate.Fusion.PreMergeValidation.Rules; @@ -12,28 +9,15 @@ namespace HotChocolate.Fusion.PreMergeValidation.Rules; /// /// Specification /// -internal sealed class OutputFieldTypesMergeableRule : IPreMergeValidationRule +internal sealed class OutputFieldTypesMergeableRule : PreMergeValidationRule { - public CompositionResult Run(PreMergeValidationContext context) + public override void OnEachOutputFieldGroup(EachOutputFieldGroupEvent @event) { - var loggingSession = context.Log.CreateSession(); + var (context, fieldName, fieldGroup, typeName) = @event; - foreach (var outputTypeInfo in context.OutputTypeInfo) + if (!ValidationHelper.FieldsAreMergeable([.. fieldGroup.Select(i => i.Field)])) { - foreach (var fieldInfo in outputTypeInfo.FieldInfo) - { - if (!ValidationHelper.FieldsAreMergeable(fieldInfo.Fields)) - { - loggingSession.Write( - LogEntryHelper.OutputFieldTypesNotMergeable( - fieldInfo.FieldName, - outputTypeInfo.TypeName)); - } - } + context.Log.Write(LogEntryHelper.OutputFieldTypesNotMergeable(fieldName, typeName)); } - - return loggingSession.ErrorCount == 0 - ? CompositionResult.Success() - : ErrorHelper.PreMergeValidationRuleFailed(this); } } diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/Properties/CompositionResources.Designer.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/Properties/CompositionResources.Designer.cs index b3a9cb1b02d..416eba365d5 100644 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/Properties/CompositionResources.Designer.cs +++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/Properties/CompositionResources.Designer.cs @@ -60,11 +60,11 @@ internal CompositionResources() { } /// - /// Looks up a localized string similar to Pre-merge validation rule '{0}' failed. View the composition log for details.. + /// Looks up a localized string similar to Pre-merge validation failed. View the composition log for details.. /// - internal static string ErrorHelper_PreMergeValidationRuleFailed { + internal static string ErrorHelper_PreMergeValidationFailed { get { - return ResourceManager.GetString("ErrorHelper_PreMergeValidationRuleFailed", resourceCulture); + return ResourceManager.GetString("ErrorHelper_PreMergeValidationFailed", resourceCulture); } } diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/Properties/CompositionResources.resx b/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/Properties/CompositionResources.resx index d291d0f232a..6ec14bcc4c0 100644 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/Properties/CompositionResources.resx +++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/Properties/CompositionResources.resx @@ -18,8 +18,8 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - Pre-merge validation rule '{0}' failed. View the composition log for details. + + Pre-merge validation failed. View the composition log for details. The built-in scalar type '{0}' is not accessible. diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/SourceSchemaMerger.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/SourceSchemaMerger.cs index eb2266bc711..3947119100c 100644 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/SourceSchemaMerger.cs +++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/SourceSchemaMerger.cs @@ -1,5 +1,7 @@ using HotChocolate.Fusion.PostMergeValidation; using HotChocolate.Fusion.PreMergeValidation; +using HotChocolate.Fusion.PreMergeValidation.Contracts; +using HotChocolate.Fusion.PreMergeValidation.Rules; using HotChocolate.Fusion.Results; using HotChocolate.Skimmed; @@ -10,7 +12,8 @@ internal sealed class SourceSchemaMerger public CompositionResult Merge(CompositionContext context) { // Pre Merge Validation - var preMergeValidationResult = new PreMergeValidator().Validate(context); + var preMergeValidationResult = + new PreMergeValidator(_preMergeValidationRules).Validate(context); if (preMergeValidationResult.IsFailure) { @@ -41,4 +44,10 @@ private CompositionResult MergeSchemaDefinitions(CompositionCo // FIXME: Implement. return new SchemaDefinition(); } + + private static readonly List _preMergeValidationRules = + [ + new DisallowedInaccessibleElementsRule(), + new OutputFieldTypesMergeableRule() + ]; } diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.Composition.Tests/PreMergeValidation/Rules/DisallowedInaccessibleElementsRuleTests.cs b/src/HotChocolate/Fusion-vnext/test/Fusion.Composition.Tests/PreMergeValidation/Rules/DisallowedInaccessibleElementsRuleTests.cs index b46fee89348..3789b4ad1b3 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.Composition.Tests/PreMergeValidation/Rules/DisallowedInaccessibleElementsRuleTests.cs +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.Composition.Tests/PreMergeValidation/Rules/DisallowedInaccessibleElementsRuleTests.cs @@ -14,13 +14,11 @@ public async Task Examples_Valid(string[] sdl) { // arrange var log = new CompositionLog(); - var context = new PreMergeValidationContext( - new CompositionContext([.. sdl.Select(SchemaParser.Parse)], log)); - - context.Initialize(); + var context = new CompositionContext([.. sdl.Select(SchemaParser.Parse)], log); + var preMergeValidator = new PreMergeValidator([new DisallowedInaccessibleElementsRule()]); // act - var result = new DisallowedInaccessibleElementsRule().Run(context); + var result = preMergeValidator.Validate(context); // assert await Assert.That(result.IsSuccess).IsTrue(); @@ -33,13 +31,11 @@ public async Task Examples_Invalid(string[] sdl) { // arrange var log = new CompositionLog(); - var context = new PreMergeValidationContext( - new CompositionContext([.. sdl.Select(SchemaParser.Parse)], log)); - - context.Initialize(); + var context = new CompositionContext([.. sdl.Select(SchemaParser.Parse)], log); + var preMergeValidator = new PreMergeValidator([new DisallowedInaccessibleElementsRule()]); // act - var result = new DisallowedInaccessibleElementsRule().Run(context); + var result = preMergeValidator.Validate(context); // assert await Assert.That(result.IsFailure).IsTrue(); diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.Composition.Tests/PreMergeValidation/Rules/OutputFieldTypesMergeableRuleTests.cs b/src/HotChocolate/Fusion-vnext/test/Fusion.Composition.Tests/PreMergeValidation/Rules/OutputFieldTypesMergeableRuleTests.cs index 998ee86ef0d..c87318a0e0a 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.Composition.Tests/PreMergeValidation/Rules/OutputFieldTypesMergeableRuleTests.cs +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.Composition.Tests/PreMergeValidation/Rules/OutputFieldTypesMergeableRuleTests.cs @@ -14,13 +14,11 @@ public async Task Examples_Valid(string[] sdl) { // arrange var log = new CompositionLog(); - var context = new PreMergeValidationContext( - new CompositionContext([.. sdl.Select(SchemaParser.Parse)], log)); - - context.Initialize(); + var context = new CompositionContext([.. sdl.Select(SchemaParser.Parse)], log); + var preMergeValidator = new PreMergeValidator([new OutputFieldTypesMergeableRule()]); // act - var result = new OutputFieldTypesMergeableRule().Run(context); + var result = preMergeValidator.Validate(context); // assert await Assert.That(result.IsSuccess).IsTrue(); @@ -33,13 +31,11 @@ public async Task Examples_Invalid(string[] sdl) { // arrange var log = new CompositionLog(); - var context = new PreMergeValidationContext( - new CompositionContext([.. sdl.Select(SchemaParser.Parse)], log)); - - context.Initialize(); + var context = new CompositionContext([.. sdl.Select(SchemaParser.Parse)], log); + var preMergeValidator = new PreMergeValidator([new OutputFieldTypesMergeableRule()]); // act - var result = new OutputFieldTypesMergeableRule().Run(context); + var result = preMergeValidator.Validate(context); // assert await Assert.That(result.IsFailure).IsTrue();