1eb6e972b0
Bulk CommentChecker pass: fills in <param>/<inheritdoc> tags on public APIs across all 23 src/ projects so the doc-coverage gate is green. Also adds a Sister Projects section to CLAUDE.md pointing at the MxAccess Gateway and OtOpcUa sibling repos, and gitignores local credential captures (*login*.txt) and the wonder-app-vd03 deploy/ artifacts.
58 lines
2.4 KiB
C#
58 lines
2.4 KiB
C#
using ScadaLink.Commons.Entities.Templates;
|
|
|
|
namespace ScadaLink.TemplateEngine;
|
|
|
|
/// <summary>
|
|
/// Resolves the hierarchical ("qualified") name of a composition-derived
|
|
/// template. A derived template stores only its <em>contained</em> name — the
|
|
/// owning composition slot's <c>InstanceName</c>, unique only within that owner.
|
|
/// The qualified path (<c>Owner.Slot.Slot…</c>) is computed on demand by
|
|
/// walking the <see cref="Template.OwnerCompositionId"/> chain up to the base
|
|
/// template.
|
|
/// </summary>
|
|
public static class TemplateNaming
|
|
{
|
|
/// <summary>
|
|
/// Returns the dotted hierarchical name of <paramref name="template"/>. For
|
|
/// a base (non-derived) template this is just its stored name. The walk is
|
|
/// null-safe: if any owner link is missing from the supplied lookups it
|
|
/// stops and falls back to the stored contained name, and a cycle (which
|
|
/// the composition graph should never contain) is broken defensively.
|
|
/// </summary>
|
|
/// <param name="template">The template whose qualified name to compute.</param>
|
|
/// <param name="byId">Lookup of all templates by primary key.</param>
|
|
/// <param name="compById">Lookup of all template compositions by primary key.</param>
|
|
/// <returns>The dotted hierarchical name (e.g., <c>Owner.Slot.Name</c>).</returns>
|
|
public static string QualifiedName(
|
|
Template template,
|
|
IReadOnlyDictionary<int, Template> byId,
|
|
IReadOnlyDictionary<int, TemplateComposition> compById)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(template);
|
|
ArgumentNullException.ThrowIfNull(byId);
|
|
ArgumentNullException.ThrowIfNull(compById);
|
|
|
|
return Resolve(template, byId, compById, new HashSet<int>());
|
|
}
|
|
|
|
private static string Resolve(
|
|
Template template,
|
|
IReadOnlyDictionary<int, Template> byId,
|
|
IReadOnlyDictionary<int, TemplateComposition> compById,
|
|
HashSet<int> visited)
|
|
{
|
|
// Base template, broken owner link, or a cycle → the stored name is the
|
|
// best (and contained) answer.
|
|
if (!template.IsDerived
|
|
|| template.OwnerCompositionId is not { } compId
|
|
|| !compById.TryGetValue(compId, out var composition)
|
|
|| !byId.TryGetValue(composition.TemplateId, out var owner)
|
|
|| !visited.Add(template.Id))
|
|
{
|
|
return template.Name;
|
|
}
|
|
|
|
return $"{Resolve(owner, byId, compById, visited)}.{composition.InstanceName}";
|
|
}
|
|
}
|