refactor(core): EquipmentNodeWalker.ExtractFullName delegates to TagConfigIntent; repoint canonical-parser doc cites (R2-11)
Full walker deletion remains round-1 U-1's task.
This commit is contained in:
@@ -10,7 +10,7 @@
|
||||
{ "id": "T6", "subject": "Device-host re-home: composer TryExtractDeviceHost/NormalizeDeviceHost → DeviceConfigIntent; update DriverHostActor + DeploymentArtifact callers", "status": "completed", "blockedBy": ["T4", "T5"] },
|
||||
{ "id": "T7", "subject": "DeploymentArtifact swap: delete 4 private mirrors, parse once per tag element via TagConfigIntent", "status": "completed", "blockedBy": ["T5"] },
|
||||
{ "id": "T8", "subject": "DraftValidator swap: Configuration→Commons ProjectReference; ExtractTagConfigFullName → TagConfigIntent.ExplicitFullName (null-on-absent preserved)", "status": "completed", "blockedBy": ["T2", "T3"] },
|
||||
{ "id": "T9", "subject": "EquipmentNodeWalker.ExtractFullName delegates to TagConfigIntent; repoint tree-wide canonical-parser doc cites", "status": "pending", "blockedBy": ["T2", "T3"] },
|
||||
{ "id": "T9", "subject": "EquipmentNodeWalker.ExtractFullName delegates to TagConfigIntent; repoint tree-wide canonical-parser doc cites", "status": "completed", "blockedBy": ["T2", "T3"] },
|
||||
{ "id": "T10", "subject": "Retire OpcUaServer.Tests ExtractTag*Tests (authority moved to Commons.Tests); verify zero 'MUST parse identically' hits", "status": "pending", "blockedBy": ["T3", "T5"] },
|
||||
{ "id": "T11", "subject": "TagConfigJson strict-capable readers in Core.Abstractions (TryReadEnum Absent/Valid/Invalid, ReadEnumOrDefault, ReadWritable, DescribeInvalidEnum) (TDD)", "status": "pending", "blockedBy": [] },
|
||||
{ "id": "T12", "subject": "Modbus equipment-tag parser: freeze test, shared readers, honour writable key, Inspect warnings", "status": "pending", "blockedBy": ["T11"] },
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Text.Json;
|
||||
using ZB.MOM.WW.OtOpcUa.Commons.Types;
|
||||
using ZB.MOM.WW.OtOpcUa.Configuration.Entities;
|
||||
using ZB.MOM.WW.OtOpcUa.Core.Abstractions;
|
||||
|
||||
@@ -190,22 +190,8 @@ public static class EquipmentNodeWalker
|
||||
/// </remarks>
|
||||
/// <param name="tagConfig">The tag configuration JSON or string.</param>
|
||||
/// <returns>The extracted <c>FullName</c> value, or the raw <paramref name="tagConfig"/> if it can't be extracted.</returns>
|
||||
internal static string ExtractFullName(string tagConfig)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(tagConfig)) return tagConfig;
|
||||
try
|
||||
{
|
||||
using var doc = JsonDocument.Parse(tagConfig);
|
||||
if (doc.RootElement.ValueKind == JsonValueKind.Object
|
||||
&& doc.RootElement.TryGetProperty("FullName", out var fullName)
|
||||
&& fullName.ValueKind == JsonValueKind.String)
|
||||
{
|
||||
return fullName.GetString() ?? tagConfig;
|
||||
}
|
||||
}
|
||||
catch (JsonException) { /* fall through */ }
|
||||
return tagConfig;
|
||||
}
|
||||
internal static string ExtractFullName(string tagConfig) =>
|
||||
TagConfigIntent.Parse(tagConfig).FullName;
|
||||
|
||||
/// <summary>
|
||||
/// Parse <see cref="Tag.DataType"/> (stored as the <see cref="DriverDataType"/> enum
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ZB.MOM.WW.OtOpcUa.Core.Abstractions\ZB.MOM.WW.OtOpcUa.Core.Abstractions.csproj"/>
|
||||
<ProjectReference Include="..\ZB.MOM.WW.OtOpcUa.Configuration\ZB.MOM.WW.OtOpcUa.Configuration.csproj"/>
|
||||
<!-- R2-11: EquipmentNodeWalker.ExtractFullName delegates to the shared TagConfigIntent.Parse. -->
|
||||
<ProjectReference Include="..\ZB.MOM.WW.OtOpcUa.Commons\ZB.MOM.WW.OtOpcUa.Commons.csproj"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -53,7 +53,7 @@ public sealed record ScriptTagInfo(string Path, string Kind, string DataType, st
|
||||
/// <c>DriverInstanceActor.AttributeValuePublished.FullReference</c>
|
||||
/// (<c>src/Server/…Runtime/VirtualTags/DependencyMuxActor.cs:97</c>) — and that
|
||||
/// <c>FullReference</c> is the <c>FullName</c> field extracted from <c>Tag.TagConfig</c>
|
||||
/// (see <c>AddressSpaceComposer.ExtractTagFullName</c> + <c>EquipmentNodeWalker.ExtractFullName</c>).
|
||||
/// (see <c>Commons.Types.TagConfigIntent.Parse</c>, the shared byte-parity FullName authority).
|
||||
/// The UNS-path engine (<c>Core.VirtualTags.VirtualTagEngine</c>, keyed by a slash-joined
|
||||
/// <c>Enterprise/Site/Area/Line/Equipment/TagName</c>) is dormant — it is NOT wired into the
|
||||
/// host — so UNS browse paths never resolve at runtime and are intentionally NOT suggested.
|
||||
@@ -179,8 +179,8 @@ public sealed class ScriptTagCatalog(IDbContextFactory<OtOpcUaConfigDbContext> d
|
||||
/// <summary>
|
||||
/// Extracts the driver-side full reference from a <c>Tag.TagConfig</c> JSON blob — the
|
||||
/// top-level <c>FullName</c> string every shipped driver stores. Mirrors
|
||||
/// <c>EquipmentNodeWalker.ExtractFullName</c> / <c>AddressSpaceComposer.ExtractTagFullName</c>
|
||||
/// (AdminUI does not reference those assemblies). Falls back to the raw blob when it is not
|
||||
/// <c>Commons.Types.TagConfigIntent.Parse(...).FullName</c> (the shared byte-parity authority;
|
||||
/// AdminUI does not reference that assembly here). Falls back to the raw blob when it is not
|
||||
/// a JSON object carrying a string <c>FullName</c>.
|
||||
/// </summary>
|
||||
private static string ExtractFullNameFromTagConfig(string tagConfig)
|
||||
|
||||
@@ -7,9 +7,9 @@ namespace ZB.MOM.WW.OtOpcUa.AdminUI.Uns.TagEditors;
|
||||
/// stable <c>nsu=…;s=…</c> or plain <c>ns=2;s=…</c> NodeId the driver reads/writes/subscribes against).
|
||||
/// Preserves unrecognised JSON keys across a load→save.</summary>
|
||||
/// <remarks>
|
||||
/// The <c>FullName</c> key is intentionally PascalCase: the deploy-time composer + node walker
|
||||
/// (<c>AddressSpaceComposer.ExtractTagFullName</c>, <c>EquipmentNodeWalker</c>) read it via a
|
||||
/// case-sensitive <c>TryGetProperty("FullName", …)</c>, so the editor MUST persist that exact
|
||||
/// The <c>FullName</c> key is intentionally PascalCase: the shared deploy-time parser
|
||||
/// (<c>Commons.Types.TagConfigIntent.Parse</c>, consumed by the composer, artifact decoder, draft
|
||||
/// gate, and node walker) reads it via a case-sensitive <c>TryGetProperty("FullName", …)</c>, so the editor MUST persist that exact
|
||||
/// casing. The driver-agnostic server-side HistoryRead intent keys (<c>isHistorized</c> /
|
||||
/// <c>historianTagname</c>) are NOT modelled here — they are owned by the TagModal-merge seam
|
||||
/// (<see cref="TagHistorizeConfig"/>) and survive a load→save of this model as preserved unknown keys.
|
||||
|
||||
@@ -647,7 +647,7 @@ public sealed class AddressSpaceApplier
|
||||
// REACH (live-verified): the shape path only fires for drivers whose TagConfig carries a stable
|
||||
// top-level "FullName" (Galaxy = tag_name.AttributeName; OpcUaClient = the node id) — there a DataType/array
|
||||
// edit leaves FullName untouched ⇒ surgical. For structured-TagConfig protocol drivers (Modbus/S7/AbCip/…)
|
||||
// AddressSpaceComposer.ExtractTagFullName falls back to the RAW TagConfig blob as FullName, so a DataType/
|
||||
// TagConfigIntent.Parse falls back to the RAW TagConfig blob as FullName, so a DataType/
|
||||
// array edit also mutates that blob ⇒ FullName differs ⇒ this returns false ⇒ full rebuild. That is the
|
||||
// correct safe default (a protocol driver's subscription needs re-spawning for a new shape anyway).
|
||||
private static bool TagDeltaIsSurgicalEligible(AddressSpacePlan.EquipmentTagDelta d) =>
|
||||
|
||||
Reference in New Issue
Block a user