using System.Globalization; using NodePipeline.Abstractions; using NodePipeline.Abstractions.Exceptions.Validation; using NodePipeline.Abstractions.Interfaces; using NodePipeline.Abstractions.Interfaces.Nodes; using NodePipeline.Abstractions.Interfaces.Validation; using NodePipeline.Abstractions.Models.Validation; using NodePipeline.Abstractions.Validators; using NodePipeline.Configuration.Abstractions.Models.Execute; using NodePipeline.Engine.Abstractions; using NodePipeline.Engine.NodeFields; using NodePipeline.Engine.Utils; using NodePipeline.Engine.Abstractions.Validation; // ReSharper disable CheckNamespace // ReSharper disable RedundantNameQualifier // ReSharper disable UnusedParameter.Local #nullable enable namespace NodePipeline.Engine.Generated; public sealed class GeneratedNodeValidator : IPipelineNodeValidator { private Dictionary? _allPorts; public Dictionary NodeValidators { get; set; } = []; public Dictionary NodeFieldValidators { get; set; } = []; public IPipelineLocalizationProvider PipelineLocalizationProvider { get; set; } = new PipelineLocalizationProvider(); public NodeValidationResult ValidateNode(string pipelineId, INodeFactory nodeFactory, NodeConfig nodeConfig, List allNodes, Dictionary parameters, CultureInfo cultureInfo) { var node = nodeFactory.CreateNode(pipelineId, nodeConfig); nodeFactory.SetNodeParametersValues(pipelineId, node, nodeConfig.Id, parameters); var nodeConnections = allNodes.SelectMany(q => q.Inputs .Select(x => new KeyValuePair(GetNodeInputKey(q.Id, x.Key), x.Value)) ).ToDictionary(q => q.Key, q => q.Value); var ports = GetAllPorts(pipelineId, nodeFactory, allNodes); switch (node) { case global::NodePipeline.Application.Nodes.FileImageSource2Node t1: return Validate__NodePipeline_Application_Nodes_FileImageSource2Node__Node(pipelineId, nodeFactory, t1, nodeConfig.Id, nodeConnections, ports, cultureInfo); case global::NodePipeline.Application.Nodes.FileImageSourceNode t2: return Validate__NodePipeline_Application_Nodes_FileImageSourceNode__Node(pipelineId, nodeFactory, t2, nodeConfig.Id, nodeConnections, ports, cultureInfo); case global::NodePipeline.Application.Nodes.GaussianBlurNode t3: return Validate__NodePipeline_Application_Nodes_GaussianBlurNode__Node(pipelineId, nodeFactory, t3, nodeConfig.Id, nodeConnections, ports, cultureInfo); case global::NodePipeline.Application.Nodes.MaskApplyNode t4: return Validate__NodePipeline_Application_Nodes_MaskApplyNode__Node(pipelineId, nodeFactory, t4, nodeConfig.Id, nodeConnections, ports, cultureInfo); case global::NodePipeline.Application.Nodes.SaveImage2Node t5: return Validate__NodePipeline_Application_Nodes_SaveImage2Node__Node(pipelineId, nodeFactory, t5, nodeConfig.Id, nodeConnections, ports, cultureInfo); case global::NodePipeline.Application.Nodes.SaveImageNode t6: return Validate__NodePipeline_Application_Nodes_SaveImageNode__Node(pipelineId, nodeFactory, t6, nodeConfig.Id, nodeConnections, ports, cultureInfo); default: throw new UnknownNodeTypeException(nodeConfig.Type, nodeConfig.Id); } } private NodeValidationResult Validate__NodePipeline_Application_Nodes_FileImageSource2Node__Node(string pipelineId, INodeFactory nodeFactory, global::NodePipeline.Application.Nodes.FileImageSource2Node node, string nodeId, IReadOnlyDictionary nodePortConnections, IReadOnlyDictionary ports, CultureInfo cultureInfo) { var fieldResults = new Dictionary>(); var portsValidationResult = ValidateNodePorts(pipelineId, nodeFactory, NodeNamePrefixSettings.TrimNodeName("NodePipeline.Application.Nodes.FileImageSource2"), nodeId, nodePortConnections, ports, out var portResults, cultureInfo); var isValid = portsValidationResult != ValidationResult.HasErrors; return !isValid ? GetErrorValidationResult(ValidationResult.HasErrors, nodeId, fieldResults, portResults, cultureInfo) : SuccessNodeValidationResult(portsValidationResult == ValidationResult.HasWarnings, fieldResults, portResults); } private NodeValidationResult Validate__NodePipeline_Application_Nodes_FileImageSourceNode__Node(string pipelineId, INodeFactory nodeFactory, global::NodePipeline.Application.Nodes.FileImageSourceNode node, string nodeId, IReadOnlyDictionary nodePortConnections, IReadOnlyDictionary ports, CultureInfo cultureInfo) { var validationResult = ValidationResult.Valid; var fieldResults = new Dictionary> { { "FileName", [] }, { "Extension", [] }, { "Directory", [] }, }; var r2 = new StringLengthValidator(PipelineLocalizationProvider, 1, null).Validate(node.FileName); fieldResults["FileName"].Add(r2); UpdateValidationResult(r2.Result, ref validationResult); var r3 = CheckRequiredNodeParameter(nodeId, node.FileName, "FileName", cultureInfo); fieldResults["FileName"].Add(r3); UpdateValidationResult(r3.Result, ref validationResult); var r4 = new StringLengthValidator(PipelineLocalizationProvider, 1, 10).Validate(node.Extension); fieldResults["Extension"].Add(r4); UpdateValidationResult(r4.Result, ref validationResult); var r5 = CheckRequiredNodeParameter(nodeId, node.Extension, "Extension", cultureInfo); fieldResults["Extension"].Add(r5); UpdateValidationResult(r5.Result, ref validationResult); var r6 = new StringLengthValidator(PipelineLocalizationProvider, 1, null).Validate(node.Directory); fieldResults["Directory"].Add(r6); UpdateValidationResult(r6.Result, ref validationResult); var r7 = CheckRequiredNodeParameter(nodeId, node.Directory, "Directory", cultureInfo); fieldResults["Directory"].Add(r7); UpdateValidationResult(r7.Result, ref validationResult); var portsValidationResult = ValidateNodePorts(pipelineId, nodeFactory, NodeNamePrefixSettings.TrimNodeName("NodePipeline.Application.Nodes.FileImageSource"), nodeId, nodePortConnections, ports, out var portResults, cultureInfo); var isValid = validationResult != ValidationResult.HasErrors && portsValidationResult != ValidationResult.HasErrors; UpdateValidationResult(portsValidationResult, ref validationResult); return !isValid ? GetErrorValidationResult(validationResult, nodeId, fieldResults, portResults, cultureInfo) : GetNodeValidator(typeof(global::NodePipeline.Application.FileImageSourceNodeValidator)).Validate( new Dictionary { { "FileName", node.FileName.Value }, { "Extension", node.Extension.Value }, { "Directory", node.Directory.Value }, }, fieldResults, portResults); } private NodeValidationResult Validate__NodePipeline_Application_Nodes_GaussianBlurNode__Node(string pipelineId, INodeFactory nodeFactory, global::NodePipeline.Application.Nodes.GaussianBlurNode node, string nodeId, IReadOnlyDictionary nodePortConnections, IReadOnlyDictionary ports, CultureInfo cultureInfo) { var validationResult = ValidationResult.Valid; var fieldResults = new Dictionary> { { "Radius", [] }, }; var r2 = new NumberRangeValidator(PipelineLocalizationProvider, 0, 300).Validate(node.Radius); fieldResults["Radius"].Add(r2); UpdateValidationResult(r2.Result, ref validationResult); var portsValidationResult = ValidateNodePorts(pipelineId, nodeFactory, NodeNamePrefixSettings.TrimNodeName("NodePipeline.Application.Nodes.GaussianBlur"), nodeId, nodePortConnections, ports, out var portResults, cultureInfo); var isValid = validationResult != ValidationResult.HasErrors && portsValidationResult != ValidationResult.HasErrors; UpdateValidationResult(portsValidationResult, ref validationResult); return !isValid ? GetErrorValidationResult(validationResult, nodeId, fieldResults, portResults, cultureInfo) : SuccessNodeValidationResult(validationResult == ValidationResult.HasWarnings || portsValidationResult == ValidationResult.HasWarnings, fieldResults, portResults); } private NodeValidationResult Validate__NodePipeline_Application_Nodes_MaskApplyNode__Node(string pipelineId, INodeFactory nodeFactory, global::NodePipeline.Application.Nodes.MaskApplyNode node, string nodeId, IReadOnlyDictionary nodePortConnections, IReadOnlyDictionary ports, CultureInfo cultureInfo) { var fieldResults = new Dictionary> { { "Mode", [] }, }; var portsValidationResult = ValidateNodePorts(pipelineId, nodeFactory, NodeNamePrefixSettings.TrimNodeName("NodePipeline.Application.Nodes.MaskApply"), nodeId, nodePortConnections, ports, out var portResults, cultureInfo); var isValid = portsValidationResult != ValidationResult.HasErrors; return !isValid ? GetErrorValidationResult(ValidationResult.HasErrors, nodeId, fieldResults, portResults, cultureInfo) : SuccessNodeValidationResult(portsValidationResult == ValidationResult.HasWarnings, fieldResults, portResults); } private NodeValidationResult Validate__NodePipeline_Application_Nodes_SaveImage2Node__Node(string pipelineId, INodeFactory nodeFactory, global::NodePipeline.Application.Nodes.SaveImage2Node node, string nodeId, IReadOnlyDictionary nodePortConnections, IReadOnlyDictionary ports, CultureInfo cultureInfo) { var fieldResults = new Dictionary>(); var portsValidationResult = ValidateNodePorts(pipelineId, nodeFactory, NodeNamePrefixSettings.TrimNodeName("NodePipeline.Application.Nodes.SaveImage2"), nodeId, nodePortConnections, ports, out var portResults, cultureInfo); var isValid = portsValidationResult != ValidationResult.HasErrors; return !isValid ? GetErrorValidationResult(ValidationResult.HasErrors, nodeId, fieldResults, portResults, cultureInfo) : SuccessNodeValidationResult(portsValidationResult == ValidationResult.HasWarnings, fieldResults, portResults); } private NodeValidationResult Validate__NodePipeline_Application_Nodes_SaveImageNode__Node(string pipelineId, INodeFactory nodeFactory, global::NodePipeline.Application.Nodes.SaveImageNode node, string nodeId, IReadOnlyDictionary nodePortConnections, IReadOnlyDictionary ports, CultureInfo cultureInfo) { var validationResult = ValidationResult.Valid; var fieldResults = new Dictionary> { { "FileName", [] }, { "Extension", [] }, { "Directory", [] }, }; var r2 = CheckRequiredNodeParameter(nodeId, node.FileName, "FileName", cultureInfo); fieldResults["FileName"].Add(r2); UpdateValidationResult(r2.Result, ref validationResult); var r3 = CheckRequiredNodeParameter(nodeId, node.Extension, "Extension", cultureInfo); fieldResults["Extension"].Add(r3); UpdateValidationResult(r3.Result, ref validationResult); var r4 = GetNodeFieldValidator(typeof(global::NodePipeline.Application.ExtensionValidator)).Validate(node.Extension); fieldResults["Extension"].Add(r4); UpdateValidationResult(r4.Result, ref validationResult); var r5 = CheckRequiredNodeParameter(nodeId, node.Directory, "Directory", cultureInfo); fieldResults["Directory"].Add(r5); UpdateValidationResult(r5.Result, ref validationResult); var portsValidationResult = ValidateNodePorts(pipelineId, nodeFactory, "FileImageDestination", nodeId, nodePortConnections, ports, out var portResults, cultureInfo); var isValid = validationResult != ValidationResult.HasErrors && portsValidationResult != ValidationResult.HasErrors; UpdateValidationResult(portsValidationResult, ref validationResult); return !isValid ? GetErrorValidationResult(validationResult, nodeId, fieldResults, portResults, cultureInfo) : SuccessNodeValidationResult(validationResult == ValidationResult.HasWarnings || portsValidationResult == ValidationResult.HasWarnings, fieldResults, portResults); } private IReadOnlyDictionary GetAllPorts(string pipelineId, INodeFactory nodeFactory, List allNodes) { var nodeTypes = allNodes.Select(q => q.Type) .Distinct() .ToHashSet(); var nodeList = allNodes .GroupBy(q => q.Type, (type, g) => new { Type = type, NodeIds = g.Select(q => q.Id) }) .ToDictionary(q => q.Type, q => q.NodeIds); _allPorts ??= nodeFactory.GetAllPorts(pipelineId, nodeTypes, nodeList); return _allPorts.AsReadOnly(); } private INodeFieldValidator GetNodeFieldValidator(Type validatorType) { if (!NodeFieldValidators.TryGetValue(validatorType, out var validator) || validator is not INodeFieldValidator genericValidator) throw new UserDefinedNodeFieldValidatorNotFoundException(validatorType.FullName ?? validatorType.Name); return genericValidator; } private ValidationResult ValidateNodePorts(string pipelineId, INodeFactory nodeFactory, string nodeType, string nodeId, IReadOnlyDictionary nodePortConnections, IReadOnlyDictionary ports, out Dictionary> inputPortValidationResults, CultureInfo cultureInfo) { var result = ValidationResult.Valid; inputPortValidationResults = new Dictionary>(); var inputPorts = nodeFactory.GetNodeInputPorts(pipelineId, nodeType, nodeId); foreach (var inputPort in inputPorts) { var code = NodeFieldCodeGenerator.GenerateFieldCode(nodeId, inputPort.Name, inputPort.Input ? FieldDirection.Input : FieldDirection.Output); inputPortValidationResults[code] = []; var hasConnection = nodePortConnections.TryGetValue(GetNodeInputKey(nodeId, inputPort.Name), out var connection); if (inputPort.Required && !hasConnection) { inputPortValidationResults[code].Add(new NodeFieldValidationResult(ValidationResult.HasErrors, PipelineLocalizationProvider.GetLocalizedString(Constants.ValidationResults.ErrorMessages.RequiredInputPortHasNoConnectionError, cultureInfo, inputPort.Name, nodeId))); UpdateValidationResult(ValidationResult.HasErrors, ref result); continue; } if (!hasConnection || connection == null) continue; var portValidationResult = ValidateInputPort(nodeId, inputPort, connection, ports, cultureInfo); inputPortValidationResults[code].Add(portValidationResult); UpdateValidationResult(portValidationResult.Result, ref result); } return result; } private NodeFieldValidationResult ValidateInputPort(string nodeId, NodePortInfo inputPort, InputSource connection, IReadOnlyDictionary ports, CultureInfo cultureInfo) { if (!ports.TryGetValue(new NodePortKey(connection.NodeId, connection.OutputName, false), out var outputPort)) { return new NodeFieldValidationResult(ValidationResult.HasErrors, PipelineLocalizationProvider .GetLocalizedString(Constants.ValidationResults.ErrorMessages.OutputPortNotFoundError, cultureInfo, connection.OutputName, connection.NodeId, inputPort.Name, nodeId)); } if (inputPort.Type != outputPort.Type) { return new NodeFieldValidationResult(ValidationResult.HasErrors, PipelineLocalizationProvider .GetLocalizedString(Constants.ValidationResults.ErrorMessages.PortsTypeMismatchError, cultureInfo, inputPort.Name, nodeId, inputPort.Type, connection.OutputName, connection.NodeId, outputPort.Type)); } if (inputPort.IsNullable == outputPort.IsNullable) { return SuccessNodeFieldValidationResult(); } if (!inputPort.IsNullable && outputPort.IsNullable) { return new NodeFieldValidationResult( ValidationResult.HasWarnings, PipelineLocalizationProvider .GetLocalizedString(Constants.ValidationResults.ErrorMessages.NullableAndNonNullablePortsConnectionWarning, cultureInfo, inputPort.Name, nodeId, inputPort.Type, connection.OutputName, connection.NodeId, outputPort.Type)); } return SuccessNodeFieldValidationResult(); } private static string GetNodeInputKey(string nodeId, string inputPortName) { return string.Concat(nodeId, "_", inputPortName); } private INodeValidator GetNodeValidator(Type validatorType) { if (!NodeValidators.TryGetValue(validatorType, out var validator)) throw new UserDefinedNodeValidatorNotFoundException(validatorType.FullName ?? validatorType.Name); return validator; } private NodeFieldValidationResult CheckRequiredNodeParameter(string nodeId, NodePipeline.Abstractions.Models.NodeField nodeField, string nodeParameterName, CultureInfo cultureInfo) { return nodeField.Value is not null ? new NodeFieldValidationResult(ValidationResult.Valid, null) : new NodeFieldValidationResult(ValidationResult.HasErrors, PipelineLocalizationProvider .GetLocalizedString(Constants.ValidationResults.ErrorMessages.RequiredNodeParameterValidationError, cultureInfo, nodeParameterName, nodeId)); } private static NodeValidationResult SuccessNodeValidationResult(bool hasWarnings, Dictionary> fieldResults, Dictionary> portResults) => new(hasWarnings ? ValidationResult.HasWarnings : ValidationResult.Valid, string.Empty, fieldResults.AsReadOnly(), portResults.AsReadOnly()); private NodeValidationResult GetErrorValidationResult(ValidationResult validationResult, string nodeId, Dictionary> fieldResults, Dictionary> portResults, CultureInfo cultureInfo) => new(validationResult, PipelineLocalizationProvider.GetLocalizedString(Constants.ValidationResults.ErrorMessages.NodeValidationError, cultureInfo, nodeId), fieldResults.AsReadOnly(), portResults.AsReadOnly()); private static NodeFieldValidationResult SuccessNodeFieldValidationResult() => new NodeFieldValidationResult(ValidationResult.Valid, null); private static void UpdateValidationResult(ValidationResult validationResult, ref ValidationResult parametersValidationResult) { if (validationResult == parametersValidationResult || validationResult == ValidationResult.Valid) return; parametersValidationResult = validationResult switch { ValidationResult.HasWarnings when parametersValidationResult == ValidationResult.Valid => ValidationResult.HasWarnings, ValidationResult.HasErrors when parametersValidationResult != ValidationResult.HasErrors => ValidationResult.HasErrors, _ => parametersValidationResult }; } } #nullable restore