Centralize ExcludeProperty filter application in ViewGenerator base class (#26574)

This commit is contained in:
Yoshifumi
2025-12-10 21:22:36 +05:00
committed by GitHub
parent 2a49561af4
commit 235ff058e7
5 changed files with 150 additions and 146 deletions
@@ -348,19 +348,49 @@ namespace Microsoft.PowerShell.Commands.Internal.Format
protected DataBaseInfo dataBaseInfo = new DataBaseInfo();
protected List<MshResolvedExpressionParameterAssociation> activeAssociationList = null;
/// <summary>
/// Apply ExcludeProperty filter to activeAssociationList if specified.
/// This method filters and updates "activeAssociationList" instance property.
/// Builds the raw association list for the given object.
/// Subclasses override this to provide cmdlet-specific property expansion logic.
/// </summary>
protected void ApplyExcludePropertyFilter()
/// <param name="so">The object to build the association list for.</param>
/// <param name="propertyList">The list of properties specified by the user, or null if not specified.</param>
/// <returns>The raw association list, or null if not applicable.</returns>
protected virtual List<MshResolvedExpressionParameterAssociation> BuildRawAssociationList(PSObject so, List<MshParameter> propertyList)
{
if (this.parameters is not null && this.parameters.excludePropertyFilter is not null)
return null;
}
/// <summary>
/// Builds the active association list for the given object, with ExcludeProperty filter applied.
/// </summary>
/// <param name="so">The object to build the association list for.</param>
/// <returns>The filtered association list.</returns>
protected List<MshResolvedExpressionParameterAssociation> BuildActiveAssociationList(PSObject so)
{
var propertyList = parameters?.mshParameterList;
var excludeFilter = parameters?.excludePropertyFilter;
var rawList = BuildRawAssociationList(so, propertyList);
return ApplyExcludeFilter(rawList, excludeFilter);
}
/// <summary>
/// Applies the ExcludeProperty filter to the given association list.
/// </summary>
/// <param name="associationList">The list to filter.</param>
/// <param name="excludeFilter">The exclude filter to apply.</param>
/// <returns>The filtered list, or the original list if no filter is specified.</returns>
internal static List<MshResolvedExpressionParameterAssociation> ApplyExcludeFilter(
List<MshResolvedExpressionParameterAssociation> associationList,
PSPropertyExpressionFilter excludeFilter)
{
if (associationList is null || excludeFilter is null)
{
this.activeAssociationList = this.activeAssociationList
.Where(item => !this.parameters.excludePropertyFilter.IsMatch(item.ResolvedExpression))
.ToList();
return associationList;
}
return associationList
.Where(item => !excludeFilter.IsMatch(item.ResolvedExpression))
.ToList();
}
protected string GetExpressionDisplayValue(PSObject so, int enumerationLimit, PSPropertyExpression ex,
@@ -3,7 +3,6 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Internal;
@@ -514,13 +513,8 @@ namespace Microsoft.PowerShell.Commands.Internal.Format
List<MshResolvedExpressionParameterAssociation> activeAssociationList =
AssociationManager.SetupActiveProperties(parameterList, so, _expressionFactory);
// Apply ExcludeProperty filter if specified
if (_parameters != null && _parameters.excludePropertyFilter != null)
{
activeAssociationList = activeAssociationList
.Where(item => !_parameters.excludePropertyFilter.IsMatch(item.ResolvedExpression))
.ToList();
}
// Apply ExcludeProperty filter using the centralized method
activeAssociationList = ViewGenerator.ApplyExcludeFilter(activeAssociationList, _parameters?.excludePropertyFilter);
// create a format entry
FormatEntry fe = new FormatEntry();
@@ -30,9 +30,14 @@ namespace Microsoft.PowerShell.Commands.Internal.Format
{
_listBody = (ListControlBody)this.dataBaseInfo.view.mainControl;
}
}
this.parameters = parameters;
SetUpActiveProperties(so);
/// <summary>
/// Builds the raw association list for list formatting.
/// </summary>
protected override List<MshResolvedExpressionParameterAssociation> BuildRawAssociationList(PSObject so, List<MshParameter> propertyList)
{
return AssociationManager.SetupActiveProperties(propertyList, so, this.expressionFactory);
}
/// <summary>
@@ -178,17 +183,14 @@ namespace Microsoft.PowerShell.Commands.Internal.Format
private ListViewEntry GenerateListViewEntryFromProperties(PSObject so, int enumerationLimit)
{
// compute active properties every time
if (this.activeAssociationList == null)
{
SetUpActiveProperties(so);
}
// Build active association list (with ExcludeProperty filter applied)
var associationList = BuildActiveAssociationList(so);
ListViewEntry lve = new ListViewEntry();
for (int k = 0; k < this.activeAssociationList.Count; k++)
for (int k = 0; k < associationList.Count; k++)
{
MshResolvedExpressionParameterAssociation a = this.activeAssociationList[k];
MshResolvedExpressionParameterAssociation a = associationList[k];
ListViewField lvf = new ListViewField();
if (a.OriginatingParameter != null)
@@ -218,21 +220,7 @@ namespace Microsoft.PowerShell.Commands.Internal.Format
lvf.formatPropertyField.propertyValue = this.GetExpressionDisplayValue(so, enumerationLimit, a.ResolvedExpression, directive);
lve.listViewFieldList.Add(lvf);
}
this.activeAssociationList = null;
return lve;
}
private void SetUpActiveProperties(PSObject so)
{
List<MshParameter> mshParameterList = null;
if (this.parameters != null)
mshParameterList = this.parameters.mshParameterList;
this.activeAssociationList = AssociationManager.SetupActiveProperties(mshParameterList, so, this.expressionFactory);
ApplyExcludePropertyFilter();
}
}
}
@@ -14,6 +14,8 @@ namespace Microsoft.PowerShell.Commands.Internal.Format
// tableBody to use for this instance of the ViewGenerator;
private TableControlBody _tableBody;
private List<MshResolvedExpressionParameterAssociation> _activeAssociationList;
internal override void Initialize(TerminatingErrorContext terminatingErrorContext, PSPropertyExpressionFactory mshExpressionFactory, TypeInfoDataBase db, ViewDefinition view, FormattingCommandLineParameters formatParameters)
{
base.Initialize(terminatingErrorContext, mshExpressionFactory, db, view, formatParameters);
@@ -34,51 +36,48 @@ namespace Microsoft.PowerShell.Commands.Internal.Format
_tableBody = (TableControlBody)this.dataBaseInfo.view.mainControl;
}
List<MshParameter> rawMshParameterList = null;
if (parameters != null)
rawMshParameterList = parameters.mshParameterList;
// Build the active association list (with ExcludeProperty filter applied)
_activeAssociationList = BuildActiveAssociationList(so);
}
/// <summary>
/// Builds the raw association list for table formatting.
/// </summary>
protected override List<MshResolvedExpressionParameterAssociation> BuildRawAssociationList(PSObject so, List<MshParameter> propertyList)
{
// check if we received properties from the command line
if (rawMshParameterList is not null && rawMshParameterList.Count > 0)
if (propertyList is not null && propertyList.Count > 0)
{
this.activeAssociationList = AssociationManager.ExpandTableParameters(rawMshParameterList, so);
}
else
{
// we did not get any properties:
// try to get properties from the default property set of the object
this.activeAssociationList = AssociationManager.ExpandDefaultPropertySet(so, this.expressionFactory);
if (this.activeAssociationList.Count > 0)
{
// we got a valid set of properties from the default property set..add computername for
// remoteobjects (if available)
if (PSObjectHelper.ShouldShowComputerNameProperty(so))
{
activeAssociationList.Add(new MshResolvedExpressionParameterAssociation(null,
new PSPropertyExpression(RemotingConstants.ComputerNameNoteProperty)));
}
}
else
{
// we failed to get anything from the default property set
this.activeAssociationList = AssociationManager.ExpandAll(so);
if (this.activeAssociationList.Count > 0)
{
// Remove PSComputerName and PSShowComputerName from the display as needed.
AssociationManager.HandleComputerNameProperties(so, activeAssociationList);
FilterActiveAssociationList();
}
else
{
// we were unable to retrieve any properties, so we leave an empty list
this.activeAssociationList = new List<MshResolvedExpressionParameterAssociation>();
return;
}
}
return AssociationManager.ExpandTableParameters(propertyList, so);
}
ApplyExcludePropertyFilter();
// we did not get any properties:
// try to get properties from the default property set of the object
var list = AssociationManager.ExpandDefaultPropertySet(so, this.expressionFactory);
if (list.Count > 0)
{
// we got a valid set of properties from the default property set..add computername for
// remoteobjects (if available)
if (PSObjectHelper.ShouldShowComputerNameProperty(so))
{
list.Add(new MshResolvedExpressionParameterAssociation(null,
new PSPropertyExpression(RemotingConstants.ComputerNameNoteProperty)));
}
return list;
}
// we failed to get anything from the default property set
list = AssociationManager.ExpandAll(so);
if (list.Count > 0)
{
// Remove PSComputerName and PSShowComputerName from the display as needed.
AssociationManager.HandleComputerNameProperties(so, list);
return LimitAssociationListSize(list);
}
// we were unable to retrieve any properties, so we leave an empty list
return new List<MshResolvedExpressionParameterAssociation>();
}
/// <summary>
@@ -129,30 +128,29 @@ namespace Microsoft.PowerShell.Commands.Internal.Format
}
/// <summary>
/// Method to filter resolved expressions as per table view needs.
/// Limits the association list size for table view.
/// For v1.0, table view supports only 10 properties.
///
/// This method filters and updates "activeAssociationList" instance property.
/// </summary>
/// <returns>None.</returns>
/// <remarks>This method updates "activeAssociationList" instance property.</remarks>
private void FilterActiveAssociationList()
/// <param name="list">The list to limit.</param>
/// <returns>The limited list.</returns>
private static List<MshResolvedExpressionParameterAssociation> LimitAssociationListSize(
List<MshResolvedExpressionParameterAssociation> list)
{
// we got a valid set of properties from the default property set
// make sure we do not have too many properties
// NOTE: this is an arbitrary number, chosen to be a sensitive default
const int nMax = 10;
const int maxCount = 10;
if (activeAssociationList.Count > nMax)
if (list.Count <= maxCount)
{
List<MshResolvedExpressionParameterAssociation> tmp = this.activeAssociationList;
this.activeAssociationList = new List<MshResolvedExpressionParameterAssociation>();
for (int k = 0; k < nMax; k++)
this.activeAssociationList.Add(tmp[k]);
return list;
}
return;
var result = new List<MshResolvedExpressionParameterAssociation>(maxCount);
for (int k = 0; k < maxCount; k++)
{
result.Add(list[k]);
}
return result;
}
private TableHeaderInfo GenerateTableHeaderInfoFromDataBaseInfo(PSObject so)
@@ -228,9 +226,9 @@ namespace Microsoft.PowerShell.Commands.Internal.Format
thi.hideHeader = this.HideHeaders;
thi.repeatHeader = this.RepeatHeader;
for (int k = 0; k < this.activeAssociationList.Count; k++)
for (int k = 0; k < _activeAssociationList.Count; k++)
{
MshResolvedExpressionParameterAssociation a = this.activeAssociationList[k];
MshResolvedExpressionParameterAssociation a = _activeAssociationList[k];
TableColumnInfo ci = new TableColumnInfo();
// set the label of the column
@@ -241,7 +239,7 @@ namespace Microsoft.PowerShell.Commands.Internal.Format
ci.propertyName = (string)key;
}
ci.propertyName ??= this.activeAssociationList[k].ResolvedExpression.ToString();
ci.propertyName ??= _activeAssociationList[k].ResolvedExpression.ToString();
// set the width of the table
if (a.OriginatingParameter != null)
@@ -473,13 +471,13 @@ namespace Microsoft.PowerShell.Commands.Internal.Format
private TableRowEntry GenerateTableRowEntryFromFromProperties(PSObject so, int enumerationLimit)
{
TableRowEntry tre = new TableRowEntry();
for (int k = 0; k < this.activeAssociationList.Count; k++)
for (int k = 0; k < _activeAssociationList.Count; k++)
{
FormatPropertyField fpf = new FormatPropertyField();
FieldFormattingDirective directive = null;
if (activeAssociationList[k].OriginatingParameter != null)
if (_activeAssociationList[k].OriginatingParameter != null)
{
directive = activeAssociationList[k].OriginatingParameter.GetEntry(FormatParameterDefinitionKeys.FormatStringEntryKey) as FieldFormattingDirective;
directive = _activeAssociationList[k].OriginatingParameter.GetEntry(FormatParameterDefinitionKeys.FormatStringEntryKey) as FieldFormattingDirective;
}
if (directive is null)
@@ -488,7 +486,7 @@ namespace Microsoft.PowerShell.Commands.Internal.Format
directive.isTable = true;
}
fpf.propertyValue = this.GetExpressionDisplayValue(so, enumerationLimit, this.activeAssociationList[k].ResolvedExpression, directive);
fpf.propertyValue = this.GetExpressionDisplayValue(so, enumerationLimit, _activeAssociationList[k].ResolvedExpression, directive);
tre.formatPropertyFieldList.Add(fpf);
}
@@ -15,6 +15,40 @@ namespace Microsoft.PowerShell.Commands.Internal.Format
base.Initialize(errorContext, expressionFactory, so, db, parameters);
}
/// <summary>
/// Builds the raw association list for wide formatting.
/// </summary>
protected override List<MshResolvedExpressionParameterAssociation> BuildRawAssociationList(PSObject so, List<MshParameter> propertyList)
{
// check if we received properties from the command line
if (propertyList is not null && propertyList.Count > 0)
{
return AssociationManager.ExpandParameters(propertyList, so);
}
// we did not get any properties:
// try to get the display property of the object
PSPropertyExpression displayNameExpression = PSObjectHelper.GetDisplayNameExpression(so, this.expressionFactory);
if (displayNameExpression is not null)
{
return new List<MshResolvedExpressionParameterAssociation>
{
new MshResolvedExpressionParameterAssociation(null, displayNameExpression)
};
}
// try to get the default property set (we will use the first property)
var list = AssociationManager.ExpandDefaultPropertySet(so, this.expressionFactory);
if (list.Count == 0)
{
// we failed to get anything from the default property set
// just get all the properties
list = AssociationManager.ExpandAll(so);
}
return list;
}
internal override FormatStartData GenerateStartData(PSObject so)
{
FormatStartData startFormat = base.GenerateStartData(so);
@@ -129,20 +163,17 @@ namespace Microsoft.PowerShell.Commands.Internal.Format
private WideViewEntry GenerateWideViewEntryFromProperties(PSObject so, int enumerationLimit)
{
// compute active properties every time
if (this.activeAssociationList == null)
{
SetUpActiveProperty(so);
}
// Build active association list (with ExcludeProperty filter applied)
var associationList = BuildActiveAssociationList(so);
WideViewEntry wve = new WideViewEntry();
FormatPropertyField fpf = new FormatPropertyField();
wve.formatPropertyField = fpf;
if (this.activeAssociationList.Count > 0)
if (associationList.Count > 0)
{
// get the first one
MshResolvedExpressionParameterAssociation a = this.activeAssociationList[0];
MshResolvedExpressionParameterAssociation a = associationList[0];
FieldFormattingDirective directive = null;
if (a.OriginatingParameter != null)
{
@@ -151,44 +182,7 @@ namespace Microsoft.PowerShell.Commands.Internal.Format
fpf.propertyValue = this.GetExpressionDisplayValue(so, enumerationLimit, a.ResolvedExpression, directive);
}
this.activeAssociationList = null;
return wve;
}
private void SetUpActiveProperty(PSObject so)
{
List<MshParameter> rawMshParameterList = this.parameters?.mshParameterList;
// check if we received properties from the command line
if (rawMshParameterList is not null && rawMshParameterList.Count > 0)
{
this.activeAssociationList = AssociationManager.ExpandParameters(rawMshParameterList, so);
}
else
{
// we did not get any properties:
// try to get the display property of the object
PSPropertyExpression displayNameExpression = PSObjectHelper.GetDisplayNameExpression(so, this.expressionFactory);
if (displayNameExpression is not null)
{
this.activeAssociationList = new List<MshResolvedExpressionParameterAssociation>();
this.activeAssociationList.Add(new MshResolvedExpressionParameterAssociation(null, displayNameExpression));
}
else
{
// try to get the default property set (we will use the first property)
this.activeAssociationList = AssociationManager.ExpandDefaultPropertySet(so, this.expressionFactory);
if (this.activeAssociationList.Count == 0)
{
// we failed to get anything from the default property set
// just get all the properties
this.activeAssociationList = AssociationManager.ExpandAll(so);
}
}
}
ApplyExcludePropertyFilter();
}
}
}