diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/Options/SatisfiabilityOptions.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/Options/SatisfiabilityOptions.cs
index d32383b690b..03ee555fef6 100644
--- a/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/Options/SatisfiabilityOptions.cs
+++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/Options/SatisfiabilityOptions.cs
@@ -5,6 +5,11 @@ namespace HotChocolate.Fusion.Options;
///
public sealed class SatisfiabilityOptions
{
+ ///
+ /// Gets a value indicating whether to show paths in satisfiability error messages.
+ ///
+ public bool IncludeSatisfiabilityPaths { get; set; }
+
///
/// A collection of fields that should be ignored during the satisfiability analysis
/// because they are known to be non-accessible. The key is the qualified field name (e.g.
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 2615f4805b0..6c32735fb05 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
@@ -1238,6 +1238,15 @@ internal static string RequirementsValidator_NoOtherSchemasContainField {
}
}
+ ///
+ /// Looks up a localized string similar to Unable to access the required field '{0}.{1}'..
+ ///
+ internal static string RequirementsValidator_UnableToAccessField {
+ get {
+ return ResourceManager.GetString("RequirementsValidator_UnableToAccessField", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Unable to access the required field '{0}.{1}' on path '{2}'..
///
@@ -1319,6 +1328,15 @@ internal static string SatisfiabilityValidator_NoLookupsFoundForType {
}
}
+ ///
+ /// Looks up a localized string similar to Unable to access the field '{0}.{1}'..
+ ///
+ internal static string SatisfiabilityValidator_UnableToAccessField {
+ get {
+ return ResourceManager.GetString("SatisfiabilityValidator_UnableToAccessField", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Unable to access the field '{0}.{1}' on path '{2}'..
///
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 4f443e50546..73f3d0ddfdf 100644
--- a/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/Properties/CompositionResources.resx
+++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/Properties/CompositionResources.resx
@@ -408,6 +408,9 @@
No other schemas contain the field '{0}.{1}'.
+
+ Unable to access the required field '{0}.{1}'.
+
Unable to access the required field '{0}.{1}' on path '{2}'.
@@ -435,6 +438,9 @@
No lookups found for type '{0}' in schema '{1}'.
+
+ Unable to access the field '{0}.{1}'.
+
Unable to access the field '{0}.{1}' on path '{2}'.
diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/Satisfiability/RequirementsValidator.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/Satisfiability/RequirementsValidator.cs
index 4324be05a5b..653588e52b5 100644
--- a/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/Satisfiability/RequirementsValidator.cs
+++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/Satisfiability/RequirementsValidator.cs
@@ -9,7 +9,9 @@
namespace HotChocolate.Fusion.Satisfiability;
-internal sealed class RequirementsValidator(MutableSchemaDefinition schema)
+internal sealed class RequirementsValidator(
+ MutableSchemaDefinition schema,
+ bool includeSatisfiabilityPaths = false)
{
public ImmutableArray Validate(
SelectionSetNode requirements,
@@ -62,14 +64,19 @@ private ImmutableArray Visit(
if (fieldErrors.Length != 0)
{
var type = context.TypeContext.Peek();
-
- errors.Add(new SatisfiabilityError(
- string.Format(
- RequirementsValidator_UnableToAccessFieldOnPath,
- type.Name,
- fieldNode.Name.Value,
- context.Path),
- [.. fieldErrors]));
+ var message =
+ includeSatisfiabilityPaths
+ ? string.Format(
+ RequirementsValidator_UnableToAccessFieldOnPath,
+ type.Name,
+ fieldNode.Name.Value,
+ context.Path)
+ : string.Format(
+ RequirementsValidator_UnableToAccessField,
+ type.Name,
+ fieldNode.Name.Value);
+
+ errors.Add(new SatisfiabilityError(message, [.. fieldErrors]));
}
break;
@@ -191,7 +198,7 @@ private ImmutableArray Visit(
if (requirements is not null)
{
var requirementErrors =
- new RequirementsValidator(schema).Validate(
+ new RequirementsValidator(schema, includeSatisfiabilityPaths).Validate(
requirements,
type,
context.Path.Peek(),
diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/SatisfiabilityValidator.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/SatisfiabilityValidator.cs
index e40bc0b90e5..8a71abadb20 100644
--- a/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/SatisfiabilityValidator.cs
+++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Composition/SatisfiabilityValidator.cs
@@ -16,20 +16,30 @@
namespace HotChocolate.Fusion;
-internal sealed class SatisfiabilityValidator(
- MutableSchemaDefinition schema,
- ICompositionLog log,
- SatisfiabilityOptions? options = null)
+internal sealed class SatisfiabilityValidator
{
- private readonly SatisfiabilityOptions _options = options ?? new SatisfiabilityOptions();
- private readonly RequirementsValidator _requirementsValidator = new(schema);
+ private readonly SatisfiabilityOptions _options;
+ private readonly RequirementsValidator _requirementsValidator;
+ private readonly MutableSchemaDefinition _schema;
+ private readonly ICompositionLog _log;
+
+ public SatisfiabilityValidator(
+ MutableSchemaDefinition schema,
+ ICompositionLog log,
+ SatisfiabilityOptions? options = null)
+ {
+ _schema = schema;
+ _log = log;
+ _options = options ?? new SatisfiabilityOptions();
+ _requirementsValidator = new RequirementsValidator(schema, _options.IncludeSatisfiabilityPaths);
+ }
public CompositionResult Validate()
{
var context = new SatisfiabilityValidatorContext();
MutableObjectTypeDefinition?[] rootTypes =
- [schema.QueryType, schema.MutationType, schema.SubscriptionType];
+ [_schema.QueryType, _schema.MutationType, _schema.SubscriptionType];
foreach (var rootType in rootTypes)
{
@@ -39,7 +49,7 @@ public CompositionResult Validate()
}
}
- return log.HasErrors
+ return _log.HasErrors
? ErrorHelper.SatisfiabilityValidationFailed()
: CompositionResult.Success();
}
@@ -60,8 +70,8 @@ private void VisitObjectType(
// The node and nodes fields are "virtual" fields that might not directly map
// to an underlying source schema, so we have to validate them differently.
if (field.Name is FieldNames.Node or FieldNames.Nodes
- && objectType == schema.QueryType
- && schema.Types.TryGetType(WellKnownTypeNames.Node, out var nodeType)
+ && objectType == _schema.QueryType
+ && _schema.Types.TryGetType(WellKnownTypeNames.Node, out var nodeType)
&& field.Type.NamedType() == nodeType)
{
if (field.Name == FieldNames.Nodes)
@@ -107,7 +117,7 @@ private void VisitOutputField(
// If the field is marked as partial, it must be provided by the current schema for it
// to be an option.
if (field.IsPartial(schemaName)
- && previousPathItem?.Provides(field, type, schemaName, schema) != true)
+ && previousPathItem?.Provides(field, type, schemaName, _schema) != true)
{
continue;
}
@@ -178,7 +188,7 @@ private void VisitOutputField(
// Visit each of the possible types that the field may return.
if (fieldType is MutableComplexTypeDefinition or MutableUnionTypeDefinition)
{
- var possibleTypes = fieldType.GetPossibleTypes(schemaName, schema);
+ var possibleTypes = fieldType.GetPossibleTypes(schemaName, _schema);
foreach (var possibleType in possibleTypes)
{
@@ -211,15 +221,21 @@ private void VisitOutputField(
return;
}
- var error = new SatisfiabilityError(
- string.Format(
- SatisfiabilityValidator_UnableToAccessFieldOnPath,
- type.Name,
- field.Name,
- context.Path),
- [.. errors]);
+ var message =
+ _options.IncludeSatisfiabilityPaths
+ ? string.Format(
+ SatisfiabilityValidator_UnableToAccessFieldOnPath,
+ type.Name,
+ field.Name,
+ context.Path)
+ : string.Format(
+ SatisfiabilityValidator_UnableToAccessField,
+ type.Name,
+ field.Name);
+
+ var error = new SatisfiabilityError(message, [.. errors]);
- log.Write(
+ _log.Write(
LogEntryBuilder.New()
.SetMessage(error.ToString())
.SetCode(LogEntryCodes.Unsatisfiable)
@@ -235,9 +251,9 @@ private void VisitNodeField(
IInterfaceTypeDefinition nodeType,
SatisfiabilityValidatorContext context)
{
- foreach (var possibleType in schema.GetPossibleTypes(nodeType))
+ foreach (var possibleType in _schema.GetPossibleTypes(nodeType))
{
- var byIdLookups = schema
+ var byIdLookups = _schema
.GetPossibleFusionLookupDirectivesById(possibleType);
var hasNodeLookup = false;
@@ -252,7 +268,7 @@ private void VisitNodeField(
var lookupFieldDefinition = ParseFieldDefinition(fieldDirectiveArgument);
var lookupFieldTypeName = lookupFieldDefinition.Type.NamedType().Name.Value;
- if (!schema.Types.TryGetType(lookupFieldTypeName, out var lookupFieldNamedType))
+ if (!_schema.Types.TryGetType(lookupFieldTypeName, out var lookupFieldNamedType))
{
continue;
}
@@ -279,7 +295,7 @@ private void VisitNodeField(
var error = new SatisfiabilityError(
string.Format(SatisfiabilityValidator_NodeTypeHasNoNodeLookup, possibleType.Name));
- log.Write(
+ _log.Write(
LogEntryBuilder.New()
.SetMessage(error.ToString())
.SetCode(LogEntryCodes.Unsatisfiable)
@@ -300,7 +316,7 @@ private ImmutableArray ValidateSourceSchemaTransition(
var errors = new List();
var lookupDirectives =
- schema.GetPossibleFusionLookupDirectives(type, transitionToSchemaName);
+ _schema.GetPossibleFusionLookupDirectives(type, transitionToSchemaName);
if (!lookupDirectives.Any() && !CanTransitionToSchemaThroughPath(context.Path, transitionToSchemaName))
{
@@ -365,7 +381,7 @@ private bool CanTransitionToSchemaThroughPath(
foreach (var pathItem in path)
{
var lookupDirectives =
- schema.GetPossibleFusionLookupDirectives(
+ _schema.GetPossibleFusionLookupDirectives(
pathItem.Type,
schemaName);
diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.Composition.Tests/SatisfiabilityValidatorTests.cs b/src/HotChocolate/Fusion-vnext/test/Fusion.Composition.Tests/SatisfiabilityValidatorTests.cs
index 0d8c4566bc2..cc86ba2bbb0 100644
--- a/src/HotChocolate/Fusion-vnext/test/Fusion.Composition.Tests/SatisfiabilityValidatorTests.cs
+++ b/src/HotChocolate/Fusion-vnext/test/Fusion.Composition.Tests/SatisfiabilityValidatorTests.cs
@@ -53,7 +53,8 @@ type User {
var schema = merger.Merge().Value;
var log = new CompositionLog();
- var satisfiabilityValidator = new SatisfiabilityValidator(schema, log);
+ var options = new SatisfiabilityOptions { IncludeSatisfiabilityPaths = true };
+ var satisfiabilityValidator = new SatisfiabilityValidator(schema, log, options);
// act
var result = satisfiabilityValidator.Validate();
@@ -109,7 +110,8 @@ type Product {
var schema = merger.Merge().Value;
var log = new CompositionLog();
- var satisfiabilityValidator = new SatisfiabilityValidator(schema, log);
+ var options = new SatisfiabilityOptions { IncludeSatisfiabilityPaths = true };
+ var satisfiabilityValidator = new SatisfiabilityValidator(schema, log, options);
// act
var result = satisfiabilityValidator.Validate();
@@ -168,7 +170,8 @@ type Product {
var schema = merger.Merge().Value;
var log = new CompositionLog();
- var satisfiabilityValidator = new SatisfiabilityValidator(schema, log);
+ var options = new SatisfiabilityOptions { IncludeSatisfiabilityPaths = true };
+ var satisfiabilityValidator = new SatisfiabilityValidator(schema, log, options);
// act
var result = satisfiabilityValidator.Validate();
@@ -307,7 +310,8 @@ type Address @shareable {
var schema = merger.Merge().Value;
var log = new CompositionLog();
- var satisfiabilityValidator = new SatisfiabilityValidator(schema, log);
+ var options = new SatisfiabilityOptions { IncludeSatisfiabilityPaths = true };
+ var satisfiabilityValidator = new SatisfiabilityValidator(schema, log, options);
// act
var result = satisfiabilityValidator.Validate();
@@ -362,7 +366,8 @@ type Category @key(fields: "id") {
var schema = merger.Merge().Value;
var log = new CompositionLog();
- var satisfiabilityValidator = new SatisfiabilityValidator(schema, log);
+ var options = new SatisfiabilityOptions { IncludeSatisfiabilityPaths = true };
+ var satisfiabilityValidator = new SatisfiabilityValidator(schema, log, options);
// act
var result = satisfiabilityValidator.Validate();
@@ -1456,7 +1461,8 @@ type Product {
var schema = merger.Merge().Value;
var log = new CompositionLog();
- var satisfiabilityValidator = new SatisfiabilityValidator(schema, log);
+ var options = new SatisfiabilityOptions { IncludeSatisfiabilityPaths = true };
+ var satisfiabilityValidator = new SatisfiabilityValidator(schema, log, options);
// act
var result = satisfiabilityValidator.Validate();
@@ -1617,7 +1623,8 @@ interface Animal {
var schema = merger.Merge().Value;
var log = new CompositionLog();
- var satisfiabilityValidator = new SatisfiabilityValidator(schema, log);
+ var options = new SatisfiabilityOptions { IncludeSatisfiabilityPaths = true };
+ var satisfiabilityValidator = new SatisfiabilityValidator(schema, log, options);
// act
var result = satisfiabilityValidator.Validate();
@@ -1964,7 +1971,8 @@ type Dog {
var schema = merger.Merge().Value;
var log = new CompositionLog();
- var satisfiabilityValidator = new SatisfiabilityValidator(schema, log);
+ var options = new SatisfiabilityOptions { IncludeSatisfiabilityPaths = true };
+ var satisfiabilityValidator = new SatisfiabilityValidator(schema, log, options);
// act
var result = satisfiabilityValidator.Validate();
@@ -2015,7 +2023,8 @@ type Product {
var schema = merger.Merge().Value;
var log = new CompositionLog();
- var satisfiabilityValidator = new SatisfiabilityValidator(schema, log);
+ var options = new SatisfiabilityOptions { IncludeSatisfiabilityPaths = true };
+ var satisfiabilityValidator = new SatisfiabilityValidator(schema, log, options);
// act
var result = satisfiabilityValidator.Validate();
@@ -2102,7 +2111,8 @@ type Section {
var schema = merger.Merge().Value;
var log = new CompositionLog();
- var satisfiabilityValidator = new SatisfiabilityValidator(schema, log);
+ var options = new SatisfiabilityOptions { IncludeSatisfiabilityPaths = true };
+ var satisfiabilityValidator = new SatisfiabilityValidator(schema, log, options);
// act
var result = satisfiabilityValidator.Validate();
@@ -2281,7 +2291,8 @@ type Viewer {
var schema = merger.Merge().Value;
var log = new CompositionLog();
- var satisfiabilityValidator = new SatisfiabilityValidator(schema, log);
+ var options = new SatisfiabilityOptions { IncludeSatisfiabilityPaths = true };
+ var satisfiabilityValidator = new SatisfiabilityValidator(schema, log, options);
// act
var result = satisfiabilityValidator.Validate();
@@ -2340,7 +2351,8 @@ type Viewer {
var schema = merger.Merge().Value;
var log = new CompositionLog();
- var satisfiabilityValidator = new SatisfiabilityValidator(schema, log);
+ var options = new SatisfiabilityOptions { IncludeSatisfiabilityPaths = true };
+ var satisfiabilityValidator = new SatisfiabilityValidator(schema, log, options);
// act
var result = satisfiabilityValidator.Validate();
@@ -2506,7 +2518,8 @@ type Section {
"Section.name",
["A:Query.productById -> B:Product.section"]
}
- }
+ },
+ IncludeSatisfiabilityPaths = true
};
var satisfiabilityValidator = new SatisfiabilityValidator(schema, log, options);
@@ -2534,7 +2547,8 @@ public void GlobalObjectIdentification_Examples(string[] sdl, bool success, stri
var schema = merger.Merge().Value;
var log = new CompositionLog();
- var satisfiabilityValidator = new SatisfiabilityValidator(schema, log);
+ var options = new SatisfiabilityOptions { IncludeSatisfiabilityPaths = true };
+ var satisfiabilityValidator = new SatisfiabilityValidator(schema, log, options);
// act
var result = satisfiabilityValidator.Validate();
diff --git a/src/Nitro/CommandLine/src/CommandLine/Commands/Fusion/FusionComposeCommand.cs b/src/Nitro/CommandLine/src/CommandLine/Commands/Fusion/FusionComposeCommand.cs
index 69a1a4771e8..859db16bcac 100644
--- a/src/Nitro/CommandLine/src/CommandLine/Commands/Fusion/FusionComposeCommand.cs
+++ b/src/Nitro/CommandLine/src/CommandLine/Commands/Fusion/FusionComposeCommand.cs
@@ -67,6 +67,11 @@ public FusionComposeCommand() : base("compose")
Description = ComposeCommand_EnableGlobalObjectIdentification_Description
};
+ var includeSatisfiabilityPathsOption = new Option("--include-satisfiability-paths")
+ {
+ Description = ComposeCommand_IncludeSatisfiabilityPaths_Description
+ };
+
var watchModeOption = new Option("--watch") { Arity = ArgumentArity.ZeroOrOne };
var printSchemaOption = new Option("--print") { IsHidden = true };
@@ -76,6 +81,7 @@ public FusionComposeCommand() : base("compose")
AddOption(archiveOption);
AddOption(environmentOption);
AddOption(enableGlobalIdsOption);
+ AddOption(includeSatisfiabilityPathsOption);
AddOption(watchModeOption);
AddOption(printSchemaOption);
@@ -86,6 +92,7 @@ public FusionComposeCommand() : base("compose")
var archive = context.ParseResult.GetValueForOption(archiveOption);
var environment = context.ParseResult.GetValueForOption(environmentOption);
var enableGlobalIds = context.ParseResult.GetValueForOption(enableGlobalIdsOption);
+ var includeSatisfiabilityPaths = context.ParseResult.GetValueForOption(includeSatisfiabilityPathsOption);
var watchMode = context.ParseResult.GetValueForOption(watchModeOption);
var printSchema = context.ParseResult.GetValueForOption(printSchemaOption);
@@ -96,6 +103,7 @@ public FusionComposeCommand() : base("compose")
archive,
environment,
enableGlobalIds,
+ includeSatisfiabilityPaths,
watchMode,
printSchema,
context.GetCancellationToken());
@@ -109,6 +117,7 @@ private static async Task ExecuteAsync(
string? archiveFile,
string? environment,
bool? enableGlobalObjectIdentification,
+ bool? includeSatisfiabilityPaths,
bool watchMode,
bool printSchema,
CancellationToken cancellationToken)
@@ -153,6 +162,7 @@ private static async Task ExecuteAsync(
archiveFile,
environment,
enableGlobalObjectIdentification,
+ includeSatisfiabilityPaths,
cancellationToken);
}
@@ -166,6 +176,10 @@ private static async Task ExecuteAsync(
Merger = new CompositionSettings.MergerSettings
{
EnableGlobalObjectIdentification = enableGlobalObjectIdentification
+ },
+ Satisfiability = new CompositionSettings.SatisfiabilitySettings
+ {
+ IncludeSatisfiabilityPaths = includeSatisfiabilityPaths
}
},
printSchema,
@@ -179,6 +193,7 @@ private static async Task WatchComposeAsync(
string archiveFile,
string? environment,
bool? enableGlobalObjectIdentification,
+ bool? includeSatisfiabilityPaths,
CancellationToken cancellationToken)
{
console.Out.WriteLine("🔍 Starting watch mode...");
@@ -194,6 +209,10 @@ await ComposeAsync(
Merger = new CompositionSettings.MergerSettings
{
EnableGlobalObjectIdentification = enableGlobalObjectIdentification
+ },
+ Satisfiability = new CompositionSettings.SatisfiabilitySettings
+ {
+ IncludeSatisfiabilityPaths = includeSatisfiabilityPaths
}
},
false,
@@ -218,6 +237,7 @@ await ComposeAsync(
archiveFile,
environment,
enableGlobalObjectIdentification,
+ includeSatisfiabilityPaths,
cancellationToken);
var sourceSchemaFileWatchers = new List();
@@ -334,6 +354,7 @@ private static async Task ProcessCompositionRequestsAsync(
string archiveFile,
string? environment,
bool? enableGlobalObjectIdentification,
+ bool? includeSatisfiabilityPaths,
CancellationToken cancellationToken)
{
var lastComposition = DateTime.MinValue;
@@ -369,6 +390,10 @@ await ComposeAsync(
Merger = new CompositionSettings.MergerSettings
{
EnableGlobalObjectIdentification = enableGlobalObjectIdentification
+ },
+ Satisfiability = new CompositionSettings.SatisfiabilitySettings
+ {
+ IncludeSatisfiabilityPaths = includeSatisfiabilityPaths
}
},
false,
@@ -529,8 +554,8 @@ await archive.GetSourceSchemaNamesAsync(cancellationToken),
compositionSettings?.MergeInto(existingCompositionSettings) ?? existingCompositionSettings;
var sourceSchemaOptionsMap = new Dictionary();
- var mergerOptions = mergedCompositionSettings.Merger?.ToOptions() ?? new SourceSchemaMergerOptions();
- var satisfiabilityOptions = new SatisfiabilityOptions();
+ var mergerOptions = mergedCompositionSettings.Merger.ToOptions();
+ var satisfiabilityOptions = mergedCompositionSettings.Satisfiability.ToOptions();
foreach (var (sourceSchemaName, (_, sourceSchemaSettings)) in sourceSchemas)
{
@@ -551,7 +576,7 @@ await archive.GetSourceSchemaNamesAsync(cancellationToken),
Satisfiability = satisfiabilityOptions
};
- if (existingCompositionSettings.Merger?.EnableGlobalObjectIdentification
+ if (existingCompositionSettings.Merger.EnableGlobalObjectIdentification
!= schemaComposerOptions.Merger.EnableGlobalObjectIdentification)
{
compositionLog.Write(
@@ -746,6 +771,10 @@ private static async Task SaveCompositionSettingsAsync(
Merger = new CompositionSettings.MergerSettings
{
EnableGlobalObjectIdentification = options.Merger.EnableGlobalObjectIdentification
+ },
+ Satisfiability = new CompositionSettings.SatisfiabilitySettings
+ {
+ IncludeSatisfiabilityPaths = options.Satisfiability.IncludeSatisfiabilityPaths
}
};
var settingsJson = JsonSerializer.SerializeToDocument(
diff --git a/src/Nitro/CommandLine/src/CommandLine/Commands/Fusion/FusionSettingsSetCommand.cs b/src/Nitro/CommandLine/src/CommandLine/Commands/Fusion/FusionSettingsSetCommand.cs
index f9397d603b2..295d82755ae 100644
--- a/src/Nitro/CommandLine/src/CommandLine/Commands/Fusion/FusionSettingsSetCommand.cs
+++ b/src/Nitro/CommandLine/src/CommandLine/Commands/Fusion/FusionSettingsSetCommand.cs
@@ -69,7 +69,7 @@ private static async Task ExecuteAsync(
var tags = settingValue
.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
- compositionSettings.Preprocessor!.ExcludeByTag = tags.ToHashSet();
+ compositionSettings.Preprocessor.ExcludeByTag = tags.ToHashSet();
break;
case SettingNames.GlobalObjectIdentification:
@@ -79,7 +79,17 @@ private static async Task ExecuteAsync(
return ExitCodes.Error;
}
- compositionSettings.Merger!.EnableGlobalObjectIdentification = enableGlobalObjectIdentification;
+ compositionSettings.Merger.EnableGlobalObjectIdentification = enableGlobalObjectIdentification;
+ break;
+
+ case SettingNames.IncludeSatisfiabilityPaths:
+ if (!bool.TryParse(settingValue, out var includeSatisfiabilityPaths))
+ {
+ console.ErrorLine($"Expected a boolean value for setting '{settingName}'.");
+ return ExitCodes.Error;
+ }
+
+ compositionSettings.Satisfiability.IncludeSatisfiabilityPaths = includeSatisfiabilityPaths;
break;
default:
@@ -104,5 +114,6 @@ private static class SettingNames
{
public const string ExcludeByTag = "exclude-by-tag";
public const string GlobalObjectIdentification = "global-object-identification";
+ public const string IncludeSatisfiabilityPaths = "include-satisfiability-paths";
}
}
diff --git a/src/Nitro/CommandLine/src/CommandLine/Extensions/SettingsExtensions.cs b/src/Nitro/CommandLine/src/CommandLine/Extensions/SettingsExtensions.cs
index d2ed97cc7e9..b5834987c6c 100644
--- a/src/Nitro/CommandLine/src/CommandLine/Extensions/SettingsExtensions.cs
+++ b/src/Nitro/CommandLine/src/CommandLine/Extensions/SettingsExtensions.cs
@@ -14,20 +14,26 @@ public CompositionSettings MergeInto(CompositionSettings settings)
Merger = new CompositionSettings.MergerSettings
{
AddFusionDefinitions =
- compositionSettings.Merger?.AddFusionDefinitions
- ?? settings.Merger?.AddFusionDefinitions,
+ compositionSettings.Merger.AddFusionDefinitions
+ ?? settings.Merger.AddFusionDefinitions,
CacheControlMergeBehavior =
- compositionSettings.Merger?.CacheControlMergeBehavior
- ?? settings.Merger?.CacheControlMergeBehavior,
+ compositionSettings.Merger.CacheControlMergeBehavior
+ ?? settings.Merger.CacheControlMergeBehavior,
EnableGlobalObjectIdentification =
- compositionSettings.Merger?.EnableGlobalObjectIdentification
- ?? settings.Merger?.EnableGlobalObjectIdentification,
+ compositionSettings.Merger.EnableGlobalObjectIdentification
+ ?? settings.Merger.EnableGlobalObjectIdentification,
RemoveUnreferencedDefinitions =
- compositionSettings.Merger?.RemoveUnreferencedDefinitions
- ?? settings.Merger?.RemoveUnreferencedDefinitions,
+ compositionSettings.Merger.RemoveUnreferencedDefinitions
+ ?? settings.Merger.RemoveUnreferencedDefinitions,
TagMergeBehavior =
- compositionSettings.Merger?.TagMergeBehavior
- ?? settings.Merger?.TagMergeBehavior
+ compositionSettings.Merger.TagMergeBehavior
+ ?? settings.Merger.TagMergeBehavior
+ },
+ Satisfiability = new CompositionSettings.SatisfiabilitySettings
+ {
+ IncludeSatisfiabilityPaths =
+ compositionSettings.Satisfiability.IncludeSatisfiabilityPaths
+ ?? settings.Satisfiability.IncludeSatisfiabilityPaths
}
};
}
@@ -79,6 +85,21 @@ public SourceSchemaMergerOptions ToOptions()
}
}
+ extension(CompositionSettings.SatisfiabilitySettings satisfiabilitySettings)
+ {
+ public SatisfiabilityOptions ToOptions()
+ {
+ var satisfiabilityOptions = new SatisfiabilityOptions();
+
+ if (satisfiabilitySettings.IncludeSatisfiabilityPaths is { } includeSatisfiabilityPaths)
+ {
+ satisfiabilityOptions.IncludeSatisfiabilityPaths = includeSatisfiabilityPaths;
+ }
+
+ return satisfiabilityOptions;
+ }
+ }
+
extension(SourceSchemaSettings sourceSchemaSettings)
{
public SourceSchemaOptions ToOptions()
diff --git a/src/Nitro/CommandLine/src/CommandLine/Properties/CommandLineResources.Designer.cs b/src/Nitro/CommandLine/src/CommandLine/Properties/CommandLineResources.Designer.cs
index ac7f4cafd67..a4a3ece8ffa 100644
--- a/src/Nitro/CommandLine/src/CommandLine/Properties/CommandLineResources.Designer.cs
+++ b/src/Nitro/CommandLine/src/CommandLine/Properties/CommandLineResources.Designer.cs
@@ -176,6 +176,15 @@ internal static string ComposeCommand_GlobalObjectIdentification_Enabled {
}
}
+ ///
+ /// Looks up a localized string similar to Determines whether to include paths in satisfiability error messages..
+ ///
+ internal static string ComposeCommand_IncludeSatisfiabilityPaths_Description {
+ get {
+ return ResourceManager.GetString("ComposeCommand_IncludeSatisfiabilityPaths_Description", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Specifies the path to a source schema file (.graphqls) to include in the composition..
///
diff --git a/src/Nitro/CommandLine/src/CommandLine/Properties/CommandLineResources.resx b/src/Nitro/CommandLine/src/CommandLine/Properties/CommandLineResources.resx
index 025105d5ea8..9e6fe41e6d9 100644
--- a/src/Nitro/CommandLine/src/CommandLine/Properties/CommandLineResources.resx
+++ b/src/Nitro/CommandLine/src/CommandLine/Properties/CommandLineResources.resx
@@ -57,6 +57,9 @@
❌ Working directory '{0}' does not exist.
+
+ Determines whether to include paths in satisfiability error messages.
+
Specifies the path to a source schema file (.graphqls) to include in the composition.
diff --git a/src/Nitro/CommandLine/src/CommandLine/Settings/CompositionSettings.cs b/src/Nitro/CommandLine/src/CommandLine/Settings/CompositionSettings.cs
index 52f9b7c46ce..623d4294297 100644
--- a/src/Nitro/CommandLine/src/CommandLine/Settings/CompositionSettings.cs
+++ b/src/Nitro/CommandLine/src/CommandLine/Settings/CompositionSettings.cs
@@ -4,9 +4,11 @@ namespace ChilliCream.Nitro.CommandLine.Settings;
internal sealed record CompositionSettings
{
- public PreprocessorSettings? Preprocessor { get; init; } = new();
+ public PreprocessorSettings Preprocessor { get; init; } = new();
- public MergerSettings? Merger { get; init; } = new();
+ public MergerSettings Merger { get; init; } = new();
+
+ public SatisfiabilitySettings Satisfiability { get; init; } = new();
internal sealed record PreprocessorSettings
{
@@ -25,4 +27,9 @@ internal sealed record MergerSettings
public DirectiveMergeBehavior? TagMergeBehavior { get; init; }
}
+
+ internal sealed record SatisfiabilitySettings
+ {
+ public bool? IncludeSatisfiabilityPaths { get; set; }
+ }
}
diff --git a/src/Nitro/CommandLine/src/CommandLine/Settings/SettingsJsonSerializerContext.cs b/src/Nitro/CommandLine/src/CommandLine/Settings/SettingsJsonSerializerContext.cs
index 819ec35b90b..5a883cb1812 100644
--- a/src/Nitro/CommandLine/src/CommandLine/Settings/SettingsJsonSerializerContext.cs
+++ b/src/Nitro/CommandLine/src/CommandLine/Settings/SettingsJsonSerializerContext.cs
@@ -5,8 +5,10 @@ namespace ChilliCream.Nitro.CommandLine.Settings;
[JsonSerializable(typeof(CompositionSettings))]
[JsonSerializable(typeof(CompositionSettings.PreprocessorSettings), TypeInfoPropertyName = "CompositionPreprocessorSettings")]
+[JsonSerializable(typeof(CompositionSettings.SatisfiabilitySettings), TypeInfoPropertyName = "CompositionSatisfiabilitySettings")]
[JsonSerializable(typeof(SourceSchemaSettings))]
[JsonSerializable(typeof(SourceSchemaSettings.PreprocessorSettings), TypeInfoPropertyName = "SourceSchemaPreprocessorSettings")]
+[JsonSerializable(typeof(SourceSchemaSettings.SatisfiabilitySettings), TypeInfoPropertyName = "SourceSchemaSatisfiabilitySettings")]
[JsonSourceGenerationOptions(
Converters = [typeof(JsonStringEnumConverter)],
PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase)]
diff --git a/src/Nitro/CommandLine/test/CommandLine.Tests/Commands/Fusion/FusionComposeCommandTests.cs b/src/Nitro/CommandLine/test/CommandLine.Tests/Commands/Fusion/FusionComposeCommandTests.cs
index bf8984a21c7..c362e435a6f 100644
--- a/src/Nitro/CommandLine/test/CommandLine.Tests/Commands/Fusion/FusionComposeCommandTests.cs
+++ b/src/Nitro/CommandLine/test/CommandLine.Tests/Commands/Fusion/FusionComposeCommandTests.cs
@@ -389,7 +389,8 @@ public async Task Compose_IgnoredNonAccessibleFields()
"--source-schema-file",
"__resources__/valid-example-2/source-schema-b.graphqls",
"--fusion-archive",
- archiveFileName
+ archiveFileName,
+ "--include-satisfiability-paths"
];
var testConsole = new TestConsole();