private void HandleIncludeDirective([NotNull] IT4Directive directive, [NotNull] CompositeElement parentElement) { var fileAttr = directive.GetAttribute(_directiveInfoManager.Include.FileAttribute.Name) as T4DirectiveAttribute; if (fileAttr == null) { return; } IT4Token valueToken = fileAttr.GetValueToken(); if (valueToken == null) { return; } bool once = false; if (_t4Environment.VsVersion2.Major >= VsVersions.Vs2013) { string onceString = directive.GetAttributeValue(_directiveInfoManager.Include.OnceAttribute.Name); once = Boolean.TrueString.Equals(onceString, StringComparison.OrdinalIgnoreCase); } HandleInclude(valueToken.GetText(), fileAttr, parentElement, once); }
/// <summary> /// Adds a new directive after an existing one. /// </summary> /// <param name="directive">The directive to add.</param> /// <param name="anchor">The existing directive where <paramref name="directive"/> will be placed after.</param> /// <returns>A new instance of <see cref="IT4Directive"/>, representing <paramref name="directive"/> in the T4 file.</returns> public IT4Directive AddDirectiveAfter(IT4Directive directive, IT4Directive anchor) { if (directive == null) { throw new ArgumentNullException("directive"); } if (anchor == null) { throw new ArgumentNullException("anchor"); } using (this.CreateWriteLock()) { directive = ModificationUtil.AddChildAfter(anchor, directive); // if the directive was inserted between the anchor and a new line, add another new line before // the directive so that both directives have new lines after them ITreeNode sibling = directive.NextSibling; if (sibling is IT4Include) { sibling = sibling.NextSibling; } if (sibling != null && sibling.GetTokenType() == T4TokenNodeTypes.NewLine) { ModificationUtil.AddChildBefore(directive, T4TokenNodeTypes.NewLine.CreateLeafElement()); } return(directive); } }
private void ProcessDirective([NotNull] IT4Directive directive) { IT4Token nameToken = directive.GetNameToken(); if (nameToken == null) { return; } DirectiveInfo directiveInfo = _directiveInfoManager.GetDirectiveByName(nameToken.GetText()); if (directiveInfo == null) { return; } IEnumerable <string> attributeNames = directive.GetAttributes().SelectNotNull(attr => attr.GetName()); var hashSet = new JetHashSet <string>(attributeNames, StringComparer.OrdinalIgnoreCase); foreach (DirectiveAttributeInfo attributeInfo in directiveInfo.SupportedAttributes) { if (attributeInfo.IsRequired && !hashSet.Contains(attributeInfo.Name)) { AddHighlighting(new HighlightingInfo(nameToken.GetHighlightingRange(), new MissingRequiredAttributeHighlighting(nameToken, attributeInfo.Name))); } } }
/// <summary> /// Removes a directive. /// </summary> /// <param name="directive">The directive to remove.</param> public void RemoveDirective(IT4Directive directive) { if (directive == null) { return; } using (this.CreateWriteLock()) { ITreeNode endNode = directive; // remove the included node with the include directive if (directive.IsSpecificDirective(Shell.Instance.GetComponent <DirectiveInfoManager>().Include)) { if (directive.NextSibling is IT4Include) { endNode = directive.NextSibling; } } // remove the optional end line after the directive if (endNode.NextSibling != null && endNode.NextSibling.GetTokenType() == T4TokenNodeTypes.NewLine) { endNode = endNode.NextSibling; } ModificationUtil.DeleteChildRange(directive, endNode); } }
private void ProcessDirective([NotNull] IT4Directive directive) { IT4Token nameToken = directive.GetNameToken(); if (nameToken == null) { return; } DirectiveInfo directiveInfo = _directiveInfoManager.GetDirectiveByName(nameToken.GetText()); if (directiveInfo == null) { return; } // Notify of missing required attributes. IEnumerable <string> attributeNames = directive.GetAttributes().SelectNotNull(attr => attr.GetName()); var hashSet = new JetHashSet <string>(attributeNames, StringComparer.OrdinalIgnoreCase); foreach (DirectiveAttributeInfo attributeInfo in directiveInfo.SupportedAttributes) { if (attributeInfo.IsRequired && !hashSet.Contains(attributeInfo.Name)) { AddHighlighting(new HighlightingInfo(nameToken.GetHighlightingRange(), new MissingRequiredAttributeHighlighting(nameToken, attributeInfo.Name))); } } // Assembly attributes in preprocessed templates are useless. if (directiveInfo == _directiveInfoManager.Assembly && DaemonProcess.SourceFile.ToProjectFile().IsPreprocessedT4Template()) { AddHighlighting(new HighlightingInfo(directive.GetHighlightingRange(), new IgnoredAssemblyDirectiveHighlighting(directive))); } }
/// <summary> /// Handles a parameter directive, outputting an extra property. /// </summary> /// <param name="directive">The parameter directive.</param> private void HandleParameterDirective([NotNull] IT4Directive directive) { Pair <IT4Token, string> type = directive.GetAttributeValueIgnoreOnlyWhitespace(_directiveInfoManager.Parameter.TypeAttribute.Name); if (type.First == null || type.Second == null) { return; } Pair <IT4Token, string> name = directive.GetAttributeValueIgnoreOnlyWhitespace(_directiveInfoManager.Parameter.NameAttribute.Name); if (name.First == null || name.Second == null) { return; } StringBuilder builder = _parametersResult.Builder; builder.Append("[System.CodeDom.Compiler.GeneratedCodeAttribute] private global::"); _parametersResult.AppendMapped(type.Second, type.First.GetTreeTextRange()); builder.Append(' '); _parametersResult.AppendMapped(name.Second, name.First.GetTreeTextRange()); builder.Append(" { get { return default(global::"); builder.Append(type.Second); builder.AppendLine("); } }"); }
private void ReportDuplicateDirective([NotNull] IT4Directive directive) { var warning = new IgnoredDirectiveWarning(directive); var highlightingInfo = new HighlightingInfo(directive.GetHighlightingRange(), warning); MyHighlightings.Add(highlightingInfo); }
public override void VisitDirectiveNode(IT4Directive directiveParam, FoldingHighlightingConsumer context) { // It is necessary to determine offset like this // because using a <see cref="TreeNodeExtensions.GetDocumentStartOffset(ITreeNode)"/> // would yield incorrect results in some edge cases DirectiveFoldingStart ??= directiveParam.GetDocumentRange().StartOffset; DirectiveFoldingEnd = directiveParam.GetDocumentRange().EndOffset; }
public static IT4Token GetAttributeValueToken([CanBeNull] this IT4Directive directive, [CanBeNull] string attributeName) { if (String.IsNullOrEmpty(attributeName)) { return(null); } return(directive?.GetAttribute(attributeName)?.GetValueToken()); }
public new static T4ImportWithLineDescription FromDirective([NotNull] IT4Directive directive) { (var source, string _) = directive.GetAttributeValueIgnoreOnlyWhitespace(T4DirectiveInfoManager.Import.NamespaceAttribute.Name); if (source == null) { return(null); } return(new T4ImportWithLineDescription(source)); }
/// <summary>Handles a template directive, determining if we should output a Host property and use a base class.</summary> /// <param name="directive">The template directive.</param> private void HandleTemplateDirective([NotNull] IT4Directive directive) { string value = directive.GetAttributeValue(_directiveInfoManager.Template.HostSpecificAttribute.Name); _hasHost = Boolean.TrueString.Equals(value, StringComparison.OrdinalIgnoreCase); (IT4Token classNameToken, string className) = directive.GetAttributeValueIgnoreOnlyWhitespace(_directiveInfoManager.Template.InheritsAttribute.Name); if (classNameToken != null && className != null) { _inheritsResult.AppendMapped(className, classNameToken.GetTreeTextRange()); } }
/// <summary> /// Handles an import directive, equivalent of an using directive in C#. /// </summary> /// <param name="directive">The import directive.</param> private void HandleImportDirective([NotNull] IT4Directive directive) { Pair <IT4Token, string> ns = directive.GetAttributeValueIgnoreOnlyWhitespace(_directiveInfoManager.Import.NamespaceAttribute.Name); if (ns.First == null || ns.Second == null) { return; } _usingsResult.Builder.Append("using "); _usingsResult.AppendMapped(ns.Second, ns.First.GetTreeTextRange()); _usingsResult.Builder.AppendLine(";"); }
public static IT4Directive AddDirective([NotNull] this IT4File t4File, [NotNull] IT4Directive directive, [NotNull] DirectiveInfoManager directiveInfoManager) { Pair <IT4Directive, BeforeOrAfter> anchor = directive.FindAnchor(t4File.GetDirectives().ToArray(), directiveInfoManager); if (anchor.First == null) { return(t4File.AddDirective(directive)); } return(anchor.Second == BeforeOrAfter.Before ? t4File.AddDirectiveBefore(directive, anchor.First) : t4File.AddDirectiveAfter(directive, anchor.First)); }
/// <summary>Adds a new directive before an existing one.</summary> /// <param name="directive">The directive to add.</param> /// <param name="anchor">The existing directive where <paramref name="directive"/> will be placed before.</param> /// <returns>A new instance of <see cref="IT4Directive"/>, representing <paramref name="directive"/> in the T4 file.</returns> public IT4Directive AddDirectiveBefore(IT4Directive directive, IT4Directive anchor) { using (WriteLockCookie.Create(IsPhysical())) { directive = ModificationUtil.AddChildBefore(anchor, directive); // if the directive was inserted between a new line (or the file start) and the anchor, add another new line after // the directive so that both directives have new lines after them if (directive.PrevSibling == null || directive.PrevSibling.GetTokenType() == T4TokenNodeTypes.NewLine) { ModificationUtil.AddChildAfter(directive, T4TokenNodeTypes.NewLine.CreateLeafElement()); } return(directive); } }
public static IT4TreeNode GetAttributeValueToken( [CanBeNull] this IT4Directive directive, [CanBeNull] string attributeName ) { if (string.IsNullOrEmpty(attributeName)) { return(null); } return(directive ?.Attributes .Where(it => string.Equals(it.Name.GetText(), attributeName, StringComparison.OrdinalIgnoreCase)) ?.FirstOrDefault() ?.Value); }
/// <summary> /// Handles a directive in the tree. /// </summary> /// <param name="directive">The directive.</param> private void HandleDirective([NotNull] IT4Directive directive) { if (directive.IsSpecificDirective(_directiveInfoManager.Import)) { HandleImportDirective(directive); } else if (directive.IsSpecificDirective(_directiveInfoManager.Template)) { HandleTemplateDirective(directive); } else if (directive.IsSpecificDirective(_directiveInfoManager.Parameter)) { HandleParameterDirective(directive); } }
public static IT4Token GetAttributeValueToken([CanBeNull] this IT4Directive directive, [CanBeNull] string attributeName) { if (directive == null || String.IsNullOrEmpty(attributeName)) { return(null); } IT4DirectiveAttribute attribute = directive.GetAttribute(attributeName); if (attribute == null) { return(null); } return(attribute.GetValueToken()); }
private static string GetSortValue([NotNull] IT4Directive directive, [CanBeNull] DirectiveInfo directiveInfo, [NotNull] DirectiveInfoManager directiveInfoManager) { if (directiveInfo == directiveInfoManager.Assembly) { return(directive.GetAttributeValue(directiveInfoManager.Assembly.NameAttribute.Name)); } if (directiveInfo == directiveInfoManager.Import) { return(directive.GetAttributeValue(directiveInfoManager.Import.NamespaceAttribute.Name)); } if (directiveInfo == directiveInfoManager.Parameter) { return(directive.GetAttributeValue(directiveInfoManager.Parameter.NameAttribute.Name)); } return(null); }
public static T4ParameterDescription FromDirective([NotNull] IT4Directive directive) { var typeToken = directive.GetAttributeValueToken(T4DirectiveInfoManager.Parameter.TypeAttribute.Name); string typeText = typeToken?.GetText(); var nameToken = directive.GetAttributeValueToken(T4DirectiveInfoManager.Parameter.NameAttribute.Name); string nameText = nameToken?.GetText(); if (string.IsNullOrEmpty(typeText)) { return(null); } if (string.IsNullOrEmpty(nameText)) { return(null); } return(new T4ParameterDescription(typeToken, nameToken, nameText)); }
/// <summary> /// Adds a new directive. /// </summary> /// <param name="directive">The directive to add.</param> /// <returns>A new instance of <see cref="IT4Directive"/>, representing <paramref name="directive"/> in the T4 file.</returns> public IT4Directive AddDirective(IT4Directive directive) { if (directive == null) throw new ArgumentNullException("directive"); IT4Directive anchor = GetDirectives().LastOrDefault(); if (anchor != null) return AddDirectiveAfter(directive, anchor); using (this.CreateWriteLock()) { directive = FirstChild != null ? ModificationUtil.AddChildBefore(FirstChild, directive) : ModificationUtil.AddChild(this, directive); ModificationUtil.AddChildAfter(directive, T4TokenNodeTypes.NewLine.CreateLeafElement()); return directive; } }
/// <summary>Adds a new directive.</summary> /// <param name="directive">The directive to add.</param> /// <returns>A new instance of <see cref="IT4Directive"/>, representing <paramref name="directive"/> in the T4 file.</returns> public IT4Directive AddDirective(IT4Directive directive) { IT4Directive anchor = GetDirectives().LastOrDefault(); if (anchor != null) { return(AddDirectiveAfter(directive, anchor)); } using (WriteLockCookie.Create(IsPhysical())) { directive = FirstChild != null ? ModificationUtil.AddChildBefore(FirstChild, directive) : ModificationUtil.AddChild(this, directive); ModificationUtil.AddChildAfter(directive, T4TokenNodeTypes.NewLine.CreateLeafElement()); return(directive); } }
public static Pair <IT4Token, string> GetAttributeValueIgnoreOnlyWhitespace([CanBeNull] this IT4Directive directive, [CanBeNull] string attributeName) { IT4Token valueToken = directive.GetAttributeValueToken(attributeName); if (valueToken == null) { return(new Pair <IT4Token, string>()); } string value = valueToken.GetText(); if (value.Trim().Length == 0) { return(new Pair <IT4Token, string>()); } return(new Pair <IT4Token, string>(valueToken, value)); }
/// <summary> /// Handles an assembly directive. /// </summary> /// <param name="directive">The directive containing a potential assembly reference.</param> private void HandleAssemblyDirective([NotNull] IT4Directive directive) { string assemblyNameOrFile = directive.GetAttributeValue(_directiveInfoManager.Assembly.NameAttribute.Name); if (assemblyNameOrFile == null || (assemblyNameOrFile = assemblyNameOrFile.Trim()).Length == 0) { // Handle <#@ assembly name="" completion="someassembly" #>, which is a ForTea-specific way // to get completion for an implicit assembly (for example, added by a custom directive). assemblyNameOrFile = directive.GetAttributeValue("completion"); if (assemblyNameOrFile == null || (assemblyNameOrFile = assemblyNameOrFile.Trim()).Length == 0) { return; } } VsBuildMacroHelper.GetMacros(assemblyNameOrFile, _macros); _referencedAssemblies.Add(assemblyNameOrFile); }
private void HandleIncludeDirective([NotNull] IT4Directive directive, [NotNull] CompositeElement parentElement) { var fileAttr = (T4DirectiveAttribute)directive.GetAttribute(_directiveInfoManager.Include.FileAttribute.Name); if (fileAttr == null) { return; } IT4Token valueToken = fileAttr.GetValueToken(); if (valueToken == null) { return; } HandleInclude(valueToken.GetText(), fileAttr, parentElement); }
private void AddDirective([NotNull] IT4File t4File, [NotNull] IT4Directive directive) { Pair <IT4Directive, BeforeOrAfter> anchor = directive.FindAnchor(t4File.GetDirectives().ToArray(), _directiveInfoManager); if (anchor.First != null) { if (anchor.Second == BeforeOrAfter.Before) { t4File.AddDirectiveBefore(directive, anchor.First); } else { t4File.AddDirectiveAfter(directive, anchor.First); } } else { t4File.AddDirective(directive); } }
/// <summary>Adds a new directive after an existing one.</summary> /// <param name="directive">The directive to add.</param> /// <param name="anchor">The existing directive where <paramref name="directive"/> will be placed after.</param> /// <returns>A new instance of <see cref="IT4Directive"/>, representing <paramref name="directive"/> in the T4 file.</returns> public IT4Directive AddDirectiveAfter(IT4Directive directive, IT4Directive anchor) { using (WriteLockCookie.Create(IsPhysical())) { directive = ModificationUtil.AddChildAfter(anchor, directive); // if the directive was inserted between the anchor and a new line, add another new line before // the directive so that both directives have new lines after them ITreeNode sibling = directive.NextSibling; if (sibling is IT4Include) { sibling = sibling.NextSibling; } if (sibling != null && sibling.GetTokenType() == T4TokenNodeTypes.NewLine) { ModificationUtil.AddChildBefore(directive, T4TokenNodeTypes.NewLine.CreateLeafElement()); } return(directive); } }
private void ProcessDirective(IT4Directive directive) { switch (directive) { case IT4OutputDirective _ when !SeenOutputDirective: SeenOutputDirective = true; break; case IT4OutputDirective _: ReportDuplicateDirective(directive); break; case IT4TemplateDirective _ when !SeenTemplateDirective: SeenTemplateDirective = true; break; case IT4TemplateDirective _: ReportDuplicateDirective(directive); break; } }
public static Pair <IT4TreeNode, string> GetAttributeValueIgnoreOnlyWhitespace( [NotNull] this IT4Directive directive, [NotNull] string attributeName ) { var valueToken = directive.GetAttributeValueToken(attributeName); if (valueToken == null) { return(new Pair <IT4TreeNode, string>()); } string value = valueToken.GetText(); if (value.IsNullOrWhitespace()) { return(new Pair <IT4TreeNode, string>()); } return(new Pair <IT4TreeNode, string>(valueToken, value)); }
/// <summary> /// Adds a new directive. /// </summary> /// <param name="directive">The directive to add.</param> /// <returns>A new instance of <see cref="IT4Directive"/>, representing <paramref name="directive"/> in the T4 file.</returns> public IT4Directive AddDirective(IT4Directive directive) { if (directive == null) { throw new ArgumentNullException("directive"); } IT4Directive anchor = GetDirectives().LastOrDefault(); if (anchor != null) { return(AddDirectiveAfter(directive, anchor)); } using (this.CreateWriteLock()) { directive = FirstChild != null ? ModificationUtil.AddChildBefore(FirstChild, directive) : ModificationUtil.AddChild(this, directive); ModificationUtil.AddChildAfter(directive, T4TokenNodeTypes.NewLine.CreateLeafElement()); return(directive); } }
/// <summary> /// Adds a new directive before an existing one. /// </summary> /// <param name="directive">The directive to add.</param> /// <param name="anchor">The existing directive where <paramref name="directive"/> will be placed before.</param> /// <returns>A new instance of <see cref="IT4Directive"/>, representing <paramref name="directive"/> in the T4 file.</returns> public IT4Directive AddDirectiveBefore(IT4Directive directive, IT4Directive anchor) { if (directive == null) { throw new ArgumentNullException("directive"); } if (anchor == null) { throw new ArgumentNullException("anchor"); } using (this.CreateWriteLock()) { directive = ModificationUtil.AddChildBefore(anchor, directive); // if the directive was inserted between a new line (or the file start) and the anchor, add another new line after // the directive so that both directives have new lines after them if (directive.PrevSibling == null || directive.PrevSibling.GetTokenType() == T4TokenNodeTypes.NewLine) { ModificationUtil.AddChildAfter(directive, T4TokenNodeTypes.NewLine.CreateLeafElement()); } return(directive); } }
/// <summary> /// Removes a directive. /// </summary> /// <param name="directive">The directive to remove.</param> public void RemoveDirective(IT4Directive directive) { if (directive == null) return; using (this.CreateWriteLock()) { ITreeNode endNode = directive; // remove the included node with the include directive if (directive.IsSpecificDirective(Shell.Instance.GetComponent<DirectiveInfoManager>().Include)) { if (directive.NextSibling is IT4Include) endNode = directive.NextSibling; } // remove the optional end line after the directive if (endNode.NextSibling != null && endNode.NextSibling.GetTokenType() == T4TokenNodeTypes.NewLine) endNode = endNode.NextSibling; ModificationUtil.DeleteChildRange(directive, endNode); } }
/// <summary> /// Adds a new directive before an existing one. /// </summary> /// <param name="directive">The directive to add.</param> /// <param name="anchor">The existing directive where <paramref name="directive"/> will be placed before.</param> /// <returns>A new instance of <see cref="IT4Directive"/>, representing <paramref name="directive"/> in the T4 file.</returns> public IT4Directive AddDirectiveBefore(IT4Directive directive, IT4Directive anchor) { if (directive == null) throw new ArgumentNullException("directive"); if (anchor == null) throw new ArgumentNullException("anchor"); using (this.CreateWriteLock()) { directive = ModificationUtil.AddChildBefore(anchor, directive); // if the directive was inserted between a new line (or the file start) and the anchor, add another new line after // the directive so that both directives have new lines after them if (directive.PrevSibling == null || directive.PrevSibling.GetTokenType() == T4TokenNodeTypes.NewLine) ModificationUtil.AddChildAfter(directive, T4TokenNodeTypes.NewLine.CreateLeafElement()); return directive; } }
/// <summary> /// Adds a new directive after an existing one. /// </summary> /// <param name="directive">The directive to add.</param> /// <param name="anchor">The existing directive where <paramref name="directive"/> will be placed after.</param> /// <returns>A new instance of <see cref="IT4Directive"/>, representing <paramref name="directive"/> in the T4 file.</returns> public IT4Directive AddDirectiveAfter(IT4Directive directive, IT4Directive anchor) { if (directive == null) throw new ArgumentNullException("directive"); if (anchor == null) throw new ArgumentNullException("anchor"); using (this.CreateWriteLock()) { directive = ModificationUtil.AddChildAfter(anchor, directive); // if the directive was inserted between the anchor and a new line, add another new line before // the directive so that both directives have new lines after them ITreeNode sibling = directive.NextSibling; if (sibling is IT4Include) sibling = sibling.NextSibling; if (sibling != null && sibling.GetTokenType() == T4TokenNodeTypes.NewLine) ModificationUtil.AddChildBefore(directive, T4TokenNodeTypes.NewLine.CreateLeafElement()); return directive; } }
/// <summary>Finds an anchor for a newly created directive inside a list of existing directives.</summary> /// <param name="newDirective">The directive to add.</param> /// <param name="existingDirectives">The existing directives.</param> /// <param name="directiveInfoManager">An instance of <see cref="DirectiveInfoManager"/>.</param> /// <returns>A pair indicating the anchor (can be null) and its relative position.</returns> public static Pair <IT4Directive, BeforeOrAfter> FindAnchor( [NotNull] this IT4Directive newDirective, [NotNull] IT4Directive[] existingDirectives, [NotNull] DirectiveInfoManager directiveInfoManager ) { // no anchor if (existingDirectives.Length == 0) { return(Pair.Of((IT4Directive)null, BeforeOrAfter.Before)); } // directive name should never be null, but you never know string newName = newDirective.GetName(); if (String.IsNullOrEmpty(newName)) { return(Pair.Of(existingDirectives.Last(), BeforeOrAfter.After)); } var lastDirectiveByName = new Dictionary <string, IT4Directive>(StringComparer.OrdinalIgnoreCase); DirectiveInfo directiveInfo = directiveInfoManager.GetDirectiveByName(newName); string newsortValue = GetSortValue(newDirective, directiveInfo, directiveInfoManager); foreach (IT4Directive existingDirective in existingDirectives) { string existingName = existingDirective.GetName(); if (existingName == null) { continue; } lastDirectiveByName[existingName] = existingDirective; // directive of the same type as the new one: // if the new directive comes alphabetically before the existing one, we got out anchor if (String.Equals(existingName, newName, StringComparison.OrdinalIgnoreCase)) { string existingSortValue = GetSortValue(existingDirective, directiveInfo, directiveInfoManager); if (String.Compare(newsortValue, existingSortValue, StringComparison.OrdinalIgnoreCase) < 0) { return(Pair.Of(existingDirective, BeforeOrAfter.Before)); } } } // no anchor being alphabetically after the new directive was found: // the last directive of the same type will be used as an anchor if (lastDirectiveByName.TryGetValue(newName, out IT4Directive lastDirective)) { return(Pair.Of(lastDirective, BeforeOrAfter.After)); } // there was no directive of the same type as the new one // the anchor will be the last directive of the type just before (determined by the position in DirectiveInfo.AllDirectives) if (directiveInfo != null) { int index = directiveInfoManager.AllDirectives.IndexOf(directiveInfo) - 1; while (index >= 0) { if (lastDirectiveByName.TryGetValue(directiveInfoManager.AllDirectives[index].Name, out lastDirective)) { return(Pair.Of(lastDirective, BeforeOrAfter.After)); } --index; } return(Pair.Of(existingDirectives.First(), BeforeOrAfter.Before)); } // we don't know the directive name (shouldn't happen), use the last directive as an anchor return(Pair.Of(existingDirectives.Last(), BeforeOrAfter.After)); }