feat(commons): TryParseRelayBody — detect pure ctx.GetTag relay scripts
This commit is contained in:
@@ -32,6 +32,13 @@ public static class EquipmentScriptPaths
|
|||||||
private static readonly Regex PathLiteralRegex =
|
private static readonly Regex PathLiteralRegex =
|
||||||
new(@"(ctx\s*\.\s*(?:GetTag|SetVirtualTag)\s*\(\s*"")([^""]*)("")", RegexOptions.Compiled);
|
new(@"(ctx\s*\.\s*(?:GetTag|SetVirtualTag)\s*\(\s*"")([^""]*)("")", RegexOptions.Compiled);
|
||||||
|
|
||||||
|
// A pure pass-through virtual-tag body: exactly `return ctx.GetTag("<ref>").Value;`
|
||||||
|
// (whitespace-insensitive). Captures <ref> for relay→alias conversion. Anything with extra
|
||||||
|
// statements, arithmetic, a different member than .Value, or multiple GetTag calls is NOT a relay.
|
||||||
|
private static readonly Regex RelayBodyRegex = new(
|
||||||
|
@"^\s*return\s+ctx\s*\.\s*GetTag\s*\(\s*""([^""]+)""\s*\)\s*\.\s*Value\s*;\s*$",
|
||||||
|
RegexOptions.Compiled);
|
||||||
|
|
||||||
/// <summary>True when the source uses the <c>{{equip}}</c> token anywhere.</summary>
|
/// <summary>True when the source uses the <c>{{equip}}</c> token anywhere.</summary>
|
||||||
/// <param name="source">The script source to scan.</param>
|
/// <param name="source">The script source to scan.</param>
|
||||||
public static bool ContainsEquipToken(string? source) =>
|
public static bool ContainsEquipToken(string? source) =>
|
||||||
@@ -136,4 +143,30 @@ public static class EquipmentScriptPaths
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Recognise a pure relay virtual-tag body — one whose entire body is exactly
|
||||||
|
/// <c>return ctx.GetTag("<paramref name="tagReference"/>").Value;</c> (whitespace-insensitive) —
|
||||||
|
/// and capture its single <c>GetTag</c> reference. Bodies with extra statements, arithmetic,
|
||||||
|
/// a member other than <c>.Value</c>, or multiple <c>GetTag</c> calls are <em>not</em> relays.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="source">The virtual-tag script source to inspect.</param>
|
||||||
|
/// <param name="tagReference">
|
||||||
|
/// When the method returns <see langword="true"/>, the captured <c>GetTag</c> path literal
|
||||||
|
/// (e.g. <c>TestMachine_020.TestChangingInt</c> or <c>{{equip}}.Speed</c>);
|
||||||
|
/// otherwise <see langword="null"/>.
|
||||||
|
/// </param>
|
||||||
|
/// <returns>
|
||||||
|
/// <see langword="true"/> when <paramref name="source"/> is a pure pass-through relay;
|
||||||
|
/// <see langword="false"/> for any other body or <see langword="null"/>/<see langword="whitespace"/> input.
|
||||||
|
/// </returns>
|
||||||
|
public static bool TryParseRelayBody(string? source, out string? tagReference)
|
||||||
|
{
|
||||||
|
tagReference = null;
|
||||||
|
if (string.IsNullOrWhiteSpace(source)) return false;
|
||||||
|
var m = RelayBodyRegex.Match(source);
|
||||||
|
if (!m.Success) return false;
|
||||||
|
tagReference = m.Groups[1].Value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -211,4 +211,29 @@ public class EquipmentScriptPathsTests
|
|||||||
{
|
{
|
||||||
EquipmentScriptPaths.ContainsEquipToken(null).ShouldBeFalse();
|
EquipmentScriptPaths.ContainsEquipToken(null).ShouldBeFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---- TryParseRelayBody ----
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("return ctx.GetTag(\"TestMachine_020.TestChangingInt\").Value;", "TestMachine_020.TestChangingInt")]
|
||||||
|
[InlineData(" return ctx . GetTag ( \"A.B\" ) . Value ; ", "A.B")]
|
||||||
|
[InlineData("return ctx.GetTag(\"{{equip}}.Speed\").Value;", "{{equip}}.Speed")]
|
||||||
|
public void TryParseRelayBody_accepts_exact_passthrough(string src, string expectedRef)
|
||||||
|
{
|
||||||
|
EquipmentScriptPaths.TryParseRelayBody(src, out var r).ShouldBeTrue();
|
||||||
|
r.ShouldBe(expectedRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("return ctx.GetTag(\"A.B\").Value * 2;")]
|
||||||
|
[InlineData("var x = ctx.GetTag(\"A.B\").Value; return x;")]
|
||||||
|
[InlineData("return ctx.GetTag(\"A.B\").Value + ctx.GetTag(\"C.D\").Value;")]
|
||||||
|
[InlineData("return ctx.GetTag(\"A.B\").Quality;")]
|
||||||
|
[InlineData("return 5;")]
|
||||||
|
[InlineData("")]
|
||||||
|
public void TryParseRelayBody_rejects_non_relay(string src)
|
||||||
|
{
|
||||||
|
EquipmentScriptPaths.TryParseRelayBody(src, out var r).ShouldBeFalse();
|
||||||
|
r.ShouldBeNull();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user