< Summary

Information
Class: Elsa.AI.Host.Services.WorkflowDraftValidationService
Assembly: Elsa.AI.Host
File(s): /home/runner/work/elsa-core/elsa-core/src/modules/Elsa.AI.Host/Services/WorkflowDraftValidationService.cs
Line coverage
100%
Covered lines: 33
Uncovered lines: 0
Coverable lines: 33
Total lines: 72
Line coverage: 100%
Branch coverage
100%
Covered branches: 36
Total branches: 36
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
Validate(...)100%1212100%
FindActivityTypes()100%1818100%
TryReadString(...)100%88100%
Error(...)100%11100%
Warning(...)100%11100%

File(s)

/home/runner/work/elsa-core/elsa-core/src/modules/Elsa.AI.Host/Services/WorkflowDraftValidationService.cs

#LineLine coverage
 1using Elsa.AI.Abstractions.Models;
 2using Elsa.Workflows;
 3
 4namespace Elsa.AI.Host.Services;
 5
 476public class WorkflowDraftValidationService(IServiceProvider serviceProvider)
 7{
 8    public IReadOnlyCollection<AIValidationDiagnostic> Validate(JsonObject draft, string? baselineVersionId = null, stri
 9    {
 410        var diagnostics = new List<AIValidationDiagnostic>();
 411        if (draft.Count == 0)
 112            diagnostics.Add(Error("draft.empty", "Draft payload is empty.", "$"));
 13
 414        if (!string.IsNullOrWhiteSpace(expectedBaselineVersionId) &&
 415            !string.Equals(baselineVersionId, expectedBaselineVersionId, StringComparison.Ordinal))
 116            diagnostics.Add(Error("baseline.stale", "The proposal baseline version is stale.", "$.baselineVersionId"));
 17
 418        var registry = serviceProvider.GetService(typeof(IActivityRegistry)) as IActivityRegistry;
 419        if (registry == null)
 20        {
 321            diagnostics.Add(Warning("activityRegistry.unavailable", "Activity Registry is not available, so activity val
 322            return diagnostics;
 23        }
 24
 625        foreach (var activityType in FindActivityTypes(draft).Distinct(StringComparer.OrdinalIgnoreCase))
 26        {
 227            if (registry.Find(activityType) == null)
 128                diagnostics.Add(Error("activity.unavailable", $"Activity '{activityType}' is not installed.", "$"));
 29        }
 30
 131        return diagnostics;
 32    }
 33
 34    private static IEnumerable<string> FindActivityTypes(JsonNode? node)
 35    {
 836        if (node is JsonObject jsonObject)
 37        {
 338            if (TryReadString(jsonObject, "type", out var type) || TryReadString(jsonObject, "typeName", out type) || Tr
 239                yield return type;
 40
 2141            foreach (var child in jsonObject.Select(x => x.Value))
 42            {
 1443                foreach (var activityType in FindActivityTypes(child))
 244                    yield return activityType;
 45            }
 46        }
 547        else if (node is JsonArray jsonArray)
 48        {
 649            foreach (var child in jsonArray)
 50            {
 851                foreach (var activityType in FindActivityTypes(child))
 252                    yield return activityType;
 53            }
 54        }
 855    }
 56
 57    private static bool TryReadString(JsonObject jsonObject, string name, out string value)
 58    {
 559        value = "";
 560        if (!jsonObject.TryGetPropertyValue(name, out var node) || node is not JsonValue jsonValue || !jsonValue.TryGetV
 361            return false;
 62
 263        value = result;
 264        return true;
 65    }
 66
 67    private static AIValidationDiagnostic Error(string code, string message, string path) =>
 368        new() { Code = code, Message = message, Path = path, Severity = AIValidationSeverity.Error };
 69
 70    private static AIValidationDiagnostic Warning(string code, string message, string path) =>
 371        new() { Code = code, Message = message, Path = path, Severity = AIValidationSeverity.Warning };
 72}