fix(scriptanalysis): mirror WaitAsync/WaitForAsync on CompileAttributeAccessor

Adds the four missing overloads (value + predicate × WaitAsync + WaitForAsync)
to CompileAttributeAccessor so template/call scripts that use Attributes.WaitAsync
or Attributes.WaitForAsync pass design-time Roslyn validation.  Covers both root
scope and composed/child scope (Children["x"].Attributes.WaitAsync) automatically
since CompileCompositionAccessor.Attributes already returns CompileAttributeAccessor.
This commit is contained in:
Joseph Doherty
2026-06-17 11:03:24 -04:00
parent dc43a3f0f6
commit a1186685a9
2 changed files with 28 additions and 0 deletions
@@ -185,6 +185,14 @@ public sealed class ScriptCompileSurface
/// <summary>Mirrors <c>AttributeAccessor.Resolve</c>.</summary>
public string Resolve(string key) => throw new NotSupportedException(CompileOnly);
/// <summary>Mirrors <c>AttributeAccessor.WaitAsync</c>.</summary>
public Task<bool> WaitAsync(string key, object? targetValue, TimeSpan timeout, bool requireGoodQuality = false) => throw new NotSupportedException(CompileOnly);
public Task<bool> WaitAsync(string key, Func<object?, bool> predicate, TimeSpan timeout, bool requireGoodQuality = false) => throw new NotSupportedException(CompileOnly);
/// <summary>Mirrors <c>AttributeAccessor.WaitForAsync</c>.</summary>
public Task<WaitResult> WaitForAsync(string key, object? targetValue, TimeSpan timeout, bool requireGoodQuality = false) => throw new NotSupportedException(CompileOnly);
public Task<WaitResult> WaitForAsync(string key, Func<object?, bool> predicate, TimeSpan timeout, bool requireGoodQuality = false) => throw new NotSupportedException(CompileOnly);
}
/// <summary>Compile-only mirror of <c>ChildrenAccessor</c>.</summary>
@@ -69,4 +69,24 @@ public class RoslynScriptCompilerTests
var diagnostics = RoslynScriptCompiler.Compile(expr, typeof(TriggerCompileSurface));
Assert.Empty(diagnostics);
}
[Fact]
public void Compile_Empty_ForWaitAsyncAndWaitForAsync()
{
// Covers all four overloads: value + predicate for both WaitAsync and
// WaitForAsync, on both root scope and composed/child scope.
const string code = """
// Root scope — value overload
var matched = await Attributes.WaitAsync("Flag", true, System.TimeSpan.FromSeconds(5));
// Root scope — predicate overload with requireGoodQuality
var matched2 = await Attributes.WaitAsync("Flag", v => v != null, System.TimeSpan.FromSeconds(5), true);
// Root scope — WaitForAsync value overload
var r = await Attributes.WaitForAsync("Flag", true, System.TimeSpan.FromSeconds(5));
// Composed/child scope — value overload
var childMatched = await Children["LeftMESReceiver"].Attributes.WaitAsync("MoveInCompleteFlag", true, System.TimeSpan.FromSeconds(5));
""";
var diagnostics = RoslynScriptCompiler.Compile(code, typeof(ScriptCompileSurface));
Assert.Empty(diagnostics);
}
}