|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections.Generic;
using System.Xml;
using Microsoft.Build.Construction;
#nullable disable
namespace Microsoft.Build.ObjectModelRemoting
{
/// <summary>
/// This interface will allow us to share a single field between
/// <see cref="XmlElementWithLocation"/> and <see cref="ProjectElementLink"/>
/// for construction objects so therefore not increasing the storage size while supporting
/// external linking.
/// <see cref="ProjectElement.XmlElement"/> and <see cref="ProjectElement.Link"/>
/// </summary>
internal interface ILinkedXml
{
/// <summary>
/// Not null for "external" objects, null for internal objects
/// </summary>
ProjectElementLink Link { get; }
/// <summary>
/// Null for "external" objects, not null for internal objects
/// </summary>
XmlElementWithLocation Xml { get; }
}
/// <summary>
/// External projects support.
/// Allow for creating a local representation to external construction objects derived from <see cref="ProjectElement"/>
/// </summary>
public abstract class ProjectElementLink : ILinkedXml
{
/// <summary>
/// <see cref="ILinkedXml.Link"/>
/// </summary>
ProjectElementLink ILinkedXml.Link => this;
/// <summary>
/// <see cref="ILinkedXml.Xml"/>
/// </summary>
XmlElementWithLocation ILinkedXml.Xml => null;
/// <summary>
/// Access to remote <see cref="ProjectElement.Parent"/>.
/// </summary>
public abstract ProjectElementContainer Parent { get; }
/// <summary>
/// Access to remote <see cref="ProjectElement.ContainingProject"/>.
/// </summary>
public abstract ProjectRootElement ContainingProject { get; }
/// <summary>
/// Access to remote <see cref="ProjectElement.ElementName"/>.
/// </summary>
public abstract string ElementName { get; }
/// <summary>
/// Access to remote <see cref="ProjectElement.OuterElement"/>.
/// </summary>
public abstract string OuterElement { get; }
/// <summary>
/// Access to remote <see cref="ProjectElement.ExpressedAsAttribute"/>.
/// </summary>
public abstract bool ExpressedAsAttribute { get; set; }
/// <summary>
/// Access to remote <see cref="ProjectElement.PreviousSibling"/>.
/// </summary>
public abstract ProjectElement PreviousSibling { get; }
/// <summary>
/// Access to remote <see cref="ProjectElement.NextSibling"/>.
/// </summary>
public abstract ProjectElement NextSibling { get; }
/// <summary>
/// Access to remote <see cref="ProjectElement.Location"/>.
/// </summary>
public abstract ElementLocation Location { get; }
/// <summary>
/// Supports <see cref="ProjectElement.CopyFrom"/>.
/// </summary>
public abstract IReadOnlyCollection<XmlAttributeLink> Attributes { get; }
/// <summary>
/// Supports <see cref="ProjectElement.CopyFrom"/>.
/// return raw xml content of the element if it has exactly 1 text child
/// </summary>
public abstract string PureText { get; }
/// <summary>
/// Required to implement Attribute access for remote element.
/// </summary>
public abstract ElementLocation GetAttributeLocation(string attributeName);
/// <summary>
/// Required to implement Attribute access for remote element.
/// </summary>
public abstract string GetAttributeValue(string attributeName, bool nullIfNotExists);
/// <summary>
/// Required to implement Attribute access for remote element.
/// </summary>
public abstract void SetOrRemoveAttribute(string name, string value, bool clearAttributeCache, string reason, string param);
/// <summary>
/// Facilitate remoting to remote <see cref="ProjectElement.CopyFrom"/>.
/// </summary>
public abstract void CopyFrom(ProjectElement element);
/// <summary>
/// Facilitate remoting to remote <see cref="ProjectElement.CreateNewInstance(ProjectRootElement)"/>.
/// </summary>
public abstract ProjectElement CreateNewInstance(ProjectRootElement owner);
/// <summary>
/// Utility function for ExternalProjects provider
/// </summary>
public static bool GetExpressedAsAttribute(ProjectElement xml) => xml.ExpressedAsAttribute;
public static void SetExpressedAsAttribute(ProjectElement xml, bool value) => xml.ExpressedAsAttribute = value;
public static ElementLocation GetAttributeLocation(ProjectElement xml, string attributeName) => xml.GetAttributeLocation(attributeName);
public static string GetAttributeValue(ProjectElement xml, string attributeName, bool nullIfNotExists) => xml.GetAttributeValue(attributeName, nullIfNotExists);
public static void SetOrRemoveAttribute(ProjectElement xml, string name, string value, bool clearAttributeCache, string reason, string param) => xml.SetOrRemoveAttributeForLink(name, value, clearAttributeCache, reason, param);
public static void MarkDirty(ProjectElement xml, string reason, string param) => xml.MarkDirty(reason, param);
public static ProjectElement CreateNewInstance(ProjectElement xml, ProjectRootElement owner) => ProjectElement.CreateNewInstance(xml, owner);
public static string GetPureText(ProjectElement xml)
{
string result = null;
if (xml.XmlElement.ChildNodes.Count == 1 && xml.XmlElement.FirstChild.NodeType == XmlNodeType.Text)
{
result = xml.XmlElement.FirstChild.Value;
}
return result;
}
public static IReadOnlyCollection<XmlAttributeLink> GetAttributes(ProjectElement xml)
{
List<XmlAttributeLink> result = new List<XmlAttributeLink>();
foreach (XmlAttribute attribute in xml.XmlElement.Attributes)
{
result.Add(new XmlAttributeLink(attribute.LocalName, attribute.Value, attribute.NamespaceURI));
}
return result;
}
}
public struct XmlAttributeLink
{
public XmlAttributeLink(string localName, string value, string namespaceUri)
{
this.LocalName = localName;
this.Value = value;
this.NamespaceURI = namespaceUri;
}
public string LocalName { get; }
public string Value { get; }
public string NamespaceURI { get; }
}
// the "equivalence" classes in cases when we don't need additional functionality,
// but want to allow for such to be added in the future.
/// <summary>
/// External projects support.
/// Allow for creating a local representation to external object of type <see cref="ProjectOnErrorElement"/>
/// </summary>
public abstract class ProjectOnErrorElementLink : ProjectElementLink { }
/// <summary>
/// External projects support.
/// Allow for creating a local representation to external object of type <see cref="ProjectOutputElement"/>
/// </summary>
public abstract class ProjectOutputElementLink : ProjectElementLink { }
}
|